From ff84b0a495954feea486162770f4ad8b377f1edd Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Fri, 4 Jul 2025 12:09:51 +1000 Subject: [PATCH] refactor(ui): navigation api --- .../src/features/ui/components/AppContent.tsx | 55 ++++++------------- .../ui/layouts/canvas-tab-auto-layout.tsx | 15 ++--- .../ui/layouts/generate-tab-auto-layout.tsx | 15 ++--- .../src/features/ui/layouts/navigation-api.ts | 2 +- .../ui/layouts/upscaling-tab-auto-layout.tsx | 16 +++--- .../ui/layouts/workflows-tab-auto-layout.tsx | 15 ++--- 6 files changed, 50 insertions(+), 68 deletions(-) diff --git a/invokeai/frontend/web/src/features/ui/components/AppContent.tsx b/invokeai/frontend/web/src/features/ui/components/AppContent.tsx index 618877f578..2e67c94b2f 100644 --- a/invokeai/frontend/web/src/features/ui/components/AppContent.tsx +++ b/invokeai/frontend/web/src/features/ui/components/AppContent.tsx @@ -1,8 +1,9 @@ import 'dockview/dist/styles/dockview.css'; import 'features/ui/styles/dockview-theme-invoke.css'; -import { TabPanel, TabPanels, Tabs } from '@invoke-ai/ui-library'; +import { Flex } from '@invoke-ai/ui-library'; import { useAppSelector } from 'app/store/storeHooks'; +import Loading from 'common/components/Loading/Loading'; import { useDndMonitor } from 'features/dnd/useDndMonitor'; import { selectWithCanvasTab, @@ -17,15 +18,16 @@ import { CanvasTabAutoLayout } from 'features/ui/layouts/canvas-tab-auto-layout' import { GenerateTabAutoLayout } from 'features/ui/layouts/generate-tab-auto-layout'; import { UpscalingTabAutoLayout } from 'features/ui/layouts/upscaling-tab-auto-layout'; import { WorkflowsTabAutoLayout } from 'features/ui/layouts/workflows-tab-auto-layout'; -import { selectActiveTabIndex } from 'features/ui/store/uiSelectors'; -import { memo } from 'react'; +import { selectActiveTab } from 'features/ui/store/uiSelectors'; +import { memo, useState } from 'react'; import ModelManagerTab from './tabs/ModelManagerTab'; import QueueTab from './tabs/QueueTab'; export const AppContent = memo(() => { useDndMonitor(); - const tabIndex = useAppSelector(selectActiveTabIndex); + const tab = useAppSelector(selectActiveTab); + const [isLoading, setIsLoading] = useState(true); const withGenerateTab = useAppSelector(selectWithGenerateTab); const withCanvasTab = useAppSelector(selectWithCanvasTab); const withUpscalingTab = useAppSelector(selectWithUpscalingTab); @@ -34,41 +36,18 @@ export const AppContent = memo(() => { const withQueueTab = useAppSelector(selectWithQueueTab); return ( - + - - {withGenerateTab && ( - - - - )} - {withCanvasTab && ( - - - - )} - {withUpscalingTab && ( - - - - )} - {withWorkflowsTab && ( - - - - )} - {withModelsTab && ( - - - - )} - {withQueueTab && ( - - - - )} - - + + {withGenerateTab && tab === 'generate' && } + {withCanvasTab && tab === 'canvas' && } + {withUpscalingTab && tab === 'upscaling' && } + {withWorkflowsTab && tab === 'workflows' && } + {withModelsTab && tab === 'models' && } + {withQueueTab && tab === 'queue' && } + {isLoading && } + + ); }); AppContent.displayName = 'AppContent'; diff --git a/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx index 27f78fd49d..980ffedf2b 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/canvas-tab-auto-layout.tsx @@ -56,7 +56,6 @@ import { } from './shared'; import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon'; import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator'; -import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible'; const tabComponents = { [DEFAULT_TAB_ID]: TabWithoutCloseButton, @@ -326,28 +325,30 @@ export const initializeRootPanelLayout = (api: GridviewApi) => { return { main, left, right } satisfies Record; }; -export const CanvasTabAutoLayout = memo(() => { +export const CanvasTabAutoLayout = memo(({ setIsLoading }: { setIsLoading: (isLoading: boolean) => void }) => { const rootRef = useRef(null); const [rootApi, setRootApi] = useState(null); const onReady = useCallback(({ api }) => { setRootApi(api); }, []); - useResizeMainPanelOnFirstVisit(rootApi, rootRef); - useEffect(() => { + setIsLoading(true); + if (!rootApi) { return; } + initializeRootPanelLayout(rootApi); - // Focus the launchpad panel once it's ready - navigationApi.focusPanel('canvas', LAUNCHPAD_PANEL_ID); + setTimeout(() => { + setIsLoading(false); + }, 300); return () => { navigationApi.unregisterTab('canvas'); }; - }, [rootApi]); + }, [rootApi, setIsLoading]); return ( diff --git a/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx index 1cd6e1eab6..3a5d99eb7b 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/generate-tab-auto-layout.tsx @@ -51,7 +51,6 @@ import { } from './shared'; import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon'; import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator'; -import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible'; const tabComponents = { [DEFAULT_TAB_ID]: TabWithoutCloseButton, @@ -288,28 +287,30 @@ export const initializeRootPanelLayout = (layoutApi: GridviewApi) => { return { main, left, right } satisfies Record; }; -export const GenerateTabAutoLayout = memo(() => { +export const GenerateTabAutoLayout = memo(({ setIsLoading }: { setIsLoading: (isLoading: boolean) => void }) => { const rootRef = useRef(null); const [rootApi, setRootApi] = useState(null); const onReady = useCallback(({ api }) => { setRootApi(api); }, []); - useResizeMainPanelOnFirstVisit(rootApi, rootRef); - useEffect(() => { + setIsLoading(true); + if (!rootApi) { return; } + initializeRootPanelLayout(rootApi); - // Focus the launchpad panel once it's ready - navigationApi.focusPanel('generate', LAUNCHPAD_PANEL_ID); + setTimeout(() => { + setIsLoading(false); + }, 300); return () => { navigationApi.unregisterTab('generate'); }; - }, [rootApi]); + }, [rootApi, setIsLoading]); return ( diff --git a/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts b/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts index ddc9384b16..5a5018ca5e 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts +++ b/invokeai/frontend/web/src/features/ui/layouts/navigation-api.ts @@ -14,7 +14,7 @@ type Waiter = { timeoutId: ReturnType | null; }; -const PANEL_ENABLED_TABS: TabName[] = ['canvas', 'generate', 'workflows', 'queue']; +const PANEL_ENABLED_TABS: TabName[] = ['canvas', 'generate', 'workflows', 'upscaling']; export class NavigationApi { private panels: Map = new Map(); diff --git a/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx index dbc9771c2a..f9a5667fcd 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/upscaling-tab-auto-layout.tsx @@ -51,7 +51,6 @@ import { import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon'; import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator'; import { UpscalingTabLeftPanel } from './UpscalingTabLeftPanel'; -import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible'; const tabComponents = { [DEFAULT_TAB_ID]: TabWithoutCloseButton, @@ -288,28 +287,29 @@ export const initializeRootPanelLayout = (layoutApi: GridviewApi) => { return { main, left, right } satisfies Record; }; -export const UpscalingTabAutoLayout = memo(() => { +export const UpscalingTabAutoLayout = memo(({ setIsLoading }: { setIsLoading: (isLoading: boolean) => void }) => { const rootRef = useRef(null); const [rootApi, setRootApi] = useState(null); const onReady = useCallback(({ api }) => { setRootApi(api); }, []); - useResizeMainPanelOnFirstVisit(rootApi, rootRef); - useEffect(() => { + setIsLoading(true); + if (!rootApi) { return; } + initializeRootPanelLayout(rootApi); - // Focus the launchpad panel once it's ready - navigationApi.focusPanel('upscaling', LAUNCHPAD_PANEL_ID); - + setTimeout(() => { + setIsLoading(false); + }, 300); return () => { navigationApi.unregisterTab('upscaling'); }; - }, [rootApi]); + }, [rootApi, setIsLoading]); return ( diff --git a/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx b/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx index 6003c2b650..d4bc09b586 100644 --- a/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx +++ b/invokeai/frontend/web/src/features/ui/layouts/workflows-tab-auto-layout.tsx @@ -53,7 +53,6 @@ import { } from './shared'; import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon'; import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator'; -import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible'; const tabComponents = { [DEFAULT_TAB_ID]: TabWithoutCloseButton, @@ -305,28 +304,30 @@ export const initializeRootPanelLayout = (api: GridviewApi) => { return { main, left, right } satisfies Record; }; -export const WorkflowsTabAutoLayout = memo(() => { +export const WorkflowsTabAutoLayout = memo(({ setIsLoading }: { setIsLoading: (isLoading: boolean) => void }) => { const rootRef = useRef(null); const [rootApi, setRootApi] = useState(null); const onReady = useCallback(({ api }) => { setRootApi(api); }, []); - useResizeMainPanelOnFirstVisit(rootApi, rootRef); - useEffect(() => { + setIsLoading(true); + if (!rootApi) { return; } + initializeRootPanelLayout(rootApi); - // Focus the launchpad panel once it's ready - navigationApi.focusPanel('workflows', LAUNCHPAD_PANEL_ID); + setTimeout(() => { + setIsLoading(false); + }, 300); return () => { navigationApi.unregisterTab('workflows'); }; - }, [rootApi]); + }, [rootApi, setIsLoading]); return (