mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-01 15:03:57 +08:00
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.
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
# Queue
|
||||
# Queue Management
|
||||
|
||||
## One-Liner
|
||||
|
||||
**The Queue page manages issue execution queues, displaying grouped tasks and solutions with conflict detection and merge capabilities.**
|
||||
**The Queue Management page provides centralized control over issue execution queues with scheduler controls, status monitoring, and session pool management.**
|
||||
|
||||
---
|
||||
|
||||
@@ -11,153 +10,627 @@
|
||||
| Pain Point | Current State | Queue Solution |
|
||||
|------------|---------------|----------------|
|
||||
| **Disorganized execution** | No unified task queue | Centralized queue with grouped items |
|
||||
| **Unknown queue status** | Can't tell if queue is ready | Status indicator with conflicts warning |
|
||||
| **Manual queue management** | No way to control execution | Activate/deactivate/delete with actions |
|
||||
| **Duplicate handling** | Confusing duplicate items | Merge queues functionality |
|
||||
| **No visibility** | Don't know what's queued | Stats cards with items/groups/tasks/solutions counts |
|
||||
| **Unknown scheduler status** | Can't tell if scheduler is running | Real-time status indicator (idle/running/paused) |
|
||||
| **No execution control** | Can't start/stop queue processing | Start/Pause/Stop controls with confirmation |
|
||||
| **Concurrency limits** | Too many simultaneous sessions | Configurable max concurrent sessions |
|
||||
| **No visibility** | Don't know what's queued | Stats cards + item list with status tracking |
|
||||
| **Resource waste** | Idle sessions consuming resources | Session pool overview with timeout config |
|
||||
|
||||
---
|
||||
|
||||
## Page Overview
|
||||
## Overview
|
||||
|
||||
**Location**: `ccw/frontend/src/pages/QueuePage.tsx`
|
||||
**Location**: `ccw/frontend/src/pages/QueuePage.tsx` (legacy), `ccw/frontend/src/components/terminal-dashboard/QueuePanel.tsx` (current)
|
||||
|
||||
**Purpose**: View and manage issue execution queues with stats, conflict detection, and queue operations.
|
||||
**Purpose**: View and manage issue execution queues with scheduler controls, progress tracking, and session pool management.
|
||||
|
||||
**Access**: Navigation → Issues → Queue tab OR directly via `/queue` route
|
||||
|
||||
### Layout
|
||||
**Access**: Navigation → Issues → Queue tab OR Terminal Dashboard → Queue floating panel
|
||||
|
||||
**Layout**:
|
||||
```
|
||||
+--------------------------------------------------------------------------+
|
||||
| Queue Title [Refresh] |
|
||||
| Queue Panel Header |
|
||||
+--------------------------------------------------------------------------+
|
||||
| Stats Cards |
|
||||
| +-------------+ +-------------+ +-------------+ +-------------+ |
|
||||
| | Total Items | | Groups | | Tasks | | Solutions | |
|
||||
| +-------------+ +-------------+ +-------------+ +-------------+ |
|
||||
| Scheduler Status Bar |
|
||||
| +----------------+ +-------------+ +-------------------------------+ |
|
||||
| | Status Badge | | Progress | | Concurrency (2/2) | |
|
||||
| +----------------+ +-------------+ +-------------------------------+ |
|
||||
+--------------------------------------------------------------------------+
|
||||
| Conflicts Warning (when conflicts exist) |
|
||||
| Scheduler Controls |
|
||||
| +--------+ +--------+ +--------+ +-----------+ |
|
||||
| | Start | | Pause | | Stop | | Config | |
|
||||
| +--------+ +--------+ +--------+ +-----------+ |
|
||||
+--------------------------------------------------------------------------+
|
||||
| Queue Cards (1-2 columns) |
|
||||
| Queue Items List |
|
||||
| +---------------------------------------------------------------------+ |
|
||||
| | QueueCard | |
|
||||
| | - Queue info | |
|
||||
| | - Grouped items preview | |
|
||||
| | - Action buttons (Activate/Deactivate/Delete/Merge) | |
|
||||
| | QueueItemRow (status, issue_id, session_key, actions) | |
|
||||
| | - Status icon (pending/executing/completed/blocked/failed) | |
|
||||
| | - Issue ID / Item ID display | |
|
||||
| | - Session binding info | |
|
||||
| | - Progress indicator (for executing items) | |
|
||||
| +---------------------------------------------------------------------+ |
|
||||
| | [More queue items...] | |
|
||||
| +---------------------------------------------------------------------+ |
|
||||
+--------------------------------------------------------------------------+
|
||||
| Status Footer (Ready/Pending indicator) |
|
||||
+--------------------------------------------------------------------------+
|
||||
| Session Pool Overview (optional) |
|
||||
| +--------------------------------------------------------------------------+
|
||||
| | Active Sessions | Idle Sessions | Total Sessions |
|
||||
| +--------------------------------------------------------------------------+
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Live Demo
|
||||
|
||||
:::demo QueueManagementDemo
|
||||
# queue-management-demo.tsx
|
||||
/**
|
||||
* Queue Management Demo
|
||||
* Shows scheduler controls and queue items list
|
||||
*/
|
||||
export function QueueManagementDemo() {
|
||||
const [schedulerStatus, setSchedulerStatus] = React.useState('idle')
|
||||
const [progress, setProgress] = React.useState(0)
|
||||
|
||||
const queueItems = [
|
||||
{ id: '1', status: 'completed', issueId: 'ISSUE-1', sessionKey: 'session-1' },
|
||||
{ id: '2', status: 'executing', issueId: 'ISSUE-2', sessionKey: 'session-2' },
|
||||
{ id: '3', status: 'pending', issueId: 'ISSUE-3', sessionKey: null },
|
||||
{ id: '4', status: 'pending', issueId: 'ISSUE-4', sessionKey: null },
|
||||
{ id: '5', status: 'blocked', issueId: 'ISSUE-5', sessionKey: null },
|
||||
]
|
||||
|
||||
const statusConfig = {
|
||||
idle: { label: 'Idle', color: 'bg-gray-500/20 text-gray-600 border-gray-500' },
|
||||
running: { label: 'Running', color: 'bg-green-500/20 text-green-600 border-green-500' },
|
||||
paused: { label: 'Paused', color: 'bg-amber-500/20 text-amber-600 border-amber-500' },
|
||||
}
|
||||
|
||||
const itemStatusConfig = {
|
||||
completed: { icon: '✓', color: 'text-green-500', label: 'Completed' },
|
||||
executing: { icon: '▶', color: 'text-blue-500', label: 'Executing' },
|
||||
pending: { icon: '○', color: 'text-gray-400', label: 'Pending' },
|
||||
blocked: { icon: '✕', color: 'text-red-500', label: 'Blocked' },
|
||||
failed: { icon: '!', color: 'text-red-500', label: 'Failed' },
|
||||
}
|
||||
|
||||
// Simulate progress when running
|
||||
React.useEffect(() => {
|
||||
if (schedulerStatus === 'running') {
|
||||
const interval = setInterval(() => {
|
||||
setProgress((p) => (p >= 100 ? 0 : p + 10))
|
||||
}, 500)
|
||||
return () => clearInterval(interval)
|
||||
}
|
||||
}, [schedulerStatus])
|
||||
|
||||
const handleStart = () => {
|
||||
if (schedulerStatus === 'idle' || schedulerStatus === 'paused') {
|
||||
setSchedulerStatus('running')
|
||||
}
|
||||
}
|
||||
|
||||
const handlePause = () => {
|
||||
if (schedulerStatus === 'running') {
|
||||
setSchedulerStatus('paused')
|
||||
}
|
||||
}
|
||||
|
||||
const handleStop = () => {
|
||||
setSchedulerStatus('idle')
|
||||
setProgress(0)
|
||||
}
|
||||
|
||||
const currentConfig = statusConfig[schedulerStatus]
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-background space-y-6">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold">Queue Management</h3>
|
||||
<p className="text-sm text-muted-foreground">Manage issue execution queue</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scheduler Status Bar */}
|
||||
<div className="border rounded-lg p-4 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={`px-3 py-1 rounded text-xs font-medium border ${currentConfig.color}`}>
|
||||
{currentConfig.label}
|
||||
</span>
|
||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
||||
<span>{queueItems.filter((i) => i.status === 'completed').length}/{queueItems.length} items</span>
|
||||
<span>2/2 concurrent</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
{schedulerStatus === 'running' && (
|
||||
<div className="space-y-1">
|
||||
<div className="h-2 bg-muted rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-green-500 rounded-full transition-all"
|
||||
style={{ width: `${progress}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground">{progress}% complete</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Scheduler Controls */}
|
||||
<div className="flex items-center gap-2">
|
||||
{(schedulerStatus === 'idle' || schedulerStatus === 'paused') && (
|
||||
<button
|
||||
onClick={handleStart}
|
||||
className="px-4 py-2 text-sm bg-green-500 text-white rounded hover:bg-green-600 flex items-center gap-2"
|
||||
>
|
||||
<span>▶</span> Start
|
||||
</button>
|
||||
)}
|
||||
{schedulerStatus === 'running' && (
|
||||
<button
|
||||
onClick={handlePause}
|
||||
className="px-4 py-2 text-sm bg-amber-500 text-white rounded hover:bg-amber-600 flex items-center gap-2"
|
||||
>
|
||||
<span>⏸</span> Pause
|
||||
</button>
|
||||
)}
|
||||
{schedulerStatus !== 'idle' && (
|
||||
<button
|
||||
onClick={handleStop}
|
||||
className="px-4 py-2 text-sm bg-red-500 text-white rounded hover:bg-red-600 flex items-center gap-2"
|
||||
>
|
||||
<span>⬛</span> Stop
|
||||
</button>
|
||||
)}
|
||||
<button className="px-4 py-2 text-sm border rounded hover:bg-accent">
|
||||
Config
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Queue Items List */}
|
||||
<div className="border rounded-lg">
|
||||
<div className="px-4 py-3 border-b bg-muted/30">
|
||||
<h4 className="text-sm font-semibold">Queue Items</h4>
|
||||
</div>
|
||||
<div className="divide-y max-h-80 overflow-auto">
|
||||
{queueItems.map((item) => {
|
||||
const config = itemStatusConfig[item.status]
|
||||
return (
|
||||
<div key={item.id} className="px-4 py-3 flex items-center gap-4 hover:bg-accent/50">
|
||||
<span className={`text-lg ${config.color}`}>{config.icon}</span>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium">{item.issueId}</span>
|
||||
<span className={`text-xs px-2 py-0.5 rounded-full ${config.color} bg-opacity-10`}>
|
||||
{config.label}
|
||||
</span>
|
||||
</div>
|
||||
{item.sessionKey && (
|
||||
<div className="text-xs text-muted-foreground mt-1">
|
||||
Session: {item.sessionKey}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{item.status === 'executing' && (
|
||||
<div className="w-20 h-1.5 bg-muted rounded-full overflow-hidden">
|
||||
<div className="h-full bg-blue-500 animate-pulse" style={{ width: '60%' }}/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Core Features
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| **Stats Cards** | Four metric cards showing total items, groups, tasks, and solutions counts |
|
||||
| **Conflicts Warning** | Banner alert when conflicts exist, showing count and description |
|
||||
| **Queue Card** | Displays queue information with grouped items preview and action buttons |
|
||||
| **Activate/Deactivate** | Toggle queue active state for execution control |
|
||||
| **Delete Queue** | Remove queue with confirmation dialog |
|
||||
| **Merge Queues** | Combine multiple queues (if multiple exist) |
|
||||
| **Status Footer** | Visual indicator showing if queue is ready (active) or pending (inactive/conflicts) |
|
||||
| **Loading State** | Skeleton placeholders during data fetch |
|
||||
| **Empty State** | Friendly message when no queue exists |
|
||||
| **Scheduler Status** | Real-time status indicator (idle/running/paused) with visual badge |
|
||||
| **Progress Tracking** | Progress bar showing overall queue completion percentage |
|
||||
| **Start/Pause/Stop Controls** | Control queue execution with confirmation dialog for stop action |
|
||||
| **Concurrency Display** | Shows current active sessions vs max concurrent sessions |
|
||||
| **Queue Items List** | Scrollable list of all queue items with status, issue ID, and session binding |
|
||||
| **Status Icons** | Visual indicators for item status (pending/executing/completed/blocked/failed) |
|
||||
| **Session Pool** | Overview of active, idle, and total sessions in the pool |
|
||||
| **Config Panel** | Adjust max concurrent sessions and timeout settings |
|
||||
| **Empty State** | Friendly message when queue is empty with instructions to add items |
|
||||
|
||||
---
|
||||
|
||||
## Usage Guide
|
||||
## Component Hierarchy
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
1. **Check Queue Status**: Review stats cards and status footer to understand queue state
|
||||
2. **Review Conflicts**: If conflicts warning is shown, resolve conflicts before activation
|
||||
3. **Activate Queue**: Click "Activate" to enable queue for execution (only if no conflicts)
|
||||
4. **Deactivate Queue**: Click "Deactivate" to pause execution
|
||||
5. **Delete Queue**: Click "Delete" to remove the queue (requires confirmation)
|
||||
6. **Merge Queues**: Use merge action to combine multiple queues when applicable
|
||||
|
||||
### Key Interactions
|
||||
|
||||
| Interaction | How to Use |
|
||||
|-------------|------------|
|
||||
| **Refresh queue** | Click the refresh button to reload queue data |
|
||||
| **Activate queue** | Click the Activate button on the queue card |
|
||||
| **Deactivate queue** | Click the Deactivate button to pause the queue |
|
||||
| **Delete queue** | Click the Delete button, confirm in the dialog |
|
||||
| **Merge queues** | Select source and target queues, click merge |
|
||||
| **View status** | Check the status footer for ready/pending indication |
|
||||
|
||||
### Queue Status
|
||||
|
||||
| Status | Condition | Appearance |
|
||||
|--------|-----------|------------|
|
||||
| **Ready/Active** | Total items > 0 AND no conflicts | Green badge with checkmark |
|
||||
| **Pending/Inactive** | No items OR conflicts exist | Gray/amber badge with clock icon |
|
||||
|
||||
### Conflict Resolution
|
||||
|
||||
When conflicts are detected:
|
||||
1. A warning banner appears showing conflict count
|
||||
2. Queue cannot be activated until conflicts are resolved
|
||||
3. Status footer shows "Pending" state
|
||||
4. Resolve conflicts through the Issues panel or related workflows
|
||||
```
|
||||
QueuePage (legacy) / QueuePanel (current)
|
||||
├── QueuePanelHeader
|
||||
│ ├── Title
|
||||
│ └── Tab Switcher (Queue | Orchestrator)
|
||||
├── SchedulerBar (inline in QueueListColumn)
|
||||
│ ├── Status Badge
|
||||
│ ├── Progress + Concurrency
|
||||
│ └── Control Buttons (Play/Pause/Stop)
|
||||
├── QueueItemsList
|
||||
│ └── QueueItemRow (repeating)
|
||||
│ ├── Status Icon
|
||||
│ ├── Issue ID / Item ID
|
||||
│ ├── Session Binding
|
||||
│ └── Progress (for executing items)
|
||||
└── SchedulerPanel (standalone)
|
||||
├── Status Section
|
||||
├── Progress Bar
|
||||
├── Control Buttons
|
||||
├── Config Section
|
||||
│ ├── Max Concurrent Sessions
|
||||
│ ├── Session Idle Timeout
|
||||
│ └── Resume Key Binding Timeout
|
||||
└── Session Pool Overview
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Components Reference
|
||||
## Props API
|
||||
|
||||
### Main Components
|
||||
### QueuePanel
|
||||
|
||||
| Component | Location | Purpose |
|
||||
|-----------|----------|---------|
|
||||
| `QueuePage` | `@/pages/QueuePage.tsx` | Main queue management page |
|
||||
| `QueueCard` | `@/components/issue/queue/QueueCard.tsx` | Queue display with actions |
|
||||
| `QueuePageSkeleton` | (internal to QueuePage) | Loading placeholder |
|
||||
| `QueueEmptyState` | (internal to QueuePage) | Empty state display |
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `embedded` | `boolean` | `false` | Whether panel is embedded in another component |
|
||||
|
||||
### State Management
|
||||
### SchedulerPanel
|
||||
|
||||
- **Local state**:
|
||||
- None (all data from hooks)
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| - | - | - | This component accepts no props (all data from Zustand store) |
|
||||
|
||||
- **Custom hooks**:
|
||||
- `useIssueQueue` - Queue data fetching
|
||||
- `useQueueMutations` - Queue operations (activate, deactivate, delete, merge)
|
||||
### QueueListColumn
|
||||
|
||||
### Mutation States
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| - | - | - | This component accepts no props (all data from Zustand store) |
|
||||
|
||||
| State | Loading Indicator |
|
||||
|-------|------------------|
|
||||
| `isActivating` | Disable activate button during activation |
|
||||
| `isDeactivating` | Disable deactivate button during deactivation |
|
||||
| `isDeleting` | Disable delete button during deletion |
|
||||
| `isMerging` | Disable merge button during merge operation |
|
||||
---
|
||||
|
||||
## State Management
|
||||
|
||||
### Zustand Stores
|
||||
|
||||
| Store | Selector | Purpose |
|
||||
|-------|----------|---------|
|
||||
| `queueSchedulerStore` | `selectQueueSchedulerStatus` | Current scheduler status (idle/running/paused) |
|
||||
| `queueSchedulerStore` | `selectSchedulerProgress` | Overall queue completion percentage |
|
||||
| `queueSchedulerStore` | `selectQueueItems` | List of all queue items |
|
||||
| `queueSchedulerStore` | `selectCurrentConcurrency` | Active sessions count |
|
||||
| `queueSchedulerStore` | `selectSchedulerConfig` | Scheduler configuration |
|
||||
| `queueSchedulerStore` | `selectSessionPool` | Session pool overview |
|
||||
| `queueSchedulerStore` | `selectSchedulerError` | Error message if any |
|
||||
| `issueQueueIntegrationStore` | `selectAssociationChain` | Current association chain for highlighting |
|
||||
| `queueExecutionStore` | `selectByQueueItem` | Execution data for queue item |
|
||||
|
||||
### Queue Item Status
|
||||
|
||||
```typescript
|
||||
type QueueItemStatus =
|
||||
| 'pending' // Waiting to be executed
|
||||
| 'executing' // Currently being processed
|
||||
| 'completed' // Finished successfully
|
||||
| 'blocked' // Blocked by dependency
|
||||
| 'failed'; // Failed with error
|
||||
```
|
||||
|
||||
### Scheduler Status
|
||||
|
||||
```typescript
|
||||
type QueueSchedulerStatus =
|
||||
| 'idle' // No items or stopped
|
||||
| 'running' // Actively processing items
|
||||
| 'paused'; // Temporarily paused
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Queue Panel
|
||||
|
||||
```tsx
|
||||
import { QueuePanel } from '@/components/terminal-dashboard/QueuePanel'
|
||||
|
||||
function QueueSection() {
|
||||
return <QueuePanel />
|
||||
}
|
||||
```
|
||||
|
||||
### Standalone Scheduler Panel
|
||||
|
||||
```tsx
|
||||
import { SchedulerPanel } from '@/components/terminal-dashboard/SchedulerPanel'
|
||||
|
||||
function SchedulerControls() {
|
||||
return <SchedulerPanel />
|
||||
}
|
||||
```
|
||||
|
||||
### Queue List Column (Embedded)
|
||||
|
||||
```tsx
|
||||
import { QueueListColumn } from '@/components/terminal-dashboard/QueueListColumn'
|
||||
|
||||
function EmbeddedQueue() {
|
||||
return <QueueListColumn />
|
||||
}
|
||||
```
|
||||
|
||||
### Queue Store Actions
|
||||
|
||||
```tsx
|
||||
import { useQueueSchedulerStore } from '@/stores/queueSchedulerStore'
|
||||
|
||||
function QueueActions() {
|
||||
const startQueue = useQueueSchedulerStore((s) => s.startQueue)
|
||||
const pauseQueue = useQueueSchedulerStore((s) => s.pauseQueue)
|
||||
const stopQueue = useQueueSchedulerStore((s) => s.stopQueue)
|
||||
const updateConfig = useQueueSchedulerStore((s) => s.updateConfig)
|
||||
|
||||
const handleStart = () => startQueue()
|
||||
const handlePause = () => pauseQueue()
|
||||
const handleStop = () => stopQueue()
|
||||
const handleConfig = (config) => updateConfig(config)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={handleStart}>Start</button>
|
||||
<button onClick={handlePause}>Pause</button>
|
||||
<button onClick={handleStop}>Stop</button>
|
||||
<button onClick={() => handleConfig({ maxConcurrentSessions: 4 })}>
|
||||
Set Max 4
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Interactive Demos
|
||||
|
||||
### Queue Item Status Demo
|
||||
|
||||
:::demo QueueItemStatusDemo
|
||||
# queue-item-status-demo.tsx
|
||||
/**
|
||||
* Queue Item Status Demo
|
||||
* Shows all possible queue item states
|
||||
*/
|
||||
export function QueueItemStatusDemo() {
|
||||
const itemStates = [
|
||||
{ status: 'pending', issueId: 'ISSUE-101', sessionKey: null },
|
||||
{ status: 'executing', issueId: 'ISSUE-102', sessionKey: 'cli-session-abc' },
|
||||
{ status: 'completed', issueId: 'ISSUE-103', sessionKey: 'cli-session-def' },
|
||||
{ status: 'blocked', issueId: 'ISSUE-104', sessionKey: null },
|
||||
{ status: 'failed', issueId: 'ISSUE-105', sessionKey: 'cli-session-ghi' },
|
||||
]
|
||||
|
||||
const statusConfig = {
|
||||
pending: { icon: '○', color: 'text-gray-400', bg: 'bg-gray-500/10', label: 'Pending' },
|
||||
executing: { icon: '▶', color: 'text-blue-500', bg: 'bg-blue-500/10', label: 'Executing' },
|
||||
completed: { icon: '✓', color: 'text-green-500', bg: 'bg-green-500/10', label: 'Completed' },
|
||||
blocked: { icon: '✕', color: 'text-red-500', bg: 'bg-red-500/10', label: 'Blocked' },
|
||||
failed: { icon: '!', color: 'text-red-500', bg: 'bg-red-500/10', label: 'Failed' },
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-background space-y-4">
|
||||
<h3 className="text-sm font-semibold">Queue Item Status States</h3>
|
||||
<div className="space-y-2">
|
||||
{itemStates.map((item) => {
|
||||
const config = statusConfig[item.status]
|
||||
return (
|
||||
<div key={item.status} className="border rounded-lg p-4 flex items-center gap-4">
|
||||
<span className={`text-2xl ${config.color}`}>{config.icon}</span>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">{item.issueId}</span>
|
||||
<span className={`text-xs px-2 py-0.5 rounded-full ${config.bg} ${config.color}`}>
|
||||
{config.label}
|
||||
</span>
|
||||
</div>
|
||||
{item.sessionKey && (
|
||||
<div className="text-sm text-muted-foreground mt-1">
|
||||
Bound session: <code className="text-xs bg-muted px-1 rounded">{item.sessionKey}</code>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{item.status === 'executing' && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-24 h-2 bg-muted rounded-full overflow-hidden">
|
||||
<div className="h-full bg-blue-500 animate-pulse" style={{ width: '60%' }}/>
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground">60%</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
:::
|
||||
|
||||
### Scheduler Config Demo
|
||||
|
||||
:::demo SchedulerConfigDemo
|
||||
# scheduler-config-demo.tsx
|
||||
/**
|
||||
* Scheduler Config Demo
|
||||
* Interactive configuration panel
|
||||
*/
|
||||
export function SchedulerConfigDemo() {
|
||||
const [config, setConfig] = React.useState({
|
||||
maxConcurrentSessions: 2,
|
||||
sessionIdleTimeoutMs: 60000,
|
||||
resumeKeySessionBindingTimeoutMs: 300000,
|
||||
})
|
||||
|
||||
const formatMs = (ms) => {
|
||||
if (ms >= 60000) return `${ms / 60000}m`
|
||||
if (ms >= 1000) return `${ms / 1000}s`
|
||||
return `${ms}ms`
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-background space-y-6 max-w-md">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-sm font-semibold">Scheduler Configuration</h3>
|
||||
<button className="px-3 py-1.5 text-xs bg-primary text-primary-foreground rounded hover:opacity-90">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Max Concurrent Sessions */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Max Concurrent Sessions</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min="1"
|
||||
max="8"
|
||||
value={config.maxConcurrentSessions}
|
||||
onChange={(e) => setConfig({ ...config, maxConcurrentSessions: parseInt(e.target.value) })}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="text-sm font-medium w-8 text-center">{config.maxConcurrentSessions}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Maximum number of sessions to run simultaneously
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Session Idle Timeout */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Session Idle Timeout</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min="10000"
|
||||
max="300000"
|
||||
step="10000"
|
||||
value={config.sessionIdleTimeoutMs}
|
||||
onChange={(e) => setConfig({ ...config, sessionIdleTimeoutMs: parseInt(e.target.value) })}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="text-sm font-medium w-12 text-right">{formatMs(config.sessionIdleTimeoutMs)}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Time before idle session is terminated
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Resume Key Binding Timeout */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium">Resume Key Binding Timeout</label>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="range"
|
||||
min="60000"
|
||||
max="600000"
|
||||
step="60000"
|
||||
value={config.resumeKeySessionBindingTimeoutMs}
|
||||
onChange={(e) => setConfig({ ...config, resumeKeySessionBindingTimeoutMs: parseInt(e.target.value) })}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="text-sm font-medium w-12 text-right">{formatMs(config.resumeKeySessionBindingTimeoutMs)}</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Time to preserve resume key session binding
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current Config Display */}
|
||||
<div className="border rounded-lg p-4 bg-muted/30">
|
||||
<h4 className="text-xs font-semibold mb-3">Current Configuration</h4>
|
||||
<dl className="space-y-2 text-sm">
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-muted-foreground">Max Concurrent</dt>
|
||||
<dd className="font-medium">{config.maxConcurrentSessions} sessions</dd>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-muted-foreground">Idle Timeout</dt>
|
||||
<dd className="font-medium">{formatMs(config.sessionIdleTimeoutMs)}</dd>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<dt className="text-muted-foreground">Binding Timeout</dt>
|
||||
<dd className="font-medium">{formatMs(config.resumeKeySessionBindingTimeoutMs)}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration required. Queue data is automatically fetched from the backend.
|
||||
### Scheduler Config
|
||||
|
||||
### Queue Data Structure
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `maxConcurrentSessions` | `number` | `2` | Maximum sessions running simultaneously |
|
||||
| `sessionIdleTimeoutMs` | `number` | `60000` | Idle session timeout in milliseconds |
|
||||
| `resumeKeySessionBindingTimeoutMs` | `number` | `300000` | Resume key binding timeout in milliseconds |
|
||||
|
||||
### Queue Item Structure
|
||||
|
||||
```typescript
|
||||
interface QueueData {
|
||||
tasks: Task[];
|
||||
solutions: Solution[];
|
||||
conflicts: Conflict[];
|
||||
grouped_items: Record<string, GroupedItem>;
|
||||
interface QueueItem {
|
||||
item_id: string;
|
||||
issue_id?: string;
|
||||
sessionKey?: string;
|
||||
status: QueueItemStatus;
|
||||
execution_order: number;
|
||||
created_at?: number;
|
||||
updated_at?: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accessibility
|
||||
|
||||
- **Keyboard Navigation**:
|
||||
- <kbd>Tab</kbd> - Navigate through queue items and controls
|
||||
- <kbd>Enter</kbd>/<kbd>Space</kbd> - Activate buttons
|
||||
- <kbd>Escape</kbd> - Close dialogs
|
||||
|
||||
- **ARIA Attributes**:
|
||||
- `aria-label` on control buttons
|
||||
- `aria-live` regions for status updates
|
||||
- `aria-current` for active queue item
|
||||
- `role="list"` on queue items list
|
||||
|
||||
- **Screen Reader Support**:
|
||||
- Status changes announced
|
||||
- Progress updates spoken
|
||||
- Error messages announced
|
||||
|
||||
---
|
||||
|
||||
## Related Links
|
||||
|
||||
- [Issue Hub](/features/issue-hub) - Unified issues, queue, and discovery management
|
||||
- [Terminal Dashboard](/features/terminal) - Terminal-first workspace with integrated queue panel
|
||||
- [Discovery](/features/discovery) - Discovery session tracking
|
||||
- [Issues Panel](/features/issue-hub) - Issue list and GitHub sync
|
||||
- [Sessions](/features/sessions) - Session management and details
|
||||
|
||||
Reference in New Issue
Block a user