refactor(issue-manager): Enhance queue detail item styling and update modal content

This commit is contained in:
catlog22
2025-12-27 23:43:40 +08:00
parent 5aa0c9610d
commit 0992d27523
10 changed files with 260 additions and 393 deletions

View File

@@ -100,10 +100,49 @@ mcp__ace-tool__search_context({
- [ ] Discover dependencies
- [ ] Locate test patterns
**Fallback**: ACE → ripgrep → Glob
**Fallback Chain**: ACE → smart_search → Grep → rg → Glob
| Tool | When to Use |
|------|-------------|
| `mcp__ace-tool__search_context` | Semantic search (primary) |
| `mcp__ccw-tools__smart_search` | Symbol/pattern search |
| `Grep` | Exact regex matching |
| `rg` / `grep` | CLI fallback |
| `Glob` | File path discovery |
#### Phase 3: Solution Planning
**Multi-Solution Generation**:
Generate multiple candidate solutions when:
- Issue complexity is HIGH
- Multiple valid implementation approaches exist
- Trade-offs between approaches (performance vs simplicity, etc.)
| Condition | Solutions |
|-----------|-----------|
| Low complexity, single approach | 1 solution, auto-bind |
| Medium complexity, clear path | 1-2 solutions |
| High complexity, multiple approaches | 2-3 solutions, user selection |
**Solution Evaluation** (for each candidate):
```javascript
{
analysis: {
risk: "low|medium|high", // Implementation risk
impact: "low|medium|high", // Scope of changes
complexity: "low|medium|high" // Technical complexity
},
score: 0.0-1.0 // Overall quality score (higher = recommended)
}
```
**Selection Flow**:
1. Generate all candidate solutions
2. Evaluate and score each
3. Single solution → auto-bind
4. Multiple solutions → return `pending_selection` for user choice
**Task Decomposition** following schema:
```javascript
function decomposeTasks(issue, exploration) {
@@ -139,56 +178,33 @@ ccw issue bind <issue-id> --solution /tmp/sol.json
---
## 2. Output Specifications
## 2. Output Requirements
### 2.1 Return Format
```json
{
"bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
"pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "...", "description": "...", "task_count": N }] }],
"conflicts": [{ "file": "...", "issues": [...] }]
}
```
### 2.2 Binding Rules
| Scenario | Action |
|----------|--------|
| Single solution | Register AND auto-bind |
| Multiple solutions | Register only, return for user selection |
### 2.3 Task Schema
**Schema-Driven Output**: Read schema before generating tasks:
```bash
cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json
```
**Required Fields**:
- `id`: Task ID (pattern: `TASK-NNN`)
- `title`: Short summary (max 100 chars)
- `type`: feature | bug | refactor | test | chore | docs
- `description`: Detailed instructions
- `depends_on`: Array of prerequisite task IDs
- `delivery_criteria`: Checklist items defining completion
- `status`: pending | ready | in_progress | completed | failed | paused | skipped
- `current_phase`: analyze | implement | test | optimize | commit | done
- `executor`: agent | codex | gemini | auto
**Optional Fields**:
- `file_context`: Relevant files/globs
- `pause_criteria`: Conditions to halt execution
- `priority`: 1-5 (1=highest)
- `phase_results`: Results from each execution phase
### 2.4 Solution File Structure
### 2.1 Generate Files (Primary)
**Solution file per issue**:
```
.workflow/issues/solutions/{issue-id}.jsonl
```
Each line is a complete solution JSON.
Each line is a solution JSON containing tasks. Schema: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
### 2.2 Binding
| Scenario | Action |
|----------|--------|
| Single solution | `ccw issue bind <id> --solution <file>` (auto) |
| Multiple solutions | Register only, return for selection |
### 2.3 Return Summary
```json
{
"bound": [{ "issue_id": "...", "solution_id": "...", "task_count": N }],
"pending_selection": [{ "issue_id": "...", "solutions": [{ "id": "SOL-001", "description": "...", "task_count": N }] }],
"conflicts": [{ "file": "...", "issues": [...] }]
}
```
---
@@ -215,12 +231,14 @@ Each line is a complete solution JSON.
### 3.3 Guidelines
**ALWAYS**:
1. Read schema first: `cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json`
1. Read schema first: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
2. Use ACE semantic search as PRIMARY exploration tool
3. Fetch issue details via `ccw issue status <id> --json`
4. Quantify delivery_criteria with testable conditions
4. Quantify acceptance.criteria with testable conditions
5. Validate DAG before output
6. Single solution → auto-bind; Multiple → return for selection
6. Evaluate each solution with `analysis` and `score`
7. Single solution → auto-bind; Multiple → return `pending_selection`
8. For HIGH complexity: generate 2-3 candidate solutions
**NEVER**:
1. Execute implementation (return plan only)

View File

@@ -36,21 +36,21 @@ color: orange
```javascript
{
tasks: [{
key: string, // e.g., "GH-123:TASK-001"
issue_id: string, // e.g., "GH-123"
solution_id: string, // e.g., "SOL-001"
task: {
id: string, // e.g., "TASK-001"
title: string,
type: string,
file_context: string[],
depends_on: string[]
}
task_id: string, // e.g., "TASK-001"
type: string, // feature | bug | refactor | test | chore | docs
file_context: string[],
depends_on: string[] // composite keys, e.g., ["GH-123:TASK-001"]
}],
project_root?: string,
rebuild?: boolean
}
```
**Note**: Agent generates unique `item_id` (pattern: `T-{N}`) for queue output.
### 1.2 Execution Flow
```
@@ -76,19 +76,17 @@ function buildDependencyGraph(tasks) {
const fileModifications = new Map()
for (const item of tasks) {
const key = `${item.issue_id}:${item.task.id}`
graph.set(key, { ...item, key, inDegree: 0, outEdges: [] })
graph.set(item.key, { ...item, inDegree: 0, outEdges: [] })
for (const file of item.task.file_context || []) {
for (const file of item.file_context || []) {
if (!fileModifications.has(file)) fileModifications.set(file, [])
fileModifications.get(file).push(key)
fileModifications.get(file).push(item.key)
}
}
// Add dependency edges
for (const [key, node] of graph) {
for (const dep of node.task.depends_on || []) {
const depKey = `${node.issue_id}:${dep}`
for (const depKey of node.depends_on || []) {
if (graph.has(depKey)) {
graph.get(depKey).outEdges.push(key)
node.inDegree++
@@ -147,48 +145,29 @@ function detectConflicts(fileModifications, graph) {
---
## 3. Output Specifications
## 3. Output Requirements
### 3.1 Queue Schema
### 3.1 Generate Files (Primary)
Read schema before output:
```bash
cat .claude/workflows/cli-templates/schemas/queue-schema.json
**Queue files**:
```
.workflow/issues/queues/{queue-id}.json # Full queue with tasks, conflicts, groups
.workflow/issues/queues/index.json # Update with new queue entry
```
### 3.2 Output Format
Queue ID format: `QUE-YYYYMMDD-HHMMSS` (UTC timestamp)
Schema: `cat .claude/workflows/cli-templates/schemas/queue-schema.json`
### 3.2 Return Summary
```json
{
"tasks": [{
"item_id": "T-1",
"issue_id": "GH-123",
"solution_id": "SOL-001",
"task_id": "TASK-001",
"status": "pending",
"execution_order": 1,
"execution_group": "P1",
"depends_on": [],
"semantic_priority": 0.7
}],
"conflicts": [{
"file": "src/auth.ts",
"tasks": ["GH-123:TASK-001", "GH-124:TASK-002"],
"resolution": "sequential",
"resolution_order": ["GH-123:TASK-001", "GH-124:TASK-002"],
"rationale": "TASK-001 creates file before TASK-002 updates",
"resolved": true
}],
"execution_groups": [
{ "id": "P1", "type": "parallel", "task_count": 3, "tasks": ["T-1", "T-2", "T-3"] },
{ "id": "S2", "type": "sequential", "task_count": 2, "tasks": ["T-4", "T-5"] }
],
"_metadata": {
"total_tasks": 5,
"total_conflicts": 1,
"resolved_conflicts": 1,
"timestamp": "2025-12-27T10:00:00Z"
}
"queue_id": "QUE-20251227-143000",
"total_tasks": N,
"execution_groups": [{ "id": "P1", "type": "parallel", "count": N }],
"conflicts_resolved": N,
"issues_queued": ["GH-123", "GH-124"]
}
```
@@ -231,5 +210,6 @@ cat .claude/workflows/cli-templates/schemas/queue-schema.json
5. Merge conflicting tasks in parallel group
**OUTPUT**:
1. Write queue via `ccw issue queue` CLI
2. Return JSON with `tasks`, `conflicts`, `execution_groups`, `_metadata`
1. Write `.workflow/issues/queues/{queue-id}.json`
2. Update `.workflow/issues/queues/index.json`
3. Return summary with `queue_id`, `total_tasks`, `execution_groups`, `conflicts_resolved`, `issues_queued`

View File

@@ -1,7 +1,7 @@
---
name: plan
description: Batch plan issue resolution using issue-plan-agent (explore + plan closed-loop)
argument-hint: "<issue-id>[,<issue-id>,...] [--batch-size 3] --all-pending"
argument-hint: "--all-pending <issue-id>[,<issue-id>,...] [--batch-size 3] "
allowed-tools: TodoWrite(*), Task(*), SlashCommand(*), AskUserQuestion(*), Bash(*), Read(*), Write(*)
---
@@ -29,7 +29,7 @@ Unified planning command using **issue-plan-agent** that combines exploration an
- [ ] Solution file generated for each issue
- [ ] Single solution → auto-bound via `ccw issue bind`
- [ ] Multiple solutions → returned for user selection
- [ ] Tasks conform to schema: `cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json`
- [ ] Tasks conform to schema: `cat .claude/workflows/cli-templates/schemas/solution-schema.json`
- [ ] Each task has quantified `delivery_criteria`
## Core Capabilities
@@ -164,7 +164,7 @@ for (const [batchIndex, batch] of batches.entries()) {
3. Register & bind: \`ccw issue bind <id> --solution <file>\`
### Generate Files
\`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/issue-task-jsonl-schema.json)
\`.workflow/issues/solutions/{issue-id}.jsonl\` - Solution with tasks (schema: cat .claude/workflows/cli-templates/schemas/solution-schema.json)
### Binding Rules
- **Single solution**: Auto-bind via \`ccw issue bind <id> --solution <file>\`

View File

@@ -1,136 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Issue Task JSONL Schema",
"description": "Schema for individual task entries in tasks.jsonl file",
"type": "object",
"required": ["id", "title", "type", "description", "depends_on", "delivery_criteria", "status", "current_phase", "executor"],
"properties": {
"id": {
"type": "string",
"description": "Unique task identifier (e.g., TASK-001)",
"pattern": "^TASK-[0-9]+$"
},
"title": {
"type": "string",
"description": "Short summary of the task",
"maxLength": 100
},
"type": {
"type": "string",
"enum": ["feature", "bug", "refactor", "test", "chore", "docs"],
"description": "Task category"
},
"description": {
"type": "string",
"description": "Detailed instructions for the task"
},
"file_context": {
"type": "array",
"items": { "type": "string" },
"description": "List of relevant files/globs",
"default": []
},
"depends_on": {
"type": "array",
"items": { "type": "string" },
"description": "Array of Task IDs that must complete first",
"default": []
},
"delivery_criteria": {
"type": "array",
"items": { "type": "string" },
"description": "Checklist items that define task completion",
"minItems": 1
},
"pause_criteria": {
"type": "array",
"items": { "type": "string" },
"description": "Conditions that should halt execution (e.g., 'API spec unclear')",
"default": []
},
"status": {
"type": "string",
"enum": ["pending", "ready", "in_progress", "completed", "failed", "paused", "skipped"],
"description": "Current task status",
"default": "pending"
},
"current_phase": {
"type": "string",
"enum": ["analyze", "implement", "test", "optimize", "commit", "done"],
"description": "Current execution phase within the task lifecycle",
"default": "analyze"
},
"executor": {
"type": "string",
"enum": ["agent", "codex", "gemini", "auto"],
"description": "Preferred executor for this task",
"default": "auto"
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "Task priority (1=highest, 5=lowest)",
"default": 3
},
"phase_results": {
"type": "object",
"description": "Results from each execution phase",
"properties": {
"analyze": {
"type": "object",
"properties": {
"status": { "type": "string" },
"findings": { "type": "array", "items": { "type": "string" } },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"implement": {
"type": "object",
"properties": {
"status": { "type": "string" },
"files_modified": { "type": "array", "items": { "type": "string" } },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"test": {
"type": "object",
"properties": {
"status": { "type": "string" },
"test_results": { "type": "string" },
"retry_count": { "type": "integer" },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"optimize": {
"type": "object",
"properties": {
"status": { "type": "string" },
"improvements": { "type": "array", "items": { "type": "string" } },
"timestamp": { "type": "string", "format": "date-time" }
}
},
"commit": {
"type": "object",
"properties": {
"status": { "type": "string" },
"commit_hash": { "type": "string" },
"message": { "type": "string" },
"timestamp": { "type": "string", "format": "date-time" }
}
}
}
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "Task creation timestamp"
},
"updated_at": {
"type": "string",
"format": "date-time",
"description": "Last update timestamp"
}
},
"additionalProperties": false
}

View File

@@ -9,11 +9,11 @@
"description": "Ordered list of tasks to execute",
"items": {
"type": "object",
"required": ["queue_id", "issue_id", "solution_id", "task_id", "status"],
"required": ["item_id", "issue_id", "solution_id", "task_id", "status"],
"properties": {
"queue_id": {
"item_id": {
"type": "string",
"pattern": "^Q-[0-9]+$",
"pattern": "^T-[0-9]+$",
"description": "Unique queue item identifier"
},
"issue_id": {

View File

@@ -23,7 +23,7 @@
"description": "Task breakdown for this solution",
"items": {
"type": "object",
"required": ["id", "title", "scope", "action", "acceptance"],
"required": ["id", "title", "scope", "action", "implementation", "acceptance"],
"properties": {
"id": {
"type": "string",
@@ -61,10 +61,40 @@
"items": { "type": "string" },
"description": "Step-by-step implementation guide"
},
"acceptance": {
"test": {
"type": "object",
"description": "Test requirements",
"properties": {
"unit": { "type": "array", "items": { "type": "string" } },
"integration": { "type": "array", "items": { "type": "string" } },
"commands": { "type": "array", "items": { "type": "string" } },
"coverage_target": { "type": "number" }
}
},
"regression": {
"type": "array",
"items": { "type": "string" },
"description": "Quantified completion criteria"
"description": "Regression check points"
},
"acceptance": {
"type": "object",
"description": "Acceptance criteria & verification",
"required": ["criteria", "verification"],
"properties": {
"criteria": { "type": "array", "items": { "type": "string" } },
"verification": { "type": "array", "items": { "type": "string" } },
"manual_checks": { "type": "array", "items": { "type": "string" } }
}
},
"commit": {
"type": "object",
"description": "Commit specification",
"properties": {
"type": { "type": "string", "enum": ["feat", "fix", "refactor", "test", "docs", "chore"] },
"scope": { "type": "string" },
"message_template": { "type": "string" },
"breaking": { "type": "boolean" }
}
},
"depends_on": {
"type": "array",
@@ -80,6 +110,28 @@
"type": "string",
"enum": ["codex", "gemini", "agent", "auto"],
"default": "auto"
},
"lifecycle_status": {
"type": "object",
"description": "Lifecycle phase tracking",
"properties": {
"implemented": { "type": "boolean" },
"tested": { "type": "boolean" },
"regression_passed": { "type": "boolean" },
"accepted": { "type": "boolean" },
"committed": { "type": "boolean" }
}
},
"status": {
"type": "string",
"enum": ["pending", "ready", "executing", "completed", "failed", "blocked"],
"default": "pending"
},
"priority": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"default": 3
}
}
}
@@ -97,6 +149,21 @@
"integration_points": { "type": "string" }
}
},
"analysis": {
"type": "object",
"description": "Solution risk assessment",
"properties": {
"risk": { "type": "string", "enum": ["low", "medium", "high"] },
"impact": { "type": "string", "enum": ["low", "medium", "high"] },
"complexity": { "type": "string", "enum": ["low", "medium", "high"] }
}
},
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Solution quality score (0.0-1.0)"
},
"status": {
"type": "string",
"enum": ["draft", "candidate", "bound", "queued", "executing", "completed", "failed"],

View File

@@ -1,125 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Solutions JSONL Schema",
"description": "Schema for each line in solutions/{issue-id}.jsonl",
"type": "object",
"required": ["id", "tasks", "created_at"],
"properties": {
"id": {
"type": "string",
"description": "Unique solution identifier",
"pattern": "^SOL-[0-9]+$"
},
"description": {
"type": "string",
"description": "Solution approach description"
},
"tasks": {
"type": "array",
"description": "Task breakdown for this solution",
"items": {
"type": "object",
"required": ["id", "title", "scope", "action", "acceptance"],
"properties": {
"id": {
"type": "string",
"pattern": "^T[0-9]+$"
},
"title": {
"type": "string",
"description": "Action verb + target"
},
"scope": {
"type": "string",
"description": "Module path or feature area"
},
"action": {
"type": "string",
"enum": ["Create", "Update", "Implement", "Refactor", "Add", "Delete", "Configure", "Test", "Fix"]
},
"description": {
"type": "string",
"description": "1-2 sentences describing what to implement"
},
"modification_points": {
"type": "array",
"items": {
"type": "object",
"properties": {
"file": { "type": "string" },
"target": { "type": "string" },
"change": { "type": "string" }
}
}
},
"implementation": {
"type": "array",
"items": { "type": "string" },
"description": "Step-by-step implementation guide"
},
"acceptance": {
"type": "array",
"items": { "type": "string" },
"description": "Quantified completion criteria"
},
"depends_on": {
"type": "array",
"items": { "type": "string" },
"default": [],
"description": "Task IDs this task depends on"
},
"estimated_minutes": {
"type": "integer",
"description": "Estimated time to complete"
},
"executor": {
"type": "string",
"enum": ["codex", "gemini", "agent", "auto"],
"default": "auto"
}
}
}
},
"exploration_context": {
"type": "object",
"description": "ACE exploration results",
"properties": {
"project_structure": { "type": "string" },
"relevant_files": {
"type": "array",
"items": { "type": "string" }
},
"patterns": { "type": "string" },
"integration_points": { "type": "string" }
}
},
"analysis": {
"type": "object",
"properties": {
"risk": { "type": "string", "enum": ["low", "medium", "high"] },
"impact": { "type": "string", "enum": ["low", "medium", "high"] },
"complexity": { "type": "string", "enum": ["low", "medium", "high"] }
}
},
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Solution quality score (0.0-1.0)"
},
"is_bound": {
"type": "boolean",
"default": false,
"description": "Whether this solution is bound to the issue"
},
"created_at": {
"type": "string",
"format": "date-time"
},
"bound_at": {
"type": "string",
"format": "date-time",
"description": "When this solution was bound to the issue"
}
}
}

View File

@@ -129,14 +129,31 @@ interface QueueItem {
failure_reason?: string;
}
interface QueueConflict {
type: 'file_conflict' | 'dependency_conflict' | 'resource_conflict';
tasks: string[]; // Item IDs involved in conflict
file?: string; // Conflicting file path
resolution: 'sequential' | 'merge' | 'manual';
resolution_order?: string[];
rationale?: string;
resolved: boolean;
}
interface ExecutionGroup {
id: string; // Group ID: P1, S1, etc.
type: 'parallel' | 'sequential';
task_count: number;
tasks: string[]; // Item IDs in this group
}
interface Queue {
id: string; // Queue unique ID: QUE-YYYYMMDD-HHMMSS (derived from filename)
name?: string; // Optional queue name
status: 'active' | 'completed' | 'archived' | 'failed';
issue_ids: string[]; // Issues in this queue
tasks: QueueItem[]; // Task items (formerly 'queue')
conflicts: any[];
execution_groups?: any[];
conflicts: QueueConflict[];
execution_groups?: ExecutionGroup[];
_metadata: {
version: string;
total_tasks: number;

View File

@@ -2723,28 +2723,66 @@
.queue-detail-item {
display: flex;
align-items: center;
gap: 1rem;
flex-direction: column;
gap: 0.25rem;
padding: 0.5rem 0.75rem;
border-radius: 0.25rem;
border-left: 3px solid transparent;
}
.queue-detail-item:hover {
background: hsl(var(--muted) / 0.3);
}
.queue-detail-item.completed {
border-left-color: hsl(142 76% 36%);
}
.queue-detail-item.pending {
border-left-color: hsl(48 96% 53%);
}
.queue-detail-item.executing {
border-left-color: hsl(217 91% 60%);
}
.queue-detail-item.failed {
border-left-color: hsl(0 84% 60%);
}
.queue-detail-item .item-main {
display: flex;
align-items: center;
gap: 0.75rem;
}
.queue-detail-item .item-id {
min-width: 120px;
min-width: 50px;
color: hsl(var(--muted-foreground));
font-family: var(--font-mono);
}
.queue-detail-item .item-title {
flex: 1;
color: hsl(var(--foreground));
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.queue-detail-item .item-meta {
display: flex;
align-items: center;
gap: 0.75rem;
padding-left: calc(50px + 0.75rem);
}
.queue-detail-item .item-issue {
min-width: 80px;
color: hsl(var(--primary));
font-family: var(--font-mono);
}
.queue-detail-item .item-status {
margin-left: auto;
padding: 0.125rem 0.5rem;
font-size: 0.75rem;
border-radius: 0.25rem;

View File

@@ -1555,7 +1555,7 @@ async function showQueueHistoryModal() {
<div class="issue-modal-backdrop" onclick="hideQueueHistoryModal()"></div>
<div class="issue-modal-content" style="max-width: 700px; max-height: 80vh;">
<div class="issue-modal-header">
<h3><i data-lucide="history" class="w-5 h-5 inline mr-2"></i>${t('issues.queueHistory') || 'Queue History'}</h3>
<h3><i data-lucide="history" class="w-5 h-5 inline mr-2"></i>Queue History</h3>
<button class="btn-icon" onclick="hideQueueHistoryModal()">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
@@ -1563,7 +1563,7 @@ async function showQueueHistoryModal() {
<div class="issue-modal-body" style="overflow-y: auto; max-height: calc(80vh - 120px);">
<div class="flex items-center justify-center py-8">
<i data-lucide="loader-2" class="w-6 h-6 animate-spin"></i>
<span class="ml-2">${t('common.loading') || 'Loading...'}</span>
<span class="ml-2">Loading...</span>
</div>
</div>
</div>
@@ -1583,7 +1583,7 @@ async function showQueueHistoryModal() {
const queueListHtml = queues.length === 0
? `<div class="text-center py-8 text-muted-foreground">
<i data-lucide="inbox" class="w-12 h-12 mx-auto mb-2 opacity-50"></i>
<p>${t('issues.noQueueHistory') || 'No queue history found'}</p>
<p>No queue history found</p>
</div>`
: `<div class="queue-history-list">
${queues.map(q => `
@@ -1611,12 +1611,12 @@ async function showQueueHistoryModal() {
${q.id !== activeQueueId ? `
<button class="btn-sm btn-primary" onclick="event.stopPropagation(); switchToQueue('${q.id}')">
<i data-lucide="arrow-right-circle" class="w-3 h-3"></i>
${t('issues.switchTo') || 'Switch'}
Switch
</button>
` : ''}
<button class="btn-sm btn-secondary" onclick="event.stopPropagation(); viewQueueDetail('${q.id}')">
<i data-lucide="eye" class="w-3 h-3"></i>
${t('issues.view') || 'View'}
View
</button>
</div>
</div>
@@ -1631,7 +1631,7 @@ async function showQueueHistoryModal() {
modal.querySelector('.issue-modal-body').innerHTML = `
<div class="text-center py-8 text-red-500">
<i data-lucide="alert-circle" class="w-8 h-8 mx-auto mb-2"></i>
<p>${t('errors.loadFailed') || 'Failed to load queue history'}</p>
<p>Failed to load queue history</p>
</div>
`;
lucide.createIcons();
@@ -1689,7 +1689,7 @@ async function viewQueueDetail(queueId) {
throw new Error(queue.error);
}
const tasks = queue.tasks || [];
const tasks = queue.queue || [];
const metadata = queue._metadata || {};
// Group by execution_group
@@ -1705,27 +1705,30 @@ async function viewQueueDetail(queueId) {
<div class="queue-detail-header mb-4">
<button class="btn-sm btn-secondary" onclick="showQueueHistoryModal()">
<i data-lucide="arrow-left" class="w-3 h-3"></i>
${t('common.back') || 'Back'}
Back
</button>
<h4 class="text-lg font-semibold ml-4">${queue.id || queueId}</h4>
<div class="ml-4">
<h4 class="text-lg font-semibold">${queue.name || queue.id || queueId}</h4>
${queue.name ? `<span class="text-xs text-muted-foreground font-mono">${queue.id}</span>` : ''}
</div>
</div>
<div class="queue-detail-stats mb-4">
<div class="stat-item">
<span class="stat-value">${tasks.length}</span>
<span class="stat-label">${t('issues.totalTasks') || 'Total'}</span>
<span class="stat-label">Total</span>
</div>
<div class="stat-item completed">
<span class="stat-value">${tasks.filter(t => t.status === 'completed').length}</span>
<span class="stat-label">${t('issues.completed') || 'Completed'}</span>
<span class="stat-label">Completed</span>
</div>
<div class="stat-item pending">
<span class="stat-value">${tasks.filter(t => t.status === 'pending').length}</span>
<span class="stat-label">${t('issues.pending') || 'Pending'}</span>
<span class="stat-label">Pending</span>
</div>
<div class="stat-item failed">
<span class="stat-value">${tasks.filter(t => t.status === 'failed').length}</span>
<span class="stat-label">${t('issues.failed') || 'Failed'}</span>
<span class="stat-label">Failed</span>
</div>
</div>
@@ -1740,9 +1743,14 @@ async function viewQueueDetail(queueId) {
<div class="queue-group-items">
${items.map(item => `
<div class="queue-detail-item ${item.status || ''}">
<span class="item-id font-mono text-xs">${item.item_id || item.task_id}</span>
<span class="item-issue text-xs">${item.issue_id}</span>
<span class="item-status ${item.status || ''}">${item.status || 'unknown'}</span>
<div class="item-main">
<span class="item-id font-mono text-xs">${item.queue_id || item.task_id || 'N/A'}</span>
<span class="item-title text-sm">${item.title || item.action || 'Untitled'}</span>
</div>
<div class="item-meta">
<span class="item-issue text-xs">${item.issue_id || ''}</span>
<span class="item-status ${item.status || ''}">${item.status || 'unknown'}</span>
</div>
</div>
`).join('')}
</div>
@@ -1761,11 +1769,11 @@ async function viewQueueDetail(queueId) {
<div class="text-center py-8">
<button class="btn-sm btn-secondary mb-4" onclick="showQueueHistoryModal()">
<i data-lucide="arrow-left" class="w-3 h-3"></i>
${t('common.back') || 'Back'}
Back
</button>
<div class="text-red-500">
<i data-lucide="alert-circle" class="w-8 h-8 mx-auto mb-2"></i>
<p>${t('errors.loadFailed') || 'Failed to load queue detail'}</p>
<p>Failed to load queue detail</p>
</div>
</div>
`;