Skip to content

Commit 3f78ac9

Browse files
psychedeliciousmaryhipp
authored andcommitted
fix(ui): really do not load disabled tabs
Ensure disabled tabs are never mounted: - Add didLoad flag to configSlice, default false - Always merge in config - even it is is empty - On first merge, set didLoad to true - Until didLoad is true, mark _all_ tabs as disabled This gets around an issue where tabs are all enabled for a brief moment before the config is loaded. A bit hacky but it works.
1 parent 79fea1a commit 3f78ac9

File tree

4 files changed

+75
-40
lines changed

4 files changed

+75
-40
lines changed

invokeai/frontend/web/src/app/components/GlobalHookIsolator.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import type { PartialAppConfig } from 'app/types/invokeai';
1010
import { useFocusRegionWatcher } from 'common/hooks/focus';
1111
import { useCloseChakraTooltipsOnDragFix } from 'common/hooks/useCloseChakraTooltipsOnDragFix';
1212
import { useGlobalHotkeys } from 'common/hooks/useGlobalHotkeys';
13-
import { size } from 'es-toolkit/compat';
1413
import { useDynamicPromptsWatcher } from 'features/dynamicPrompts/hooks/useDynamicPromptsWatcher';
1514
import { useStarterModelsToast } from 'features/modelManagerV2/hooks/useStarterModelsToast';
1615
import { useWorkflowBuilderWatcher } from 'features/nodes/components/sidePanel/workflow/IsolatedWorkflowBuilderWatcher';
@@ -55,10 +54,8 @@ export const GlobalHookIsolator = memo(
5554
}, [language]);
5655

5756
useEffect(() => {
58-
if (size(config)) {
59-
logger.info({ config }, 'Received config');
60-
dispatch(configChanged(config));
61-
}
57+
logger.info({ config }, 'Received config');
58+
dispatch(configChanged(config));
6259
}, [dispatch, config, logger]);
6360

6461
useEffect(() => {

invokeai/frontend/web/src/features/system/store/configSlice.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ const baseDimensionConfig: NumericalParameterConfig = {
1616
coarseStep: 64,
1717
};
1818

19-
const initialConfigState: AppConfig = {
19+
const initialConfigState: AppConfig & { didLoad: boolean } = {
20+
didLoad: false,
2021
isLocal: true,
2122
shouldUpdateImagesOnConnect: false,
2223
shouldFetchMetadataFromApi: false,
@@ -191,14 +192,16 @@ export const configSlice = createSlice({
191192
reducers: {
192193
configChanged: (state, action: PayloadAction<PartialAppConfig>) => {
193194
merge(state, action.payload);
195+
state.didLoad = true;
194196
},
195197
},
196198
});
197199

198200
export const { configChanged } = configSlice.actions;
199201

200202
export const selectConfigSlice = (state: RootState) => state.config;
201-
const createConfigSelector = <T>(selector: Selector<AppConfig, T>) => createSelector(selectConfigSlice, selector);
203+
const createConfigSelector = <T>(selector: Selector<typeof initialConfigState, T>) =>
204+
createSelector(selectConfigSlice, selector);
202205

203206
export const selectWidthConfig = createConfigSelector((config) => config.sd.width);
204207
export const selectHeightConfig = createConfigSelector((config) => config.sd.height);
@@ -236,3 +239,23 @@ export const selectEnabledTabs = createConfigSelector((config) => {
236239
}
237240
return enabledTabs;
238241
});
242+
const selectDisabledTabs = createConfigSelector((config) => config.disabledTabs);
243+
const selectDidLoad = createConfigSelector((config) => config.didLoad);
244+
export const selectWithGenerateTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
245+
didLoad ? !disabledTabs.includes('generate') : false
246+
);
247+
export const selectWithCanvasTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
248+
didLoad ? !disabledTabs.includes('canvas') : false
249+
);
250+
export const selectWithUpscalingTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
251+
didLoad ? !disabledTabs.includes('upscaling') : false
252+
);
253+
export const selectWithWorkflowsTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
254+
didLoad ? !disabledTabs.includes('workflows') : false
255+
);
256+
export const selectWithModelsTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
257+
didLoad ? !disabledTabs.includes('models') : false
258+
);
259+
export const selectWithQueueTab = createSelector(selectDidLoad, selectDisabledTabs, (didLoad, disabledTabs) =>
260+
didLoad ? !disabledTabs.includes('queue') : false
261+
);

invokeai/frontend/web/src/features/ui/components/AppContent.tsx

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import 'features/ui/styles/dockview-theme-invoke.css';
44
import { TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library';
55
import { useAppSelector } from 'app/store/storeHooks';
66
import { useDndMonitor } from 'features/dnd/useDndMonitor';
7+
import {
8+
selectWithCanvasTab,
9+
selectWithGenerateTab,
10+
selectWithModelsTab,
11+
selectWithQueueTab,
12+
selectWithUpscalingTab,
13+
selectWithWorkflowsTab,
14+
} from 'features/system/store/configSlice';
715
import { VerticalNavBar } from 'features/ui/components/VerticalNavBar';
816
import { CanvasTabAutoLayout } from 'features/ui/layouts/canvas-tab-auto-layout';
917
import { GenerateTabAutoLayout } from 'features/ui/layouts/generate-tab-auto-layout';
@@ -12,48 +20,53 @@ import { WorkflowsTabAutoLayout } from 'features/ui/layouts/workflows-tab-auto-l
1220
import { selectActiveTabIndex } from 'features/ui/store/uiSelectors';
1321
import { memo } from 'react';
1422

15-
import { TabMountGate } from './TabMountGate';
1623
import ModelManagerTab from './tabs/ModelManagerTab';
1724
import QueueTab from './tabs/QueueTab';
1825

1926
export const AppContent = memo(() => {
20-
const tabIndex = useAppSelector(selectActiveTabIndex);
2127
useDndMonitor();
28+
const tabIndex = useAppSelector(selectActiveTabIndex);
29+
const withGenerateTab = useAppSelector(selectWithGenerateTab);
30+
const withCanvasTab = useAppSelector(selectWithCanvasTab);
31+
const withUpscalingTab = useAppSelector(selectWithUpscalingTab);
32+
const withWorkflowsTab = useAppSelector(selectWithWorkflowsTab);
33+
const withModelsTab = useAppSelector(selectWithModelsTab);
34+
const withQueueTab = useAppSelector(selectWithQueueTab);
2235

2336
return (
2437
<Tabs index={tabIndex} display="flex" w="full" h="full" p={0} overflow="hidden">
2538
<VerticalNavBar />
2639
<TabPanels w="full" h="full" p={0}>
27-
<TabMountGate tab="generate">
40+
{withGenerateTab && (
2841
<TabPanel w="full" h="full" p={0}>
2942
<GenerateTabAutoLayout />
3043
</TabPanel>
31-
</TabMountGate>
32-
<TabMountGate tab="canvas">
44+
)}
45+
{withCanvasTab && (
3346
<TabPanel w="full" h="full" p={0}>
3447
<CanvasTabAutoLayout />
3548
</TabPanel>
36-
</TabMountGate>
37-
<TabMountGate tab="upscaling">
49+
)}
50+
{withUpscalingTab && (
3851
<TabPanel w="full" h="full" p={0}>
3952
<UpscalingTabAutoLayout />
4053
</TabPanel>
41-
</TabMountGate>
42-
<TabMountGate tab="workflows">
54+
)}
55+
{withWorkflowsTab && (
4356
<TabPanel w="full" h="full" p={0}>
4457
<WorkflowsTabAutoLayout />
4558
</TabPanel>
46-
</TabMountGate>
47-
<TabMountGate tab="models">
59+
)}
60+
{withModelsTab && (
4861
<TabPanel w="full" h="full" p={0}>
4962
<ModelManagerTab />
5063
</TabPanel>
51-
</TabMountGate>
52-
<TabMountGate tab="queue">
64+
)}
65+
{withQueueTab && (
5366
<TabPanel w="full" h="full" p={0}>
5467
<QueueTab />
5568
</TabPanel>
56-
</TabMountGate>
69+
)}
5770
</TabPanels>
5871
</Tabs>
5972
);

invokeai/frontend/web/src/features/ui/components/VerticalNavBar.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import { Flex, Spacer } from '@invoke-ai/ui-library';
22
import { useStore } from '@nanostores/react';
33
import { $customNavComponent } from 'app/store/nanostores/customNavComponent';
4+
import { useAppSelector } from 'app/store/storeHooks';
45
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
56
import SettingsMenu from 'features/system/components/SettingsModal/SettingsMenu';
67
import StatusIndicator from 'features/system/components/StatusIndicator';
78
import { VideosModalButton } from 'features/system/components/VideosModal/VideosModalButton';
8-
import { TabMountGate } from 'features/ui/components/TabMountGate';
9+
import {
10+
selectWithCanvasTab,
11+
selectWithGenerateTab,
12+
selectWithModelsTab,
13+
selectWithQueueTab,
14+
selectWithUpscalingTab,
15+
selectWithWorkflowsTab,
16+
} from 'features/system/store/configSlice';
917
import { memo } from 'react';
1018
import { useTranslation } from 'react-i18next';
1119
import {
@@ -23,29 +31,23 @@ import { TabButton } from './TabButton';
2331
export const VerticalNavBar = memo(() => {
2432
const { t } = useTranslation();
2533
const customNavComponent = useStore($customNavComponent);
34+
const withGenerateTab = useAppSelector(selectWithGenerateTab);
35+
const withCanvasTab = useAppSelector(selectWithCanvasTab);
36+
const withUpscalingTab = useAppSelector(selectWithUpscalingTab);
37+
const withWorkflowsTab = useAppSelector(selectWithWorkflowsTab);
38+
const withModelsTab = useAppSelector(selectWithModelsTab);
39+
const withQueueTab = useAppSelector(selectWithQueueTab);
2640

2741
return (
2842
<Flex flexDir="column" alignItems="center" py={6} ps={4} pe={2} gap={4} minW={0} flexShrink={0}>
2943
<InvokeAILogoComponent />
3044
<Flex gap={6} pt={6} h="full" flexDir="column">
31-
<TabMountGate tab="generate">
32-
<TabButton tab="generate" icon={<PiTextAaBold />} label="Generate" />
33-
</TabMountGate>
34-
<TabMountGate tab="canvas">
35-
<TabButton tab="canvas" icon={<PiBoundingBoxBold />} label={t('ui.tabs.canvas')} />
36-
</TabMountGate>
37-
<TabMountGate tab="upscaling">
38-
<TabButton tab="upscaling" icon={<PiFrameCornersBold />} label={t('ui.tabs.upscaling')} />
39-
</TabMountGate>
40-
<TabMountGate tab="workflows">
41-
<TabButton tab="workflows" icon={<PiFlowArrowBold />} label={t('ui.tabs.workflows')} />
42-
</TabMountGate>
43-
<TabMountGate tab="models">
44-
<TabButton tab="models" icon={<PiCubeBold />} label={t('ui.tabs.models')} />
45-
</TabMountGate>
46-
<TabMountGate tab="queue">
47-
<TabButton tab="queue" icon={<PiQueueBold />} label={t('ui.tabs.queue')} />
48-
</TabMountGate>
45+
{withGenerateTab && <TabButton tab="generate" icon={<PiTextAaBold />} label="Generate" />}
46+
{withCanvasTab && <TabButton tab="canvas" icon={<PiBoundingBoxBold />} label={t('ui.tabs.canvas')} />}
47+
{withUpscalingTab && <TabButton tab="upscaling" icon={<PiFrameCornersBold />} label={t('ui.tabs.upscaling')} />}
48+
{withWorkflowsTab && <TabButton tab="workflows" icon={<PiFlowArrowBold />} label={t('ui.tabs.workflows')} />}
49+
{withModelsTab && <TabButton tab="models" icon={<PiCubeBold />} label={t('ui.tabs.models')} />}
50+
{withQueueTab && <TabButton tab="queue" icon={<PiQueueBold />} label={t('ui.tabs.queue')} />}
4951
</Flex>
5052
<Spacer />
5153
<StatusIndicator />

0 commit comments

Comments
 (0)