Skip to content

feat(ui): files-uploaded stat card with sparkline and smoother Activity load-in - #157

Merged
pmaxhogan merged 2 commits into
mainfrom
feat/files-uploaded-sparkline
Jul 25, 2026
Merged

pmaxhogan merged 2 commits into
mainfrom
feat/files-uploaded-sparkline

Conversation

@pmaxhogan

Copy link
Copy Markdown
Owner

Feature A: files-uploaded stat card with sparkline

A new Files uploaded tile sits immediately after the throughput tile in the
Activity header, in the same Grafana stat-panel style: a headline count with the
last 5 minutes of per-bucket file counts drawn behind it.

The chart itself was extracted rather than duplicated. SparklineStatTile.vue
now owns the geometry, the marks, the hover crosshair/readout and the empty
state; ThroughputStatTile.vue became a thin wrapper that turns bytes into a
rate, and FilesUploadedStatTile.vue is its sibling that keeps a count a count
(a bucket reads as "6 files", never "0.6 files/s"). Counts are pluralized and
grouped through Intl.NumberFormat, all strings via vue-i18n.

Both tiles read one window: the headline is the summary's new
throughputWindowFiles, the same window throughputWindowBytes already
covered, and both sparklines come from one query over one bucketisation.

Wire-shape change (breaking, in-tree only)

activity_throughput_series now returns { bytes: u64[], files: u64[] }
instead of a bare u64[]. Both arrays are dense, oldest-first and the same
length, so bucket i means the same slice of time in each. The frontend is the
only caller and is updated in this PR; the store treats a bare-array response
(a skewed backend) as "no data" rather than plotting indices.

Bug fixed along the way

activity_summary and the series both filtered event_type = 'upload_done',
which silently dropped every bundle_upload row - the V2-bundling rows that
pack N small files into one object. A source whose files get bundled therefore
under-reported "Uploaded today / this week" and read as idle on the throughput
tile. Both queries now match event_type IN ('upload_done', 'bundle_upload'),
and file counts use COALESCE(file_count, 1) so a plain upload counts as one
file and a bundle counts as all of its members. Covered by new tests.

Feature B: smoother Activity load-in

Switching to the Activity tab painted empty tiles, an empty filter bar and
"Showing 0 of 0", then swapped each one out as its query landed. The view now
holds a skeleton of its own shape (tiles, filter bar, table) until the first
load settles - in a finally, so a failed load falls through to its error state
rather than pulsing forever - then fades the real content in with a one-shot CSS
animation. prefers-reduced-motion disables both the fade and the pulse.

A plain keyframe rather than <Transition>: the content enters a fragment that
was never in the DOM, so there is nothing to transition from, and a keyframe
cannot get stuck mid-flight.

Also

loadEventTypeOptions now coerces a non-array response to []. An
unregistered/skewed command resolves undefined instead of rejecting, which
crashed the view's eventTypeOptions.length read on the next render.

Tests

  • cargo test -p driven-core state:: - 83 passed, 0 failed
  • vitest run - 365 passed, 0 failed (38 files)
  • cargo clippy --workspace --all-targets - no warnings
  • cargo fmt --all, eslint . (0 errors), vue-tsc --noEmit clean
  • .sqlx/ offline cache regenerated via just sqlx-prepare

New: sqlite tests for per-bucket file counts, bundle rows counting all members,
and the summary's window file count; mount tests for SparklineStatTile and
FilesUploadedStatTile; an Activity.vue test covering the skeleton, the
failed-load path and the new tile's position and headline.

🤖 Generated with Claude Code

…ty load-in

Adds a "Files uploaded" stat tile next to the throughput tile, sharing one
generalized sparkline component, and replaces the Activity tab's load-in
flash with a skeleton that fades into the real content.

Backend: activity_throughput_series now returns {bytes, files} per bucket
from one query, and both it and activity_summary count bundle_upload rows
(which they previously dropped entirely).
@github-actions

Copy link
Copy Markdown
Contributor

Coverage

Area main this PR delta
Rust (lib crates) 79.50% 79.53% +0.03 (OK)
UI (vue/ts) 90.39% 90.61% +0.22 (OK)

Gate: passed - no coverage regression (epsilon 0.1 pp).

@pmaxhogan
pmaxhogan merged commit 2d85c99 into main Jul 25, 2026
18 checks passed
@pmaxhogan
pmaxhogan deleted the feat/files-uploaded-sparkline branch July 25, 2026 15:50
@github-project-automation github-project-automation Bot moved this from Todo to Done in Driven Jul 25, 2026
pmaxhogan added a commit that referenced this pull request Jul 25, 2026
## Summary
- `telemetry_events_since` counted only `upload_done` rows via
`COUNT(*)`, so `bundle_upload` rows (N member files each) were invisible
to anonymous telemetry - the same undercount class #157 fixed for the
dashboard summary and throughput series.
- Now uses the shared upload-row definition: `event_type IN
('upload_done','bundle_upload')` with `SUM(COALESCE(file_count, 1))` for
files; bytes sum both types.
- `.sqlx` offline cache regenerated (`just sqlx-prepare` steps).

## Testing
- Extended
`telemetry_events_since_aggregates_uploads_errors_and_deep_verify` with
in-window, pre-window, and future-dated `bundle_upload` rows (in-window
bundle of 5 files counts as 5; window bounds still apply).
- `cargo test -p driven-core --lib` telemetry test green; `cargo test -p
driven-app --lib telemetry` 31/31; clippy clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01JLB3E2Jm7knNJd37fVpH8X

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
pmaxhogan added a commit that referenced this pull request Jul 25, 2026
🤖 I have created a release *beep* *boop*
---


## [2.3.0](v2.2.0...v2.3.0)
(2026-07-25)


### Features

* **core:** record a backup_done activity row when a run completes
([#160](#160))
([90cde5c](90cde5c))
* **ui:** files-uploaded stat card with sparkline and smoother Activity
load-in ([#157](#157))
([2d85c99](2d85c99))
* **ui:** live streaming folder-tree preview for the exclusion editor
([#158](#158))
([47ebe14](47ebe14))


### Bug Fixes

* **telemetry:** count bundled uploads in the anonymous aggregate
([#159](#159))
([11af7ea](11af7ea))
* **ui:** label bundle_upload and hook activity event types
([#154](#154))
([2998c76](2998c76))
* **ui:** make the backing-up bar a true determinate progress bar
([#155](#155))
([eed80a6](eed80a6))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant