diff --git a/invokeai/frontend/web/src/Loading.tsx b/invokeai/frontend/web/src/Loading.tsx deleted file mode 100644 index 671c2cd640..0000000000 --- a/invokeai/frontend/web/src/Loading.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Flex, Spinner, Text } from '@chakra-ui/react'; -import { useTranslation } from 'react-i18next'; - -interface LoaderProps { - showText?: boolean; - text?: string; -} - -// This component loads before the theme so we cannot use theme tokens here - -const Loading = (props: LoaderProps) => { - const { t } = useTranslation(); - const { showText = false, text = t('common.loadingInvokeAI') } = props; - - return ( - - - {showText && ( - - {text} - - )} - - ); -}; - -export default Loading; diff --git a/invokeai/frontend/web/src/app/App.tsx b/invokeai/frontend/web/src/app/App.tsx index d2287136c3..4bbf8f4429 100644 --- a/invokeai/frontend/web/src/app/App.tsx +++ b/invokeai/frontend/web/src/app/App.tsx @@ -15,17 +15,24 @@ import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel'; import Lightbox from 'features/lightbox/components/Lightbox'; import { useAppDispatch, useAppSelector } from './storeHooks'; import { PropsWithChildren, useEffect } from 'react'; -import { setDisabledPanels, setDisabledTabs } from 'features/ui/store/uiSlice'; import { InvokeTabName } from 'features/ui/store/tabMap'; import { shouldTransformUrlsChanged } from 'features/system/store/systemSlice'; import { setShouldFetchImages } from 'features/gallery/store/resultsSlice'; +import { motion, AnimatePresence } from 'framer-motion'; +import Loading from 'common/components/Loading/Loading'; +import { + ApplicationFeature, + disabledFeaturesChanged, + disabledTabsChanged, +} from 'features/system/store/systemSlice'; +import { useIsApplicationReady } from 'features/system/hooks/useIsApplicationReady'; keepGUIAlive(); interface Props extends PropsWithChildren { options: { - disabledPanels: string[]; disabledTabs: InvokeTabName[]; + disabledFeatures: ApplicationFeature[]; shouldTransformUrls?: boolean; shouldFetchImages: boolean; }; @@ -35,15 +42,21 @@ const App = (props: Props) => { useToastWatcher(); const currentTheme = useAppSelector((state) => state.ui.currentTheme); + const disabledFeatures = useAppSelector( + (state) => state.system.disabledFeatures + ); + + const isApplicationReady = useIsApplicationReady(); + const { setColorMode } = useColorMode(); const dispatch = useAppDispatch(); useEffect(() => { - dispatch(setDisabledPanels(props.options.disabledPanels)); - }, [dispatch, props.options.disabledPanels]); + dispatch(disabledFeaturesChanged(props.options.disabledFeatures)); + }, [dispatch, props.options.disabledFeatures]); useEffect(() => { - dispatch(setDisabledTabs(props.options.disabledTabs)); + dispatch(disabledTabsChanged(props.options.disabledTabs)); }, [dispatch, props.options.disabledTabs]); useEffect(() => { @@ -61,8 +74,8 @@ const App = (props: Props) => { }, [setColorMode, currentTheme]); return ( - - + + {!disabledFeatures.includes('lightbox') && } { - - - + + + {!isApplicationReady && ( + + + + + + )} + + + + + ); }; diff --git a/invokeai/frontend/web/src/common/components/Loading/Loading.tsx b/invokeai/frontend/web/src/common/components/Loading/Loading.tsx new file mode 100644 index 0000000000..16c646b0a3 --- /dev/null +++ b/invokeai/frontend/web/src/common/components/Loading/Loading.tsx @@ -0,0 +1,21 @@ +import { Flex, Image } from '@chakra-ui/react'; +import InvokeAILogoImage from 'assets/images/logo.png'; + +// This component loads before the theme so we cannot use theme tokens here + +const Loading = () => { + return ( + + + + ); +}; + +export default Loading; diff --git a/invokeai/frontend/web/src/component.tsx b/invokeai/frontend/web/src/component.tsx index c4cd876fbd..03ea485588 100644 --- a/invokeai/frontend/web/src/component.tsx +++ b/invokeai/frontend/web/src/component.tsx @@ -15,11 +15,12 @@ import '@fontsource/inter/700.css'; import '@fontsource/inter/800.css'; import '@fontsource/inter/900.css'; -import Loading from './Loading'; +import Loading from './common/components/Loading/Loading'; // Localization import './i18n'; import { addMiddleware, resetMiddlewares } from 'redux-dynamic-middlewares'; +import { ApplicationFeature } from 'features/system/store/systemSlice'; const App = lazy(() => import('./app/App')); const ThemeLocaleProvider = lazy(() => import('./app/ThemeLocaleProvider')); @@ -28,6 +29,7 @@ interface Props extends PropsWithChildren { apiUrl?: string; disabledPanels?: string[]; disabledTabs?: InvokeTabName[]; + disabledFeatures?: ApplicationFeature[]; token?: string; shouldTransformUrls?: boolean; shouldFetchImages?: boolean; @@ -35,8 +37,15 @@ interface Props extends PropsWithChildren { export default function Component({ apiUrl, - disabledPanels = [], disabledTabs = [], + disabledFeatures = [ + 'lightbox', + 'bugLink', + 'discordLink', + 'githubLink', + 'localization', + 'modelManager', + ], token, children, shouldTransformUrls, @@ -69,12 +78,12 @@ export default function Component({ } persistor={persistor}> - }> + }> { activeTabName, shouldHidePreview, selectedImage, + disabledFeatures, } = useAppSelector(currentImageButtonsSelector); + const { getUrl, shouldTransformUrls } = useGetUrl(); const toast = useToast(); @@ -328,24 +333,19 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { useHotkeys( 'Shift+U', () => { - if ( - isESRGANAvailable && - !shouldDisableToolbarButtons && - isConnected && - !isProcessing && - upscalingLevel - ) { - handleClickUpscale(); - } else { - toast({ - title: t('toast.upscalingFailed'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } + handleClickUpscale(); + }, + { + enabled: () => + disabledFeatures.includes('upscaling') || + !isESRGANAvailable || + shouldDisableToolbarButtons || + !isConnected || + isProcessing || + !upscalingLevel, }, [ + disabledFeatures, selectedImage, isESRGANAvailable, shouldDisableToolbarButtons, @@ -362,24 +362,20 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { useHotkeys( 'Shift+R', () => { - if ( - isGFPGANAvailable && - !shouldDisableToolbarButtons && - isConnected && - !isProcessing && - facetoolStrength - ) { - handleClickFixFaces(); - } else { - toast({ - title: t('toast.faceRestoreFailed'), - status: 'error', - duration: 2500, - isClosable: true, - }); - } + handleClickFixFaces(); }, + { + enabled: () => + disabledFeatures.includes('faceRestore') || + !isGFPGANAvailable || + shouldDisableToolbarButtons || + !isConnected || + isProcessing || + !facetoolStrength, + }, + [ + disabledFeatures, selectedImage, isGFPGANAvailable, shouldDisableToolbarButtons, @@ -509,21 +505,23 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { isChecked={shouldHidePreview} onClick={handlePreviewVisibility} /> - } - tooltip={ - !isLightboxOpen - ? `${t('parameters.openInViewer')} (Z)` - : `${t('parameters.closeViewer')} (Z)` - } - aria-label={ - !isLightboxOpen - ? `${t('parameters.openInViewer')} (Z)` - : `${t('parameters.closeViewer')} (Z)` - } - isChecked={isLightboxOpen} - onClick={handleLightBox} - /> + {!disabledFeatures.includes('lightbox') && ( + } + tooltip={ + !isLightboxOpen + ? `${t('parameters.openInViewer')} (Z)` + : `${t('parameters.closeViewer')} (Z)` + } + aria-label={ + !isLightboxOpen + ? `${t('parameters.openInViewer')} (Z)` + : `${t('parameters.closeViewer')} (Z)` + } + isChecked={isLightboxOpen} + onClick={handleLightBox} + /> + )} @@ -556,65 +554,74 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => { /> - - } - aria-label={t('parameters.restoreFaces')} - /> - } - > - - - + {!disabledFeatures.includes('faceRestore') && ( + } + aria-label={t('parameters.restoreFaces')} + /> } - onClick={handleClickFixFaces} > - {t('parameters.restoreFaces')} - - - + + + + {t('parameters.restoreFaces')} + + + + )} - } - aria-label={t('parameters.upscale')} - /> - } - > - - - } + aria-label={t('parameters.upscale')} + /> } - onClick={handleClickUpscale} > - {t('parameters.upscaleImage')} - - - - + + + + {t('parameters.upscaleImage')} + + + + )} + + )} { galleryImageMinimumWidth, mayDeleteImage, shouldUseSingleGalleryColumn, + disabledFeatures, } = useAppSelector(hoverableImageSelector); const { image, isSelected } = props; const { url, thumbnail, name, metadata } = image; @@ -133,7 +134,6 @@ const HoverableImage = memo((props: HoverableImageProps) => { metadata.sd_metadata?.image?.init_image_path ); if (response.ok) { - dispatch(setActiveTab('img2img')); dispatch(setAllImageToImageParameters(metadata?.sd_metadata)); toast({ title: t('toast.initialImageSet'), @@ -174,9 +174,11 @@ const HoverableImage = memo((props: HoverableImageProps) => { menuProps={{ size: 'sm', isLazy: true }} renderMenu={() => ( - - {t('parameters.openInViewer')} - + {!disabledFeatures.includes('lightbox') && ( + + {t('parameters.openInViewer')} + + )} { - state.schema = action.payload; - state.invocationTemplates = parseSchema(action.payload); + state.invocationTemplates = action.payload; }); builder.addMatcher(isFulfilledAnyGraphBuilt, (state, action) => { diff --git a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts index c4c2b8fcf1..550af295f1 100644 --- a/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts +++ b/invokeai/frontend/web/src/features/nodes/util/parseSchema.ts @@ -114,7 +114,5 @@ export const parseSchema = (openAPI: OpenAPIV3.Document) => { return acc; }, {}); - console.debug('Generated invocations: ', invocations); - return invocations; }; diff --git a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx index e729082603..a2d12f96ff 100644 --- a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx +++ b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx @@ -2,36 +2,41 @@ import { Accordion } from '@chakra-ui/react'; import { createSelector } from '@reduxjs/toolkit'; import { Feature } from 'app/features'; import { useAppDispatch, useAppSelector } from 'app/storeHooks'; +import { systemSelector } from 'features/system/store/systemSelectors'; import { tabMap } from 'features/ui/store/tabMap'; import { uiSelector } from 'features/ui/store/uiSelectors'; import { openAccordionItemsChanged } from 'features/ui/store/uiSlice'; -import { filter } from 'lodash'; +import { filter, map } from 'lodash'; import { ReactNode, useCallback } from 'react'; import InvokeAccordionItem from './AccordionItems/InvokeAccordionItem'; -const parametersAccordionSelector = createSelector([uiSelector], (uiSlice) => { - const { - activeTab, - openLinearAccordionItems, - openUnifiedCanvasAccordionItems, - disabledParameterPanels, - } = uiSlice; +const parametersAccordionSelector = createSelector( + [uiSelector, systemSelector], + (uiSlice, system) => { + const { + activeTab, + openLinearAccordionItems, + openUnifiedCanvasAccordionItems, + } = uiSlice; - let openAccordions: number[] = []; + const { disabledFeatures } = system; - if (tabMap[activeTab] === 'linear') { - openAccordions = openLinearAccordionItems; + let openAccordions: number[] = []; + + if (tabMap[activeTab] === 'linear') { + openAccordions = openLinearAccordionItems; + } + + if (tabMap[activeTab] === 'unifiedCanvas') { + openAccordions = openUnifiedCanvasAccordionItems; + } + + return { + openAccordions, + disabledFeatures, + }; } - - if (tabMap[activeTab] === 'unifiedCanvas') { - openAccordions = openUnifiedCanvasAccordionItems; - } - - return { - openAccordions, - disabledParameterPanels, - }; -}); +); export type ParametersAccordionItem = { name: string; @@ -53,7 +58,7 @@ type ParametersAccordionProps = { * Main container for generation and processing parameters. */ const ParametersAccordion = ({ accordionItems }: ParametersAccordionProps) => { - const { openAccordions, disabledParameterPanels } = useAppSelector( + const { openAccordions, disabledFeatures } = useAppSelector( parametersAccordionSelector ); @@ -68,20 +73,16 @@ const ParametersAccordion = ({ accordionItems }: ParametersAccordionProps) => { }; // Render function for accordion items - const renderAccordionItems = useCallback(() => { - // Filter out disabled accordions - const filteredAccordionItems = filter( - accordionItems, - (item) => disabledParameterPanels.indexOf(item.name) === -1 - ); - - return filteredAccordionItems.map((accordionItem) => ( - - )); - }, [disabledParameterPanels, accordionItems]); + const renderAccordionItems = useCallback( + () => + map(accordionItems, (accordionItem) => ( + + )), + [accordionItems] + ); return ( { position: 'fixed', insetInlineStart: 0, bottom: 0, - zIndex: 9999, + zIndex: 1, }} maxHeight="90vh" > @@ -128,6 +128,7 @@ const Console = () => { borderTopWidth: 5, bg: 'base.850', borderColor: 'base.700', + zIndex: 2, }} ref={viewerRef} onScroll={handleOnScroll} @@ -166,7 +167,7 @@ const Console = () => { position: 'fixed', insetInlineStart: 2, bottom: 12, - zIndex: '10000', + zIndex: 1, }} /> @@ -184,7 +185,7 @@ const Console = () => { position: 'fixed', insetInlineStart: 2, bottom: 2, - zIndex: '10000', + zIndex: 1, }} colorScheme={hasError || !wasErrorSeen ? 'error' : 'base'} /> diff --git a/invokeai/frontend/web/src/features/system/components/SiteHeaderMenu.tsx b/invokeai/frontend/web/src/features/system/components/SiteHeaderMenu.tsx index 09118b4a0f..836b88665a 100644 --- a/invokeai/frontend/web/src/features/system/components/SiteHeaderMenu.tsx +++ b/invokeai/frontend/web/src/features/system/components/SiteHeaderMenu.tsx @@ -8,8 +8,13 @@ import ModelManagerModal from './ModelManager/ModelManagerModal'; import SettingsModal from './SettingsModal/SettingsModal'; import ThemeChanger from './ThemeChanger'; import IAIIconButton from 'common/components/IAIIconButton'; +import { useAppSelector } from 'app/storeHooks'; +import { RootState } from 'app/store'; const SiteHeaderMenu = () => { + const disabledFeatures = useAppSelector( + (state: RootState) => state.system.disabledFeatures + ); const { t } = useTranslation(); return ( @@ -18,17 +23,19 @@ const SiteHeaderMenu = () => { flexDirection={{ base: 'column', xl: 'row' }} gap={{ base: 4, xl: 1 }} > - - } - /> - + {!disabledFeatures.includes('modelManager') && ( + + } + /> + + )} { - + {!disabledFeatures.includes('localization') && } - - } - /> - + {!disabledFeatures.includes('bugLink') && ( + + } + /> + + )} - - } - /> - + {!disabledFeatures.includes('githubLink') && ( + + } + /> + + )} - - } - /> - + {!disabledFeatures.includes('discordLink') && ( + + } + /> + + )} state.system], + (system) => { + const { + disabledFeatures, + disabledTabs, + wereModelsReceived, + wasSchemaParsed, + } = system; + + return { + disabledTabs, + disabledFeatures, + wereModelsReceived, + wasSchemaParsed, + }; + } +); + +export const useIsApplicationReady = () => { + const { + disabledTabs, + disabledFeatures, + wereModelsReceived, + wasSchemaParsed, + } = useAppSelector(isApplicationReadySelector); + + const isApplicationReady = useMemo(() => { + if (!wereModelsReceived) { + return false; + } + + if (!disabledTabs.includes('nodes') && !wasSchemaParsed) { + return false; + } + + return true; + }, [disabledTabs, wereModelsReceived, wasSchemaParsed]); + + return isApplicationReady; +}; diff --git a/invokeai/frontend/web/src/features/system/store/systemPersistsBlacklist.ts b/invokeai/frontend/web/src/features/system/store/systemPersistsBlacklist.ts index 31ac7a43e6..27ecd65f9e 100644 --- a/invokeai/frontend/web/src/features/system/store/systemPersistsBlacklist.ts +++ b/invokeai/frontend/web/src/features/system/store/systemPersistsBlacklist.ts @@ -19,6 +19,8 @@ const itemsToBlacklist: (keyof SystemState)[] = [ 'isCancelScheduled', 'sessionId', 'progressImage', + 'wereModelsReceived', + 'wasSchemaParsed', ]; export const systemBlacklist = itemsToBlacklist.map( diff --git a/invokeai/frontend/web/src/features/system/store/systemSlice.ts b/invokeai/frontend/web/src/features/system/store/systemSlice.ts index f52a199aec..32868ddb4f 100644 --- a/invokeai/frontend/web/src/features/system/store/systemSlice.ts +++ b/invokeai/frontend/web/src/features/system/store/systemSlice.ts @@ -19,6 +19,9 @@ import { ProgressImage } from 'services/events/types'; import { initialImageSelected } from 'features/parameters/store/generationSlice'; import { makeToast } from '../hooks/useToastWatcher'; import { sessionCanceled, sessionInvoked } from 'services/thunks/session'; +import { InvokeTabName } from 'features/ui/store/tabMap'; +import { receivedModels } from 'services/thunks/model'; +import { receivedOpenAPISchema } from 'services/thunks/schema'; export type LogLevel = 'info' | 'warning' | 'error'; @@ -32,10 +35,18 @@ export interface Log { [index: number]: LogEntry; } -export type ReadinessPayload = { - isReady: boolean; - reasonsWhyNotReady: string[]; -}; +/** + * A disable-able application feature + */ +export type ApplicationFeature = + | 'faceRestore' + | 'upscaling' + | 'lightbox' + | 'modelManager' + | 'githubLink' + | 'discordLink' + | 'bugLink' + | 'localization'; export type InProgressImageType = 'none' | 'full-res' | 'latents'; @@ -96,6 +107,22 @@ export interface SystemState * Whether or not URLs should be transformed to use a different host */ shouldTransformUrls: boolean; + /** + * Array of disabled tabs + */ + disabledTabs: InvokeTabName[]; + /** + * Array of disabled features + */ + disabledFeatures: ApplicationFeature[]; + /** + * Whether or not the available models were received + */ + wereModelsReceived: boolean; + /** + * Whether or not the OpenAPI schema was received and parsed + */ + wasSchemaParsed: boolean; } const initialSystemState: SystemState = { @@ -144,6 +171,10 @@ const initialSystemState: SystemState = { isCancelScheduled: false, subscribedNodeIds: [], shouldTransformUrls: false, + disabledTabs: [], + disabledFeatures: [], + wereModelsReceived: false, + wasSchemaParsed: false, }; export const systemSlice = createSlice({ @@ -347,6 +378,21 @@ export const systemSlice = createSlice({ shouldTransformUrlsChanged: (state, action: PayloadAction) => { state.shouldTransformUrls = action.payload; }, + /** + * `disabledTabs` was changed + */ + disabledTabsChanged: (state, action: PayloadAction) => { + state.disabledTabs = action.payload; + }, + /** + * `disabledFeatures` was changed + */ + disabledFeaturesChanged: ( + state, + action: PayloadAction + ) => { + state.disabledFeatures = action.payload; + }, }, extraReducers(builder) { /** @@ -417,7 +463,8 @@ export const systemSlice = createSlice({ step, total_steps, progress_image, - invocation, + node, + source_node_id, graph_execution_state_id, } = action.payload.data; @@ -514,6 +561,20 @@ export const systemSlice = createSlice({ builder.addCase(initialImageSelected, (state) => { state.toastQueue.push(makeToast(i18n.t('toast.sentToImageToImage'))); }); + + /** + * Received available models from the backend + */ + builder.addCase(receivedModels.fulfilled, (state, action) => { + state.wereModelsReceived = true; + }); + + /** + * OpenAPI schema was received and parsed + */ + builder.addCase(receivedOpenAPISchema.fulfilled, (state, action) => { + state.wasSchemaParsed = true; + }); }, }); @@ -554,6 +615,8 @@ export const { cancelTypeChanged, subscribedNodeIdsSet, shouldTransformUrlsChanged, + disabledTabsChanged, + disabledFeaturesChanged, } = systemSlice.actions; export default systemSlice.reducer; diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx index 303e1e8837..bb259d242d 100644 --- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx +++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx @@ -64,8 +64,13 @@ export default function InvokeTabs() { (state: RootState) => state.lightbox.isLightboxOpen ); - const { shouldPinGallery, disabledTabs, shouldPinParametersPanel } = - useAppSelector((state: RootState) => state.ui); + const { shouldPinGallery, shouldPinParametersPanel } = useAppSelector( + (state: RootState) => state.ui + ); + + const disabledTabs = useAppSelector( + (state: RootState) => state.system.disabledTabs + ); const activeTabs = buildTabs(disabledTabs); diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts index 9cdf26c042..fd8ba78f01 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts @@ -1,11 +1,10 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import { initialImageSelected } from 'features/parameters/store/generationSlice'; import { setActiveTabReducer } from './extraReducers'; import { InvokeTabName, tabMap } from './tabMap'; import { AddNewModelType, UIState } from './uiTypes'; -const initialtabsState: UIState = { +const initialUIState: UIState = { activeTab: 0, currentTheme: 'dark', parametersPanelScrollPosition: 0, @@ -19,13 +18,11 @@ const initialtabsState: UIState = { shouldPinGallery: true, shouldShowGallery: true, shouldHidePreview: false, - disabledParameterPanels: [], - disabledTabs: [], openLinearAccordionItems: [], openUnifiedCanvasAccordionItems: [], }; -const initialState: UIState = initialtabsState; +const initialState: UIState = initialUIState; export const uiSlice = createSlice({ name: 'ui', @@ -98,12 +95,6 @@ export const uiSlice = createSlice({ state.shouldShowParametersPanel = true; } }, - setDisabledPanels: (state, action: PayloadAction) => { - state.disabledParameterPanels = action.payload; - }, - setDisabledTabs: (state, action: PayloadAction) => { - state.disabledTabs = action.payload; - }, openAccordionItemsChanged: (state, action: PayloadAction) => { if (tabMap[state.activeTab] === 'linear') { state.openLinearAccordionItems = action.payload; @@ -135,8 +126,6 @@ export const { togglePinParametersPanel, toggleParametersPanel, toggleGalleryPanel, - setDisabledPanels, - setDisabledTabs, openAccordionItemsChanged, } = uiSlice.actions; diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts index a1cba603bb..a222aaee88 100644 --- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts +++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts @@ -1,5 +1,3 @@ -import { InvokeTabName } from './tabMap'; - export type AddNewModelType = 'ckpt' | 'diffusers' | null; export interface UIState { @@ -16,8 +14,6 @@ export interface UIState { shouldHidePreview: boolean; shouldPinGallery: boolean; shouldShowGallery: boolean; - disabledParameterPanels: string[]; - disabledTabs: InvokeTabName[]; openLinearAccordionItems: number[]; openUnifiedCanvasAccordionItems: number[]; } diff --git a/invokeai/frontend/web/src/services/events/middleware.ts b/invokeai/frontend/web/src/services/events/middleware.ts index 33e198d797..f581521d6b 100644 --- a/invokeai/frontend/web/src/services/events/middleware.ts +++ b/invokeai/frontend/web/src/services/events/middleware.ts @@ -92,7 +92,9 @@ export const socketMiddleware = () => { socket.on('connect', () => { dispatch(socketConnected({ timestamp: getTimestamp() })); - const { results, uploads, models, nodes } = getState(); + const { results, uploads, models, nodes, system } = getState(); + + const { disabledTabs } = system; // These thunks need to be dispatch in middleware; cannot handle in a reducer if (!results.ids.length) { @@ -107,7 +109,7 @@ export const socketMiddleware = () => { dispatch(receivedModels()); } - if (!nodes.schema) { + if (!nodes.schema && !disabledTabs.includes('nodes')) { dispatch(receivedOpenAPISchema()); } }); diff --git a/invokeai/frontend/web/src/services/thunks/schema.ts b/invokeai/frontend/web/src/services/thunks/schema.ts index edf237032f..bd5135cdf9 100644 --- a/invokeai/frontend/web/src/services/thunks/schema.ts +++ b/invokeai/frontend/web/src/services/thunks/schema.ts @@ -1,4 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; +import { parseSchema } from 'features/nodes/util/parseSchema'; import { OpenAPIV3 } from 'openapi-types'; export const receivedOpenAPISchema = createAsyncThunk( @@ -9,6 +10,10 @@ export const receivedOpenAPISchema = createAsyncThunk( console.debug('OpenAPI schema: ', jsonData); - return jsonData; + const parsedSchema = parseSchema(jsonData); + + console.debug('Parsed schema: ', parsedSchema); + + return parsedSchema; } );