mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-03 13:45:02 -05:00
feat(ui): add graph-to-workflow debug helper
This is intended for debug usage, so it's hidden away in the workflow library `...` menu. Hold shift to see the button for it. - Paste a graph (from a network request, for example) and then click the convert button to convert it to a workflow. - Disable auto layout to stack the nodes with an offset (try it out). If you change this, you must re-convert to get the changes. - Edit the workflow JSON if you need to tweak something before loading it.
This commit is contained in:
committed by
Kent Keirsey
parent
dca30d5462
commit
b58494c420
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormLabel,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Spacer,
|
||||
Textarea,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useAppDispatch } from 'app/store/storeHooks';
|
||||
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
||||
import { graphToWorkflow } from 'features/nodes/util/workflow/graphToWorkflow';
|
||||
import { atom } from 'nanostores';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const $isOpen = atom<boolean>(false);
|
||||
|
||||
export const useLoadWorkflowFromGraphModal = () => {
|
||||
const isOpen = useStore($isOpen);
|
||||
const onOpen = useCallback(() => {
|
||||
$isOpen.set(true);
|
||||
}, []);
|
||||
const onClose = useCallback(() => {
|
||||
$isOpen.set(false);
|
||||
}, []);
|
||||
|
||||
return { isOpen, onOpen, onClose };
|
||||
};
|
||||
|
||||
export const LoadWorkflowFromGraphModal = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const { isOpen, onClose } = useLoadWorkflowFromGraphModal();
|
||||
const [graphRaw, setGraphRaw] = useState<string>('');
|
||||
const [workflowRaw, setWorkflowRaw] = useState<string>('');
|
||||
const [shouldAutoLayout, setShouldAutoLayout] = useState(true);
|
||||
const onChangeGraphRaw = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setGraphRaw(e.target.value);
|
||||
}, []);
|
||||
const onChangeWorkflowRaw = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setWorkflowRaw(e.target.value);
|
||||
}, []);
|
||||
const onChangeShouldAutoLayout = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
setShouldAutoLayout(e.target.checked);
|
||||
}, []);
|
||||
const parse = useCallback(() => {
|
||||
const graph = JSON.parse(graphRaw);
|
||||
const workflow = graphToWorkflow(graph, shouldAutoLayout);
|
||||
setWorkflowRaw(JSON.stringify(workflow, null, 2));
|
||||
}, [graphRaw, shouldAutoLayout]);
|
||||
const loadWorkflow = useCallback(() => {
|
||||
const workflow = JSON.parse(workflowRaw);
|
||||
dispatch(workflowLoadRequested({ workflow, asCopy: true }));
|
||||
onClose();
|
||||
}, [dispatch, onClose, workflowRaw]);
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} isCentered>
|
||||
<ModalOverlay />
|
||||
<ModalContent w="80vw" h="80vh" maxW="unset" maxH="unset">
|
||||
<ModalHeader>{t('workflows.loadFromGraph')}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody as={Flex} flexDir="column" gap={4} w="full" h="full" pb={4}>
|
||||
<Flex gap={4}>
|
||||
<Button onClick={parse} size="sm" flexShrink={0}>
|
||||
{t('workflows.convertGraph')}
|
||||
</Button>
|
||||
<FormControl>
|
||||
<FormLabel>{t('workflows.autoLayout')}</FormLabel>
|
||||
<Checkbox isChecked={shouldAutoLayout} onChange={onChangeShouldAutoLayout} />
|
||||
</FormControl>
|
||||
<Spacer />
|
||||
<Button onClick={loadWorkflow} size="sm" flexShrink={0}>
|
||||
{t('workflows.loadWorkflow')}
|
||||
</Button>
|
||||
</Flex>
|
||||
<FormControl orientation="vertical" h="50%">
|
||||
<FormLabel>{t('nodes.graph')}</FormLabel>
|
||||
<Textarea
|
||||
h="full"
|
||||
value={graphRaw}
|
||||
fontFamily="monospace"
|
||||
whiteSpace="pre-wrap"
|
||||
overflowWrap="normal"
|
||||
onChange={onChangeGraphRaw}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl orientation="vertical" h="50%">
|
||||
<FormLabel>{t('nodes.workflow')}</FormLabel>
|
||||
<Textarea
|
||||
h="full"
|
||||
value={workflowRaw}
|
||||
fontFamily="monospace"
|
||||
whiteSpace="pre-wrap"
|
||||
overflowWrap="normal"
|
||||
onChange={onChangeWorkflowRaw}
|
||||
/>
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import { MenuItem } from '@invoke-ai/ui-library';
|
||||
import { useLoadWorkflowFromGraphModal } from 'features/workflowLibrary/components/LoadWorkflowFromGraphModal/LoadWorkflowFromGraphModal';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiFlaskBold } from 'react-icons/pi';
|
||||
|
||||
const LoadWorkflowFromGraphMenuItem = () => {
|
||||
const { t } = useTranslation();
|
||||
const { onOpen } = useLoadWorkflowFromGraphModal();
|
||||
|
||||
return (
|
||||
<MenuItem as="button" icon={<PiFlaskBold />} onClick={onOpen}>
|
||||
{t('workflows.loadFromGraph')}
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(LoadWorkflowFromGraphMenuItem);
|
||||
@@ -6,8 +6,10 @@ import {
|
||||
MenuList,
|
||||
useDisclosure,
|
||||
useGlobalMenuClose,
|
||||
useShiftModifier,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import DownloadWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/DownloadWorkflowMenuItem';
|
||||
import LoadWorkflowFromGraphMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/LoadWorkflowFromGraphMenuItem';
|
||||
import { NewWorkflowMenuItem } from 'features/workflowLibrary/components/WorkflowLibraryMenu/NewWorkflowMenuItem';
|
||||
import SaveWorkflowAsMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowAsMenuItem';
|
||||
import SaveWorkflowMenuItem from 'features/workflowLibrary/components/WorkflowLibraryMenu/SaveWorkflowMenuItem';
|
||||
@@ -20,6 +22,7 @@ import { PiDotsThreeOutlineFill } from 'react-icons/pi';
|
||||
const WorkflowLibraryMenu = () => {
|
||||
const { t } = useTranslation();
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const shift = useShiftModifier();
|
||||
useGlobalMenuClose(onClose);
|
||||
return (
|
||||
<Menu isOpen={isOpen} onOpen={onOpen} onClose={onClose}>
|
||||
@@ -38,6 +41,8 @@ const WorkflowLibraryMenu = () => {
|
||||
<DownloadWorkflowMenuItem />
|
||||
<MenuDivider />
|
||||
<SettingsMenuItem />
|
||||
{shift && <MenuDivider />}
|
||||
{shift && <LoadWorkflowFromGraphMenuItem />}
|
||||
</MenuList>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user