Repository navigation
feat(ui): dashboard with collapsible sections and history charts - #105
khaosdoctor wants to merge 32 commits into
Conversation
…ing errors, summarize uploads in SQL
…history migration
[High impact] The PR appears safe to merge, with a remaining non-blocking issue where stalled downloads can keep showing an old speed.
|
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved findings compromise statistics accuracy and refresh scalability, allow inflated upload totals, and leave dashboard error handling and keyboard/screen-reader accessibility incomplete.
7 open issues
Record zero-size history for peers with empty catalogs · New Aggregate statistics by stable peer IDs, not display names · New Aggregate statistics in SQL instead of loading all history · New Reject receipts whose byte count differs from the request · New Restore section headings for screen-reader navigation · New Make chart values accessible without pointer movement · New Show statistics load errors with a retry action · New
What changed in this PR
Redesigns jack's dashboard around collapsible sections and history charts,
building on #104's upload tracking and live download progress.
Changes:
- Adds daily activity charts and lifetime rankings backed by
/stats. - Records catalog-size history and import timestamps for dashboard reporting.
- Includes #104's transfer controls, uploads view, and build-version display.
| File | Description |
|---|---|
website/reference/configuration.md |
Documents failed-download retry and removal settings. |
website/guide/management-ui.md |
Describes dashboard charts and uploads. |
apps/ui/nuxt.config.ts |
Resolves the displayed build version. |
apps/ui/Dockerfile |
Accepts the version as a build argument. |
apps/ui/app/utils/format.ts |
Adds transfer-rate, date, and version formatting. |
apps/ui/app/utils/format.test.ts |
Tests release-version formatting. |
apps/ui/app/types/management.ts |
Defines upload and dashboard statistics types. |
apps/ui/app/pages/uploads.vue |
Adds a filterable upload-history page. |
apps/ui/app/pages/settings.vue |
Updates version display and adds repository link. |
apps/ui/app/pages/index.vue |
Builds the collapsible dashboard and polls statistics. |
apps/ui/app/pages/downloads.vue |
Adds bulk actions and live transfer rates. |
apps/ui/app/layouts/default.vue |
Adds uploads navigation and sidebar version. |
apps/ui/app/components/RankBars.vue |
Renders ranked statistics as bars. |
apps/ui/app/components/LineChart.vue |
Adds SVG time-series charts. |
apps/ui/app/components/DownloadsSection.vue |
Exposes failed-download cleanup settings. |
apps/ui/app/components/DashSection.vue |
Provides collapsible dashboard sections. |
apps/ui/app/components/ColumnChart.vue |
Adds stacked daily-volume charts. |
apps/ui/app/assets/css/main.css |
Defines chart colors for both themes. |
apps/backend/src/modules/uploads/uploads.service.ts |
Handles upload tracking and receipt expiry. |
apps/backend/src/modules/uploads/uploads.repository.ts |
Persists upload history and summaries. |
apps/backend/src/modules/status/status.router.ts |
Exposes uploads, streams, and statistics routes. |
apps/backend/src/modules/status/status.controller.ts |
Supplies dashboard data and coalesces live updates. |
apps/backend/src/modules/stats/stats.ts |
Computes daily series and lifetime rankings. |
apps/backend/src/modules/stats/stats.repository.ts |
Records daily catalog sizes. |
apps/backend/src/modules/peer/peer.router.ts |
Tracks file requests and accepts upload receipts. |
apps/backend/src/modules/peer/peer.controller.ts |
Explains zero-copy tracking in comments. |
apps/backend/src/modules/downloads/live-progress.ts |
Tracks in-memory progress and recent speed. |
apps/backend/src/modules/downloads/failed-download-reaper.ts |
Retries and removes persistent failures. |
apps/backend/src/modules/downloads/downloads.service.ts |
Feeds live progress and guards automated deletion. |
apps/backend/src/modules/downloads/downloads.repository.ts |
Records import completion timestamps. |
apps/backend/src/modules/config/config.service.ts |
Updates comments on live configuration behavior. |
apps/backend/src/modules/config/config.router.ts |
Documents immediately applied settings. |
apps/backend/src/modules/catalog/catalog-sync.service.ts |
Adds a post-sync history callback. |
apps/backend/src/middleware/require-auth.ts |
Exposes key IDs for receipt ownership checks. |
apps/backend/src/management-app.ts |
Injects upload and statistics services. |
apps/backend/src/lib/servers/peer.ts |
Reports live bytes and sends upload receipts. |
apps/backend/src/lib/openapi.ts |
Adds upload API documentation grouping. |
apps/backend/src/lib/config.ts |
Validates failed-download cleanup settings. |
apps/backend/src/index.ts |
Wires history recording and transfer services. |
apps/backend/src/database/schema.ts |
Defines uploads and dashboard-history fields. |
apps/backend/src/app.ts |
Connects upload tracking to peer routes. |
apps/backend/src/__tests__/uploads-repository.test.ts |
Tests upload persistence and lifecycle. |
apps/backend/src/__tests__/upload-tracking.test.ts |
Tests tracking and receipt routes. |
apps/backend/src/__tests__/stream-coalesce.test.ts |
Tests stream notification coalescing. |
apps/backend/src/__tests__/stats.test.ts |
Tests statistics and catalog-history recording. |
apps/backend/src/__tests__/qbittorrent-mapper.test.ts |
Adds import timestamps to fixtures. |
apps/backend/src/__tests__/peer-download.test.ts |
Tests sending upload receipts. |
apps/backend/src/__tests__/live-progress.test.ts |
Tests speed calculations and progress overlays. |
apps/backend/src/__tests__/failed-download-reaper.test.ts |
Tests retry, removal, and cancellation safeguards. |
apps/backend/src/__tests__/downloads-service.test.ts |
Extends configuration fixtures. |
apps/backend/drizzle/meta/0015_snapshot.json |
Captures dashboard-history schema state. |
apps/backend/drizzle/meta/0014_snapshot.json |
Captures upload schema state. |
apps/backend/drizzle/meta/_journal.json |
Registers the new migrations. |
apps/backend/drizzle/0015_dashboard_history.sql |
Creates catalog history and import timestamps. |
apps/backend/drizzle/0014_uploads.sql |
Creates upload storage and indexes. |
.github/workflows/publish.yml |
Passes the image version into UI builds. |
Review effort: Balanced
|
@greptileai review |
|
@greptileai review |
…oad speed from progress samples
# Conflicts: # apps/backend/src/modules/status/status.controller.ts # apps/ui/app/pages/index.vue
| // Measured between progress writes (every 10 s / 64 MiB); only while running. | ||
| const speedBps = d.status === 'downloading' | ||
| ? d.speedBps | ||
| : null |
There was a problem hiding this comment.
Stopped downloads show old speeds
Removing LiveProgressTracker also removes the check that stopped showing old speeds. After a transfer has reported a speed, a network stall or retry delay leaves its status as downloading. enrichDownload therefore keeps returning the old speedBps and ETA even when no bytes are arriving, making the download look like it is still moving.
Clear the speed when an attempt fails, and expire old samples with a notification so open pages update too.
There was a problem hiding this comment.
Fixed in ffca03e without bringing back a second byte count: a failed attempt clears speed_bps (and notifies) before its retry wait, and enrichDownload drops a speed whose row hasn't been written for 30 s, so a stall shows no speed past that. The 10 s / 64 MiB cadence is discussed in the maintainer's thread above.
…ount uploads of replaced files
# Conflicts: # apps/backend/drizzle/meta/0015_snapshot.json # apps/backend/drizzle/meta/_journal.json
roziscoding
left a comment
There was a problem hiding this comment.
Re-reviewed the current stacked delta after the follow-up fixes. Existing review findings are addressed, and I found no new actionable issues. Backend tests, UI typecheck, targeted lint, and diff checks pass.

What does this PR do?
Redesigns the Dashboard into collapsible sections with history charts. Builds on #104 (its uploads data and live progress), so its commits show up here until #104 is merged.
There's a range picker in the top bar now (5 min, 30 min, 60 min, 24 h, 7 days, 30 days) and every history chart follows it. Sections, top to bottom, each one folds and starts open:
Backend:
GET /stats(management API) with arangeof5m,30m,1h,24h,7dor30d(the default, also used for anything it doesn't know). Each range comes back as 24 to 30 buckets (10 s, 1 min, 2 min, 1 h, 6 h or a day) plus the fastest/average/slowest single import and lifetime rankings. Computed in SQL from the download and upload rows; nothing is streamed, the page refetches once per bucket, between 10 s and a minute.0016addsdownloads.imported_at(set when *arr confirms the import) and acatalog_size_historytable, one row per source per UTC day, written after every catalog sync. Both start recording after the upgrade, so those charts fill in from then on. Catalog size stays daily, so on the short ranges it shows that day's reading.The charts are plain SVG and CSS (no chart library), with a fixed categorical palette checked for color vision deficiencies in both themes, hover tooltips, and a screen-reader table per chart.
Related issue
Depends on #104.
Screenshots
Checklist
mise run lint:fixwas run and its output is committedmise run testpasses (andmise run test:e2eif transfer/request paths changed)