'use client'; import { memo, useMemo, useState, useCallback } from 'react'; import { Group, Panel, type Layout } from 'react-resizable-panels'; import { useDefaultLayout } from '@/lib/layout/use-default-layout'; import { useResponsiveBreakpoint } from '@/hooks/use-responsive-breakpoint'; import { useSessionLayoutState } from '@/hooks/use-session-layout-state'; import { TaskCenterPanel } from './task-center-panel'; import { TaskRightPanel } from './task-right-panel'; import { TaskFilesPanel } from './task-files-panel'; import { TaskSessionSidebar } from './task-session-sidebar'; import { SessionMobileLayout, SessionTabletLayout } from './mobile'; import { PreviewPanel } from '@/components/task/preview/preview-panel'; import { PreviewController } from '@/components/task/preview/preview-controller'; import { useLayoutStore } from '@/lib/state/layout-store'; import type { Repository, RepositoryScript } from '@/lib/types/http'; import type { Terminal } from '@/hooks/domains/session/use-terminals'; // Re-export for backwards compatibility export type { SelectedDiff } from '@/hooks/use-session-layout-state'; const DEFAULT_HORIZONTAL_LAYOUT: Record = { left: 18, chat: 57, preview: 57, right: 25, }; const DEFAULT_PREVIEW_LAYOUT: Record = { chat: 60, preview: 40, }; const DEFAULT_LAYOUT_STATE = { left: true, chat: true, right: true, preview: false }; type TaskLayoutProps = { workspaceId: string | null; boardId: string | null; sessionId?: string | null; repository?: Repository | null; initialScripts?: RepositoryScript[]; initialTerminals?: Terminal[]; defaultLayouts?: Record; taskTitle?: string; baseBranch?: string; worktreeBranch?: string | null; }; export const TaskLayout = memo(function TaskLayout({ workspaceId, boardId, sessionId = null, repository = null, initialScripts = [], initialTerminals, defaultLayouts = {}, taskTitle, baseBranch, worktreeBranch, }: TaskLayoutProps) { const { isMobile, isTablet } = useResponsiveBreakpoint(); // Use shared layout state hook const { effectiveSessionId, sessionKey, selectedDiff, handleSelectDiff, handleClearSelectedDiff, openFileRequest, handleOpenFile, handleFileOpenHandled, } = useSessionLayoutState({ sessionId }); // Track active file path for highlighting in file tree const [activeFilePath, setActiveFilePath] = useState(null); const handleActiveFileChange = useCallback((filePath: string | null) => { setActiveFilePath(filePath); }, []); const layoutBySession = useLayoutStore((state) => state.columnsBySessionId); const layoutState = useMemo( () => layoutBySession[sessionKey] ?? DEFAULT_LAYOUT_STATE, [layoutBySession, sessionKey] ); const hasDevScript = Boolean(repository?.dev_script?.trim()); const sessionForPreview = effectiveSessionId; const horizontalPanelIds = useMemo(() => { const ids: string[] = []; if (layoutState.left) ids.push('left'); ids.push(layoutState.preview ? 'preview' : 'chat'); if (layoutState.right) ids.push('right'); return ids; }, [layoutState.left, layoutState.preview, layoutState.right]); const horizontalLayoutKey = `task-layout-horizontal-v3:${horizontalPanelIds.join('|')}`; const { defaultLayout: defaultHorizontalLayout, onLayoutChanged: onHorizontalLayoutChange } = useDefaultLayout({ id: horizontalLayoutKey, panelIds: horizontalPanelIds, baseLayout: DEFAULT_HORIZONTAL_LAYOUT, serverDefaultLayout: defaultLayouts[horizontalLayoutKey], }); const previewPanelIds = ['chat', 'preview']; const previewLayoutKey = 'task-layout-preview-v2'; const { defaultLayout: defaultPreviewLayout, onLayoutChanged: onPreviewLayoutChange } = useDefaultLayout({ id: previewLayoutKey, panelIds: previewPanelIds, baseLayout: DEFAULT_PREVIEW_LAYOUT, serverDefaultLayout: defaultLayouts[previewLayoutKey], }); // Mobile layout if (isMobile) { return ( ); } // Tablet layout if (isTablet) { return ( ); } // Desktop layout const topFilesPanel = ( ); return (
{layoutState.left ? ( <> ) : null} {layoutState.preview ? ( ) : ( )} {layoutState.right ? ( <> ) : null}
); });