Страница /reports трансформирована в Центр статусов задач:
Backend:
- GET /api/reports/summary — агрегированные счётчики тип×статус (5 корзин)
- GET/PUT /api/settings/reports — глобальные настройки отчётов
- _filter_tasks_by_rbac() — row-level фильтрация по роли
- normalize_task_report: LLM-валидация с ошибками → FAILED/PARTIAL
- get_summary(): 5 корзин pending/running/awaiting_input/success/failed
Frontend:
- TaskCenterModel.svelte.ts (400 строк) — Screen Model
- SummaryPanel — сводная панель с цветовым кодированием и active filter
- ReportCard — humanized labels, duration, task_id, failed border
- FilterBar — search + sort + time range с label'ами
- Pagination — showingText, уникальные id для select
- Quick views: «Упавшие», «В работе», «Успешные»
- TaskDrawer: scroll-to-error, footer скрыт для terminal, «Н/Д» fix
Тесты: 48 backend + 38 frontend (2521 всего)
Build: ✅ Console errors: 0
3.7 KiB
3.7 KiB
#region UxScreenModels [C:3] [TYPE ADR] [SEMANTICS ux,screen-models,task-status-center] @defgroup Ux Screen Model inventory for Task Status Center.
Model: TaskCenterModel
- File:
frontend/src/lib/models/TaskCenterModel.svelte.ts - Type:
[TYPE Model]C4 - Bound to:
/reportspage (TaskCenterReportsPage) - Complexity: C4 — stateful, WebSocket lifecycle, side effects
Atoms ($state)
| Atom | Type | Default | Purpose |
|---|---|---|---|
tasks |
TaskReport[] |
[] |
Full task list from backend |
summary |
TaskSummary | null |
null |
Aggregated counts by type×status |
filters |
TaskCenterFilter |
defaults | Current filter state |
screenState |
ScreenState |
'loading' |
FSM state: loading/ready/empty/disconnected/reconnecting/error |
wsConnected |
boolean |
false |
WebSocket connection status |
selectedTaskId |
string | null |
null |
Currently selected task for drawer |
page |
number |
1 |
Current page |
pageSize |
number |
20 |
Items per page |
disabledTypes |
TaskType[] |
[] |
Admin-disabled types (from backend) |
visibleTypes |
TaskType[] |
all | Operator preference (from localStorage) |
lastUpdated |
Date | null |
null |
Timestamp of last data update (for stale indicator) |
Derived ($derived)
| Derived | Type | Computation |
|---|---|---|
filteredTasks |
TaskReport[] |
tasks → filter by types/statuses/search/time_range → sort (active first, then sort_by) |
visibleSummary |
TaskSummary | null |
summary filtered by disabledTypes AND visibleTypes |
isEmpty |
boolean |
tasks.length === 0 && screenState === 'ready' |
isFilteredEmpty |
boolean |
filteredTasks.length === 0 && filters active |
hasActiveFilters |
boolean |
any filter non-default |
Actions
| Action | Signature | Side Effects |
|---|---|---|
loadInitialData |
(initialFilters?: Partial<TaskCenterFilter>) => Promise<void> |
REST: summary + list + settings; WS: connect |
applyFilter |
(partial: Partial<TaskCenterFilter>) => void |
URL: replaceState (debounced 300ms) |
clearFilters |
() => void |
URL: replaceState |
selectTask |
(taskId: string) => void |
Store: openDrawerForTask |
refreshSummary |
() => Promise<void> |
REST: summary + list |
connectWebSocket |
() => void |
WS: connect /ws/task-events |
disconnectWebSocket |
() => void |
WS: close |
destroy |
() => void |
WS: disconnect, timers: clear |
toggleTypeVisibility |
(type: TaskType) => void |
localStorage: update visibleTypes |
Invariants
- Active tasks (PENDING, RUNNING, AWAITING_INPUT) always sorted before completed in
filteredTasks visibleSummaryexcludes types indisabledTypes(admin priority) and not invisibleTypes(operator preference)- WebSocket lifecycle: connect on
loadInitialData, disconnect ondestroy - DECOMPOSITION GATE: 400 lines, 40 methods (ADR-0010)
Private
_ws: WebSocket | null_eventBuffer: TaskStatusEvent[]_flushTimeout: ReturnType<typeof setTimeout> | null_reconnectAttempt: number_reconnectTimer: ReturnType<typeof setTimeout> | null_urlSyncTimeout: ReturnType<typeof setTimeout> | null
FSM
loading ──(data loaded)──► ready
loading ──(data empty)───► empty
loading ──(fetch fail)────► error
ready ──(ws close)────────► reconnecting ──(2s)──► disconnected
reconnecting ──(ws open)──► ready
disconnected ──(ws open)──► ready
ready ──(filter applied, no results)──► filtered_empty (list only, summary stays)
#endregion UxScreenModels