From 6c1ec6798f393bf245e3a06692b1c5fbb0038868 Mon Sep 17 00:00:00 2001
From: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Date: Thu, 27 Aug 2026 18:25:51 -0700
Subject: [PATCH] Better Messaging
---
.../components/recordings/dashcam_routes.js | 16 ++++++-----
.../recordings/dashcam_routes_helpers.js | 8 ++++++
.../tests/test_dashcam_routes_helpers.py | 27 +++++++++++++++++++
3 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes.js b/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes.js
index 4dad08354c..749697c7ea 100644
--- a/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes.js
+++ b/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes.js
@@ -12,6 +12,7 @@ import {
groupRoutesForView,
MAX_RENDERED_ROUTES,
normalizeRoute,
+ routeMetadataErrorMessage,
routeViewRenderKey,
} from "/assets/components/recordings/dashcam_routes_helpers.js"
@@ -738,8 +739,8 @@ async function openOverlay(route) {
try {
const response = await fetch(`/api/routes/${route.name}`)
- if (!response.ok) throw new Error(`Route metadata request failed (${response.status})`)
- const data = await response.json()
+ const data = await response.json().catch(() => ({}))
+ if (!response.ok) throw new Error(routeMetadataErrorMessage(response.status, data?.error))
segments = Array.isArray(data.segment_urls) ? data.segment_urls.filter(url => typeof url === "string") : []
const availableCameras = ["forward", "wide", "driver"].filter(camera => data.available_cameras?.includes(camera))
if (!segments.length) throw new Error("No video segments are stored for this route")
@@ -884,12 +885,15 @@ export function RouteRecordings() {
const view = buildRouteView(state.routes, { preservedOnly: state.showPreservedOnly, searchQuery: state.searchQuery, sortOrder: state.sortOrder })
const groups = groupRoutesForView(view.visible, state.sortOrder)
const renderKey = routeViewRenderKey(view.visible, state.sortOrder, state.viewMode)
+ const hasActiveSearch = Boolean(state.searchQuery.trim())
return html`
-
- ${view.matching.length} matching drive${view.matching.length === 1 ? "" : "s"}
- ${state.loading ? html`Loading ${state.progress} of ${state.total}` : html`${state.routes.length} total local`}
-
+ ${state.loading || hasActiveSearch ? html`
+
+ ${hasActiveSearch ? html`${view.matching.length} matching drive${view.matching.length === 1 ? "" : "s"}` : ""}
+ ${state.loading ? html`Loading routes` : ""}
+
+ ` : ""}
${state.error ? html`${state.error}
` : ""}
${state.isDeletingAll ? html`Deleting routes…
` : ""}
${!view.visible.length && state.loading ? html`` : ""}
diff --git a/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes_helpers.js b/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes_helpers.js
index 2cd9ecf48f..3ea1a613e5 100644
--- a/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes_helpers.js
+++ b/starpilot/system/the_galaxy/assets/components/recordings/dashcam_routes_helpers.js
@@ -264,6 +264,14 @@ export function cameraVideoUrl(segmentUrl, camera, quality) {
return quality ? `${url}&quality=${encodeURIComponent(quality)}` : url
}
+export function routeMetadataErrorMessage(status, serverError) {
+ if (status === 404) {
+ return "This route is no longer available on this device. Its local video segments may have been deleted or moved."
+ }
+ const detail = String(serverError || "").trim()
+ return detail || `Could not load route details (${status}).`
+}
+
// loggerd only writes qcamera.ts alongside the road camera.
export function supportsLowQuality(camera) {
return camera === "forward"
diff --git a/starpilot/system/the_galaxy/tests/test_dashcam_routes_helpers.py b/starpilot/system/the_galaxy/tests/test_dashcam_routes_helpers.py
index af26f45690..631463f6ec 100644
--- a/starpilot/system/the_galaxy/tests/test_dashcam_routes_helpers.py
+++ b/starpilot/system/the_galaxy/tests/test_dashcam_routes_helpers.py
@@ -200,6 +200,17 @@ def test_route_search_input_updates_on_every_keystroke():
assert '@input="${event => { state.searchQuery = event.target.value }}"' in source
+def test_route_summary_only_shows_loading_or_active_search_status():
+ source = COMPONENT_PATH.read_text(encoding="utf-8")
+
+ assert "const hasActiveSearch = Boolean(state.searchQuery.trim())" in source
+ assert '${state.loading || hasActiveSearch ? html`' in source
+ assert '${hasActiveSearch ? html`${view.matching.length} matching drive' in source
+ assert '${state.loading ? html`Loading routes` : ""}' in source
+ assert "Loading ${state.progress} of ${state.total}" not in source
+ assert "total local" not in source
+
+
def test_search_indexes_the_displayed_time_for_every_route():
result = evaluate('''
const routes = [
@@ -368,6 +379,22 @@ def test_camera_video_url_carries_an_optional_quality_tier():
assert result["low"] == "/video/0000006a--9f0a7bdf9c--7?camera=forward&quality=low"
+def test_route_metadata_errors_explain_missing_local_segments():
+ result = evaluate('''
+ return {
+ missing: routeMetadataErrorMessage(404, "Route not found"),
+ backend: routeMetadataErrorMessage(400, "Invalid route name"),
+ fallback: routeMetadataErrorMessage(503),
+ }
+ ''')
+
+ assert result == {
+ "missing": "This route is no longer available on this device. Its local video segments may have been deleted or moved.",
+ "backend": "Invalid route name",
+ "fallback": "Could not load route details (503).",
+ }
+
+
def test_only_the_road_camera_has_a_preview():
"""loggerd writes qcamera.ts alongside the road camera only."""
assert evaluate('return ["forward", "wide", "driver"].map(supportsLowQuality)') == [True, False, False]