Downloader analytics v2: multi-plot workspace, state timeline, fault decoding, and docs#78
Conversation
Allocate generation when a range is queued, clear stale errors immediately, and reject superseded state updates so in-flight responses cannot overwrite the current UI.
… signal never reaches the API
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 61d5f72d11
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def build_envelope_sql(table: str, signal: str) -> str: | ||
| column = _quoted(signal) | ||
| return ( | ||
| "SELECT time_bucket(%(bucket)s::interval, time) AS bucket, " |
There was a problem hiding this comment.
Anchor envelope buckets to the requested range
When a dense signal switches to envelope mode and the requested start is not aligned to the computed bucket interval, time_bucket labels the first aggregate with TimescaleDB's global bucket boundary, which can be before payload.start. The analysis plot clamps the x-axis to the requested [start, end], so that first aggregate can be clipped from the visible range, while CSV exports can contain out-of-range timestamps. Anchor buckets to the request start (or clamp/center returned bucket timestamps) so envelope data represents the selected window correctly.
Useful? React with 👍 / 👎.
| const movedRight = new Set( | ||
| layout.flatMap((g) => g.rightAxis.filter((s) => unique.includes(s))), | ||
| ); | ||
| const removed = removeSignals(layout, new Set(unique)); |
There was a problem hiding this comment.
Preserve the target plot during self-assignments
When the dragged/assigned payload contains every signal currently in the target plot, such as dropping a selected one-signal plot back onto itself or dropping a message group that includes the target's only signal, removeSignals prunes the target before the later append step. Since the target id no longer exists in removed, the assignment returns without re-adding those signals, making them disappear from the layout. Handle no-op/self-target cases or keep the target group until after the destination is rebuilt.
Useful? React with 👍 / 👎.
# Conflicts: # server/installer/data-downloader/backend/app.py # server/installer/data-downloader/frontend/src/analysis/plot-traces.test.ts # server/installer/data-downloader/frontend/src/analysis/plot-traces.ts # server/installer/data-downloader/frontend/src/api.ts # server/installer/data-downloader/frontend/src/components/AnalysisPlotStack.test.tsx # server/installer/data-downloader/frontend/src/components/AnalysisPlotStack.tsx # server/installer/data-downloader/frontend/src/components/AnalysisSignalPicker.test.tsx # server/installer/data-downloader/frontend/src/components/AnalysisSignalPicker.tsx # server/installer/data-downloader/frontend/src/components/AnalysisWorkspace.test.tsx # server/installer/data-downloader/frontend/src/components/AnalysisWorkspace.tsx # server/installer/data-downloader/frontend/src/components/sensor-palette.ts # server/installer/data-downloader/frontend/src/styles.css # server/installer/data-downloader/frontend/src/test-setup.ts
Adds the Analysis tab to the data-downloader with multi-signal Plotly plots, vehicle state timeline with PM100 fault decoding, CSV export, and comprehensive documentation.
Backend
POST /api/series: density-aware multi-signal time-series endpoint (raw or time-bucketed envelope)POST /api/states: vehicle state lane segments and PM100 fault interval decodingsignal_choices()in dbc_utils for DBC VAL_ label lookupFrontend
Tests: 178 total (48 backend + 130 frontend), all passing
Docs: Analytics feature documentation added to data-downloader README