Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8531fd6
UI-SP2 spec — download-manager Task Detail (4 additive read endpoints…
l17728 May 19, 2026
1549d31
UI-SP2 implementation plan — 20 bite-sized TDD tasks across M1-M4
l17728 May 19, 2026
269c882
UI-SP2 plan: fix 2 pre-execution BLOCKERs found by opus reviewers
l17728 May 19, 2026
0b7f695
UI-SP2 M1: openapi — add subtask-chunks + participating-executors pat…
l17728 May 19, 2026
7b80005
UI-SP2 M1: task_detail DTOs + subtask-chunks test (red)
l17728 May 19, 2026
0071708
UI-SP2 M1: subtask-chunks service + route (green)
l17728 May 19, 2026
90fcf05
UI-SP2 M1: source-allocation + participating-executors service+routes
l17728 May 19, 2026
f7022db
UI-SP2 M1: task events service + route (audit-derived, cursor paginated)
l17728 May 19, 2026
bc06e11
UI-SP2 M2: useLiveResource additive enabled option (view-transparent)
l17728 May 19, 2026
d501e4b
UI-SP2 M2: API DTO types for the 4 task-detail endpoints
l17728 May 19, 2026
cf71fb6
UI-SP2 M2: pure formatting utils (bytes/rate/duration)
l17728 May 19, 2026
fa4c52c
UI-SP2 M2: computeRate pure fn + useDownloadRate composable
l17728 May 19, 2026
c5bb627
UI-SP2 M2: 4 live data composables (single useLiveResource seam)
l17728 May 19, 2026
3cc5453
UI-SP2 M3: AggregateRing (inline SVG donut) + ringDash
l17728 May 19, 2026
0bb1d52
UI-SP2 M3: ChunkBar+chunkSegments + SourceBar (inline SVG)
l17728 May 19, 2026
a9c1c11
UI-SP2 M3: SwimLane + SpeedEta
l17728 May 19, 2026
1fa6da5
UI-SP2 M3: EventRow + eventLevel classifier
l17728 May 19, 2026
dec6cd9
UI-SP2 M4: i18n tasks.detail.* keys (en/zh parity)
l17728 May 19, 2026
66950dc
UI-SP2 M4: rebuild TaskDetail (header+ring+tabs+DataBoundary+chunk ta…
l17728 May 19, 2026
0ac67ee
UI-SP2 M4: operator docs for the download-manager Task Detail
l17728 May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@

# ========== Tasks ==========
/tasks:
get:

Check warning on line 169 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: List tasks
operationId: listTasks
Expand Down Expand Up @@ -194,7 +194,7 @@
schema: {$ref: '#/components/schemas/RbacDenied'}
'429': {$ref: '#/components/responses/RateLimited'}

post:

Check warning on line 197 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Create download task
operationId: createTask
Expand Down Expand Up @@ -296,7 +296,7 @@
parameters:
- $ref: '#/components/parameters/TaskId'

get:

Check warning on line 299 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Get task by ID
operationId: getTask
Expand All @@ -315,7 +315,7 @@
'404':
description: Task not found or cross-tenant ID (existence not leaked)

patch:

Check warning on line 318 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Update task (priority only)
operationId: updateTask
Expand Down Expand Up @@ -368,7 +368,7 @@
/tasks/{taskId}/cancel:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 371 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Cancel task (async)
operationId: cancelTask
Expand Down Expand Up @@ -402,7 +402,7 @@
/tasks/{taskId}/retry:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 405 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Retry failed subtasks
operationId: retrySubtasks
Expand Down Expand Up @@ -448,7 +448,7 @@
/tasks/{taskId}/upgrade:
parameters:
- $ref: '#/components/parameters/TaskId'
post:

Check warning on line 451 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Upgrade to new revision (incremental)
operationId: upgradeTask
Expand All @@ -472,7 +472,7 @@
/tasks/{taskId}/subtasks:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 475 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [subtasks]
summary: List subtasks of a task
operationId: listSubtasks
Expand All @@ -495,7 +495,7 @@
/tasks/{taskId}/source-allocation:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 498 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: View source allocation (multi-source visualization)
operationId: getSourceAllocation
Expand All @@ -509,7 +509,7 @@
/tasks/{taskId}/events:
parameters:
- $ref: '#/components/parameters/TaskId'
get:

Check warning on line 512 in api/openapi.yaml

View workflow job for this annotation

GitHub Actions / OpenAPI lint

operation-description Operation "description" must be present and non-empty string.
tags: [tasks]
summary: Task event log
operationId: getTaskEvents
Expand All @@ -529,6 +529,34 @@
items: {$ref: '#/components/schemas/TaskEvent'}
next_cursor: {type: string, nullable: true}

/tasks/{taskId}/subtask-chunks:
parameters:
- $ref: '#/components/parameters/TaskId'
get:
tags: [tasks]
summary: Per-file chunk segments (download-manager visualization)
operationId: getSubtaskChunks
responses:
'200':
description: Subtask chunk report
content:
application/json:
schema: {$ref: '#/components/schemas/SubtaskChunkReport'}

/tasks/{taskId}/participating-executors:
parameters:
- $ref: '#/components/parameters/TaskId'
get:
tags: [tasks]
summary: Executors participating in this task (swimlanes)
operationId: getParticipatingExecutors
responses:
'200':
description: Participating executors
content:
application/json:
schema: {$ref: '#/components/schemas/ParticipatingExecutors'}

# ========== Models ==========
/models/search:
get:
Expand Down Expand Up @@ -1867,6 +1895,55 @@
type: object
additionalProperties: true

SubtaskChunkReport:
type: object
required: [items]
properties:
items:
type: array
items:
type: object
required: [subtask_id, filename, status, bytes_downloaded, is_chunked, chunks_completed, chunks]
properties:
subtask_id: {type: string, format: uuid}
filename: {type: string}
file_size: {type: integer, format: int64, nullable: true}
status: {type: string}
bytes_downloaded: {type: integer, format: int64}
is_chunked: {type: boolean}
chunks_total: {type: integer, nullable: true}
chunks_completed: {type: integer}
chunks:
type: array
items:
type: object
required: [chunk_index, byte_start, byte_end, source_id, status, bytes_done]
properties:
chunk_index: {type: integer}
byte_start: {type: integer, format: int64}
byte_end: {type: integer, format: int64}
source_id: {type: string}
status: {type: string}
bytes_done: {type: integer, format: int64}

ParticipatingExecutors:
type: object
required: [items]
properties:
items:
type: array
items:
type: object
required: [executor_id, assigned_subtasks, active_subtasks, bytes_downloaded]
properties:
executor_id: {type: string}
executor_status: {type: string, nullable: true}
health_score: {type: integer, nullable: true}
last_heartbeat_at: {type: string, format: date-time, nullable: true}
assigned_subtasks: {type: integer}
active_subtasks: {type: integer}
bytes_downloaded: {type: integer, format: int64}

# ===== Models =====
ModelSummary:
type: object
Expand Down
22 changes: 22 additions & 0 deletions docs/operator/web-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,25 @@ chip is read-only (no tenant switcher); list filtering is client-side
(no server-side filter endpoint yet).

Cross-ref: `docs/getting-started.md`, `docs/operator/cli-sdk.md`.

## UI-SP2 — Download-manager Task Detail

`/tasks/:id` is a full download-accelerator view backed by four additive
read-only endpoints (zero migration):

- `GET /api/v1/tasks/{id}/subtask-chunks` — per-file chunk segments
- `GET /api/v1/tasks/{id}/source-allocation` — per-source contribution + chunk routing
- `GET /api/v1/tasks/{id}/participating-executors` — executor swimlanes
- `GET /api/v1/tasks/{id}/events` — audit-derived event log (cursor-paginated)

The page has a header (basic info + aggregate progress ring + client-derived
speed/ETA + cancel/delete) and four tabs (Files & chunks, Sources, Executors,
Events). All polling flows through the single `useLiveResource` seam; only the
active tab polls (others paused via the `enabled` option).

Known limitations (intentional, deferred): speed/ETA are derived client-side
from successive byte-count polls (no backend speed source); retry/pause/upgrade
actions are not exposed (no endpoints); the file table uses a height-capped
`el-table` (true `el-table-v2` windowing is a documented follow-up); the event
log reads existing `audit_log` rows only; real-time push (SSE/WS) arrives in
UI-SP5 with no view changes.
Loading
Loading