Workspaces layout, automation page
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from '../ui/resizable';
|
||||
import type { LayoutNode, WidgetRegistry } from './types';
|
||||
import { pruneEmptyPanels, countPanels } from './layout-utils';
|
||||
import type { LayoutNode, AppRegistry, PanelComponents } from './types';
|
||||
import { countPanels } from './layout-utils';
|
||||
import { PanelSlot } from './PanelSlot';
|
||||
|
||||
type WorkspaceRendererProps = {
|
||||
layout: LayoutNode;
|
||||
registry: WidgetRegistry;
|
||||
registry: AppRegistry;
|
||||
components?: PanelComponents;
|
||||
editing: boolean;
|
||||
onSetWidget: (panelId: string, widgetType: string | null) => void;
|
||||
onSetApp: (panelId: string, appType: string | null) => void;
|
||||
onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
|
||||
onRemove: (panelId: string) => void;
|
||||
onResized: (groupId: string, sizes: number[]) => void;
|
||||
@@ -17,27 +18,24 @@ type WorkspaceRendererProps = {
|
||||
export const WorkspaceRenderer = ({
|
||||
layout,
|
||||
registry,
|
||||
components,
|
||||
editing,
|
||||
onSetWidget,
|
||||
onSetApp,
|
||||
onSplit,
|
||||
onRemove,
|
||||
onResized,
|
||||
}: WorkspaceRendererProps) => {
|
||||
const displayLayout = editing ? layout : pruneEmptyPanels(layout);
|
||||
if (!displayLayout) {
|
||||
return <div className="flex h-full items-center justify-center text-sm text-muted-foreground">No widgets</div>;
|
||||
}
|
||||
|
||||
const totalPanels = countPanels(layout);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<LayoutNodeRenderer
|
||||
node={displayLayout}
|
||||
node={layout}
|
||||
registry={registry}
|
||||
components={components}
|
||||
editing={editing}
|
||||
totalPanels={totalPanels}
|
||||
onSetWidget={onSetWidget}
|
||||
onSetApp={onSetApp}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
onResized={onResized}
|
||||
@@ -48,30 +46,42 @@ export const WorkspaceRenderer = ({
|
||||
|
||||
type LayoutNodeRendererProps = {
|
||||
node: LayoutNode;
|
||||
registry: WidgetRegistry;
|
||||
registry: AppRegistry;
|
||||
components?: PanelComponents;
|
||||
editing: boolean;
|
||||
totalPanels: number;
|
||||
onSetWidget: (panelId: string, widgetType: string | null) => void;
|
||||
onSetApp: (panelId: string, appType: string | null) => void;
|
||||
onSplit: (panelId: string, direction: 'horizontal' | 'vertical') => void;
|
||||
onRemove: (panelId: string) => void;
|
||||
onResized: (groupId: string, sizes: number[]) => void;
|
||||
};
|
||||
|
||||
const getFixedHeight = (node: LayoutNode, registry: AppRegistry): number | undefined => {
|
||||
if (node.type === 'panel' && node.appType) return registry[node.appType]?.fixedHeight;
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const LayoutNodeRenderer = ({
|
||||
node,
|
||||
registry,
|
||||
components,
|
||||
editing,
|
||||
totalPanels,
|
||||
onSetWidget,
|
||||
onSetApp,
|
||||
onSplit,
|
||||
onRemove,
|
||||
onResized,
|
||||
}: LayoutNodeRendererProps) => {
|
||||
const debounceRef = useRef<ReturnType<typeof setTimeout>>(null);
|
||||
const mountedRef = useRef(false);
|
||||
|
||||
const handleLayout = useCallback(
|
||||
(sizes: number[]) => {
|
||||
if (node.type !== 'group') return;
|
||||
if (!mountedRef.current) {
|
||||
mountedRef.current = true;
|
||||
return;
|
||||
}
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
debounceRef.current = setTimeout(() => {
|
||||
onResized(node.id, sizes);
|
||||
@@ -85,27 +95,56 @@ const LayoutNodeRenderer = ({
|
||||
<PanelSlot
|
||||
panel={node}
|
||||
registry={registry}
|
||||
components={components}
|
||||
editing={editing}
|
||||
isLastPanel={totalPanels <= 1}
|
||||
onSetWidget={onSetWidget}
|
||||
onSetApp={onSetApp}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const hasFixedChild = node.direction === 'vertical' && node.children.some((c) => getFixedHeight(c.node, registry) !== undefined);
|
||||
|
||||
if (hasFixedChild) {
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col">
|
||||
{node.children.map((child) => {
|
||||
const fixed = getFixedHeight(child.node, registry);
|
||||
return (
|
||||
<div key={child.node.id} className={fixed !== undefined ? 'shrink-0' : 'min-h-0 flex-1'} style={fixed !== undefined ? { height: fixed } : undefined}>
|
||||
<LayoutNodeRenderer
|
||||
node={child.node}
|
||||
registry={registry}
|
||||
components={components}
|
||||
editing={editing}
|
||||
totalPanels={totalPanels}
|
||||
onSetApp={onSetApp}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
onResized={onResized}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ResizablePanelGroup direction={node.direction} onLayout={handleLayout} className="h-full w-full">
|
||||
{node.children.map((child, i) => (
|
||||
<ChildEntry key={child.node.id} index={i} total={node.children.length}>
|
||||
<ResizablePanel defaultSize={child.size} minSize={5}>
|
||||
<div className="h-full w-full p-1">
|
||||
<div className="h-full w-full">
|
||||
<LayoutNodeRenderer
|
||||
node={child.node}
|
||||
registry={registry}
|
||||
components={components}
|
||||
editing={editing}
|
||||
totalPanels={totalPanels}
|
||||
onSetWidget={onSetWidget}
|
||||
onSetApp={onSetApp}
|
||||
onSplit={onSplit}
|
||||
onRemove={onRemove}
|
||||
onResized={onResized}
|
||||
|
||||
Reference in New Issue
Block a user