move mdoal state into nanostore

This commit is contained in:
Mary Hipp 2024-08-12 12:46:02 -04:00
parent 096f001634
commit 6c927a9fd4
8 changed files with 82 additions and 104 deletions

View File

@ -28,7 +28,6 @@ import { generationPersistConfig, generationSlice } from 'features/parameters/st
import { upscalePersistConfig, upscaleSlice } from 'features/parameters/store/upscaleSlice'; import { upscalePersistConfig, upscaleSlice } from 'features/parameters/store/upscaleSlice';
import { queueSlice } from 'features/queue/store/queueSlice'; import { queueSlice } from 'features/queue/store/queueSlice';
import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice'; import { sdxlPersistConfig, sdxlSlice } from 'features/sdxl/store/sdxlSlice';
import { stylePresetModalSlice } from 'features/stylePresets/store/stylePresetModalSlice';
import { stylePresetPersistConfig, stylePresetSlice } from 'features/stylePresets/store/stylePresetSlice'; import { stylePresetPersistConfig, stylePresetSlice } from 'features/stylePresets/store/stylePresetSlice';
import { configSlice } from 'features/system/store/configSlice'; import { configSlice } from 'features/system/store/configSlice';
import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice'; import { systemPersistConfig, systemSlice } from 'features/system/store/systemSlice';
@ -71,7 +70,6 @@ const allReducers = {
[workflowSettingsSlice.name]: workflowSettingsSlice.reducer, [workflowSettingsSlice.name]: workflowSettingsSlice.reducer,
[api.reducerPath]: api.reducer, [api.reducerPath]: api.reducer,
[upscaleSlice.name]: upscaleSlice.reducer, [upscaleSlice.name]: upscaleSlice.reducer,
[stylePresetModalSlice.name]: stylePresetModalSlice.reducer,
[stylePresetSlice.name]: stylePresetSlice.reducer, [stylePresetSlice.name]: stylePresetSlice.reducer,
}; };

View File

@ -1,7 +1,7 @@
import { skipToken } from '@reduxjs/toolkit/query'; import { skipToken } from '@reduxjs/toolkit/query';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { handlers, parseAndRecallAllMetadata, parseAndRecallPrompts } from 'features/metadata/util/handlers'; import { handlers, parseAndRecallAllMetadata, parseAndRecallPrompts } from 'features/metadata/util/handlers';
import { isModalOpenChanged, prefilledFormDataChanged } from 'features/stylePresets/store/stylePresetModalSlice'; import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
@ -13,7 +13,6 @@ export const useImageActions = (image_name?: string) => {
const [hasMetadata, setHasMetadata] = useState(false); const [hasMetadata, setHasMetadata] = useState(false);
const [hasSeed, setHasSeed] = useState(false); const [hasSeed, setHasSeed] = useState(false);
const [hasPrompts, setHasPrompts] = useState(false); const [hasPrompts, setHasPrompts] = useState(false);
const dispatch = useAppDispatch();
const { data: imageDTO } = useGetImageDTOQuery(image_name ?? skipToken); const { data: imageDTO } = useGetImageDTOQuery(image_name ?? skipToken);
useEffect(() => { useEffect(() => {
@ -71,17 +70,18 @@ export const useImageActions = (image_name?: string) => {
const positivePrompt = await handlers.positivePrompt.parse(metadata); const positivePrompt = await handlers.positivePrompt.parse(metadata);
const negativePrompt = await handlers.negativePrompt.parse(metadata); const negativePrompt = await handlers.negativePrompt.parse(metadata);
dispatch( $stylePresetModalState.set({
prefilledFormDataChanged({ prefilledFormData: {
name: '', name: '',
positivePrompt, positivePrompt,
negativePrompt, negativePrompt,
imageUrl: imageDTO.image_url, imageUrl: imageDTO.image_url,
}) },
); updatingStylePresetId: null,
dispatch(isModalOpenChanged(true)); isModalOpen: true,
});
} }
}, [image_name, metadata, dispatch, imageDTO]); }, [image_name, metadata, imageDTO]);
return { return {
recallAll, recallAll,

View File

@ -1,10 +1,5 @@
import { Button, Flex, FormControl, FormLabel, Input, Text } from '@invoke-ai/ui-library'; import { Button, Flex, FormControl, FormLabel, Input, Text } from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks'; import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
import {
isModalOpenChanged,
prefilledFormDataChanged,
updatingStylePresetIdChanged,
} from 'features/stylePresets/store/stylePresetModalSlice';
import { toast } from 'features/toast/toast'; import { toast } from 'features/toast/toast';
import { useCallback } from 'react'; import { useCallback } from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
@ -31,7 +26,6 @@ export const StylePresetForm = ({
}) => { }) => {
const [createStylePreset] = useCreateStylePresetMutation(); const [createStylePreset] = useCreateStylePresetMutation();
const [updateStylePreset] = useUpdateStylePresetMutation(); const [updateStylePreset] = useUpdateStylePresetMutation();
const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const { handleSubmit, control, register, formState } = useForm<StylePresetFormData>({ const { handleSubmit, control, register, formState } = useForm<StylePresetFormData>({
@ -69,11 +63,13 @@ export const StylePresetForm = ({
}); });
} }
dispatch(prefilledFormDataChanged(null)); $stylePresetModalState.set({
dispatch(updatingStylePresetIdChanged(null)); prefilledFormData: null,
dispatch(isModalOpenChanged(false)); updatingStylePresetId: null,
isModalOpen: false,
});
}, },
[dispatch, updatingStylePresetId, updateStylePreset, createStylePreset] [updatingStylePresetId, updateStylePreset, createStylePreset]
); );
return ( return (

View File

@ -1,11 +1,7 @@
import { Badge, ConfirmationAlertDialog, Flex, IconButton, Text, useDisclosure } from '@invoke-ai/ui-library'; import { Badge, ConfirmationAlertDialog, Flex, IconButton, Text, useDisclosure } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen'; import { $isMenuOpen } from 'features/stylePresets/store/isMenuOpen';
import { import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
isModalOpenChanged,
prefilledFormDataChanged,
updatingStylePresetIdChanged,
} from 'features/stylePresets/store/stylePresetModalSlice';
import { activeStylePresetIdChanged } from 'features/stylePresets/store/stylePresetSlice'; import { activeStylePresetIdChanged } from 'features/stylePresets/store/stylePresetSlice';
import { toast } from 'features/toast/toast'; import { toast } from 'features/toast/toast';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
@ -30,19 +26,18 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordWithI
const { name, preset_data } = preset; const { name, preset_data } = preset;
const { positive_prompt, negative_prompt } = preset_data; const { positive_prompt, negative_prompt } = preset_data;
dispatch( $stylePresetModalState.set({
prefilledFormDataChanged({ prefilledFormData: {
name, name,
positivePrompt: positive_prompt || '', positivePrompt: positive_prompt || '',
negativePrompt: negative_prompt || '', negativePrompt: negative_prompt || '',
imageUrl: preset.image, imageUrl: preset.image,
}) },
); updatingStylePresetId: preset.id,
isModalOpen: true,
dispatch(updatingStylePresetIdChanged(preset.id)); });
dispatch(isModalOpenChanged(true));
}, },
[dispatch, preset] [preset]
); );
const handleClickApply = useCallback(async () => { const handleClickApply = useCallback(async () => {
@ -64,19 +59,18 @@ export const StylePresetListItem = ({ preset }: { preset: StylePresetRecordWithI
const { name, preset_data } = preset; const { name, preset_data } = preset;
const { positive_prompt, negative_prompt } = preset_data; const { positive_prompt, negative_prompt } = preset_data;
dispatch( $stylePresetModalState.set({
prefilledFormDataChanged({ prefilledFormData: {
name: `${name} (${t('common.copy')})`, name: `${name} (${t('common.copy')})`,
positivePrompt: positive_prompt || '', positivePrompt: positive_prompt || '',
negativePrompt: negative_prompt || '', negativePrompt: negative_prompt || '',
imageUrl: preset.image, imageUrl: preset.image,
}) },
); updatingStylePresetId: null,
isModalOpen: true,
dispatch(updatingStylePresetIdChanged(null)); });
dispatch(isModalOpenChanged(true));
}, },
[dispatch, preset, t] [preset, t]
); );
const handleDeletePreset = useCallback(async () => { const handleDeletePreset = useCallback(async () => {

View File

@ -1,11 +1,7 @@
import { Flex, IconButton, Text } from '@invoke-ai/ui-library'; import { Flex, IconButton, Text } from '@invoke-ai/ui-library';
import { EMPTY_ARRAY } from 'app/store/constants'; import { EMPTY_ARRAY } from 'app/store/constants';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
isModalOpenChanged,
prefilledFormDataChanged,
updatingStylePresetIdChanged,
} from 'features/stylePresets/store/stylePresetModalSlice';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { PiPlusBold } from 'react-icons/pi'; import { PiPlusBold } from 'react-icons/pi';
@ -40,14 +36,15 @@ export const StylePresetMenu = () => {
}, },
}); });
const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const handleClickAddNew = useCallback(() => { const handleClickAddNew = useCallback(() => {
dispatch(prefilledFormDataChanged(null)); $stylePresetModalState.set({
dispatch(updatingStylePresetIdChanged(null)); prefilledFormData: null,
dispatch(isModalOpenChanged(true)); updatingStylePresetId: null,
}, [dispatch]); isModalOpen: true,
});
}, []);
return ( return (
<Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base"> <Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base">

View File

@ -8,13 +8,9 @@ import {
ModalOverlay, ModalOverlay,
Spinner, Spinner,
} from '@invoke-ai/ui-library'; } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useStore } from '@nanostores/react';
import { convertImageUrlToBlob } from 'common/util/convertImageUrlToBlob'; import { convertImageUrlToBlob } from 'common/util/convertImageUrlToBlob';
import { import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
isModalOpenChanged,
prefilledFormDataChanged,
updatingStylePresetIdChanged,
} from 'features/stylePresets/store/stylePresetModalSlice';
import type { PrefilledFormData } from 'features/stylePresets/store/types'; import type { PrefilledFormData } from 'features/stylePresets/store/types';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -24,21 +20,22 @@ import { StylePresetForm } from './StylePresetForm';
export const StylePresetModal = () => { export const StylePresetModal = () => {
const [formData, setFormData] = useState<StylePresetFormData | null>(null); const [formData, setFormData] = useState<StylePresetFormData | null>(null);
const dispatch = useAppDispatch();
const { t } = useTranslation(); const { t } = useTranslation();
const isModalOpen = useAppSelector((s) => s.stylePresetModal.isModalOpen); const stylePresetModalState = useStore($stylePresetModalState);
const updatingStylePresetId = useAppSelector((s) => s.stylePresetModal.updatingStylePresetId);
const prefilledFormData = useAppSelector((s) => s.stylePresetModal.prefilledFormData);
const modalTitle = useMemo(() => { const modalTitle = useMemo(() => {
return updatingStylePresetId ? t('stylePresets.updatePromptTemplate') : t('stylePresets.createPromptTemplate'); return stylePresetModalState.updatingStylePresetId
}, [updatingStylePresetId, t]); ? t('stylePresets.updatePromptTemplate')
: t('stylePresets.createPromptTemplate');
}, [stylePresetModalState.updatingStylePresetId, t]);
const handleCloseModal = useCallback(() => { const handleCloseModal = useCallback(() => {
dispatch(prefilledFormDataChanged(null)); $stylePresetModalState.set({
dispatch(updatingStylePresetIdChanged(null)); prefilledFormData: null,
dispatch(isModalOpenChanged(false)); updatingStylePresetId: null,
}, [dispatch]); isModalOpen: false,
});
}, []);
useEffect(() => { useEffect(() => {
setFormData(null); setFormData(null);
@ -62,18 +59,18 @@ export const StylePresetModal = () => {
}); });
} }
}; };
convertImageToBlob(prefilledFormData); convertImageToBlob(stylePresetModalState.prefilledFormData);
}, [prefilledFormData]); }, [stylePresetModalState.prefilledFormData]);
return ( return (
<Modal isOpen={isModalOpen} onClose={handleCloseModal} isCentered size="2xl"> <Modal isOpen={stylePresetModalState.isModalOpen} onClose={handleCloseModal} isCentered size="2xl">
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader>{modalTitle}</ModalHeader> <ModalHeader>{modalTitle}</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody display="flex" flexDir="column" gap={4}> <ModalBody display="flex" flexDir="column" gap={4}>
{!prefilledFormData || formData ? ( {!stylePresetModalState.prefilledFormData || formData ? (
<StylePresetForm updatingStylePresetId={updatingStylePresetId} formData={formData} /> <StylePresetForm updatingStylePresetId={stylePresetModalState.updatingStylePresetId} formData={formData} />
) : ( ) : (
<Spinner /> <Spinner />
)} )}

View File

@ -0,0 +1,25 @@
import { atom } from 'nanostores';
const initialState: StylePresetModalState = {
isModalOpen: false,
updatingStylePresetId: null,
prefilledFormData: null,
};
/**
* Tracks the state for the style preset modal.
*/
export const $stylePresetModalState = atom<StylePresetModalState>(initialState);
export type StylePresetModalState = {
isModalOpen: boolean;
updatingStylePresetId: string | null;
prefilledFormData: PrefilledFormData | null;
};
export type PrefilledFormData = {
name: string;
positivePrompt: string;
negativePrompt: string;
imageUrl: string | null;
};

View File

@ -1,29 +0,0 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import type { PrefilledFormData, StylePresetModalState } from './types';
const initialState: StylePresetModalState = {
isModalOpen: false,
updatingStylePresetId: null,
prefilledFormData: null,
};
export const stylePresetModalSlice = createSlice({
name: 'stylePresetModal',
initialState: initialState,
reducers: {
isModalOpenChanged: (state, action: PayloadAction<boolean>) => {
state.isModalOpen = action.payload;
},
updatingStylePresetIdChanged: (state, action: PayloadAction<string | null>) => {
state.updatingStylePresetId = action.payload;
},
prefilledFormDataChanged: (state, action: PayloadAction<PrefilledFormData | null>) => {
state.prefilledFormData = action.payload;
},
},
});
export const { isModalOpenChanged, updatingStylePresetIdChanged, prefilledFormDataChanged } =
stylePresetModalSlice.actions;