mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
- Introduced comprehensive documentation for the queue management feature, detailing its pain points, core functionalities, and component structure. - Added terminal dashboard documentation, highlighting its layout, core features, and usage examples. - Created an index page in Chinese for Claude Code Workflow, summarizing its purpose and core features, along with quick links to installation and guides.
633 lines
22 KiB
Markdown
633 lines
22 KiB
Markdown
# Terminal Dashboard
|
|
|
|
## One-Liner
|
|
**The Terminal Dashboard provides a terminal-first workspace with resizable panes, floating panels, and integrated tools for session monitoring and orchestration.**
|
|
|
|
---
|
|
|
|
## Pain Points Solved
|
|
|
|
| Pain Point | Current State | Terminal Dashboard Solution |
|
|
|------------|---------------|-----------------------------|
|
|
| **Scattered terminals** | Multiple terminal windows | Unified tmux-style grid layout |
|
|
| **No context linkage** | Can't associate terminal output with issues | Association highlight provider |
|
|
| **Panel overload** | Fixed layout wastes space | Floating panels (mutually exclusive) |
|
|
| **Missing tools** | Switch between apps | Integrated issues, queue, inspector, scheduler |
|
|
| **Limited workspace** | Can't see code and terminals together | Resizable three-column layout |
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
**Location**: `ccw/frontend/src/pages/TerminalDashboardPage.tsx`
|
|
|
|
**Purpose**: Terminal-first layout for multi-terminal session management with integrated tools and resizable panels.
|
|
|
|
**Access**: Navigation → Terminal Dashboard (`/terminal-dashboard`)
|
|
|
|
**Layout**:
|
|
```
|
|
+--------------------------------------------------------------------------+
|
|
| Dashboard Toolbar (panel toggles, layout presets, fullscreen) |
|
|
+--------------------------------------------------------------------------+
|
|
| +----------------+-------------------------------------------+------------+ |
|
|
| | Session | Terminal Grid (tmux-style) | File | |
|
|
| | Group Tree | +----------+ +----------+ | Sidebar | |
|
|
| | (resizable) | | Term 1 | | Term 2 | | (resizable)| |
|
|
| | | +----------+ +----------+ | | |
|
|
| | | +----------+ +----------+ | | |
|
|
| | | | Term 3 | | Term 4 | | | |
|
|
| | | +----------+ +----------+ | | |
|
|
| +----------------+-------------------------------------------+------------+ |
|
|
+--------------------------------------------------------------------------+
|
|
| [Floating Panel: Issues+Queue OR Inspector OR Execution OR Scheduler] |
|
|
+--------------------------------------------------------------------------+
|
|
```
|
|
|
|
---
|
|
|
|
## Live Demo
|
|
|
|
:::demo TerminalDashboardOverview
|
|
# terminal-dashboard-overview.tsx
|
|
/**
|
|
* Terminal Dashboard Overview Demo
|
|
* Shows the three-column layout with resizable panes and toolbar
|
|
*/
|
|
export function TerminalDashboardOverview() {
|
|
const [fileSidebarOpen, setFileSidebarOpen] = React.useState(true)
|
|
const [sessionSidebarOpen, setSessionSidebarOpen] = React.useState(true)
|
|
const [activePanel, setActivePanel] = React.useState(null)
|
|
|
|
return (
|
|
<div className="h-[600px] flex flex-col bg-background">
|
|
{/* Toolbar */}
|
|
<div className="flex items-center justify-between px-3 py-2 border-b bg-muted/30">
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-sm font-medium">Terminal Dashboard</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
{['Sessions', 'Files', 'Issues', 'Queue', 'Inspector', 'Scheduler'].map((item) => (
|
|
<button
|
|
key={item}
|
|
onClick={() => {
|
|
if (item === 'Sessions') setSessionSidebarOpen(!sessionSidebarOpen)
|
|
else if (item === 'Files') setFileSidebarOpen(!fileSidebarOpen)
|
|
else setActivePanel(activePanel === item.toLowerCase() ? null : item.toLowerCase())
|
|
}}
|
|
className={`px-2 py-1 text-xs rounded transition-colors ${
|
|
(item === 'Sessions' && sessionSidebarOpen) ||
|
|
(item === 'Files' && fileSidebarOpen) ||
|
|
activePanel === item.toLowerCase()
|
|
? 'bg-primary text-primary-foreground'
|
|
: 'hover:bg-accent'
|
|
}`}
|
|
>
|
|
{item}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Layout */}
|
|
<div className="flex-1 flex min-h-0">
|
|
{/* Session Sidebar */}
|
|
{sessionSidebarOpen && (
|
|
<div className="w-60 border-r flex flex-col">
|
|
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
|
|
Session Groups
|
|
</div>
|
|
<div className="flex-1 p-2 space-y-1 text-sm overflow-auto">
|
|
{['Active Sessions', 'Completed', 'Archived'].map((group) => (
|
|
<div key={group}>
|
|
<div className="flex items-center gap-1 px-2 py-1 rounded hover:bg-accent cursor-pointer">
|
|
<span className="text-xs">▼</span>
|
|
<span>{group}</span>
|
|
</div>
|
|
<div className="ml-4 space-y-0.5">
|
|
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
|
|
Session 1
|
|
</div>
|
|
<div className="px-2 py-1 text-xs text-muted-foreground hover:bg-accent rounded cursor-pointer">
|
|
Session 2
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Terminal Grid */}
|
|
<div className="flex-1 bg-muted/20 p-2">
|
|
<div className="grid grid-cols-2 grid-rows-2 gap-2 h-full">
|
|
{[1, 2, 3, 4].map((i) => (
|
|
<div key={i} className="bg-background border rounded p-3 font-mono text-xs">
|
|
<div className="text-green-500 mb-2">$ Terminal {i}</div>
|
|
<div className="text-muted-foreground">
|
|
<div>Working directory: /project</div>
|
|
<div>Type a command to begin...</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* File Sidebar */}
|
|
{fileSidebarOpen && (
|
|
<div className="w-64 border-l flex flex-col">
|
|
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
|
|
Project Files
|
|
</div>
|
|
<div className="flex-1 p-2 text-sm overflow-auto">
|
|
<div className="space-y-1">
|
|
{['src', 'docs', 'tests', 'package.json', 'README.md'].map((item) => (
|
|
<div key={item} className="px-2 py-1 rounded hover:bg-accent cursor-pointer flex items-center gap-2">
|
|
<span className="text-xs text-muted-foreground">📁</span>
|
|
{item}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Floating Panel */}
|
|
{activePanel && (
|
|
<div className="absolute top-12 right-4 w-80 bg-background border rounded-lg shadow-lg">
|
|
<div className="flex items-center justify-between px-3 py-2 border-b">
|
|
<span className="text-sm font-medium capitalize">{activePanel} Panel</span>
|
|
<button onClick={() => setActivePanel(null)} className="text-xs hover:bg-accent px-2 py-1 rounded">
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div className="p-4 text-sm text-muted-foreground">
|
|
{activePanel} content placeholder
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
:::
|
|
|
|
---
|
|
|
|
## Core Features
|
|
|
|
| Feature | Description |
|
|
|---------|-------------|
|
|
| **Three-Column Layout** | Resizable panes using Allotment: Session tree (left), Terminal grid (center), File sidebar (right) |
|
|
| **Terminal Grid** | Tmux-style split panes with layout presets (single, split-h, split-v, grid-2x2) |
|
|
| **Session Group Tree** | Hierarchical view of CLI sessions with grouping by tags |
|
|
| **Floating Panels** | Mutually exclusive overlay panels (Issues+Queue, Inspector, Execution Monitor, Scheduler) |
|
|
| **Association Highlight** | Cross-panel linking between terminals, issues, and queue items |
|
|
| **Layout Presets** | Quick layout buttons: single pane, horizontal split, vertical split, 2x2 grid |
|
|
| **Launch CLI** | Config modal for creating new CLI sessions with tool, model, and settings |
|
|
| **Fullscreen Mode** | Immersive mode hides app chrome (header + sidebar) |
|
|
| **Feature Flags** | Panel visibility controlled by feature flags (queue, inspector, execution monitor) |
|
|
|
|
---
|
|
|
|
## Component Hierarchy
|
|
|
|
```
|
|
TerminalDashboardPage
|
|
├── AssociationHighlightProvider (context)
|
|
├── DashboardToolbar
|
|
│ ├── Layout Preset Buttons (Single | Split-H | Split-V | Grid-2x2)
|
|
│ ├── Panel Toggles (Sessions | Files | Issues | Queue | Inspector | Execution | Scheduler)
|
|
│ ├── Fullscreen Toggle
|
|
│ └── Launch CLI Button
|
|
├── Allotment (Three-Column Layout)
|
|
│ ├── SessionGroupTree
|
|
│ │ └── Session Group Items (collapsible)
|
|
│ ├── TerminalGrid
|
|
│ │ ├── GridGroupRenderer (recursive)
|
|
│ │ └── TerminalPane
|
|
│ └── FileSidebarPanel
|
|
│ └── File Tree View
|
|
└── FloatingPanel (multiple, mutually exclusive)
|
|
├── Issues+Queue (split panel)
|
|
│ ├── IssuePanel
|
|
│ └── QueueListColumn
|
|
├── QueuePanel (feature flag)
|
|
├── InspectorContent (feature flag)
|
|
├── ExecutionMonitorPanel (feature flag)
|
|
└── SchedulerPanel
|
|
```
|
|
|
|
---
|
|
|
|
## Props API
|
|
|
|
### TerminalDashboardPage
|
|
|
|
| Prop | Type | Default | Description |
|
|
|------|------|---------|-------------|
|
|
| - | - | - | This page component accepts no props (state managed via hooks and Zustand stores) |
|
|
|
|
### DashboardToolbar
|
|
|
|
| Prop | Type | Default | Description |
|
|
|------|------|---------|-------------|
|
|
| `activePanel` | `PanelId \| null` | `null` | Currently active floating panel |
|
|
| `onTogglePanel` | `(panelId: PanelId) => void` | - | Callback to toggle panel visibility |
|
|
| `isFileSidebarOpen` | `boolean` | `true` | File sidebar visibility state |
|
|
| `onToggleFileSidebar` | `() => void` | - | Toggle file sidebar callback |
|
|
| `isSessionSidebarOpen` | `boolean` | `true` | Session sidebar visibility state |
|
|
| `onToggleSessionSidebar` | `() => void` | - | Toggle session sidebar callback |
|
|
| `isFullscreen` | `boolean` | `false` | Fullscreen mode state |
|
|
| `onToggleFullscreen` | `() => void` | - | Toggle fullscreen callback |
|
|
|
|
### FloatingPanel
|
|
|
|
| Prop | Type | Default | Description |
|
|
|------|------|---------|-------------|
|
|
| `isOpen` | `boolean` | `false` | Panel open state |
|
|
| `onClose` | `() => void` | - | Close callback |
|
|
| `title` | `string` | - | Panel title |
|
|
| `side` | `'left' \| 'right'` | `'left'` | Panel side |
|
|
| `width` | `number` | `400` | Panel width in pixels |
|
|
| `children` | `ReactNode` | - | Panel content |
|
|
|
|
---
|
|
|
|
## State Management
|
|
|
|
### Local State
|
|
|
|
| State | Type | Description |
|
|
|-------|------|-------------|
|
|
| `activePanel` | `PanelId \| null` | Currently active floating panel (mutually exclusive) |
|
|
| `isFileSidebarOpen` | `boolean` | File sidebar visibility |
|
|
| `isSessionSidebarOpen` | `boolean` | Session sidebar visibility |
|
|
|
|
### Zustand Stores
|
|
|
|
| Store | Selector | Purpose |
|
|
|-------|----------|---------|
|
|
| `workflowStore` | `selectProjectPath` | Current project path for file sidebar |
|
|
| `appStore` | `selectIsImmersiveMode` | Fullscreen mode state |
|
|
| `configStore` | `featureFlags` | Feature flag configuration |
|
|
| `terminalGridStore` | Grid layout and focused pane state |
|
|
| `executionMonitorStore` | Active execution count |
|
|
| `queueSchedulerStore` | Scheduler status and settings |
|
|
|
|
### Panel ID Type
|
|
|
|
```typescript
|
|
type PanelId = 'issues' | 'queue' | 'inspector' | 'execution' | 'scheduler';
|
|
```
|
|
|
|
---
|
|
|
|
## Usage Examples
|
|
|
|
### Basic Terminal Dashboard
|
|
|
|
```tsx
|
|
import { TerminalDashboardPage } from '@/pages/TerminalDashboardPage'
|
|
|
|
// The terminal dashboard is automatically rendered at /terminal-dashboard
|
|
// No props needed - layout state managed internally
|
|
```
|
|
|
|
### Using FloatingPanel Component
|
|
|
|
```tsx
|
|
import { FloatingPanel } from '@/components/terminal-dashboard/FloatingPanel'
|
|
import { IssuePanel } from '@/components/terminal-dashboard/IssuePanel'
|
|
|
|
function CustomLayout() {
|
|
const [isOpen, setIsOpen] = useState(false)
|
|
|
|
return (
|
|
<FloatingPanel
|
|
isOpen={isOpen}
|
|
onClose={() => setIsOpen(false)}
|
|
title="Issues"
|
|
side="left"
|
|
width={700}
|
|
>
|
|
<IssuePanel />
|
|
</FloatingPanel>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Panel Toggle Pattern
|
|
|
|
```tsx
|
|
import { useState, useCallback } from 'react'
|
|
|
|
function usePanelToggle() {
|
|
const [activePanel, setActivePanel] = useState<string | null>(null)
|
|
|
|
const togglePanel = useCallback((panelId: string) => {
|
|
setActivePanel((prev) => (prev === panelId ? null : panelId))
|
|
}, [])
|
|
|
|
const closePanel = useCallback(() => {
|
|
setActivePanel(null)
|
|
}, [])
|
|
|
|
return { activePanel, togglePanel, closePanel }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Interactive Demos
|
|
|
|
### Layout Presets Demo
|
|
|
|
:::demo TerminalLayoutPresets
|
|
# terminal-layout-presets.tsx
|
|
/**
|
|
* Terminal Layout Presets Demo
|
|
* Interactive layout preset buttons
|
|
*/
|
|
export function TerminalLayoutPresets() {
|
|
const [layout, setLayout] = React.useState('grid-2x2')
|
|
|
|
const layouts = {
|
|
single: 'grid-cols-1 grid-rows-1',
|
|
'split-h': 'grid-cols-2 grid-rows-1',
|
|
'split-v': 'grid-cols-1 grid-rows-2',
|
|
'grid-2x2': 'grid-cols-2 grid-rows-2',
|
|
}
|
|
|
|
return (
|
|
<div className="p-6 bg-background space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<h3 className="text-sm font-semibold">Terminal Layout Presets</h3>
|
|
<div className="flex gap-2">
|
|
{Object.keys(layouts).map((preset) => (
|
|
<button
|
|
key={preset}
|
|
onClick={() => setLayout(preset)}
|
|
className={`px-3 py-1.5 text-xs rounded transition-colors ${
|
|
layout === preset
|
|
? 'bg-primary text-primary-foreground'
|
|
: 'border hover:bg-accent'
|
|
}`}
|
|
>
|
|
{preset.replace('-', ' ').toUpperCase()}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className={`grid gap-2 h-64 ${layouts[layout]}`}>
|
|
{Array.from({ length: layout === 'single' ? 1 : layout.includes('2x') ? 4 : 2 }).map((_, i) => (
|
|
<div key={i} className="bg-muted/20 border rounded p-4 font-mono text-xs">
|
|
<div className="text-green-500">$ Terminal {i + 1}</div>
|
|
<div className="text-muted-foreground mt-1">Ready for input...</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
:::
|
|
|
|
### Floating Panels Demo
|
|
|
|
:::demo FloatingPanelsDemo
|
|
# floating-panels-demo.tsx
|
|
/**
|
|
* Floating Panels Demo
|
|
* Mutually exclusive overlay panels
|
|
*/
|
|
export function FloatingPanelsDemo() {
|
|
const [activePanel, setActivePanel] = React.useState(null)
|
|
|
|
const panels = [
|
|
{ id: 'issues', title: 'Issues + Queue', side: 'left', width: 700 },
|
|
{ id: 'queue', title: 'Queue', side: 'right', width: 400 },
|
|
{ id: 'inspector', title: 'Inspector', side: 'right', width: 360 },
|
|
{ id: 'execution', title: 'Execution Monitor', side: 'right', width: 380 },
|
|
{ id: 'scheduler', title: 'Scheduler', side: 'right', width: 340 },
|
|
]
|
|
|
|
return (
|
|
<div className="relative h-[500px] p-6 bg-background border rounded-lg">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h3 className="text-sm font-semibold">Floating Panels</h3>
|
|
<div className="flex gap-2">
|
|
{panels.map((panel) => (
|
|
<button
|
|
key={panel.id}
|
|
onClick={() => setActivePanel(activePanel === panel.id ? null : panel.id)}
|
|
className={`px-3 py-1.5 text-xs rounded transition-colors ${
|
|
activePanel === panel.id
|
|
? 'bg-primary text-primary-foreground'
|
|
: 'border hover:bg-accent'
|
|
}`}
|
|
>
|
|
{panel.title}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="h-[380px] bg-muted/20 border rounded flex items-center justify-center">
|
|
<p className="text-sm text-muted-foreground">
|
|
{activePanel ? `"${panels.find((p) => p.id === activePanel)?.title}" panel is open` : 'Click a button to open a floating panel'}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Floating Panel Overlay */}
|
|
{activePanel && (
|
|
<div
|
|
className={`absolute top-16 border rounded-lg shadow-lg bg-background ${
|
|
panels.find((p) => p.id === activePanel)?.side === 'left' ? 'left-6' : 'right-6'
|
|
}`}
|
|
style={{ width: panels.find((p) => p.id === activePanel)?.width }}
|
|
>
|
|
<div className="flex items-center justify-between px-3 py-2 border-b">
|
|
<span className="text-sm font-medium">{panels.find((p) => p.id === activePanel)?.title}</span>
|
|
<button
|
|
onClick={() => setActivePanel(null)}
|
|
className="text-xs hover:bg-accent px-2 py-1 rounded"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div className="p-4 text-sm text-muted-foreground">
|
|
<div className="space-y-2">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-2 h-2 rounded-full bg-blue-500"/>
|
|
<span>Item 1</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-2 h-2 rounded-full bg-green-500"/>
|
|
<span>Item 2</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-2 h-2 rounded-full bg-amber-500"/>
|
|
<span>Item 3</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
:::
|
|
|
|
### Resizable Panes Demo
|
|
|
|
:::demo ResizablePanesDemo
|
|
# resizable-panes-demo.tsx
|
|
/**
|
|
* Resizable Panes Demo
|
|
* Simulates the Allotment resizable split behavior
|
|
*/
|
|
export function ResizablePanesDemo() {
|
|
const [leftWidth, setLeftWidth] = React.useState(240)
|
|
const [rightWidth, setRightWidth] = React.useState(280)
|
|
const [isDragging, setIsDragging] = React.useState(null)
|
|
|
|
const handleDragStart = (side) => (e) => {
|
|
setIsDragging(side)
|
|
e.preventDefault()
|
|
}
|
|
|
|
React.useEffect(() => {
|
|
const handleMouseMove = (e) => {
|
|
if (isDragging === 'left') {
|
|
setLeftWidth(Math.max(180, Math.min(320, e.clientX)))
|
|
} else if (isDragging === 'right') {
|
|
setRightWidth(Math.max(200, Math.min(400, window.innerWidth - e.clientX)))
|
|
}
|
|
}
|
|
|
|
const handleMouseUp = () => setIsDragging(null)
|
|
|
|
if (isDragging) {
|
|
window.addEventListener('mousemove', handleMouseMove)
|
|
window.addEventListener('mouseup', handleMouseUp)
|
|
return () => {
|
|
window.removeEventListener('mousemove', handleMouseMove)
|
|
window.removeEventListener('mouseup', handleMouseUp)
|
|
}
|
|
}
|
|
}, [isDragging])
|
|
|
|
return (
|
|
<div className="h-[400px] flex bg-background border rounded-lg overflow-hidden">
|
|
{/* Left Sidebar */}
|
|
<div style={{ width: leftWidth }} className="border-r flex flex-col">
|
|
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
|
|
Session Groups
|
|
</div>
|
|
<div className="flex-1 p-2 text-sm space-y-1">
|
|
{['Active Sessions', 'Completed'].map((g) => (
|
|
<div key={g} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{g}</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Left Drag Handle */}
|
|
<div
|
|
onMouseDown={handleDragStart('left')}
|
|
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
|
|
isDragging === 'left' ? 'bg-primary' : ''
|
|
}`}
|
|
/>
|
|
|
|
{/* Main Content */}
|
|
<div className="flex-1 bg-muted/20 flex items-center justify-center">
|
|
<span className="text-sm text-muted-foreground">Terminal Grid Area</span>
|
|
</div>
|
|
|
|
{/* Right Drag Handle */}
|
|
<div
|
|
onMouseDown={handleDragStart('right')}
|
|
className={`w-1 bg-border hover:bg-primary cursor-col-resize transition-colors ${
|
|
isDragging === 'right' ? 'bg-primary' : ''
|
|
}`}
|
|
/>
|
|
|
|
{/* Right Sidebar */}
|
|
<div style={{ width: rightWidth }} className="border-l flex flex-col">
|
|
<div className="px-3 py-2 text-xs font-semibold border-b bg-muted/30">
|
|
Project Files
|
|
</div>
|
|
<div className="flex-1 p-2 text-sm space-y-1">
|
|
{['src/', 'docs/', 'tests/'].map((f) => (
|
|
<div key={f} className="px-2 py-1 hover:bg-accent rounded cursor-pointer">{f}</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
:::
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Feature Flags
|
|
|
|
| Flag | Controls |
|
|
|------|----------|
|
|
| `dashboardQueuePanelEnabled` | Queue panel visibility |
|
|
| `dashboardInspectorEnabled` | Inspector panel visibility |
|
|
| `dashboardExecutionMonitorEnabled` | Execution Monitor panel visibility |
|
|
|
|
### Layout Presets
|
|
|
|
| Preset | Layout |
|
|
|--------|--------|
|
|
| **Single** | One terminal pane |
|
|
| **Split-H** | Two panes side by side |
|
|
| **Split-V** | Two panes stacked vertically |
|
|
| **Grid-2x2** | Four panes in 2x2 grid |
|
|
|
|
### Panel Types
|
|
|
|
| Panel | Content | Position | Feature Flag |
|
|
|-------|---------|----------|--------------|
|
|
| **Issues+Queue** | Combined Issues panel + Queue list column | Left (overlay) | - |
|
|
| **Queue** | Full queue management panel | Right (overlay) | `dashboardQueuePanelEnabled` |
|
|
| **Inspector** | Association chain inspector | Right (overlay) | `dashboardInspectorEnabled` |
|
|
| **Execution Monitor** | Real-time execution tracking | Right (overlay) | `dashboardExecutionMonitorEnabled` |
|
|
| **Scheduler** | Queue scheduler controls | Right (overlay) | - |
|
|
|
|
---
|
|
|
|
## Accessibility
|
|
|
|
- **Keyboard Navigation**:
|
|
- <kbd>Tab</kbd> - Navigate through toolbar buttons
|
|
- <kbd>Enter</kbd>/<kbd>Space</kbd> - Activate toolbar buttons
|
|
- <kbd>Escape</kbd> - Close floating panels
|
|
- <kbd>F11</kbd> - Toggle fullscreen mode
|
|
|
|
- **ARIA Attributes**:
|
|
- `aria-label` on toolbar buttons
|
|
- `aria-expanded` on sidebar toggles
|
|
- `aria-hidden` on inactive floating panels
|
|
- `role="dialog"` on floating panels
|
|
|
|
- **Screen Reader Support**:
|
|
- Panel state announced when toggled
|
|
- Layout changes announced
|
|
- Focus management when panels open/close
|
|
|
|
---
|
|
|
|
## Related Links
|
|
|
|
- [Orchestrator](/features/orchestrator) - Visual workflow editor
|
|
- [Sessions](/features/sessions) - Session management
|
|
- [Issue Hub](/features/issue-hub) - Issues, queue, discovery
|
|
- [Explorer](/features/explorer) - File explorer
|
|
- [Queue](/features/queue) - Queue management standalone page
|