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