diff --git a/invokeai/frontend/web/index.d.ts b/invokeai/frontend/web/index.d.ts
index 06a362d3a2..4be14302cb 100644
--- a/invokeai/frontend/web/index.d.ts
+++ b/invokeai/frontend/web/index.d.ts
@@ -1,6 +1,7 @@
import React, { PropsWithChildren } from 'react';
import { IAIPopoverProps } from '../web/src/common/components/IAIPopover';
import { IAIIconButtonProps } from '../web/src/common/components/IAIIconButton';
+import { InvokeTabName } from 'features/ui/store/tabMap';
export {};
@@ -68,6 +69,8 @@ declare module '@invoke-ai/invoke-ai-ui' {
interface InvokeProps extends PropsWithChildren {
apiUrl?: string;
+ disabledPanels?: string[];
+ disabledTabs?: InvokeTabName[];
}
declare function Invoke(props: InvokeProps): JSX.Element;
diff --git a/invokeai/frontend/web/src/app/App.tsx b/invokeai/frontend/web/src/app/App.tsx
index 40c15b38c0..ef843b047e 100644
--- a/invokeai/frontend/web/src/app/App.tsx
+++ b/invokeai/frontend/web/src/app/App.tsx
@@ -13,16 +13,34 @@ import { Box, Flex, Grid, Portal, useColorMode } from '@chakra-ui/react';
import { APP_HEIGHT, APP_WIDTH } from 'theme/util/constants';
import ImageGalleryPanel from 'features/gallery/components/ImageGalleryPanel';
import Lightbox from 'features/lightbox/components/Lightbox';
-import { useAppSelector } from './storeHooks';
+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';
keepGUIAlive();
-const App = (props: PropsWithChildren) => {
+interface Props extends PropsWithChildren {
+ options: {
+ disabledPanels: string[];
+ disabledTabs: InvokeTabName[];
+ };
+}
+
+const App = (props: Props) => {
useToastWatcher();
const currentTheme = useAppSelector((state) => state.ui.currentTheme);
const { setColorMode } = useColorMode();
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(setDisabledPanels(props.options.disabledPanels));
+ }, [dispatch, props.options.disabledPanels]);
+
+ useEffect(() => {
+ dispatch(setDisabledTabs(props.options.disabledTabs));
+ }, [dispatch, props.options.disabledTabs]);
useEffect(() => {
setColorMode(['light'].includes(currentTheme) ? 'light' : 'dark');
diff --git a/invokeai/frontend/web/src/component.tsx b/invokeai/frontend/web/src/component.tsx
index a642516417..e83b8ff8d5 100644
--- a/invokeai/frontend/web/src/component.tsx
+++ b/invokeai/frontend/web/src/component.tsx
@@ -4,6 +4,7 @@ import { PersistGate } from 'redux-persist/integration/react';
import { store } from './app/store';
import { persistor } from './persistor';
import { OpenAPI } from 'services/api';
+import { InvokeTabName } from 'features/ui/store/tabMap';
import '@fontsource/inter/100.css';
import '@fontsource/inter/200.css';
import '@fontsource/inter/300.css';
@@ -24,9 +25,16 @@ const ThemeLocaleProvider = lazy(() => import('./app/ThemeLocaleProvider'));
interface Props extends PropsWithChildren {
apiUrl?: string;
+ disabledPanels?: string[];
+ disabledTabs?: InvokeTabName[];
}
-export default function Component({ apiUrl, children }: Props) {
+export default function Component({
+ apiUrl,
+ disabledPanels = [],
+ disabledTabs = [],
+ children,
+}: Props) {
useEffect(() => {
if (apiUrl) OpenAPI.BASE = apiUrl;
}, [apiUrl]);
@@ -37,7 +45,7 @@ export default function Component({ apiUrl, children }: Props) {
} persistor={persistor}>
}>
- {children}
+ {children}
diff --git a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx
index 76277867de..e3218f71e2 100644
--- a/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx
+++ b/invokeai/frontend/web/src/features/parameters/components/ParametersAccordion.tsx
@@ -21,9 +21,10 @@ type ParametersAccordionsType = {
const ParametersAccordion = (props: ParametersAccordionsType) => {
const { accordionInfo } = props;
- const openAccordions = useAppSelector(
- (state: RootState) => state.system.openAccordions
- );
+ const { system, ui } = useAppSelector((state: RootState) => state);
+
+ const { openAccordions } = system;
+ const { disabledParameterPanels } = ui;
const dispatch = useAppDispatch();
@@ -39,15 +40,19 @@ const ParametersAccordion = (props: ParametersAccordionsType) => {
Object.keys(accordionInfo).forEach((key) => {
const { header, feature, content, additionalHeaderComponents } =
accordionInfo[key];
- accordionsToRender.push(
-
- );
+
+ // do not render if panel is disabled in global state
+ if (disabledParameterPanels.indexOf(key) === -1) {
+ accordionsToRender.push(
+
+ );
+ }
});
}
return accordionsToRender;
diff --git a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
index 18db74791b..d7736eb9ea 100644
--- a/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/InvokeTabs.tsx
@@ -45,38 +45,41 @@ const tabIconStyles: ChakraProps['sx'] = {
boxSize: 6,
};
-const tabInfo: InvokeTabInfo[] = [
- {
- id: 'txt2img',
- icon: ,
- workarea: ,
- },
- {
- id: 'img2img',
- icon: ,
- workarea: ,
- },
- {
- id: 'unifiedCanvas',
- icon: ,
- workarea: ,
- },
- {
- id: 'nodes',
- icon: ,
- workarea: ,
- },
- {
- id: 'postprocessing',
- icon: ,
- workarea: ,
- },
- {
- id: 'training',
- icon: ,
- workarea: ,
- },
-];
+const buildTabs = (disabledTabs: InvokeTabName[]): InvokeTabInfo[] => {
+ const tabs: InvokeTabInfo[] = [
+ {
+ id: 'txt2img',
+ icon: ,
+ workarea: ,
+ },
+ {
+ id: 'img2img',
+ icon: ,
+ workarea: ,
+ },
+ {
+ id: 'unifiedCanvas',
+ icon: ,
+ workarea: ,
+ },
+ {
+ id: 'nodes',
+ icon: ,
+ workarea: ,
+ },
+ {
+ id: 'postprocessing',
+ icon: ,
+ workarea: ,
+ },
+ {
+ id: 'training',
+ icon: ,
+ workarea: ,
+ },
+ ];
+ return tabs.filter((tab) => !disabledTabs.includes(tab.id));
+};
export default function InvokeTabs() {
const activeTab = useAppSelector(activeTabIndexSelector);
@@ -85,13 +88,10 @@ export default function InvokeTabs() {
(state: RootState) => state.lightbox.isLightboxOpen
);
- const shouldPinGallery = useAppSelector(
- (state: RootState) => state.ui.shouldPinGallery
- );
+ const { shouldPinGallery, disabledTabs, shouldPinParametersPanel } =
+ useAppSelector((state: RootState) => state.ui);
- const shouldPinParametersPanel = useAppSelector(
- (state: RootState) => state.ui.shouldPinParametersPanel
- );
+ const activeTabs = buildTabs(disabledTabs);
const { t } = useTranslation();
@@ -142,7 +142,7 @@ export default function InvokeTabs() {
const tabs = useMemo(
() =>
- tabInfo.map((tab) => (
+ activeTabs.map((tab) => (
)),
- [t]
+ [t, activeTabs]
);
const tabPanels = useMemo(
() =>
- tabInfo.map((tab) => {tab.workarea}),
- []
+ activeTabs.map((tab) => {tab.workarea}),
+ [activeTabs]
);
return (
diff --git a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
index 3d4d68fd4c..5ec5f4f012 100644
--- a/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
+++ b/invokeai/frontend/web/src/features/ui/store/uiSlice.ts
@@ -18,6 +18,8 @@ const initialtabsState: UIState = {
addNewModelUIOption: null,
shouldPinGallery: true,
shouldShowGallery: true,
+ disabledParameterPanels: [],
+ disabledTabs: [],
};
const initialState: UIState = initialtabsState;
@@ -90,6 +92,12 @@ export const uiSlice = createSlice({
state.shouldShowParametersPanel = true;
}
},
+ setDisabledPanels: (state, action: PayloadAction) => {
+ state.disabledParameterPanels = action.payload;
+ },
+ setDisabledTabs: (state, action: PayloadAction) => {
+ state.disabledTabs = action.payload;
+ },
},
extraReducers(builder) {
builder.addCase(initialImageSelected, (state) => {
@@ -118,6 +126,8 @@ export const {
togglePinParametersPanel,
toggleParametersPanel,
toggleGalleryPanel,
+ setDisabledPanels,
+ setDisabledTabs,
} = uiSlice.actions;
export default uiSlice.reducer;
diff --git a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
index 900ea703b4..d4d8cfdcfe 100644
--- a/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
+++ b/invokeai/frontend/web/src/features/ui/store/uiTypes.ts
@@ -1,3 +1,5 @@
+import { InvokeTabName } from './tabMap';
+
export type AddNewModelType = 'ckpt' | 'diffusers' | null;
export interface UIState {
@@ -13,4 +15,6 @@ export interface UIState {
addNewModelUIOption: AddNewModelType;
shouldPinGallery: boolean;
shouldShowGallery: boolean;
+ disabledParameterPanels: string[];
+ disabledTabs: InvokeTabName[];
}