Files
Claude-Code-Workflow/docs/features/terminal.md
catlog22 2fb93d20e0 feat: add queue management and terminal dashboard documentation in Chinese
- 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.
2026-03-01 10:52:46 +08:00

22 KiB

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 (

{/* Toolbar */}
Terminal Dashboard
{['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} ))}

  {/* 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

type PanelId = 'issues' | 'queue' | 'inspector' | 'execution' | 'scheduler';

Usage Examples

Basic Terminal Dashboard

import { TerminalDashboardPage } from '@/pages/TerminalDashboardPage'

// The terminal dashboard is automatically rendered at /terminal-dashboard
// No props needed - layout state managed internally

Using FloatingPanel Component

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

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 (

Terminal Layout Presets

{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()} ))}

  <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 (

Floating Panels

{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} ))}

  <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 (

{/* Left Sidebar */} <div style={{ width: leftWidth }} className="border-r flex flex-col">
Session Groups
{['Active Sessions', 'Completed'].map((g) => (
{g}
))}

  {/* 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:

    • Tab - Navigate through toolbar buttons
    • Enter/Space - Activate toolbar buttons
    • Escape - Close floating panels
    • F11 - 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