mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
Add Clear nodes Button (#3747)
Adds a Clear Nodes Button with Confirmation Dialog, I think I Did it
right 😃
I am sure there is a way to make the Confirmation look better and have
Yes/No instead of OK/Cancel
This commit is contained in:
commit
fde9fa2fe4
@ -102,7 +102,8 @@
|
|||||||
"openInNewTab": "Open in New Tab",
|
"openInNewTab": "Open in New Tab",
|
||||||
"dontAskMeAgain": "Don't ask me again",
|
"dontAskMeAgain": "Don't ask me again",
|
||||||
"areYouSure": "Are you sure?",
|
"areYouSure": "Are you sure?",
|
||||||
"imagePrompt": "Image Prompt"
|
"imagePrompt": "Image Prompt",
|
||||||
|
"clearNodes": "Are you sure you want to clear all nodes?"
|
||||||
},
|
},
|
||||||
"gallery": {
|
"gallery": {
|
||||||
"generations": "Generations",
|
"generations": "Generations",
|
||||||
@ -596,7 +597,9 @@
|
|||||||
"initialImageNotSetDesc": "Could not load initial image",
|
"initialImageNotSetDesc": "Could not load initial image",
|
||||||
"nodesSaved": "Nodes Saved",
|
"nodesSaved": "Nodes Saved",
|
||||||
"nodesLoaded": "Nodes Loaded",
|
"nodesLoaded": "Nodes Loaded",
|
||||||
"nodesLoadedFailed": "Failed To Load Nodes"
|
"nodesLoadedFailed": "Failed To Load Nodes",
|
||||||
|
"nodesCleared": "Nodes Cleared"
|
||||||
|
|
||||||
},
|
},
|
||||||
"tooltip": {
|
"tooltip": {
|
||||||
"feature": {
|
"feature": {
|
||||||
@ -681,6 +684,7 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"reloadSchema": "Reload Schema",
|
"reloadSchema": "Reload Schema",
|
||||||
"saveNodes": "Save Nodes",
|
"saveNodes": "Save Nodes",
|
||||||
"loadNodes": "Load Nodes"
|
"loadNodes": "Load Nodes",
|
||||||
|
"clearNodes": "Clear Nodes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import LoadNodesButton from '../ui/LoadNodesButton';
|
|||||||
import NodeInvokeButton from '../ui/NodeInvokeButton';
|
import NodeInvokeButton from '../ui/NodeInvokeButton';
|
||||||
import ReloadSchemaButton from '../ui/ReloadSchemaButton';
|
import ReloadSchemaButton from '../ui/ReloadSchemaButton';
|
||||||
import SaveNodesButton from '../ui/SaveNodesButton';
|
import SaveNodesButton from '../ui/SaveNodesButton';
|
||||||
|
import ClearNodesButton from '../ui/ClearNodesButton';
|
||||||
|
|
||||||
const TopCenterPanel = () => {
|
const TopCenterPanel = () => {
|
||||||
return (
|
return (
|
||||||
@ -16,6 +17,7 @@ const TopCenterPanel = () => {
|
|||||||
<ReloadSchemaButton />
|
<ReloadSchemaButton />
|
||||||
<SaveNodesButton />
|
<SaveNodesButton />
|
||||||
<LoadNodesButton />
|
<LoadNodesButton />
|
||||||
|
<ClearNodesButton />
|
||||||
</HStack>
|
</HStack>
|
||||||
</Panel>
|
</Panel>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogBody,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogOverlay,
|
||||||
|
Button,
|
||||||
|
Text,
|
||||||
|
useDisclosure,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { makeToast } from 'app/components/Toaster';
|
||||||
|
import { RootState } from 'app/store/store';
|
||||||
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||||
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
|
import { clearNodes } from 'features/nodes/store/nodesSlice';
|
||||||
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
|
import { memo, useRef } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { FaTrash } from 'react-icons/fa';
|
||||||
|
|
||||||
|
const ClearNodesButton = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
const cancelRef = useRef<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
const nodes = useAppSelector((state: RootState) => state.nodes.nodes);
|
||||||
|
|
||||||
|
const handleConfirmClear = () => {
|
||||||
|
dispatch(clearNodes());
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
addToast(
|
||||||
|
makeToast({
|
||||||
|
title: t('toast.nodesCleared'),
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<IAIIconButton
|
||||||
|
icon={<FaTrash />}
|
||||||
|
tooltip={t('nodes.clearNodes')}
|
||||||
|
aria-label={t('nodes.clearNodes')}
|
||||||
|
onClick={onOpen}
|
||||||
|
isDisabled={nodes.length === 0}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<AlertDialog
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={onClose}
|
||||||
|
leastDestructiveRef={cancelRef}
|
||||||
|
isCentered
|
||||||
|
>
|
||||||
|
<AlertDialogOverlay />
|
||||||
|
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||||
|
{t('nodes.clearNodes')}
|
||||||
|
</AlertDialogHeader>
|
||||||
|
|
||||||
|
<AlertDialogBody>
|
||||||
|
<Text>{t('common.clearNodes')}</Text>
|
||||||
|
</AlertDialogBody>
|
||||||
|
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<Button ref={cancelRef} onClick={onClose}>
|
||||||
|
{t('common.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button colorScheme="red" ml={3} onClick={handleConfirmClear}>
|
||||||
|
{t('common.accept')}
|
||||||
|
</Button>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(ClearNodesButton);
|
@ -12,6 +12,8 @@ const SaveNodesButton = () => {
|
|||||||
(state: RootState) => state.nodes.editorInstance
|
(state: RootState) => state.nodes.editorInstance
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const nodes = useAppSelector((state: RootState) => state.nodes.nodes);
|
||||||
|
|
||||||
const saveEditorToJSON = useCallback(() => {
|
const saveEditorToJSON = useCallback(() => {
|
||||||
if (editorInstance) {
|
if (editorInstance) {
|
||||||
const editorState = editorInstance.toObject();
|
const editorState = editorInstance.toObject();
|
||||||
@ -38,6 +40,7 @@ const SaveNodesButton = () => {
|
|||||||
tooltip={t('nodes.saveNodes')}
|
tooltip={t('nodes.saveNodes')}
|
||||||
aria-label={t('nodes.saveNodes')}
|
aria-label={t('nodes.saveNodes')}
|
||||||
onClick={saveEditorToJSON}
|
onClick={saveEditorToJSON}
|
||||||
|
isDisabled={nodes.length === 0}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -133,6 +133,10 @@ const nodesSlice = createSlice({
|
|||||||
loadFileEdges: (state, action: PayloadAction<Edge[]>) => {
|
loadFileEdges: (state, action: PayloadAction<Edge[]>) => {
|
||||||
state.edges = action.payload;
|
state.edges = action.payload;
|
||||||
},
|
},
|
||||||
|
clearNodes: (state) => {
|
||||||
|
state.nodes = [];
|
||||||
|
state.edges = [];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
|
builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => {
|
||||||
@ -156,6 +160,7 @@ export const {
|
|||||||
setEditorInstance,
|
setEditorInstance,
|
||||||
loadFileNodes,
|
loadFileNodes,
|
||||||
loadFileEdges,
|
loadFileEdges,
|
||||||
|
clearNodes,
|
||||||
} = nodesSlice.actions;
|
} = nodesSlice.actions;
|
||||||
|
|
||||||
export default nodesSlice.reducer;
|
export default nodesSlice.reducer;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user