feat(ui): clean up auto layout context for panels

This commit is contained in:
psychedelicious
2025-07-07 22:57:20 +10:00
parent 0652b12a6f
commit 7de26f8e69
7 changed files with 57 additions and 112 deletions

View File

@@ -1,22 +1,21 @@
import type { FocusRegionName } from 'common/hooks/focus';
import type { IDockviewPanelProps, IGridviewPanelProps } from 'dockview';
import type { TabName } from 'features/ui/store/uiTypes';
import type { FunctionComponent, PropsWithChildren, RefObject } from 'react';
import type { FunctionComponent, PropsWithChildren } from 'react';
import { createContext, memo, useContext, useMemo } from 'react';
import { AutoLayoutPanelContainer } from './AutoLayoutPanelContainer';
type AutoLayoutContextValue = {
tab: TabName;
rootRef: RefObject<HTMLDivElement>;
};
const AutoLayoutContext = createContext<AutoLayoutContextValue | null>(null);
export const AutoLayoutProvider = (props: PropsWithChildren<AutoLayoutContextValue>) => {
const { tab, rootRef, children } = props;
const { tab, children } = props;
const value = useMemo<AutoLayoutContextValue>(() => ({ tab, rootRef }), [tab, rootRef]);
const value = useMemo<AutoLayoutContextValue>(() => ({ tab }), [tab]);
return <AutoLayoutContext.Provider value={value}>{children}</AutoLayoutContext.Provider>;
};

View File

@@ -25,7 +25,7 @@ import { AutoLayoutProvider, useAutoLayoutContext, withPanelContainer } from 'fe
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import type { TabName } from 'features/ui/store/uiTypes';
import { dockviewTheme } from 'features/ui/styles/theme';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { CanvasTabLeftPanel } from './CanvasTabLeftPanel';
import { CanvasWorkspacePanel } from './CanvasWorkspacePanel';
@@ -326,30 +326,21 @@ const initializeRootPanelLayout = (api: GridviewApi) => {
};
export const CanvasTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('canvas');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('canvas');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="canvas" rootRef={rootRef}>
<AutoLayoutProvider tab="canvas">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}

View File

@@ -24,7 +24,7 @@ import { AutoLayoutProvider, useAutoLayoutContext, withPanelContainer } from 'fe
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import type { TabName } from 'features/ui/store/uiTypes';
import { dockviewTheme } from 'features/ui/styles/theme';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { GenerateTabLeftPanel } from './GenerateTabLeftPanel';
import { navigationApi } from './navigation-api';
@@ -288,30 +288,21 @@ const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
};
export const GenerateTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('generate');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('generate');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="generate" rootRef={rootRef}>
<AutoLayoutProvider tab="generate">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}

View File

@@ -3,7 +3,7 @@ import { GridviewReact, LayoutPriority, Orientation } from 'dockview';
import ModelManagerTab from 'features/ui/components/tabs/ModelManagerTab';
import type { RootLayoutGridviewComponents } from 'features/ui/layouts/auto-layout-context';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { navigationApi } from './navigation-api';
import { MODELS_PANEL_ID } from './shared';
@@ -25,30 +25,21 @@ const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
};
export const ModelsTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('models');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('models');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="models" rootRef={rootRef}>
<AutoLayoutProvider tab="models">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}

View File

@@ -3,7 +3,7 @@ import { GridviewReact, LayoutPriority, Orientation } from 'dockview';
import QueueTab from 'features/ui/components/tabs/QueueTab';
import type { RootLayoutGridviewComponents } from 'features/ui/layouts/auto-layout-context';
import { AutoLayoutProvider } from 'features/ui/layouts/auto-layout-context';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { navigationApi } from './navigation-api';
import { QUEUE_PANEL_ID } from './shared';
@@ -25,30 +25,21 @@ const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
};
export const QueueTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('queue');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('queue');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="queue" rootRef={rootRef}>
<AutoLayoutProvider tab="queue">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}

View File

@@ -24,7 +24,7 @@ import { AutoLayoutProvider, useAutoLayoutContext, withPanelContainer } from 'fe
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import type { TabName } from 'features/ui/store/uiTypes';
import { dockviewTheme } from 'features/ui/styles/theme';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { navigationApi } from './navigation-api';
import { PanelHotkeysLogical } from './PanelHotkeysLogical';
@@ -288,30 +288,21 @@ const initializeRootPanelLayout = (layoutApi: GridviewApi) => {
};
export const UpscalingTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('upscaling');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('upscaling');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="upscaling" rootRef={rootRef}>
<AutoLayoutProvider tab="upscaling">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}

View File

@@ -26,7 +26,7 @@ import { AutoLayoutProvider, useAutoLayoutContext, withPanelContainer } from 'fe
import { TabWithoutCloseButton } from 'features/ui/layouts/TabWithoutCloseButton';
import type { TabName } from 'features/ui/store/uiTypes';
import { dockviewTheme } from 'features/ui/styles/theme';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { navigationApi } from './navigation-api';
import { PanelHotkeysLogical } from './PanelHotkeysLogical';
@@ -305,30 +305,21 @@ const initializeRootPanelLayout = (api: GridviewApi) => {
};
export const WorkflowsTabAutoLayout = memo(() => {
const rootRef = useRef<HTMLDivElement>(null);
const [rootApi, setRootApi] = useState<GridviewApi | null>(null);
const onReady = useCallback<IGridviewReactProps['onReady']>(({ api }) => {
setRootApi(api);
initializeRootPanelLayout(api);
navigationApi.onTabReady('workflows');
}, []);
useEffect(() => {
if (!rootApi) {
return;
}
initializeRootPanelLayout(rootApi);
navigationApi.onSwitchedTab();
return () => {
useEffect(
() => () => {
navigationApi.unregisterTab('workflows');
};
}, [rootApi]);
},
[]
);
return (
<AutoLayoutProvider tab="workflows" rootRef={rootRef}>
<AutoLayoutProvider tab="workflows">
<GridviewReact
ref={rootRef}
className="dockview-theme-invoke"
components={rootPanelComponents}
onReady={onReady}