mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): clean up workflow library hooks
This commit is contained in:
parent
4a14ee0e01
commit
6d7b4b8e8a
@ -14,11 +14,11 @@ import {
|
|||||||
sentImageToCanvas,
|
sentImageToCanvas,
|
||||||
sentImageToImg2Img,
|
sentImageToImg2Img,
|
||||||
} from 'features/gallery/store/actions';
|
} from 'features/gallery/store/actions';
|
||||||
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
|
||||||
import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters';
|
import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters';
|
||||||
import { initialImageSelected } from 'features/parameters/store/actions';
|
import { initialImageSelected } from 'features/parameters/store/actions';
|
||||||
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||||
|
import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { flushSync } from 'react-dom';
|
import { flushSync } from 'react-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@ -36,7 +36,6 @@ import {
|
|||||||
import { FaCircleNodes } from 'react-icons/fa6';
|
import { FaCircleNodes } from 'react-icons/fa6';
|
||||||
import { MdStar, MdStarBorder } from 'react-icons/md';
|
import { MdStar, MdStarBorder } from 'react-icons/md';
|
||||||
import {
|
import {
|
||||||
useLazyGetImageWorkflowQuery,
|
|
||||||
useStarImagesMutation,
|
useStarImagesMutation,
|
||||||
useUnstarImagesMutation,
|
useUnstarImagesMutation,
|
||||||
} from 'services/api/endpoints/images';
|
} from 'services/api/endpoints/images';
|
||||||
@ -62,12 +61,12 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
|
|||||||
imageDTO?.image_name
|
imageDTO?.image_name
|
||||||
);
|
);
|
||||||
|
|
||||||
const [getWorkflow, getWorkflowResult] = useLazyGetImageWorkflowQuery();
|
const { getAndLoadEmbeddedWorkflow, getAndLoadEmbeddedWorkflowResult } =
|
||||||
|
useGetAndLoadEmbeddedWorkflow({});
|
||||||
|
|
||||||
const handleLoadWorkflow = useCallback(() => {
|
const handleLoadWorkflow = useCallback(() => {
|
||||||
getWorkflow(imageDTO.image_name).then((workflow) => {
|
getAndLoadEmbeddedWorkflow(imageDTO.image_name);
|
||||||
dispatch(workflowLoadRequested(workflow.data));
|
}, [getAndLoadEmbeddedWorkflow, imageDTO.image_name]);
|
||||||
});
|
|
||||||
}, [dispatch, getWorkflow, imageDTO]);
|
|
||||||
|
|
||||||
const [starImages] = useStarImagesMutation();
|
const [starImages] = useStarImagesMutation();
|
||||||
const [unstarImages] = useUnstarImagesMutation();
|
const [unstarImages] = useUnstarImagesMutation();
|
||||||
@ -176,7 +175,13 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
|
|||||||
{t('parameters.downloadImage')}
|
{t('parameters.downloadImage')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={getWorkflowResult.isLoading ? <SpinnerIcon /> : <FaCircleNodes />}
|
icon={
|
||||||
|
getAndLoadEmbeddedWorkflowResult.isLoading ? (
|
||||||
|
<SpinnerIcon />
|
||||||
|
) : (
|
||||||
|
<FaCircleNodes />
|
||||||
|
)
|
||||||
|
}
|
||||||
onClickCapture={handleLoadWorkflow}
|
onClickCapture={handleLoadWorkflow}
|
||||||
isDisabled={!imageDTO.has_workflow}
|
isDisabled={!imageDTO.has_workflow}
|
||||||
>
|
>
|
||||||
|
@ -8,7 +8,7 @@ import { FaUpload } from 'react-icons/fa';
|
|||||||
const UploadWorkflowButton = () => {
|
const UploadWorkflowButton = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const resetRef = useRef<() => void>(null);
|
const resetRef = useRef<() => void>(null);
|
||||||
const loadWorkflowFromFile = useLoadWorkflowFromFile(resetRef);
|
const loadWorkflowFromFile = useLoadWorkflowFromFile({ resetRef });
|
||||||
return (
|
return (
|
||||||
<FileButton
|
<FileButton
|
||||||
resetRef={resetRef}
|
resetRef={resetRef}
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
import { useAppSelector } from 'app/store/storeHooks';
|
import { useAppSelector } from 'app/store/storeHooks';
|
||||||
import IAIButton from 'common/components/IAIButton';
|
import IAIButton from 'common/components/IAIButton';
|
||||||
import IAIIconButton from 'common/components/IAIIconButton';
|
import IAIIconButton from 'common/components/IAIIconButton';
|
||||||
import { useSaveWorkflowAs } from 'features/workflowLibrary/hooks/useDuplicateWorkflow';
|
import { useSaveWorkflowAs } from 'features/workflowLibrary/hooks/useSaveWorkflowAs';
|
||||||
import { ChangeEvent, memo, useCallback, useRef, useState } from 'react';
|
import { ChangeEvent, memo, useCallback, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaClone } from 'react-icons/fa';
|
import { FaClone } from 'react-icons/fa';
|
||||||
|
@ -3,15 +3,24 @@ import { useCallback } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useDeleteWorkflowMutation } from 'services/api/endpoints/workflows';
|
import { useDeleteWorkflowMutation } from 'services/api/endpoints/workflows';
|
||||||
|
|
||||||
type UseDeleteLibraryWorkflowArg = {
|
type UseDeleteLibraryWorkflowOptions = {
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
onError?: () => void;
|
onError?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDeleteLibraryWorkflow = ({
|
type UseDeleteLibraryWorkflowReturn = {
|
||||||
|
deleteWorkflow: (workflow_id: string) => Promise<void>;
|
||||||
|
deleteWorkflowResult: ReturnType<typeof useDeleteWorkflowMutation>[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseDeleteLibraryWorkflow = (
|
||||||
|
arg: UseDeleteLibraryWorkflowOptions
|
||||||
|
) => UseDeleteLibraryWorkflowReturn;
|
||||||
|
|
||||||
|
export const useDeleteLibraryWorkflow: UseDeleteLibraryWorkflow = ({
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onError,
|
onError,
|
||||||
}: UseDeleteLibraryWorkflowArg) => {
|
}) => {
|
||||||
const toaster = useAppToaster();
|
const toaster = useAppToaster();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [_deleteWorkflow, deleteWorkflowResult] = useDeleteWorkflowMutation();
|
const [_deleteWorkflow, deleteWorkflowResult] = useDeleteWorkflowMutation();
|
||||||
|
@ -1,21 +1,52 @@
|
|||||||
|
import { useAppToaster } from 'app/components/Toaster';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useLazyGetImageWorkflowQuery } from 'services/api/endpoints/images';
|
import { useLazyGetImageWorkflowQuery } from 'services/api/endpoints/images';
|
||||||
|
|
||||||
export const useGetAndLoadEmbeddedWorkflow = (
|
type UseGetAndLoadEmbeddedWorkflowOptions = {
|
||||||
image_name: string | undefined
|
onSuccess?: () => void;
|
||||||
) => {
|
onError?: () => void;
|
||||||
const dispatch = useAppDispatch();
|
};
|
||||||
const [_trigger, result] = useLazyGetImageWorkflowQuery();
|
|
||||||
const trigger = useCallback(() => {
|
type UseGetAndLoadEmbeddedWorkflowReturn = {
|
||||||
if (!image_name) {
|
getAndLoadEmbeddedWorkflow: (imageName: string) => Promise<void>;
|
||||||
return;
|
getAndLoadEmbeddedWorkflowResult: ReturnType<
|
||||||
}
|
typeof useLazyGetImageWorkflowQuery
|
||||||
_trigger(image_name).then((workflow) => {
|
>[1];
|
||||||
dispatch(workflowLoadRequested(workflow.data));
|
};
|
||||||
});
|
|
||||||
}, [dispatch, _trigger, image_name]);
|
type UseGetAndLoadEmbeddedWorkflow = (
|
||||||
|
options: UseGetAndLoadEmbeddedWorkflowOptions
|
||||||
return [trigger, result];
|
) => UseGetAndLoadEmbeddedWorkflowReturn;
|
||||||
|
|
||||||
|
export const useGetAndLoadEmbeddedWorkflow: UseGetAndLoadEmbeddedWorkflow = ({
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const toaster = useAppToaster();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [_getAndLoadEmbeddedWorkflow, getAndLoadEmbeddedWorkflowResult] =
|
||||||
|
useLazyGetImageWorkflowQuery();
|
||||||
|
const getAndLoadEmbeddedWorkflow = useCallback(
|
||||||
|
async (imageName: string) => {
|
||||||
|
try {
|
||||||
|
const workflow = await _getAndLoadEmbeddedWorkflow(imageName);
|
||||||
|
dispatch(workflowLoadRequested(workflow.data));
|
||||||
|
// No toast - the listener for this action does that after the workflow is loaded
|
||||||
|
onSuccess && onSuccess();
|
||||||
|
} catch {
|
||||||
|
toaster({
|
||||||
|
title: t('toast.problemRetrievingWorkflow'),
|
||||||
|
status: 'error',
|
||||||
|
});
|
||||||
|
onError && onError();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[_getAndLoadEmbeddedWorkflow, dispatch, onSuccess, toaster, t, onError]
|
||||||
|
);
|
||||||
|
|
||||||
|
return { getAndLoadEmbeddedWorkflow, getAndLoadEmbeddedWorkflowResult };
|
||||||
};
|
};
|
||||||
|
@ -5,15 +5,24 @@ import { useCallback } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useLazyGetWorkflowQuery } from 'services/api/endpoints/workflows';
|
import { useLazyGetWorkflowQuery } from 'services/api/endpoints/workflows';
|
||||||
|
|
||||||
type UseGetAndLoadLibraryWorkflowArg = {
|
type UseGetAndLoadLibraryWorkflowOptions = {
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
onError?: () => void;
|
onError?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetAndLoadLibraryWorkflow = ({
|
type UseGetAndLoadLibraryWorkflowReturn = {
|
||||||
|
getAndLoadWorkflow: (workflow_id: string) => Promise<void>;
|
||||||
|
getAndLoadWorkflowResult: ReturnType<typeof useLazyGetWorkflowQuery>[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseGetAndLoadLibraryWorkflow = (
|
||||||
|
arg: UseGetAndLoadLibraryWorkflowOptions
|
||||||
|
) => UseGetAndLoadLibraryWorkflowReturn;
|
||||||
|
|
||||||
|
export const useGetAndLoadLibraryWorkflow: UseGetAndLoadLibraryWorkflow = ({
|
||||||
onSuccess,
|
onSuccess,
|
||||||
onError,
|
onError,
|
||||||
}: UseGetAndLoadLibraryWorkflowArg) => {
|
}) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const toaster = useAppToaster();
|
const toaster = useAppToaster();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
|
|
||||||
import { useLogger } from 'app/logging/useLogger';
|
import { useLogger } from 'app/logging/useLogger';
|
||||||
import { useAppDispatch } from 'app/store/storeHooks';
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
||||||
import { addToast } from 'features/system/store/systemSlice';
|
import { addToast } from 'features/system/store/systemSlice';
|
||||||
import { makeToast } from 'features/system/util/makeToast';
|
import { makeToast } from 'features/system/util/makeToast';
|
||||||
import { RefObject, memo, useCallback } from 'react';
|
import { RefObject, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { ZodError } from 'zod';
|
|
||||||
import { fromZodIssue } from 'zod-validation-error';
|
|
||||||
import { workflowLoadRequested } from 'features/nodes/store/actions';
|
|
||||||
|
|
||||||
export const useLoadWorkflowFromFile = (resetRef: RefObject<() => void>) => {
|
type useLoadWorkflowFromFileOptions = {
|
||||||
|
resetRef: RefObject<() => void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseLoadWorkflowFromFile = (
|
||||||
|
options: useLoadWorkflowFromFileOptions
|
||||||
|
) => (file: File | null) => void;
|
||||||
|
|
||||||
|
export const useLoadWorkflowFromFile: UseLoadWorkflowFromFile = ({
|
||||||
|
resetRef,
|
||||||
|
}) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const logger = useLogger('nodes');
|
const logger = useLogger('nodes');
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -41,6 +48,7 @@ export const useLoadWorkflowFromFile = (resetRef: RefObject<() => void>) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
|
|
||||||
// Reset the file picker internal state so that the same file can be loaded again
|
// Reset the file picker internal state so that the same file can be loaded again
|
||||||
resetRef.current?.();
|
resetRef.current?.();
|
||||||
},
|
},
|
||||||
@ -49,24 +57,3 @@ export const useLoadWorkflowFromFile = (resetRef: RefObject<() => void>) => {
|
|||||||
|
|
||||||
return loadWorkflowFromFile;
|
return loadWorkflowFromFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
const WorkflowValidationErrorContent = memo((props: { error: ZodError }) => {
|
|
||||||
if (props.error.issues[0]) {
|
|
||||||
return (
|
|
||||||
<Text>
|
|
||||||
{fromZodIssue(props.error.issues[0], { prefix: null }).toString()}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<UnorderedList>
|
|
||||||
{props.error.issues.map((issue, i) => (
|
|
||||||
<ListItem key={i}>
|
|
||||||
<Text>{fromZodIssue(issue, { prefix: null }).toString()}</Text>
|
|
||||||
</ListItem>
|
|
||||||
))}
|
|
||||||
</UnorderedList>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
WorkflowValidationErrorContent.displayName = 'WorkflowValidationErrorContent';
|
|
||||||
|
@ -10,7 +10,15 @@ import {
|
|||||||
useUpdateWorkflowMutation,
|
useUpdateWorkflowMutation,
|
||||||
} from 'services/api/endpoints/workflows';
|
} from 'services/api/endpoints/workflows';
|
||||||
|
|
||||||
export const useSaveLibraryWorkflow = () => {
|
type UseSaveLibraryWorkflowReturn = {
|
||||||
|
saveWorkflow: () => Promise<void>;
|
||||||
|
isLoading: boolean;
|
||||||
|
isError: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseSaveLibraryWorkflow = () => UseSaveLibraryWorkflowReturn;
|
||||||
|
|
||||||
|
export const useSaveLibraryWorkflow: UseSaveLibraryWorkflow = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const workflow = useWorkflow();
|
const workflow = useWorkflow();
|
||||||
|
@ -7,20 +7,28 @@ import { useCallback } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useCreateWorkflowMutation } from 'services/api/endpoints/workflows';
|
import { useCreateWorkflowMutation } from 'services/api/endpoints/workflows';
|
||||||
|
|
||||||
type Arg = {
|
type SaveWorkflowAsArg = {
|
||||||
name: string;
|
name: string;
|
||||||
onSuccess?: () => void;
|
onSuccess?: () => void;
|
||||||
onError?: () => void;
|
onError?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useSaveWorkflowAs = () => {
|
type UseSaveWorkflowAsReturn = {
|
||||||
|
saveWorkflowAs: (arg: SaveWorkflowAsArg) => Promise<void>;
|
||||||
|
isLoading: boolean;
|
||||||
|
isError: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type UseSaveWorkflowAs = () => UseSaveWorkflowAsReturn;
|
||||||
|
|
||||||
|
export const useSaveWorkflowAs: UseSaveWorkflowAs = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const workflow = useWorkflow();
|
const workflow = useWorkflow();
|
||||||
const [createWorkflow, createWorkflowResult] = useCreateWorkflowMutation();
|
const [createWorkflow, createWorkflowResult] = useCreateWorkflowMutation();
|
||||||
const toaster = useAppToaster();
|
const toaster = useAppToaster();
|
||||||
const saveWorkflowAs = useCallback(
|
const saveWorkflowAs = useCallback(
|
||||||
async ({ name: newName, onSuccess, onError }: Arg) => {
|
async ({ name: newName, onSuccess, onError }: SaveWorkflowAsArg) => {
|
||||||
try {
|
try {
|
||||||
workflow.id = undefined;
|
workflow.id = undefined;
|
||||||
workflow.name = newName;
|
workflow.name = newName;
|
Loading…
Reference in New Issue
Block a user