summaryrefslogtreecommitdiff
path: root/src/SomhairlesDream.Frontend
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 10:14:24 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 10:14:24 +0800
commit958e24b0fd08e4bc92656964e832606dbf7d3fa3 (patch)
tree01606b1c010fecc4d3379cbc796c100c32363bac /src/SomhairlesDream.Frontend
parent07d6690b9b9de7db7debe25e8e3def5c0d68bb26 (diff)
downloadsomhairles-dream-fsharp-958e24b0fd08e4bc92656964e832606dbf7d3fa3.tar.gz
feat(boot): surface pre-published probe replay on landing page
- boot loads the completed run from /api/artifacts/manifest and renders its latest checkpoint with concrete build-review labels (no fake unknown-state wording); offline fallback still shows the honest placeholder - artifact manifest/steps endpoints now fall back to disk when a completed run has no in-memory registry entry, keeping pre-published history browsable after a service restart (digest-verified, .glb-only / steps/ / logs/ rejected) - driver: heritage flows pin heritage ids explicitly; new checks for the boot probe replay and its labels; 72/72 green with zero console errors
Diffstat (limited to 'src/SomhairlesDream.Frontend')
-rw-r--r--src/SomhairlesDream.Frontend/App.fs64
1 files changed, 64 insertions, 0 deletions
diff --git a/src/SomhairlesDream.Frontend/App.fs b/src/SomhairlesDream.Frontend/App.fs
index b2bb8e6..f9184c5 100644
--- a/src/SomhairlesDream.Frontend/App.fs
+++ b/src/SomhairlesDream.Frontend/App.fs
@@ -23,6 +23,18 @@ type SnapshotPayload =
abstract error: string with get
abstract isStale: bool with get
+[<Erase>]
+type ManifestStep =
+ abstract stepIndex: int with get
+ abstract artifactPath: string with get
+
+[<Erase>]
+type ManifestPayload =
+ abstract projectId: string with get
+ abstract runId: string with get
+ abstract status: string with get
+ abstract steps: ManifestStep array with get
+
type RunSelection =
{ ProjectId: string
RunId: string
@@ -687,6 +699,56 @@ let startRun (selection: RunSelection) =
}
|> Async.StartImmediate
+/// Boot-time historical load: surface the pre-published probe build replay so
+/// first-time visitors see the real vehicle instead of an empty placeholder.
+/// Any failure leaves the honest placeholder idle state untouched.
+let loadBootHistory () =
+ let selection = selectedRun ()
+ let projectId = JS.encodeURIComponent selection.ProjectId
+ let runId = JS.encodeURIComponent selection.RunId
+ let url = sprintf "/api/artifacts/manifest?projectId=%s&runId=%s" projectId runId
+ let requestOptions = createObj [ "method" ==> "GET" ]
+
+ async {
+ try
+ let! response = fetch (url, requestOptions) |> Async.AwaitPromise
+
+ if response.ok then
+ let! value = response.json () |> Async.AwaitPromise
+ let payload = value :?> ManifestPayload
+
+ if payload.status = "complete" && Array.length payload.steps > 0 then
+ let steps =
+ payload.steps
+ |> Array.sortBy (fun step -> step.stepIndex)
+ |> Array.map (fun step -> step.artifactPath)
+
+ if Array.length steps > 0 then
+ currentProjectId <- selection.ProjectId
+ currentRunId <- selection.RunId
+ historicalSteps <- steps
+ setText "project-id" selection.ProjectId
+ setText "run-id" selection.RunId
+ setText "target-version" (sprintf "V%02d" steps.Length)
+ setText "current-version" (sprintf "V%02d" steps.Length)
+ setText "version-readout" (sprintf "%02d / %02d" steps.Length steps.Length)
+ setWidth "progress-fill" "100%"
+ setText "updated-at" "预发布历史"
+ setText "mesh-label" (sprintf "历史 · %s" steps[steps.Length - 1])
+ setText "timeline-current" (sprintf "V%02d · 构建重演 · %s" steps.Length steps[steps.Length - 1])
+ setText "replay-button" "播放历史"
+ setText "replay-state" "构建重演 · 预发布历史"
+ renderTimeline ()
+ updateFollowButton ()
+
+ match viewState with
+ | Some view -> loadStepArtifact view steps[steps.Length - 1] true
+ | None -> ()
+ with _ ->
+ ()
+ }
+ |> Async.StartImmediate
+
let boot () =
showFrameMetadata frames[0]
@@ -702,6 +764,8 @@ let boot () =
event.preventDefault()
startRun (selectedRun ()))
+ loadBootHistory ()
+
renderTimeline ()
boot ()