feat(ui): clean up workflow library hooks

This commit is contained in:
psychedelicious 2023-12-02 21:01:18 +11:00
parent 4a14ee0e01
commit 6d7b4b8e8a
9 changed files with 119 additions and 62 deletions

View File

@ -14,11 +14,11 @@ import {
sentImageToCanvas,
sentImageToImg2Img,
} from 'features/gallery/store/actions';
import { workflowLoadRequested } from 'features/nodes/store/actions';
import { useRecallParameters } from 'features/parameters/hooks/useRecallParameters';
import { initialImageSelected } from 'features/parameters/store/actions';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { setActiveTab } from 'features/ui/store/uiSlice';
import { useGetAndLoadEmbeddedWorkflow } from 'features/workflowLibrary/hooks/useGetAndLoadEmbeddedWorkflow';
import { memo, useCallback } from 'react';
import { flushSync } from 'react-dom';
import { useTranslation } from 'react-i18next';
@ -36,7 +36,6 @@ import {
import { FaCircleNodes } from 'react-icons/fa6';
import { MdStar, MdStarBorder } from 'react-icons/md';
import {
useLazyGetImageWorkflowQuery,
useStarImagesMutation,
useUnstarImagesMutation,
} from 'services/api/endpoints/images';
@ -62,12 +61,12 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
imageDTO?.image_name
);
const [getWorkflow, getWorkflowResult] = useLazyGetImageWorkflowQuery();
const { getAndLoadEmbeddedWorkflow, getAndLoadEmbeddedWorkflowResult } =
useGetAndLoadEmbeddedWorkflow({});
const handleLoadWorkflow = useCallback(() => {
getWorkflow(imageDTO.image_name).then((workflow) => {
dispatch(workflowLoadRequested(workflow.data));
});
}, [dispatch, getWorkflow, imageDTO]);
getAndLoadEmbeddedWorkflow(imageDTO.image_name);
}, [getAndLoadEmbeddedWorkflow, imageDTO.image_name]);
const [starImages] = useStarImagesMutation();
const [unstarImages] = useUnstarImagesMutation();
@ -176,7 +175,13 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
{t('parameters.downloadImage')}
</MenuItem>
<MenuItem
icon={getWorkflowResult.isLoading ? <SpinnerIcon /> : <FaCircleNodes />}
icon={
getAndLoadEmbeddedWorkflowResult.isLoading ? (
<SpinnerIcon />
) : (
<FaCircleNodes />
)
}
onClickCapture={handleLoadWorkflow}
isDisabled={!imageDTO.has_workflow}
>

View File

@ -8,7 +8,7 @@ import { FaUpload } from 'react-icons/fa';
const UploadWorkflowButton = () => {
const { t } = useTranslation();
const resetRef = useRef<() => void>(null);
const loadWorkflowFromFile = useLoadWorkflowFromFile(resetRef);
const loadWorkflowFromFile = useLoadWorkflowFromFile({ resetRef });
return (
<FileButton
resetRef={resetRef}

View File

@ -13,7 +13,7 @@ import {
import { useAppSelector } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
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 { useTranslation } from 'react-i18next';
import { FaClone } from 'react-icons/fa';

View File

@ -3,15 +3,24 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDeleteWorkflowMutation } from 'services/api/endpoints/workflows';
type UseDeleteLibraryWorkflowArg = {
type UseDeleteLibraryWorkflowOptions = {
onSuccess?: () => 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,
onError,
}: UseDeleteLibraryWorkflowArg) => {
}) => {
const toaster = useAppToaster();
const { t } = useTranslation();
const [_deleteWorkflow, deleteWorkflowResult] = useDeleteWorkflowMutation();

View File

@ -1,21 +1,52 @@
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
import { workflowLoadRequested } from 'features/nodes/store/actions';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useLazyGetImageWorkflowQuery } from 'services/api/endpoints/images';
export const useGetAndLoadEmbeddedWorkflow = (
image_name: string | undefined
) => {
const dispatch = useAppDispatch();
const [_trigger, result] = useLazyGetImageWorkflowQuery();
const trigger = useCallback(() => {
if (!image_name) {
return;
}
_trigger(image_name).then((workflow) => {
dispatch(workflowLoadRequested(workflow.data));
});
}, [dispatch, _trigger, image_name]);
return [trigger, result];
type UseGetAndLoadEmbeddedWorkflowOptions = {
onSuccess?: () => void;
onError?: () => void;
};
type UseGetAndLoadEmbeddedWorkflowReturn = {
getAndLoadEmbeddedWorkflow: (imageName: string) => Promise<void>;
getAndLoadEmbeddedWorkflowResult: ReturnType<
typeof useLazyGetImageWorkflowQuery
>[1];
};
type UseGetAndLoadEmbeddedWorkflow = (
options: UseGetAndLoadEmbeddedWorkflowOptions
) => 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 };
};

View File

@ -5,15 +5,24 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useLazyGetWorkflowQuery } from 'services/api/endpoints/workflows';
type UseGetAndLoadLibraryWorkflowArg = {
type UseGetAndLoadLibraryWorkflowOptions = {
onSuccess?: () => 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,
onError,
}: UseGetAndLoadLibraryWorkflowArg) => {
}) => {
const dispatch = useAppDispatch();
const toaster = useAppToaster();
const { t } = useTranslation();

View File

@ -1,15 +1,22 @@
import { ListItem, Text, UnorderedList } from '@chakra-ui/react';
import { useLogger } from 'app/logging/useLogger';
import { useAppDispatch } from 'app/store/storeHooks';
import { workflowLoadRequested } from 'features/nodes/store/actions';
import { addToast } from 'features/system/store/systemSlice';
import { makeToast } from 'features/system/util/makeToast';
import { RefObject, memo, useCallback } from 'react';
import { RefObject, useCallback } from 'react';
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 logger = useLogger('nodes');
const { t } = useTranslation();
@ -41,6 +48,7 @@ export const useLoadWorkflowFromFile = (resetRef: RefObject<() => void>) => {
};
reader.readAsText(file);
// Reset the file picker internal state so that the same file can be loaded again
resetRef.current?.();
},
@ -49,24 +57,3 @@ export const useLoadWorkflowFromFile = (resetRef: RefObject<() => void>) => {
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';

View File

@ -10,7 +10,15 @@ import {
useUpdateWorkflowMutation,
} 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 dispatch = useAppDispatch();
const workflow = useWorkflow();

View File

@ -7,20 +7,28 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useCreateWorkflowMutation } from 'services/api/endpoints/workflows';
type Arg = {
type SaveWorkflowAsArg = {
name: string;
onSuccess?: () => 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 dispatch = useAppDispatch();
const workflow = useWorkflow();
const [createWorkflow, createWorkflowResult] = useCreateWorkflowMutation();
const toaster = useAppToaster();
const saveWorkflowAs = useCallback(
async ({ name: newName, onSuccess, onError }: Arg) => {
async ({ name: newName, onSuccess, onError }: SaveWorkflowAsArg) => {
try {
workflow.id = undefined;
workflow.name = newName;