diff --git a/starpilot/system/the_pond/assets/components/tools/speed_limits.css b/starpilot/system/the_pond/assets/components/tools/speed_limits.css index 160c55e0..9497c100 100644 --- a/starpilot/system/the_pond/assets/components/tools/speed_limits.css +++ b/starpilot/system/the_pond/assets/components/tools/speed_limits.css @@ -13,7 +13,7 @@ } .download-speed-limits-button + .download-speed-limits-button { - margin-top: var(--padding-sm); + margin-top: 0; } .download-speed-limits-button:hover { @@ -22,25 +22,39 @@ transform: var(--hover-scale-sm); } .download-speed-limits-button-wrapper { - height: calc(100% + 20px); - position: relative; + align-items: stretch; + display: flex; + flex-direction: column; + gap: var(--padding-sm); width: 100%; } .download-speed-limits-link { color: var(--text-color); font-size: var(--font-size-sm); - left: 50%; - margin-top: var(--border-radius-sm); - position: absolute; + text-align: center; text-decoration: underline; - top: 100%; - transform: translateX(-50%); white-space: nowrap; } +.download-speed-limits-note { + color: var(--secondary-fg); + font-size: var(--font-size-sm); + margin: 0; + text-align: center; +} + +.download-speed-limits-status { + color: var(--text-color); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-demi-bold); + margin: 0; + text-align: center; +} + .download-speed-limits-text { color: var(--text-color); + margin-bottom: 0; text-align: center; } diff --git a/starpilot/system/the_pond/assets/components/tools/speed_limits.js b/starpilot/system/the_pond/assets/components/tools/speed_limits.js index 31272d1e..490a41f4 100644 --- a/starpilot/system/the_pond/assets/components/tools/speed_limits.js +++ b/starpilot/system/the_pond/assets/components/tools/speed_limits.js @@ -1,4 +1,58 @@ -import { html } from "/assets/vendor/arrow-core.js" +import { html, reactive } from "/assets/vendor/arrow-core.js" + +const state = reactive({ + canProcessNow: false, + fetched: false, + loading: true, + processing: false, + reason: "", + status: "Checking...", + submitting: false, +}) + +let pollTimer = null + +async function fetchStatus() { + try { + const response = await fetch("/api/speed_limits/status") + const result = await response.json() + + state.canProcessNow = Boolean(result.canProcessNow) + state.processing = Boolean(result.processing) + state.reason = result.reason || "" + state.status = result.status || "Idle" + } catch (error) { + state.canProcessNow = false + state.processing = false + state.reason = "Failed to load processor status." + state.status = "Unavailable" + } + + state.loading = false +} + +async function handleProcessNow() { + if (state.submitting || state.processing || !state.canProcessNow) { + return + } + + state.submitting = true + try { + const response = await fetch("/api/speed_limits/process", { method: "POST" }) + const result = await response.json() + + if (response.ok) { + showSnackbar(result.message || "Speed limit processing started.") + } else { + showSnackbar(result.error || "Failed to start speed limit processing.", "error") + } + } catch (error) { + showSnackbar("Failed to start speed limit processing.", "error") + } + + state.submitting = false + fetchStatus() +} export function SpeedLimits() { function handleDownload() { @@ -10,16 +64,38 @@ export function SpeedLimits() { showSnackbar("Download started...") } + if (!state.fetched) { + state.fetched = true + fetchStatus() + + if (pollTimer === null) { + pollTimer = setInterval(fetchStatus, 3000) + } + } + return html`