mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-15 14:34:54 -05:00
feat(ui): standardize and clean up workflow loading hooks and logic
This commit is contained in:
@@ -4,7 +4,7 @@ import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useAssertSingleton } from 'common/hooks/useAssertSingleton';
|
||||
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
||||
import { selectWorkflowIsTouched, workflowModeChanged } from 'features/nodes/store/workflowSlice';
|
||||
import { useGetAndLoadLibraryWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadLibraryWorkflow';
|
||||
import { useLoadWorkflowFromLibrary } from 'features/workflowLibrary/hooks/useLoadWorkflowFromLibrary';
|
||||
import { atom } from 'nanostores';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -15,7 +15,7 @@ const cleanup = () => $workflowToLoad.set(null);
|
||||
export const useLoadWorkflow = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const workflowLibraryModal = useWorkflowLibraryModal();
|
||||
const { getAndLoadWorkflow } = useGetAndLoadLibraryWorkflow();
|
||||
const loadWorkflowFromLibrary = useLoadWorkflowFromLibrary();
|
||||
|
||||
const isTouched = useAppSelector(selectWorkflowIsTouched);
|
||||
|
||||
@@ -25,11 +25,14 @@ export const useLoadWorkflow = () => {
|
||||
return;
|
||||
}
|
||||
const { workflowId, mode } = workflow;
|
||||
await getAndLoadWorkflow(workflowId);
|
||||
dispatch(workflowModeChanged(mode));
|
||||
await loadWorkflowFromLibrary(workflowId, {
|
||||
onSuccess: () => {
|
||||
dispatch(workflowModeChanged(mode));
|
||||
},
|
||||
});
|
||||
cleanup();
|
||||
workflowLibraryModal.close();
|
||||
}, [dispatch, getAndLoadWorkflow, workflowLibraryModal]);
|
||||
}, [dispatch, loadWorkflowFromLibrary, workflowLibraryModal]);
|
||||
|
||||
const loadWithDialog = useCallback(
|
||||
(workflowId: string, mode: 'view' | 'edit') => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { graphToWorkflow } from 'features/nodes/util/workflow/graphToWorkflow';
|
||||
import { useLoadWorkflow } from 'features/workflowLibrary/hooks/useLoadWorkflow';
|
||||
import { useValidateAndLoadWorkflow } from 'features/workflowLibrary/hooks/useValidateAndLoadWorkflow';
|
||||
import { atom } from 'nanostores';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
@@ -37,16 +37,16 @@ export const useLoadWorkflowFromGraphModal = () => {
|
||||
|
||||
export const LoadWorkflowFromGraphModal = () => {
|
||||
const { t } = useTranslation();
|
||||
const _loadWorkflow = useLoadWorkflow();
|
||||
const validateAndLoadWorkflow = useValidateAndLoadWorkflow();
|
||||
const { isOpen, onClose } = useLoadWorkflowFromGraphModal();
|
||||
const [graphRaw, setGraphRaw] = useState<string>('');
|
||||
const [workflowRaw, setWorkflowRaw] = useState<string>('');
|
||||
const [unvalidatedWorkflow, setUnvalidatedWorkflow] = 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);
|
||||
setUnvalidatedWorkflow(e.target.value);
|
||||
}, []);
|
||||
const onChangeShouldAutoLayout = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
setShouldAutoLayout(e.target.checked);
|
||||
@@ -54,12 +54,12 @@ export const LoadWorkflowFromGraphModal = () => {
|
||||
const parse = useCallback(() => {
|
||||
const graph = JSON.parse(graphRaw);
|
||||
const workflow = graphToWorkflow(graph, shouldAutoLayout);
|
||||
setWorkflowRaw(JSON.stringify(workflow, null, 2));
|
||||
setUnvalidatedWorkflow(JSON.stringify(workflow, null, 2));
|
||||
}, [graphRaw, shouldAutoLayout]);
|
||||
const loadWorkflow = useCallback(() => {
|
||||
_loadWorkflow({ workflow: workflowRaw, graph: null });
|
||||
const loadWorkflow = useCallback(async () => {
|
||||
await validateAndLoadWorkflow(unvalidatedWorkflow);
|
||||
onClose();
|
||||
}, [_loadWorkflow, onClose, workflowRaw]);
|
||||
}, [validateAndLoadWorkflow, onClose, unvalidatedWorkflow]);
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={onClose} isCentered useInert={false}>
|
||||
<ModalOverlay />
|
||||
@@ -95,7 +95,7 @@ export const LoadWorkflowFromGraphModal = () => {
|
||||
<FormLabel>{t('nodes.workflow')}</FormLabel>
|
||||
<Textarea
|
||||
h="full"
|
||||
value={workflowRaw}
|
||||
value={unvalidatedWorkflow}
|
||||
fontFamily="monospace"
|
||||
whiteSpace="pre-wrap"
|
||||
overflowWrap="normal"
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
import { Button } from '@invoke-ai/ui-library';
|
||||
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
||||
import { saveWorkflowAs } from 'features/workflowLibrary/components/SaveWorkflowAsDialog';
|
||||
import { useLoadWorkflowFromFile } from 'features/workflowLibrary/hooks/useLoadWorkflowFromFile';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiUploadSimpleBold } from 'react-icons/pi';
|
||||
|
||||
export const UploadWorkflowButton = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const resetRef = useRef<() => void>(null);
|
||||
const workflowLibraryModal = useWorkflowLibraryModal();
|
||||
|
||||
const loadWorkflowFromFile = useLoadWorkflowFromFile({
|
||||
resetRef,
|
||||
onSuccess: (workflow) => {
|
||||
workflowLibraryModal.close();
|
||||
saveWorkflowAs(workflow);
|
||||
},
|
||||
});
|
||||
const loadWorkflowFromFile = useLoadWorkflowFromFile();
|
||||
|
||||
const onDropAccepted = useCallback(
|
||||
(files: File[]) => {
|
||||
if (!files[0]) {
|
||||
([file]: File[]) => {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
loadWorkflowFromFile(files[0]);
|
||||
loadWorkflowFromFile(file, {
|
||||
onSuccess: () => {
|
||||
workflowLibraryModal.close();
|
||||
},
|
||||
});
|
||||
},
|
||||
[loadWorkflowFromFile]
|
||||
[loadWorkflowFromFile, workflowLibraryModal]
|
||||
);
|
||||
|
||||
const { getInputProps, getRootProps } = useDropzone({
|
||||
@@ -36,6 +32,7 @@ export const UploadWorkflowButton = memo(() => {
|
||||
noDrag: true,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
import { MenuItem } from '@invoke-ai/ui-library';
|
||||
import { useWorkflowLibraryModal } from 'features/nodes/store/workflowLibraryModal';
|
||||
import { saveWorkflowAs } from 'features/workflowLibrary/components/SaveWorkflowAsDialog';
|
||||
import { useLoadWorkflowFromFile } from 'features/workflowLibrary/hooks/useLoadWorkflowFromFile';
|
||||
import { memo, useCallback, useRef } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiUploadSimpleBold } from 'react-icons/pi';
|
||||
|
||||
const UploadWorkflowMenuItem = () => {
|
||||
const { t } = useTranslation();
|
||||
const resetRef = useRef<() => void>(null);
|
||||
const workflowLibraryModal = useWorkflowLibraryModal();
|
||||
const loadWorkflowFromFile = useLoadWorkflowFromFile({
|
||||
resetRef,
|
||||
onSuccess: (workflow) => {
|
||||
workflowLibraryModal.close();
|
||||
saveWorkflowAs(workflow);
|
||||
},
|
||||
});
|
||||
|
||||
const loadWorkflowFromFile = useLoadWorkflowFromFile();
|
||||
|
||||
const onDropAccepted = useCallback(
|
||||
(files: File[]) => {
|
||||
if (!files[0]) {
|
||||
([file]: File[]) => {
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
loadWorkflowFromFile(files[0]);
|
||||
loadWorkflowFromFile(file, {
|
||||
onSuccess: () => {
|
||||
workflowLibraryModal.close();
|
||||
},
|
||||
});
|
||||
},
|
||||
[loadWorkflowFromFile]
|
||||
[loadWorkflowFromFile, workflowLibraryModal]
|
||||
);
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
@@ -35,6 +32,7 @@ const UploadWorkflowMenuItem = () => {
|
||||
noDrag: true,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<MenuItem as="button" icon={<PiUploadSimpleBold />} {...getRootProps()}>
|
||||
{t('workflows.uploadWorkflow')}
|
||||
|
||||
Reference in New Issue
Block a user