chore(deps): bump actions/upload-artifact from 4 to 7#14
Open
dependabot[bot] wants to merge 1 commit into
Open
chore(deps): bump actions/upload-artifact from 4 to 7#14dependabot[bot] wants to merge 1 commit into
dependabot[bot] wants to merge 1 commit into
Conversation
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
3fdc5e7 to
0ebc05d
Compare
0ebc05d to
661d726
Compare
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
661d726 to
09a9717
Compare
atulmgupta
added a commit
that referenced
this pull request
May 3, 2026
…erfiles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
atulmgupta
added a commit
that referenced
this pull request
May 4, 2026
* Add dynamic themed app icons and notification badge
Introduce runtime theming for app icons and Android notification badge support.
- Add web/src/lib/appIcon.ts: pure helpers to build SVG app icons, encode as data URLs, and rasterize to PNGs.
- Add useDynamicAppIcon hook (web/src/hooks/useDynamicAppIcon.ts) to apply themed favicon, apple-touch-icon, and a generated manifest blob (with revoke handling). Exposes data-base-href so badges can composite over the live themed icon.
- Adjust useFaviconBadge to prefer data-base-href when snapshotting/compositing, preventing badge churn over dynamically themed favicons.
- Wire the hook into Layout.tsx so it runs before the favicon badge hook.
- Add unit tests for useDynamicAppIcon (web/src/hooks/__tests__/useDynamicAppIcon.test.tsx).
- Add badge.svg and generated badge-72.png to public icons and document regeneration steps in web/public/icons/README.md.
- Update service worker (sw.ts) to use the monochrome badge (/icons/badge-72.png) and clarify badge vs icon behavior in comments.
This enables on-the-fly favicon/manifest updates to reflect user-selected themes and ensures Android notifications use the correct monochrome badge to avoid the duplicate-icon bug.
* Make shortcut keys readable in tooltip
Update PlaybackControls help content to avoid hardcoded white text and improve kbd styling. Added a comment explaining why we must inherit the Tooltip's text color (to avoid invisible text in inverted dark-mode tooltips), removed text-white/* classes, set the grid to use opacity-90, and gave each <kbd> a rounded border, subtle background, padding, and smaller monospace text so shortcut tokens are distinct and readable in both themes.
* chore(web): remove unnecessary regex escape in vehicleColors
eslint no-useless-escape was failing on [\s_\-] since the dash is
already at end-of-class position; switch to [\s_-]. Pre-existing
issue surfaced by adding lint:i18n to the lint chain.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/01-i18n: eradicate template literals + add CI rule
Convert all 31 JS template-literal placeholders (${var}) in
web/src/i18n/en.json to i18next mustache syntax ({{var}}), updating
every callsite to pass interpolation values via t(key, { var,
defaultValue }). Two legitimate ${{amount}} patterns (literal "$"
followed by a mustache placeholder, used for currency formatting) are
preserved.
Add web/scripts/lint-i18n-no-template-literals.mjs as a CI guardrail
that fails if any web/src/i18n/*.json file ever reintroduces this
syntax. The script is chained into "npm run lint" so existing CI
workflows pick it up without further wiring.
Affected user-visible strings include Year-in-Review, Cost-Per-Distance,
Battery Health insights, Notification Rules cadence, Confirm dialogs,
Pin/Unpin tooltip, and Drive efficiency labels.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/02-boundary: reset ErrorBoundary on route change
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/03-formatters: NaN/Infinity-safe duration helpers
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/04-modal: migrate hand-rolled overlays to shared <Modal>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/05-smoke: lazy-route bundle smoke test
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/06-settings: broadcast propagation for preference mutations
Adds a centralized broadcast topic registry (TOPICS in
web/src/lib/broadcastTopics.ts) and a <FormatterPrefsBridge /> mounted
near the React root that anchors a permanent useSettings() subscription
so module-level formatter globals (numberFormat locale + decimal
precision) stay current on every page — including pages that never
call useSettings() themselves.
Extends BroadcastMessage with an umbrella settings.changed topic that
non-React-Query mutators can fire to invalidate the ['settings'] query
on this and peer tabs, and refactors useSettings() to apply globals
inside useEffect rather than during render so commits are deterministic
under React.StrictMode.
Adds 9 broadcast-propagation tests covering: derived useSettings
applies/refreshes globals on data change, the bridge anchors globals
without a page-level consumer, settings.changed cross-tab broadcasts
trigger refetch + global re-application, and invalidateAndBroadcast
emits queryInvalidate envelopes on the wire.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/07-sidebar: refine section-header typography
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/08-theme: light-mode CSS-var parity re-audit + lint script
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/09-help: HelpTooltip adoption on technical screens
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/10-docker: backport bug-#14 Go-compile flags to sibling Dockerfiles
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/11-pwa: stale-chunk reload resilience + new-version banner
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/12-vitals: real-world Web Vitals reporter + Prometheus ingest
Adds end-to-end measurement of Core Web Vitals (LCP, INP, CLS, FCP, TTFB)
from real browser sessions, the prerequisite for treating the engineering
guideline performance budget (FCP < 1.5s on 4G) as an observable property
rather than a one-off check.
Frontend:
- web/src/lib/webVitalsReporter.ts: idempotent reporter that batches
metrics, ships them via navigator.sendBeacon (with fetch fallback),
flushes on visibilitychange/pagehide, and never propagates errors.
- main.tsx: starts the reporter in PROD; keeps the existing dev-console
reporter for development to avoid HMR noise.
Backend:
- internal/api/web_vitals_handler.go: POST /api/v1/web-vitals ingest
handler with strict JSON decoding, 64 KiB body cap, 100-metric batch
cap, closed allow-list of metric names + ratings, Prometheus
histogram (teslasync_web_vitals_value{name,rating,route}), and route
normalization (numeric/UUID/hex segments collapsed to :id, length cap
50) so label cardinality stays bounded.
- internal/api/router.go: mounted public (no auth) outside the /api/v1
ForwardAuth subrouter and rate-limited to 120 req/min/IP.
UI surface:
- features/system/pages/SystemStatusPage.tsx: new ClientPerformancePanel
documenting that Web Vitals are now collected and linking to a Grafana
dashboard via VITE_GRAFANA_URL when set.
- i18n/en.json: admin.systemStatus.clientPerformance.* keys.
Tests: 9 frontend tests (mocks web-vitals callbacks and exercises
sendBeacon/fetch/error paths) + 8 Go test groups (valid/invalid/empty/
oversize batches, unknown name/rating handling, strict decoding, 14
route-normalization cases, length cap).
Note: the prompt's Files-touched list referenced
features/admin/pages/SystemStatusPage.tsx, but the actual file lives at
features/system/pages/SystemStatusPage.tsx (App.tsx:124,
lazyRoutes.list.ts:135). The git_status allow-list in the gate was
adjusted to match the real path; see PREFLIGHT NOTE in the log.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/13-a11y: comprehensive accessibility audit & landmarks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/14-mobile: responsive audit, safe-area, touch tooltips
Adds the missing mobile-aware shared primitives required by the
Phase-45/14 mobile responsive audit:
- web/src/hooks/useMediaQuery.ts: reactive matchMedia hook with
SSR-safe defaults plus useIsMobile() / useIsCoarsePointer()
convenience aliases. Lets chart consumers opt into tap-to-tooltip
behaviour on touch devices without ad-hoc matchMedia plumbing.
- web/src/__tests__/mobile.viewport.test.tsx: smoke test that
exercises the shared primitives at a 375px phone viewport
(Modal as bottom sheet, BottomTabBar safe-area + touch targets,
PageHeader stacking, DataTable mobileColumns) and verifies the
useMediaQuery contract (initial state, reactive updates, listener
cleanup).
Verified: tsc --noEmit, npm run lint, npm test -- --run (1238 passed),
audit: viewport-fit=cover + safe-area-inset CSS already present.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/15-optimistic: useOptimisticMutation helper + migrate 7 hooks
Add a shared useOptimisticMutation helper that snapshots the cache,
writes the optimistic update, restores on error, and invalidates on
settle. Supports multi-key updates and an optional cross-tab broadcast.
Migrate 7 high-frequency mutations to use it so the UI updates
instantly instead of waiting for the server round-trip:
- useToggleAutomation (useAutomations.ts) - flip enabled instantly
- useDeleteSavedView (useSavedViews.ts) - row removed instantly
- useMarkAlertRead (useNotifications.ts)
- useToggleAlertRule (useNotifications.ts)
- useMarkNotificationsRead (useNotifications.ts)
- useMarkNotificationsUnread (useNotifications.ts)
- useArchiveNotifications (useNotifications.ts)
Notes:
- useTogglePin remains on plain useMutation: its mutationFn reads the
pinned-list cache to look up the row id for DELETE, which requires
pre-mutation cache access. Documented inline; revisit if the backend
exposes a delete-by-(type,item_id) endpoint.
- Toasts stay on onSuccess/onError, not onMutate, so a rolled-back
optimistic write does not mislead the user.
- Adds useAlerts.ts re-export shim so consumers can import alert hooks
from a dedicated module without churning useNotifications.ts.
Tests:
- useOptimisticMutation.test.tsx (9 tests): immediate optimistic write,
rollback on error, invalidation on settle, multi-key, function-form
keys, caller onMutate ordering, double-toggle race, broadcast.
- useMarkNotificationRead.test.tsx (6 tests): bulk mark-read +
single useMarkAlertRead happy + rollback paths.
All gates green: TS clean, lint clean, 1253/1253 frontend tests pass,
13 onMutate occurrences across hooks/.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/16-unsaved: NavigationGuardProvider + GuardedLink for in-app guards
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/17-urlstate: adopt useUrlState across 13 filter pages
Replace useState-based filter state with useUrlString/Number/Boolean/Enum
helpers in 10 filter-bearing pages so filter selections are bookmarkable,
shareable, and survive a page refresh. Also adds a static-source guard
test that asserts every listed page imports a useUrl* hook.
Pages converted:
- charging/ChargingListPage (sort, charger, search, page, dates)
- admin/ApiLogsPage (page, method, status, endpoint, service, dates)
- admin/DevToolsPage (refactor useTabParam to useUrlEnum)
- analytics/StatisticsPage (vehicle, dates)
- analytics/PeriodComparePage (vehicle, periodA, periodB)
- maps/LocationsPage (vehicle, page, search)
- system/CommandHistoryPage (vehicle, status, search, page)
- telemetry/SignalExplorerPage (signals, dates, page)
- telemetry/SignalDiffPage (vehicle, atA, atB, filter, category)
- trips/TripListPage (vehicle, page, dates)
Total adopters in features/: 10 -> 20.
NEW src/__tests__/url-state-adoption.test.ts asserts the 13 canonical
filter pages each call a useUrl* helper.
Adds top-level i18n key 'filters.reset' = 'Reset filters'.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/18-skeleton: shaped skeletons across 7 detail pages + audit script
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/19-swr: page-header DataFreshnessAuto + background refetch pulse
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/20-errors: 404/401/5xx/network branches in QueryError + ErrorDisplay
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/21-motion: motion.duration tokens + auditMotionTokens script
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/22-time: <TimeStamp> + relative/absolute toggle in Settings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/23-cb: CB-safe chart palette (Okabe-Ito) + user pref + adjacency audit
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/24-settings-search: find-as-you-type filter + fuzzy match in /settings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/25-widget-discovery: floating + AddWidgetButton + catalogue dialog + checklist task
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/26-replay-sync: bidirectional map ↔ chart cursor sync in TripReplayPage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/27-frecency: command palette frecency ranking + reset action
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/28-bulk-read: bulk mark-read in /notifications + optimistic update + undo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/29-silence: ConfirmDialog silenceKey + restore-prompts in Advanced settings
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/30-tesla-auth: recovery banner + queued mutation retry on token expiry
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/31-empty-state: shared Button + typography + CTA wiring across feature pages
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/32-bulk-actions: useBulkSelection + BulkActionToolbar + adopt across 4 list pages
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/33-ratelimit: parse Retry-After + RateLimitBanner with countdown + breaker UX
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/34-tooltip-audit: catch white-on-white tooltip content via CI script + dev-time warn
- NEW web/scripts/audit-tooltip-text-color.mjs flags <Tooltip|HelpTooltip>
callsites whose JSX content hardcodes text-white/N or text-gray-{100..400}
(collides with the tooltip's inverted surface — light card in dark mode,
dark card in light mode + light-mode global text-white overrides).
- Wire the audit into the lint chain (npm run audit:tooltip-text).
- web/src/components/ui/Tooltip.tsx: JSDoc the inverted-surface text colour
contract and add a dev-only warnIfHardcodedTextColor backstop that
console.warn's once per offending callsite (zero cost in production
builds via import.meta.env.PROD short-circuit).
- NEW web/src/components/ui/__tests__/Tooltip.contract.test.tsx — 10 tests
covering string content, JSX without overrides, decorative shades
(text-amber-300, text-emerald-300), nested-children walking, dev vs
production behaviour, and the text-gray-500 negative case.
- 0 existing offenders — PlaybackControls helpContent (the post-Phase-40
fix) remains the canonical reference for downstream tooltip authors.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(web): reconcile FSM debugger window vs 24h buffer counts
State Machine debugger no longer shows the contradictory "23 buffered" /
"No transitions in window" pair. The toolbar now reads
"{n} in window . {N} in 24 h" so both scopes are explicit, and the
empty-state timeline + snapshot inspector get an actionable hint with
"Widen window to {label}" and "Jump to last transition" buttons.
Phase-45 / Prompt 35.
Changes:
- new windowTransitions(transitions, minutes, anchor?) helper as the
single source of truth for page, timeline, and toolbar
- new nextWiderPreset(lastTs, anchor, currentMinutes) that picks the
smallest preset (5m..24h) that would surface the last transition
- StateMachineDebuggerPage now feeds pre-windowed transitions to the
timeline and threads lastTransition / widerPreset / handlers into
StateTimeline + SnapshotInspector
- LiveControls renders dual counter + Tooltip explaining the dropdown
vs fetch distinction; bufferCount kept as a one-phase deprecated
fallback (no external consumers)
- StateTimeline empty-state now flex-row with hint + Widen / Jump
buttons; component is purely presentational (callers pre-window)
- SnapshotInspector emptyOutsideWindow branch matches the timeline
hint when there is nothing selectable
- new i18n keys under debugger.{window,timeline,controls,inspector}
Tests: 14 helper + 5 timeline empty + 5 inspector empty + 3 page
integration; full suite 1548/1548 pass; tsc + lint clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/36-time-range-filter: add useUrlBatch + atomic preset writes + active-state on chips
Fixes the same-tick URL setter race in react-router-dom v6 that caused
preset chips on Signal Log Viewer (and 9 other pages) to silently lose
one of the two URL writes when applying a time-range preset.
Changes:
- Add useUrlBatch() to hooks/useUrlState.ts: single setter that
atomically commits N URL key changes via one setSearchParams updater
call, eliminating the structural race where two same-tick navigate
(replace) calls discard each other.
- Document the same-tick race in the UrlStateSetter JSDoc.
- Extend <DateRangeFilter> with optional onRangeChange prop. When
provided, preset chip clicks call it instead of dual onStart/onEnd
setters, allowing pages to wire it to a useUrlBatch-backed setter.
- Add matchTimeRangePreset() to lib/constants.ts: matches a (from, to)
datetime pair to a TIME_RANGE_PRESETS entry within +-60s tolerance.
- Add visual active-state to TIME_RANGE_PRESETS chips on
SignalLogViewerPage, SignalExplorerPage, and SignalQueryControls
(variant=primary + aria-pressed when matchTimeRangePreset matches).
- Migrate 10 affected sites: SignalLogViewerPage, SignalExplorerPage
and NotificationsPage use useUrlBatch directly; the 8
<DateRangeFilter> consumers (DrivesList, ChargingList, MyActivity,
CostAnalysis, Statistics, Energy, Efficiency, TripList) wire
onRangeChange. CostAnalysis/Energy/Efficiency also migrated from
useState to useUrlString for date filters.
- Collapse NotificationsPage.handleFiltersChange (7 setters) into one
setFiltersBatch call, fixing silent data loss when applying saved
views or clearing all filters.
- Add i18n key signalQuery.preset.aria for chip aria-label.
Tests:
- useUrlBatch: 5 new tests (atomic write, deletion semantics, push
option, plus a REGRESSION test documenting the same-tick race that
useUrlBatch fixes).
- matchTimeRangePreset: 7 new tests (each preset matches, non-match,
tolerance, custom tolerance, empty/invalid input).
- DateRangeFilter onRangeChange: 3 new tests (precedence, back-compat
fallback, onApply still fires).
- All 1567 frontend tests pass; tsc clean; lint (incl. all 4
sub-audits) clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/37-redis-viewer-diag: enrich /dev-tools/redis-signals with meta + add keys endpoint + structured empty-state diagnostic
Backend
- internal/signal/redis_cache.go: add HLen + Scan to redisSignalClient
interface; add RawFieldCount (HLEN raw HSET size, distinguishes
"Redis empty" from "fields stored but undecodable") and
ScanVehicleKeys (cursor-based SCAN, NEVER KEYS) helpers.
- internal/signal/store.go: add LastSeenAt(vehicleID) returning newest
L1 timestamp; complement of L2 GetAllValues max-Timestamp scan.
- internal/api/devtools_handler.go: wire signalStore + vehicleRepo via
new WithSignalStore option; enrich GET /dev-tools/redis-signals with
meta block (live_signal_store_mode, redis_key, redis_field_count,
l1_signal_count, l1/l2_last_seen_at, vehicle_vin); add sister
GET /dev-tools/redis-signals/keys handler that lists vehicleIDs with
cached Redis HSETs via SCAN.
- internal/api/router.go: pass WithSignalStore(opt.SignalStore) to the
dev-tools handler; register the new /redis-signals/keys route.
- internal/api/devtools_handler_test.go (NEW): table-driven tests using
miniredis covering 503-no-redis, 400-bad-vehicle-id, four meta
permutations (mode-local, hybrid+L1-only, hybrid+populated, both
empty), and keys endpoint (filters malformed keys, respects limit).
Frontend
- web/src/api/devtools.ts: add RedisSignalsMeta, RedisSignalKeyEntry,
RedisSignalKeysResponse types; getRedisSignalKeys hook function.
- web/src/features/admin/components/RedisDiagnosticEmptyState.tsx
(NEW): structured 4-branch diagnostic banner — mode=local danger,
L1>0+L2=0 mirror-broken warning, no-recent-telemetry info, neutral
fallthrough — plus quick-switch chips listing OTHER vehicles that DO
have cached signals (from the keys endpoint), and a meta KV list.
- web/src/features/admin/pages/RedisSignalViewerPage.tsx: render
persistent header chips (Mode/VIN/L1-last) whenever a vehicle is
selected so engineers don't have to clear the table to see them;
replace the generic empty-state branch with the new diagnostic.
- web/src/i18n/en.json: add redis.diagnostic.* (modeLocal, mirrorBroken,
noTelemetry, empty, otherVehicles, meta) and redis.headerChip.*
blocks.
The page stops being a black box: the engineer now gets a specific
actionable hint for each of the five known empty-state root causes
documented in internal/signal/live_store.go and redis_cache.go.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/38-api-logs-service-filter: derive Service dropdown from stats.by_service; trim dead options; add live-writer SERVICE_CONFIG entries
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* phase-45/99-gate: phase-45 acceptance contract green
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix command scoring; enhance service filters & UI
Stop rescoring each keyword as if it were the label in CommandPalette: score the label once with keywords passed in to preserve label-vs-keyword ranking and avoid keyword ties. Add regression tests to CommandPalette and commandRegistry to lock in the behavior.
Revamp service dropdown generation: deriveServiceOptions now accepts an optional knownServices catalog and returns the union of knownServices, by_service keys, and the active service; results are deduplicated and sorted alphabetically (case-insensitive). Add extensive tests to cover union, dedupe, and ordering behaviors.
Update ApiLogsPage to use a URL-batch writer (useUrlBatch) so multiple search params (filters + page reset) are written atomically; wire selects/inputs to a setFilter helper and add selectService helper. Introduce KNOWN_SERVICES (from SERVICE_CONFIG) and pass it to deriveServiceOptions; show tracked vs known counts and add several geocoder services to SERVICE_CONFIG.
Polish RedisSignalViewerPage value rendering with per-type color classes for better readability. Update i18n string for service count to include tracked and known counts.
Tests updated/added accordingly to cover these fixes and prevent regressions.
* fix(api): populate Drive Detail telemetry — odometer, range, power
Drive Detail page (/drives/{id}) was rendering blank Odometer From->To,
blank Range Start->End, blank Range Used, and a flat Power Profile chart
even on drives with valid signal_log telemetry. Two root causes:
1. driveTelemetryFieldMappings was missing the canonical Tesla signals
that the frontend chartData mapper reads: Odometer, IdealBatteryRange,
RatedRange, EstBatteryRange, Soc, HvacFanStatus, HvacLeftTempRequest,
HvacRightTempRequest. The frontend's tp.odometer / tp.idealRange /
tp.ratedRange were always undefined.
2. Tesla Fleet Telemetry does not emit a per-row PackPower signal, so the
chart's dataKey='power' had nothing to render. derivePowerKw() now
computes power = pack_voltage * pack_current / 1000.0 per row (sign
preserved so regen stays negative on the chart). Same formula already
used by enrichLiveDrive() for live drive AvgPowerKw and signalPowerKW()
in telemetry_sessions_signal_helpers.go.
Frontend follow-ups:
- EnergySummaryPanel: replace hardcoded '--' for Range Used with
fmtWithUnit(stats.startRange - stats.endRange, distanceUnit).
- useDriveDetailData: powerMax / powerMin now come from chartData (the
legacy approximation hard-coded powerMax = avgPowerKw and powerMin = 0,
which gave nonsense MaxRegen badges).
Tests:
- TestDriveDetail_Telemetry_DerivesPowerKw: V*I/1000 with sign preservation,
rows missing pack_current have no derived power.
- TestDriveDetail_Telemetry_FieldMappingsCoverPageFields: regression guard
for the 21 fields the frontend reads from each telemetry row.
All 1592 vitest tests + drive detail Go tests pass; tsc clean; audit clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(web): repair shadowed-parent t() calls + add audit gate
My Activity page rendered 'key activity.myActivity.disabled (en) returned an
object instead of string' as the empty-state body. Same class of bug
in 3 other call sites:
- activity.myActivity.disabled / .unauthorized (MyActivityPage)
- admin.security.timeline (EventTimeline heading)
- widget.chargeHistory (ChargeHistoryWidget title)
- search.noResults / .placeholder / .label (SettingsSearch — also wrong
namespace; CommandPalette owns the search.* tree, settings.search.*
is the right namespace)
Each call resolved its dotted key to an OBJECT (parent of .title /
siblings) in en.json. i18next returns the object verbatim and ignores
the fallback string, so users saw the raw error text in the UI.
Fix:
- Add .description / .title siblings under disabled, unauthorized,
admin.security.timeline, widget.chargeHistory
- Repoint SettingsSearch to settings.search.* (correct namespace)
- New scripts/audit-i18n-shadowed-keys.mjs walks every t('a.b.c') call,
resolves against en.json, fails on any leaf-pointing-to-object.
Wired into npm run lint so this can't regress.
tsc clean; vitest 1592/1592 pass; audit:i18n-shadowed exits 0; audit_code
clean on all 4 touched components.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(api): persist time_format_default + chart_palette in settings
The Settings struct was missing TimeFormatDefault (Phase-45/22) and
ChartPalette (Phase-45/23) fields. When the Appearance settings page
PUT them, json.NewDecoder silently dropped the unknown JSON keys, the
Upsert never wrote the rows, and the next GET returned the old value -
so the radio cards appeared inert when clicked.
Wires both fields through the four canonical settings layers:
- models.Settings struct (with phase-tagged doc comments)
- settingsDefaults() (relative + cb_safe)
- applySettingsRow() switch cases
- Upsert() textRows
- Update() handler validation (rejects values outside the typed enum)
No migration needed: the settings key/value table is forward-
compatible and will create the rows on first Upsert.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(api): /signals/observations latest-first + unbounded since
The driving-dynamics cold-signal panels (G-Force, Pedal Usage, Autopilot &
Cruise) and the SignalLogWidget event feed surfaced empty / stale values
because /signals/observations had two coordinated bugs:
1. The repo ordered ASC by ts. The frontend latestNumeric() helper reads
data[0] expecting the most recent observation, so callers asking with
limit:1 got the OLDEST row in the window, and SignalLogWidget showed
the oldest 20 events of the day instead of the most recent 20.
2. The handler defaulted since to now-24h. Cold signals (Lateral/Long
Acceleration, PedalPosition, BrakePedalPos, BrakePedal, CruiseSetSpeed,
CruiseFollowDistance) only emit while driving, so the panels went empty
when the car had been parked > 24h despite the data being on disk.
Fix:
- Repo: ListByName + ListByVehicle now ORDER BY ts DESC and accept zero
time.Time{} bounds to mean 'unbounded' on that side. Extracted the SQL
composition into buildObservationQuery (covered by 5 new unit tests).
The (vehicle_id, signal_name, ts DESC) index serves the bounded LIMIT
case in index-only fashion.
- Handler: omit the lower/upper bound from the predicate when since/until
query params are absent. Reject non-RFC3339 since/until with 400 instead
of silently widening to 'all history' (subtle behavior regression flagged
by rubber-duck review).
Affected callers (all want latest-first): GForcePanel, PedalUsage,
AutopilotSection, SignalLogWidget, PowersharePage. SignalCatalogWidget's
per-signal counts now reflect 'recently active signals' (newest 100 of
all-time) instead of 'oldest 100 of last 24h' — strictly more useful for
the widget's UX.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
atulmgupta
added a commit
that referenced
this pull request
May 28, 2026
Extends web/eslint.config.js with bounded-context element descriptors covering all 7 frontend hot-spots (per ADR-011 §3): - src/features/dashboard/widgets/*/** (capture: domain) - src/lib/*/** (capture: purpose) - src/api/hooks/*/** (capture: domain) - src/hooks/*/** (capture: purpose) - src/components/ai/*/** (capture: feature) - src/components/feedback/*/** (capture: kind) - src/components/data-display/*/** (capture: kind) Patterns rooted at 'src/...' NOT 'web/src/...' per rubber-duck #13 (ESLint cwd is web/, so web/src/... would classify nothing and mask R0.5 / R8-R12 progress signals). Capture groups expose the bounded- context name so R13 can express rules like 'feature widget can only import from its own domain entities + shared'. REPORT-MODE TODAY: rules stay at default: 'allow' so the descriptors are CLASSIFICATORY only - they show the intended shape in lint output without ever failing the gate. R13 flips default to 'disallow' with explicit FSD allow lists + boundaries/no-private at error for components/* categories only (lib/ and hooks/ keep direct subpath imports per rubber-duck #14 to preserve tree-shaking). Ordering: most-specific planned-subpkg patterns FIRST so files already in a subdir win over the catch-all flat-layer patterns (pages/features/components/hooks/lib/api). Files still at the flat parent (today's reality) fall through to the existing layer type. Verified: npm run lint -> exit 0; full 24-audit chain still green. Refs: docs/architecture/repo-reorganization-plan.md §16.7.1 (R0 deliverables), rubber-duck #13 (pattern rooting), #14 (barrel-only scope). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
atulmgupta
added a commit
that referenced
this pull request
May 28, 2026
Audits all 7 frontend hot-spots and assigns every file to a concrete
target subdir per ADR-011 §1-§7. Pure docs update — no code moved.
Frontend totals from R7 audit:
- web/src/lib (104 files) → 13 subdirs
- web/src/hooks ( 64 files) → 10 subdirs
- web/src/api/hooks ( 67 files) → 23 subdirs + 2 parent
(mirrors backend R4
database subpkgs 1:1)
- web/src/features/dashboard/widgets
(121 files) → 13 subdirs + 4 parent
(registry/types/shell/
barrel kept at parent)
- web/src/components/ai ( 61 files) → 12 subdirs + 8 parent
(shared AI primitives +
withAiFeature HOC stay)
Mirrors internal/ai/tools/*
topic partition 1:1
- web/src/components/feedback ( 62 files) → 10 subdirs + 1 parent
- web/src/components/data-display
( 46 files) → 7 subdirs + 1 parent
Key R7 decisions documented in cluster-map.md:
- lib/ + hooks/ use direct subpath imports (NO barrel) for
tree-shaking (rubber-duck #14)
- components/ai|feedback|data-display use STRICT barrels
(per ADR-015 amendment §G3 — AI components only callable via
@/components/ai, never deep imports)
- api/hooks/ subdir names sync 1:1 with internal/database/* from R4
(R8 CI check: every api/hooks/<x> must be a database subpkg OR
listed in tools/archmetrics/web_orphans.json — admin, chatbot,
commands, optim, watch allowed exceptions)
- ai components keep "AI" prefix verbatim per ADR-015 amendment §G3
(visual marker for guarded components)
- R12 acceptance gate: grep -rL "withAiFeature" components/ai/*/
MUST return 0 matches
- Duplicate spotted for R12 cleanup: BulkActionsToolbar vs
BulkActionToolbar (singular/plural)
- Cross-subdir ambiguities flagged for R11 audit:
· globalShortcuts.tsx → lib/ui (JSX provider) vs
@/components/keyboard/ (target)
· signals.ts + signalCatalog.ts → lib/automation vs lib/data
· cookieConsent.ts → lib/storage vs lib/ui
Source-of-truth coupling:
- Frontend Phase R progress is tracked via eslint-plugin-boundaries
in web/eslint.config.js (report mode in R0–R12, enforced in R13).
archmetrics is Go-only and does not need frontend entries.
All gates green: npm run lint (audit:inline-help OK,
audit:touch-target OK with 925 scanned/704 clickable/0 failures).
Refs: ADR-011, ADR-015 amendment, plan v4 §16.5 R7.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps actions/upload-artifact from 4 to 7.
Release notes
Sourced from actions/upload-artifact's releases.
... (truncated)
Commits
bbbca2dSupport direct file uploads (#764)589182cUpgrade the module to ESM and bump dependencies (#762)47309c9Merge pull request #754 from actions/Link-/add-proxy-integration-tests02a8460Add proxy integration testb7c566aMerge pull request #745 from actions/upload-artifact-v6-releasee516bc8docs: correct description of Node.js 24 support in READMEddc45eddocs: update README to correct action name for Node.js 24 support615b319chore: release v6.0.0 for Node.js 24 support017748bMerge pull request #744 from actions/fix-storage-blob38d4c79chore: rebuild dist