mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): modals not staying open
TBH not sure exactly why this broke. Fixed by rollback back the use of a render prop in favor of global state. Also revised the API of `useBoolean` and `buildUseBoolean`.
This commit is contained in:
parent
2e84327ca4
commit
ab11d9af8e
@ -1,52 +1,53 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import type { WritableAtom } from 'nanostores';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { atom } from 'nanostores';
|
||||
|
||||
export const useBoolean = (initialValue: boolean) => {
|
||||
const [isTrue, set] = useState(initialValue);
|
||||
const setTrue = useCallback(() => set(true), []);
|
||||
const setFalse = useCallback(() => set(false), []);
|
||||
const toggle = useCallback(() => set((v) => !v), []);
|
||||
type UseBoolean = {
|
||||
isTrue: boolean;
|
||||
setTrue: () => void;
|
||||
setFalse: () => void;
|
||||
set: (value: boolean) => void;
|
||||
toggle: () => void;
|
||||
};
|
||||
|
||||
const api = useMemo(
|
||||
() => ({
|
||||
/**
|
||||
* Creates a hook to manage a boolean state. The boolean is stored in a nanostores atom.
|
||||
* Returns a tuple containing the hook and the atom. Use this for global boolean state.
|
||||
* @param initialValue Initial value of the boolean
|
||||
*/
|
||||
export const buildUseBoolean = (initialValue: boolean): [() => UseBoolean, WritableAtom<boolean>] => {
|
||||
const $boolean = atom(initialValue);
|
||||
|
||||
const setTrue = () => {
|
||||
$boolean.set(true);
|
||||
};
|
||||
const setFalse = () => {
|
||||
$boolean.set(false);
|
||||
};
|
||||
const set = (value: boolean) => {
|
||||
$boolean.set(value);
|
||||
};
|
||||
const toggle = () => {
|
||||
$boolean.set(!$boolean.get());
|
||||
};
|
||||
|
||||
const useBoolean = () => {
|
||||
const isTrue = useStore($boolean);
|
||||
|
||||
return {
|
||||
isTrue,
|
||||
set,
|
||||
setTrue,
|
||||
setFalse,
|
||||
set,
|
||||
toggle,
|
||||
}),
|
||||
[isTrue, set, setTrue, setFalse, toggle]
|
||||
);
|
||||
|
||||
return api;
|
||||
};
|
||||
|
||||
export const buildUseBoolean = ($boolean: WritableAtom<boolean>) => {
|
||||
return () => {
|
||||
const setTrue = useCallback(() => {
|
||||
$boolean.set(true);
|
||||
}, []);
|
||||
const setFalse = useCallback(() => {
|
||||
$boolean.set(false);
|
||||
}, []);
|
||||
const set = useCallback((value: boolean) => {
|
||||
$boolean.set(value);
|
||||
}, []);
|
||||
const toggle = useCallback(() => {
|
||||
$boolean.set(!$boolean.get());
|
||||
}, []);
|
||||
|
||||
const api = useMemo(
|
||||
() => ({
|
||||
setTrue,
|
||||
setFalse,
|
||||
set,
|
||||
toggle,
|
||||
$boolean,
|
||||
}),
|
||||
[set, setFalse, setTrue, toggle]
|
||||
);
|
||||
|
||||
return api;
|
||||
};
|
||||
};
|
||||
|
||||
return [useBoolean, $boolean] as const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to manage a boolean state. Use this for a local boolean state.
|
||||
* @param initialValue Initial value of the boolean
|
||||
*/
|
||||
export const useBoolean = (initialValue: boolean) => buildUseBoolean(initialValue)[0]();
|
||||
|
@ -4,6 +4,7 @@ import { Flex } from '@invoke-ai/ui-library';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import { AddNodeCmdk } from 'features/nodes/components/flow/AddNodeCmdk/AddNodeCmdk';
|
||||
import TopPanel from 'features/nodes/components/flow/panels/TopPanel/TopPanel';
|
||||
import WorkflowEditorSettings from 'features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings';
|
||||
import { LoadWorkflowFromGraphModal } from 'features/workflowLibrary/components/LoadWorkflowFromGraphModal/LoadWorkflowFromGraphModal';
|
||||
import { SaveWorkflowAsDialog } from 'features/workflowLibrary/components/SaveWorkflowAsDialog/SaveWorkflowAsDialog';
|
||||
import { memo } from 'react';
|
||||
@ -39,6 +40,7 @@ const NodeEditor = () => {
|
||||
<LoadWorkflowFromGraphModal />
|
||||
</>
|
||||
)}
|
||||
<WorkflowEditorSettings />
|
||||
{isLoading && <IAINoContentFallback label={t('nodes.loadingNodes')} icon={MdDeviceHub} />}
|
||||
</Flex>
|
||||
);
|
||||
|
@ -163,7 +163,6 @@ const cmdkRootSx: SystemStyleObject = {
|
||||
export const AddNodeCmdk = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const addNodeCmdk = useAddNodeCmdk();
|
||||
const addNodeCmdkIsOpen = useStore(addNodeCmdk.$boolean);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const addNode = useAddNode();
|
||||
@ -192,7 +191,7 @@ export const AddNodeCmdk = memo(() => {
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={addNodeCmdkIsOpen}
|
||||
isOpen={addNodeCmdk.isTrue}
|
||||
onClose={onClose}
|
||||
useInert={false}
|
||||
initialFocusRef={inputRef}
|
||||
|
@ -14,9 +14,9 @@ import {
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Switch,
|
||||
useDisclosure,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { buildUseBoolean } from 'common/hooks/useBoolean';
|
||||
import ReloadNodeTemplatesButton from 'features/nodes/components/flow/panels/TopRightPanel/ReloadSchemaButton';
|
||||
import {
|
||||
selectionModeChanged,
|
||||
@ -32,20 +32,17 @@ import {
|
||||
shouldSnapToGridChanged,
|
||||
shouldValidateGraphChanged,
|
||||
} from 'features/nodes/store/workflowSettingsSlice';
|
||||
import type { ChangeEvent, ReactNode } from 'react';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SelectionMode } from 'reactflow';
|
||||
|
||||
const formLabelProps: FormLabelProps = { flexGrow: 1 };
|
||||
export const [useWorkflowEditorSettingsModal] = buildUseBoolean(false);
|
||||
|
||||
type Props = {
|
||||
children: (props: { onOpen: () => void }) => ReactNode;
|
||||
};
|
||||
|
||||
const WorkflowEditorSettings = ({ children }: Props) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const WorkflowEditorSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const modal = useWorkflowEditorSettingsModal();
|
||||
|
||||
const shouldSnapToGrid = useAppSelector(selectShouldSnapToGrid);
|
||||
const selectionMode = useAppSelector(selectSelectionMode);
|
||||
@ -99,76 +96,72 @@ const WorkflowEditorSettings = ({ children }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
{children({ onOpen })}
|
||||
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="2xl" isCentered useInert={false}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>{t('nodes.workflowSettings')}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex flexDirection="column" gap={4} py={4}>
|
||||
<Heading size="sm">{t('parameters.general')}</Heading>
|
||||
<FormControlGroup orientation="vertical" formLabelProps={formLabelProps}>
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.animatedEdges')}</FormLabel>
|
||||
<Switch onChange={handleChangeShouldAnimate} isChecked={shouldAnimateEdges} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.animatedEdgesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.snapToGrid')}</FormLabel>
|
||||
<Switch isChecked={shouldSnapToGrid} onChange={handleChangeShouldSnap} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.snapToGridHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.colorCodeEdges')}</FormLabel>
|
||||
<Switch isChecked={shouldColorEdges} onChange={handleChangeShouldColor} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.colorCodeEdgesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.fullyContainNodes')}</FormLabel>
|
||||
<Switch isChecked={selectionMode === SelectionMode.Full} onChange={handleChangeSelectionMode} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.fullyContainNodesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.showEdgeLabels')}</FormLabel>
|
||||
<Switch isChecked={shouldShowEdgeLabels} onChange={handleChangeShouldShowEdgeLabels} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.showEdgeLabelsHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<Heading size="sm" pt={4}>
|
||||
{t('common.advanced')}
|
||||
</Heading>
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.validateConnections')}</FormLabel>
|
||||
<Switch isChecked={shouldValidateGraph} onChange={handleChangeShouldValidate} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.validateConnectionsHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
</FormControlGroup>
|
||||
<ReloadNodeTemplatesButton />
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
<Modal isOpen={modal.isTrue} onClose={modal.setFalse} size="2xl" isCentered useInert={false}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>{t('nodes.workflowSettings')}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Flex flexDirection="column" gap={4} py={4}>
|
||||
<Heading size="sm">{t('parameters.general')}</Heading>
|
||||
<FormControlGroup orientation="vertical" formLabelProps={formLabelProps}>
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.animatedEdges')}</FormLabel>
|
||||
<Switch onChange={handleChangeShouldAnimate} isChecked={shouldAnimateEdges} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.animatedEdgesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.snapToGrid')}</FormLabel>
|
||||
<Switch isChecked={shouldSnapToGrid} onChange={handleChangeShouldSnap} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.snapToGridHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.colorCodeEdges')}</FormLabel>
|
||||
<Switch isChecked={shouldColorEdges} onChange={handleChangeShouldColor} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.colorCodeEdgesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.fullyContainNodes')}</FormLabel>
|
||||
<Switch isChecked={selectionMode === SelectionMode.Full} onChange={handleChangeSelectionMode} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.fullyContainNodesHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.showEdgeLabels')}</FormLabel>
|
||||
<Switch isChecked={shouldShowEdgeLabels} onChange={handleChangeShouldShowEdgeLabels} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.showEdgeLabelsHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
<Heading size="sm" pt={4}>
|
||||
{t('common.advanced')}
|
||||
</Heading>
|
||||
<FormControl>
|
||||
<Flex w="full">
|
||||
<FormLabel>{t('nodes.validateConnections')}</FormLabel>
|
||||
<Switch isChecked={shouldValidateGraph} onChange={handleChangeShouldValidate} />
|
||||
</Flex>
|
||||
<FormHelperText>{t('nodes.validateConnectionsHelp')}</FormHelperText>
|
||||
</FormControl>
|
||||
<Divider />
|
||||
</FormControlGroup>
|
||||
<ReloadNodeTemplatesButton />
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,12 +2,12 @@ import { useStore } from '@nanostores/react';
|
||||
import { useAppStore } from 'app/store/storeHooks';
|
||||
import { $mouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
|
||||
import {
|
||||
$addNodeCmdk,
|
||||
$didUpdateEdge,
|
||||
$edgePendingUpdate,
|
||||
$pendingConnection,
|
||||
$templates,
|
||||
edgesChanged,
|
||||
useAddNodeCmdk,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { getFirstValidConnection } from 'features/nodes/store/util/getFirstValidConnection';
|
||||
@ -21,6 +21,7 @@ export const useConnection = () => {
|
||||
const store = useAppStore();
|
||||
const templates = useStore($templates);
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const addNodeCmdk = useAddNodeCmdk();
|
||||
|
||||
const onConnectStart = useCallback<OnConnectStart>(
|
||||
(event, { nodeId, handleId, handleType }) => {
|
||||
@ -107,9 +108,9 @@ export const useConnection = () => {
|
||||
$pendingConnection.set(null);
|
||||
} else {
|
||||
// The mouse is not over a node - we should open the add node popover
|
||||
$addNodeCmdk.set(true);
|
||||
addNodeCmdk.setTrue();
|
||||
}
|
||||
}, [store, templates, updateNodeInternals]);
|
||||
}, [addNodeCmdk, store, templates, updateNodeInternals]);
|
||||
|
||||
const api = useMemo(() => ({ onConnectStart, onConnect, onConnectEnd }), [onConnectStart, onConnect, onConnectEnd]);
|
||||
return api;
|
||||
|
@ -444,8 +444,7 @@ export const $didUpdateEdge = atom(false);
|
||||
export const $lastEdgeUpdateMouseEvent = atom<MouseEvent | null>(null);
|
||||
|
||||
export const $viewport = atom<Viewport>({ x: 0, y: 0, zoom: 1 });
|
||||
export const $addNodeCmdk = atom(false);
|
||||
export const useAddNodeCmdk = buildUseBoolean($addNodeCmdk);
|
||||
export const [useAddNodeCmdk, $addNodeCmdk] = buildUseBoolean(false);
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateNodesState = (state: any): any => {
|
||||
|
@ -5,19 +5,16 @@ import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { buildUseBoolean } from 'common/hooks/useBoolean';
|
||||
import { listCursorChanged, listPriorityChanged } from 'features/queue/store/queueSlice';
|
||||
import { toast } from 'features/toast/toast';
|
||||
import { atom } from 'nanostores';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useClearQueueMutation, useGetQueueStatusQuery } from 'services/api/endpoints/queue';
|
||||
|
||||
const $boolean = atom(false);
|
||||
const useClearQueueConfirmationAlertDialog = buildUseBoolean($boolean);
|
||||
const [useClearQueueConfirmationAlertDialog] = buildUseBoolean(false);
|
||||
|
||||
export const useClearQueue = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const dialog = useClearQueueConfirmationAlertDialog();
|
||||
const isOpen = useStore(dialog.$boolean);
|
||||
const { data: queueStatus } = useGetQueueStatusQuery();
|
||||
const isConnected = useStore($isConnected);
|
||||
const [trigger, { isLoading }] = useClearQueueMutation({
|
||||
@ -51,7 +48,7 @@ export const useClearQueue = () => {
|
||||
|
||||
return {
|
||||
clearQueue,
|
||||
isOpen,
|
||||
isOpen: dialog.isTrue,
|
||||
openDialog: dialog.setTrue,
|
||||
closeDialog: dialog.setFalse,
|
||||
isLoading,
|
||||
|
@ -8,31 +8,27 @@ import {
|
||||
ModalOverlay,
|
||||
Text,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { buildUseBoolean } from 'common/hooks/useBoolean';
|
||||
import { atom } from 'nanostores';
|
||||
import { memo, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const $refreshAfterResetModalState = atom(false);
|
||||
export const useRefreshAfterResetModal = buildUseBoolean($refreshAfterResetModalState);
|
||||
export const [useRefreshAfterResetModal] = buildUseBoolean(false);
|
||||
|
||||
const RefreshAfterResetModal = () => {
|
||||
const { t } = useTranslation();
|
||||
const [countdown, setCountdown] = useState(3);
|
||||
|
||||
const refreshModal = useRefreshAfterResetModal();
|
||||
const isOpen = useStore(refreshModal.$boolean);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
if (!refreshModal.isTrue) {
|
||||
return;
|
||||
}
|
||||
const i = window.setInterval(() => setCountdown((prev) => prev - 1), 1000);
|
||||
return () => {
|
||||
window.clearInterval(i);
|
||||
};
|
||||
}, [isOpen]);
|
||||
}, [refreshModal.isTrue]);
|
||||
|
||||
useEffect(() => {
|
||||
if (countdown <= 0) {
|
||||
@ -44,7 +40,7 @@ const RefreshAfterResetModal = () => {
|
||||
<>
|
||||
<Modal
|
||||
closeOnOverlayClick={false}
|
||||
isOpen={isOpen}
|
||||
isOpen={refreshModal.isTrue}
|
||||
onClose={refreshModal.setFalse}
|
||||
isCentered
|
||||
closeOnEsc={false}
|
||||
|
@ -14,7 +14,6 @@ import {
|
||||
Switch,
|
||||
Text,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { InformationalPopover } from 'common/components/InformationalPopover/InformationalPopover';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
@ -42,7 +41,6 @@ import {
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { selectShouldShowProgressInViewer } from 'features/ui/store/uiSelectors';
|
||||
import { setShouldShowProgressInViewer } from 'features/ui/store/uiSlice';
|
||||
import { atom } from 'nanostores';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -68,8 +66,7 @@ type SettingsModalProps = {
|
||||
config?: ConfigOptions;
|
||||
};
|
||||
|
||||
const $settingsModal = atom(false);
|
||||
export const useSettingsModal = buildUseBoolean($settingsModal);
|
||||
export const [useSettingsModal] = buildUseBoolean(false);
|
||||
|
||||
const SettingsModal = ({ config = defaultConfig }: SettingsModalProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
@ -96,7 +93,6 @@ const SettingsModal = ({ config = defaultConfig }: SettingsModalProps) => {
|
||||
refetchIntermediatesCount,
|
||||
} = useClearIntermediates(Boolean(config?.shouldShowClearIntermediates));
|
||||
const settingsModal = useSettingsModal();
|
||||
const settingsModalIsOpen = useStore(settingsModal.$boolean);
|
||||
const refreshModal = useRefreshAfterResetModal();
|
||||
|
||||
const shouldUseCpuNoise = useAppSelector(selectShouldUseCPUNoise);
|
||||
@ -110,10 +106,10 @@ const SettingsModal = ({ config = defaultConfig }: SettingsModalProps) => {
|
||||
const clearStorage = useClearStorage();
|
||||
|
||||
useEffect(() => {
|
||||
if (settingsModalIsOpen && Boolean(config?.shouldShowClearIntermediates)) {
|
||||
if (settingsModal.isTrue && Boolean(config?.shouldShowClearIntermediates)) {
|
||||
refetchIntermediatesCount();
|
||||
}
|
||||
}, [config?.shouldShowClearIntermediates, refetchIntermediatesCount, settingsModalIsOpen]);
|
||||
}, [config?.shouldShowClearIntermediates, refetchIntermediatesCount, settingsModal.isTrue]);
|
||||
|
||||
const handleClickResetWebUI = useCallback(() => {
|
||||
clearStorage();
|
||||
@ -165,7 +161,7 @@ const SettingsModal = ({ config = defaultConfig }: SettingsModalProps) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal isOpen={settingsModalIsOpen} onClose={settingsModal.setFalse} size="2xl" isCentered useInert={false}>
|
||||
<Modal isOpen={settingsModal.isTrue} onClose={settingsModal.setFalse} size="2xl" isCentered useInert={false}>
|
||||
<ModalOverlay />
|
||||
<ModalContent maxH="80vh" h="68rem">
|
||||
<ModalHeader bg="none">{t('common.settingsLabel')}</ModalHeader>
|
||||
|
@ -1,20 +1,17 @@
|
||||
import { MenuItem } from '@invoke-ai/ui-library';
|
||||
import WorkflowEditorSettings from 'features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings';
|
||||
import { useWorkflowEditorSettingsModal } from 'features/nodes/components/flow/panels/TopRightPanel/WorkflowEditorSettings';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { RiSettings4Line } from 'react-icons/ri';
|
||||
|
||||
const DownloadWorkflowMenuItem = () => {
|
||||
const { t } = useTranslation();
|
||||
const modal = useWorkflowEditorSettingsModal();
|
||||
|
||||
return (
|
||||
<WorkflowEditorSettings>
|
||||
{({ onOpen }) => (
|
||||
<MenuItem as="button" icon={<RiSettings4Line />} onClick={onOpen}>
|
||||
{t('nodes.workflowSettings')}
|
||||
</MenuItem>
|
||||
)}
|
||||
</WorkflowEditorSettings>
|
||||
<MenuItem as="button" icon={<RiSettings4Line />} onClick={modal.setTrue}>
|
||||
{t('nodes.workflowSettings')}
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user