diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts index 23244d9a80..8c5873903c 100644 --- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/index.ts @@ -8,6 +8,7 @@ import { import type { AppDispatch, RootState } from '../../store'; import { addCommitStagingAreaImageListener } from './listeners/addCommitStagingAreaImageListener'; +import { addAppConfigReceivedListener } from './listeners/appConfigReceived'; import { addAppStartedListener } from './listeners/appStarted'; import { addBoardIdSelectedListener } from './listeners/boardIdSelected'; import { addRequestedBoardImageDeletionListener } from './listeners/boardImagesDeleted'; @@ -226,3 +227,4 @@ addModelSelectedListener(); // app startup addAppStartedListener(); addModelsLoadedListener(); +addAppConfigReceivedListener(); diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts new file mode 100644 index 0000000000..68148a192f --- /dev/null +++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/appConfigReceived.ts @@ -0,0 +1,17 @@ +import { setInfillMethod } from 'features/parameters/store/generationSlice'; +import { appInfoApi } from 'services/api/endpoints/appInfo'; +import { startAppListening } from '..'; + +export const addAppConfigReceivedListener = () => { + startAppListening({ + matcher: appInfoApi.endpoints.getAppConfig.matchFulfilled, + effect: async (action, { getState, dispatch }) => { + const { infill_methods } = action.payload; + const infillMethod = getState().generation.infillMethod; + + if (!infill_methods.includes(infillMethod)) { + dispatch(setInfillMethod(infill_methods[0])); + } + }, + }); +}; diff --git a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx index 2034f11f61..9ac0e3588f 100644 --- a/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/Parameters/Canvas/InfillAndScaling/ParamInfillMethod.tsx @@ -1,25 +1,21 @@ import { createSelector } from '@reduxjs/toolkit'; +import { stateSelector } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import IAIMantineSelect from 'common/components/IAIMantineSelect'; -import { generationSelector } from 'features/parameters/store/generationSelectors'; import { setInfillMethod } from 'features/parameters/store/generationSlice'; -import { systemSelector } from 'features/system/store/systemSelectors'; -import { memo, useCallback, useEffect, useMemo } from 'react'; +import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { useGetAppConfigQuery } from '../../../../../../services/api/endpoints/appInfo'; -import { setAvailableInfillMethods } from '../../../../../system/store/systemSlice'; +import { useGetAppConfigQuery } from 'services/api/endpoints/appInfo'; const selector = createSelector( - [generationSelector, systemSelector], - (parameters, system) => { - const { infillMethod } = parameters; - const { infillMethods } = system; + [stateSelector], + ({ generation }) => { + const { infillMethod } = generation; return { infillMethod, - infillMethods, }; }, defaultSelectorOptions @@ -27,9 +23,11 @@ const selector = createSelector( const ParamInfillMethod = () => { const dispatch = useAppDispatch(); - const { infillMethod, infillMethods } = useAppSelector(selector); + const { infillMethod } = useAppSelector(selector); - const { data: appConfigData } = useGetAppConfigQuery(); + const { data: appConfigData, isLoading } = useGetAppConfigQuery(); + + const infill_methods = appConfigData?.infill_methods; const { t } = useTranslation(); @@ -40,24 +38,13 @@ const ParamInfillMethod = () => { [dispatch] ); - useEffect(() => { - if (!appConfigData) return; - if (!appConfigData.patchmatch_enabled) { - const filteredMethods = infillMethods.filter( - (method) => method !== 'patchmatch' - ); - dispatch(setAvailableInfillMethods(filteredMethods)); - dispatch(setInfillMethod(filteredMethods[0])); - } else { - dispatch(setInfillMethod('patchmatch')); - } - }, [appConfigData, infillMethods, dispatch]); - return ( ); diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index 041cb34a34..01c1344263 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -4,8 +4,14 @@ import * as InvokeAI from 'app/types/invokeai'; import { InvokeLogLevel } from 'app/logging/useLogger'; import { userInvoked } from 'app/store/actions'; +import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; import { TFuncKey, t } from 'i18next'; import { LogLevelName } from 'roarr'; +import { imageUploaded } from 'services/api/thunks/image'; +import { + isAnySessionRejected, + sessionCanceled, +} from 'services/api/thunks/session'; import { appSocketConnected, appSocketDisconnected, @@ -18,19 +24,11 @@ import { appSocketUnsubscribed, } from 'services/events/actions'; import { ProgressImage } from 'services/events/types'; -import { imageUploaded } from 'services/api/thunks/image'; -import { - isAnySessionRejected, - sessionCanceled, -} from 'services/api/thunks/session'; import { makeToast } from '../../../app/components/Toaster'; import { LANGUAGES } from '../components/LanguagePicker'; -import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice'; export type CancelStrategy = 'immediate' | 'scheduled'; -export type InfillMethod = 'tile' | 'patchmatch'; - export interface SystemState { isGFPGANAvailable: boolean; isESRGANAvailable: boolean; @@ -87,10 +85,6 @@ export interface SystemState { * When a session is canceled, its ID is stored here until a new session is created. */ canceledSession: string; - /** - * TODO: get this from backend - */ - infillMethods: InfillMethod[]; isPersisted: boolean; shouldAntialiasProgressImage: boolean; language: keyof typeof LANGUAGES; @@ -128,7 +122,6 @@ export const initialSystemState: SystemState = { shouldLogToConsole: true, statusTranslationKey: 'common.statusDisconnected', canceledSession: '', - infillMethods: ['tile', 'patchmatch'], isPersisted: false, language: 'en', isUploading: false, @@ -219,9 +212,6 @@ export const systemSlice = createSlice({ progressImageSet(state, action: PayloadAction) { state.progressImage = action.payload; }, - setAvailableInfillMethods(state, action: PayloadAction) { - state.infillMethods = action.payload; - }, }, extraReducers(builder) { /** @@ -454,7 +444,6 @@ export const { shouldAntialiasProgressImageChanged, languageChanged, progressImageSet, - setAvailableInfillMethods, } = systemSlice.actions; export default systemSlice.reducer; diff --git a/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts b/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts index 29f94c8bb2..f76b56761c 100644 --- a/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts +++ b/invokeai/frontend/web/src/services/api/endpoints/appInfo.ts @@ -1,5 +1,5 @@ import { api } from '..'; -import { AppVersion, AppConfig } from '../types'; +import { AppConfig, AppVersion } from '../types'; export const appInfoApi = api.injectEndpoints({ endpoints: (build) => ({ @@ -8,12 +8,14 @@ export const appInfoApi = api.injectEndpoints({ url: `app/version`, method: 'GET', }), + keepUnusedDataFor: 86400000, // 1 day }), getAppConfig: build.query({ query: () => ({ url: `app/config`, method: 'GET', }), + keepUnusedDataFor: 86400000, // 1 day }), }), });