diff --git a/starpilot/system/the_galaxy/assets/components/router.js b/starpilot/system/the_galaxy/assets/components/router.js index f01314895..835a49b0c 100644 --- a/starpilot/system/the_galaxy/assets/components/router.js +++ b/starpilot/system/the_galaxy/assets/components/router.js @@ -14,6 +14,7 @@ import { RouteRecordings } from "/assets/components/recordings/dashcam_routes.js import { SettingsView } from "/assets/components/settings.js" import { ScreenRecordings } from "/assets/components/recordings/screen_recordings.js" import { Sidebar } from "/assets/components/sidebar.js?v=lateral-tuning-1" +import { SentryMode } from "/assets/components/tools/sentry.js" import { SpeedLimits } from "/assets/components/tools/speed_limits.js" import { ModelManager } from "/assets/components/tools/model_manager.js?v=20260303t" import { LivePlots } from "/assets/components/tools/plots.js" @@ -55,6 +56,7 @@ function SafeHome() {
Safe mode is active while UI rendering is being repaired.
Galaxy Pairing | + Sentry Mode | Toggles | Software
@@ -72,6 +74,7 @@ function Root() { createRoute("root", "/", Home), createRoute("routes", "/dashcam_routes", RouteRecordings), createRoute("screen_recordings", "/screen_recordings", ScreenRecordings), + createRoute("sentry", "/sentry", SentryMode), createRoute("settings", "/settings/:section/:subsection?", SettingsView), createRoute("speed_limits", "/download_speed_limits", SpeedLimits), createRoute("model_manager", "/manage_models", ModelManager), diff --git a/starpilot/system/the_galaxy/assets/components/sidebar.js b/starpilot/system/the_galaxy/assets/components/sidebar.js index 12e6f948f..f2228d2b4 100644 --- a/starpilot/system/the_galaxy/assets/components/sidebar.js +++ b/starpilot/system/the_galaxy/assets/components/sidebar.js @@ -14,6 +14,7 @@ const MENU_ITEMS = { { name: "Download Speed Limits", link: "/download_speed_limits", icon: "bi-download" }, { name: "Error Logs", link: "/manage_error_logs", icon: "bi-exclamation-triangle" }, { name: "Galaxy", link: "/galaxy", icon: "bi-globe2" }, + { name: "Sentry Mode", link: "/sentry", icon: "bi-shield-exclamation" }, { name: "Lateral Tuning", link: "/tuning", icon: "bi-sign-turn-right" }, { name: "Long Maneuvers", link: "/longitudinal_maneuvers", icon: "bi-signpost-split" }, { name: "Maps", link: "/manage_maps", icon: "bi-map" }, diff --git a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json index 561ee7fc0..60385ae77 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json +++ b/starpilot/system/the_galaxy/assets/components/tools/device_settings_layout.json @@ -13,40 +13,6 @@ } ] }, - { - "name": "Sentry Mode", - "icon": "bi-shield-exclamation", - "params": [ - { - "key": "SentryModeEnabled", - "label": "Sentry Mode", - "description": "Detect movement while parked and send alerts through Galaxy.", - "data_type": "bool", - "ui_type": "toggle", - "settings_tier": "simple" - }, - { - "key": "SentryModeWebhook", - "label": "Sentry Webhook", - "description": "Optional webhook that Galaxy will POST to when sentry mode detects movement. Discord webhooks are supported.", - "data_type": "string", - "ui_type": "text", - "input_type": "url", - "placeholder": "https://…", - "settings_tier": "simple" - }, - { - "key": "SentryModeNtfyUrl", - "label": "Sentry ntfy URL", - "description": "Optional ntfy topic URL, for example https://ntfy.sh/my-starpilot-topic.", - "data_type": "string", - "ui_type": "text", - "input_type": "url", - "placeholder": "https://ntfy.sh/…", - "settings_tier": "simple" - } - ] - }, { "name": "Lateral (Steering)", "icon": "bi-arrows-move", diff --git a/starpilot/system/the_galaxy/assets/components/tools/galaxy.css b/starpilot/system/the_galaxy/assets/components/tools/galaxy.css index a468f5ba5..2363d7d2c 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/galaxy.css +++ b/starpilot/system/the_galaxy/assets/components/tools/galaxy.css @@ -129,80 +129,6 @@ background-color: rgba(224, 85, 119, 0.35); } -/* ――― Sentry event viewer ――― */ -.sentry-event-widget { - background-color: var(--secondary-bg); - border-radius: var(--border-radius-lg); - box-shadow: var(--shadow-sm); - display: flex; - flex-direction: column; - gap: var(--gap-sm); - margin-top: var(--margin-lg); - max-width: var(--width-xxxl); - padding: var(--padding-lg); -} - -.sentry-event-heading { - align-items: flex-start; - display: flex; - gap: var(--gap-base); - justify-content: space-between; -} - -.sentry-event-heading h3 { - padding-top: 0; -} - -.sentry-event-state, -.sentry-event-kind { - background-color: var(--input-bg); - border-radius: 999px; - color: var(--main-fg); - font-size: var(--font-size-xs); - font-weight: var(--font-weight-bold); - padding: 0.25rem 0.55rem; - white-space: nowrap; -} - -.sentry-event-meta { - align-items: center; - color: var(--text-muted); - display: flex; - flex-wrap: wrap; - font-size: var(--font-size-xs); - gap: var(--gap-sm); -} - -.sentry-event-message { - color: var(--text-color); - margin: 0; -} - -.sentry-image-grid { - display: grid; - gap: var(--gap-sm); - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); -} - -.sentry-image-grid a { - display: block; -} - -.sentry-image-grid img { - border: var(--border-style-main); - border-radius: var(--border-radius-base); - display: block; - height: auto; - max-width: 100%; - width: 100%; -} - -.sentry-empty { - color: var(--text-muted); - font-style: italic; - margin: 0; -} - /* ――― Mobile ――― */ @media only screen and (max-width: 768px) and (orientation: portrait) { .galaxy-wrapper { diff --git a/starpilot/system/the_galaxy/assets/components/tools/galaxy.js b/starpilot/system/the_galaxy/assets/components/tools/galaxy.js index dc2b4ecfa..e6c53c84b 100644 --- a/starpilot/system/the_galaxy/assets/components/tools/galaxy.js +++ b/starpilot/system/the_galaxy/assets/components/tools/galaxy.js @@ -1,7 +1,6 @@ import { html, reactive } from "/assets/vendor/arrow-core.js" import { isGalaxyTunnel } from "/assets/js/utils.js" import { Modal } from "/assets/components/modal.js" -import { requestSentryNotificationPermission } from "/assets/components/sentry_notifications.js" const state = reactive({ paired: false, @@ -11,14 +10,8 @@ const state = reactive({ submitting: false, showUnpairModal: false, fetched: false, - sentryLoading: true, - sentryStatus: {}, - sentryEvent: {}, - sentryTestBusy: false, }) -let sentryPollTimer = null - async function fetchStatus() { state.loading = true try { @@ -32,91 +25,6 @@ async function fetchStatus() { state.loading = false } -async function fetchSentryStatus() { - try { - const res = await fetch("/api/sentry/status", { cache: "no-store" }) - if (!res.ok) return - const data = await res.json() - state.sentryStatus = data.status || {} - state.sentryEvent = data.lastEvent || {} - } catch (e) { - console.error("Failed to fetch Sentry status:", e) - } finally { - state.sentryLoading = false - } -} - -function ensureSentryPolling() { - if (sentryPollTimer !== null) return - fetchSentryStatus() - sentryPollTimer = window.setInterval(fetchSentryStatus, 5000) -} - -async function sendSentryTest() { - if (state.sentryTestBusy) return - state.sentryTestBusy = true - try { - const res = await fetch("/api/sentry/test", { method: "POST" }) - const data = await res.json() - if (!res.ok) { - showSnackbar(data.error || "Sentry test failed.") - return - } - showSnackbar("Sentry test started. Galaxy will show the captured images when ready.") - } catch (e) { - showSnackbar("Network error — is the device reachable?") - } finally { - state.sentryTestBusy = false - } -} - -function SentryEventPanel(showTestButton = true) { - return html` - - ` -} - async function pair() { if (state.submitting) return const pw = state.password.trim() @@ -170,17 +78,12 @@ async function unpair() { } export function GalaxyPairing() { - ensureSentryPolling() - if (isGalaxyTunnel()) { return html` -Galaxy pairing requires a direct connection.
Connect to your device's local network to use this feature.
Galaxy pairing requires a direct connection.
Connect to your device's local network to use this feature.
No Sentry events recorded yet.
` + + return html` + + + ${Array.isArray(event.imageUrls) && event.imageUrls.length > 0 ? html` +No camera images were available for this event.
`} + ` +} + +export function SentryMode() { + startPolling() + const remote = isGalaxyTunnel() + + return html` +Monitor the parked vehicle and review movement captures directly in Galaxy.
+Galaxy is the built-in notification and image viewer. Webhook and ntfy delivery are optional.
+ + ${() => state.loading ? html`Events refresh automatically every five seconds.
+