Add task detail view, pipeline visualization, approve/reject workflow

API (web/api.py) — 5 new endpoints:
  GET  /api/tasks/{id}/pipeline — agent_logs as pipeline steps
  GET  /api/tasks/{id}/full — task + steps + related decisions
  POST /api/tasks/{id}/approve — mark done, optionally add decision
  POST /api/tasks/{id}/reject — return to pending with reason
  POST /api/tasks/{id}/run — launch pipeline in background (202)

Frontend:
  TaskDetail (/task/:id) — full task page with:
    - Pipeline graph: role cards with icons, arrows, status colors
    - Click step → expand output (pre-formatted, JSON detected)
    - Action bar: Approve (with optional decision), Reject, Run Pipeline
    - Polling for live pipeline updates
  Dashboard: review_tasks badge ("awaiting review" in yellow)
  ProjectView: task rows are now clickable links to /task/:id

Runner: output_summary no longer truncated (full output for GUI).
Models: get_project_summary includes review_tasks count.

13 new API tests, 105 total, all passing. Frontend builds clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
johnfrum1234 2026-03-15 14:32:29 +02:00
parent fabae74c19
commit 38c252fc1b
9 changed files with 550 additions and 7 deletions

View file

@ -190,8 +190,9 @@ async function addDecision() {
</div>
<div v-if="filteredTasks.length === 0" class="text-gray-600 text-sm">No tasks.</div>
<div v-else class="space-y-1">
<div v-for="t in filteredTasks" :key="t.id"
class="flex items-center justify-between px-3 py-2 border border-gray-800 rounded text-sm hover:border-gray-700">
<router-link v-for="t in filteredTasks" :key="t.id"
:to="`/task/${t.id}`"
class="flex items-center justify-between px-3 py-2 border border-gray-800 rounded text-sm hover:border-gray-600 no-underline block transition-colors">
<div class="flex items-center gap-2 min-w-0">
<span class="text-gray-500 shrink-0 w-24">{{ t.id }}</span>
<Badge :text="t.status" :color="taskStatusColor(t.status)" />
@ -201,7 +202,7 @@ async function addDecision() {
<span v-if="t.assigned_role">{{ t.assigned_role }}</span>
<span>pri {{ t.priority }}</span>
</div>
</div>
</router-link>
</div>
</div>