mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): move model manager in-place install state to redux
- persists across sessions/refreshes - shared state for all installers (local path, scan folder)
This commit is contained in:
@@ -12,6 +12,7 @@ type ModelManagerState = {
|
||||
searchTerm: string;
|
||||
filteredModelType: FilterableModelType | null;
|
||||
scanPath: string | undefined;
|
||||
shouldInstallInPlace: boolean;
|
||||
};
|
||||
|
||||
const initialModelManagerState: ModelManagerState = {
|
||||
@@ -21,6 +22,7 @@ const initialModelManagerState: ModelManagerState = {
|
||||
filteredModelType: null,
|
||||
searchTerm: '',
|
||||
scanPath: undefined,
|
||||
shouldInstallInPlace: true,
|
||||
};
|
||||
|
||||
export const modelManagerV2Slice = createSlice({
|
||||
@@ -37,18 +39,26 @@ export const modelManagerV2Slice = createSlice({
|
||||
setSearchTerm: (state, action: PayloadAction<string>) => {
|
||||
state.searchTerm = action.payload;
|
||||
},
|
||||
|
||||
setFilteredModelType: (state, action: PayloadAction<FilterableModelType | null>) => {
|
||||
state.filteredModelType = action.payload;
|
||||
},
|
||||
setScanPath: (state, action: PayloadAction<string | undefined>) => {
|
||||
state.scanPath = action.payload;
|
||||
},
|
||||
shouldInstallInPlaceChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldInstallInPlace = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setSelectedModelKey, setSearchTerm, setFilteredModelType, setSelectedModelMode, setScanPath } =
|
||||
modelManagerV2Slice.actions;
|
||||
export const {
|
||||
setSelectedModelKey,
|
||||
setSearchTerm,
|
||||
setFilteredModelType,
|
||||
setSelectedModelMode,
|
||||
setScanPath,
|
||||
shouldInstallInPlaceChanged,
|
||||
} = modelManagerV2Slice.actions;
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateModelManagerState = (state: any): any => {
|
||||
@@ -74,3 +84,4 @@ export const selectSelectedModelKey = createModelManagerSelector((modelManager)
|
||||
export const selectSelectedModelMode = createModelManagerSelector((modelManager) => modelManager.selectedModelMode);
|
||||
export const selectSearchTerm = createModelManagerSelector((mm) => mm.searchTerm);
|
||||
export const selectFilteredModelType = createModelManagerSelector((mm) => mm.filteredModelType);
|
||||
export const selectShouldInstallInPlace = createModelManagerSelector((mm) => mm.shouldInstallInPlace);
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import { Button, Checkbox, Flex, FormControl, FormHelperText, FormLabel, Input } from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
|
||||
import {
|
||||
selectShouldInstallInPlace,
|
||||
shouldInstallInPlaceChanged,
|
||||
} from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import { t } from 'i18next';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
import type { SubmitHandler } from 'react-hook-form';
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
type SimpleImportModelConfig = {
|
||||
location: string;
|
||||
inplace: boolean;
|
||||
};
|
||||
|
||||
export const InstallModelForm = memo(() => {
|
||||
const inplace = useAppSelector(selectShouldInstallInPlace);
|
||||
const dispatch = useAppDispatch();
|
||||
const [installModel, { isLoading }] = useInstallModel();
|
||||
|
||||
const { register, handleSubmit, formState, reset } = useForm<SimpleImportModelConfig>({
|
||||
defaultValues: {
|
||||
location: '',
|
||||
inplace: true,
|
||||
},
|
||||
mode: 'onChange',
|
||||
});
|
||||
@@ -31,12 +37,19 @@ export const InstallModelForm = memo(() => {
|
||||
|
||||
installModel({
|
||||
source: values.location,
|
||||
inplace: values.inplace,
|
||||
inplace: inplace,
|
||||
onSuccess: resetForm,
|
||||
onError: resetForm,
|
||||
});
|
||||
},
|
||||
[installModel, resetForm]
|
||||
[installModel, resetForm, inplace]
|
||||
);
|
||||
|
||||
const onChangeInplace = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(shouldInstallInPlaceChanged(e.target.checked));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -63,7 +76,7 @@ export const InstallModelForm = memo(() => {
|
||||
<FormControl>
|
||||
<Flex flexDir="column" gap={2}>
|
||||
<Flex gap={4}>
|
||||
<Checkbox {...register('inplace')} />
|
||||
<Checkbox isChecked={inplace} onChange={onChangeInplace} />
|
||||
<FormLabel>
|
||||
{t('modelManager.inplaceInstall')} ({t('modelManager.localOnly')})
|
||||
</FormLabel>
|
||||
|
||||
@@ -11,8 +11,13 @@ import {
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import { useInstallModel } from 'features/modelManagerV2/hooks/useInstallModel';
|
||||
import {
|
||||
selectShouldInstallInPlace,
|
||||
shouldInstallInPlaceChanged,
|
||||
} from 'features/modelManagerV2/store/modelManagerV2Slice';
|
||||
import type { ChangeEvent, ChangeEventHandler } from 'react';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -26,9 +31,10 @@ type ScanModelResultsProps = {
|
||||
};
|
||||
|
||||
export const ScanModelsResults = memo(({ results }: ScanModelResultsProps) => {
|
||||
const inplace = useAppSelector(selectShouldInstallInPlace);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [inplace, setInplace] = useState(true);
|
||||
const [installModel] = useInstallModel();
|
||||
|
||||
const filteredResults = useMemo(() => {
|
||||
@@ -42,9 +48,12 @@ export const ScanModelsResults = memo(({ results }: ScanModelResultsProps) => {
|
||||
setSearchTerm(e.target.value.trim());
|
||||
}, []);
|
||||
|
||||
const onChangeInplace = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
setInplace(e.target.checked);
|
||||
}, []);
|
||||
const onChangeInplace = useCallback(
|
||||
(e: ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(shouldInstallInPlaceChanged(e.target.checked));
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const clearSearch = useCallback(() => {
|
||||
setSearchTerm('');
|
||||
|
||||
Reference in New Issue
Block a user