diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 10:14:24 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 10:14:24 +0800 |
| commit | 958e24b0fd08e4bc92656964e832606dbf7d3fa3 (patch) | |
| tree | 01606b1c010fecc4d3379cbc796c100c32363bac /public | |
| parent | 07d6690b9b9de7db7debe25e8e3def5c0d68bb26 (diff) | |
| download | somhairles-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 'public')
| -rw-r--r-- | public/App.js | 65 | ||||
| -rw-r--r-- | public/index.html | 18 |
2 files changed, 72 insertions, 11 deletions
diff --git a/public/App.js b/public/App.js index ab4ae59..a401102 100644 --- a/public/App.js +++ b/public/App.js @@ -1,8 +1,8 @@ import { Union, Record } from "./fable_modules/fable-library-js.4.24.0/Types.js"; import { union_type, class_type, record_type, bool_type, string_type } from "./fable_modules/fable-library-js.4.24.0/Reflection.js"; import { Replay_frames } from "./SomhairlesDream.Shared/Replay.js"; -import { defaultOf, equals, createAtom } from "./fable_modules/fable-library-js.4.24.0/Util.js"; -import { equalsWith, tryFind, iterateIndexed, item } from "./fable_modules/fable-library-js.4.24.0/Array.js"; +import { comparePrimitives, defaultOf, equals, createAtom } from "./fable_modules/fable-library-js.4.24.0/Util.js"; +import { sortBy, map, equalsWith, tryFind, iterateIndexed, item } from "./fable_modules/fable-library-js.4.24.0/Array.js"; import { join, isNullOrWhiteSpace, printf, toText } from "./fable_modules/fable-library-js.4.24.0/String.js"; import { MeshData_triangleIndices, MeshData_positionData } from "./SomhairlesDream.Shared/Domain.js"; import { min, max } from "./fable_modules/fable-library-js.4.24.0/Double.js"; @@ -881,6 +881,66 @@ export function startRun(selection) { }))); } +/** + * 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. + */ +export function loadBootHistory() { + const selection = selectedRun(); + const projectId = encodeURIComponent(selection.ProjectId); + const runId = encodeURIComponent(selection.RunId); + const url = toText(printf("/api/artifacts/manifest?projectId=%s&runId=%s"))(projectId)(runId); + const requestOptions = { + method: "GET", + }; + startImmediate(singleton.Delay(() => singleton.TryWith(singleton.Delay(() => singleton.Bind(awaitPromise(fetch(url, requestOptions)), (_arg) => { + const response = _arg; + return response.ok ? singleton.Bind(awaitPromise(response.json()), (_arg_1) => { + let arg_2, arg_3, arg_4, arg_5, arg_6, arg_7, arg_8; + const payload = _arg_1; + if ((payload.status === "complete") && (payload.steps.length > 0)) { + const steps = map((step_1) => step_1.artifactPath, sortBy((step) => step.stepIndex, payload.steps, { + Compare: comparePrimitives, + })); + if (steps.length > 0) { + currentProjectId(selection.ProjectId); + currentRunId(selection.RunId); + historicalSteps(steps); + setText("project-id", selection.ProjectId); + setText("run-id", selection.RunId); + setText("target-version", (arg_2 = (steps.length | 0), toText(printf("V%02d"))(arg_2))); + setText("current-version", (arg_3 = (steps.length | 0), toText(printf("V%02d"))(arg_3))); + setText("version-readout", (arg_4 = (steps.length | 0), (arg_5 = (steps.length | 0), toText(printf("%02d / %02d"))(arg_4)(arg_5)))); + setWidth("progress-fill", "100%"); + setText("updated-at", "预发布历史"); + setText("mesh-label", (arg_6 = item(steps.length - 1, steps), toText(printf("历史 · %s"))(arg_6))); + setText("timeline-current", (arg_7 = (steps.length | 0), (arg_8 = item(steps.length - 1, steps), toText(printf("V%02d · 构建重演 · %s"))(arg_7)(arg_8)))); + setText("replay-button", "播放历史"); + setText("replay-state", "构建重演 · 预发布历史"); + renderTimeline(); + updateFollowButton(); + if (viewState() == null) { + return singleton.Zero(); + } + else { + loadStepArtifact(viewState(), item(steps.length - 1, steps), true); + return singleton.Zero(); + } + } + else { + return singleton.Zero(); + } + } + else { + return singleton.Zero(); + } + }) : singleton.Zero(); + })), (_arg_2) => { + return singleton.Zero(); + }))); +} + export function boot() { showFrameMetadata(item(0, frames)); try { @@ -902,6 +962,7 @@ export function boot() { event.preventDefault(); startRun(selectedRun()); }); + loadBootHistory(); renderTimeline(); } diff --git a/public/index.html b/public/index.html index 71e9e62..d6966b1 100644 --- a/public/index.html +++ b/public/index.html @@ -32,11 +32,11 @@ <section class="mission-strip" aria-label="当前任务"> <div> <span class="eyebrow">PROJECT</span> - <strong id="project-id">heritage-001</strong> + <strong id="project-id">probe-001</strong> </div> <div> <span class="eyebrow">RUN</span> - <strong id="run-id">run-001</strong> + <strong id="run-id">run-probe-real-2</strong> </div> <div class="mission-note"> <span class="eyebrow">MODE</span> @@ -58,19 +58,19 @@ <div class="control-grid"> <label> <span>项目 ID</span> - <input id="project-id-input" value="heritage-001" autocomplete="off"> + <input id="project-id-input" value="probe-001" autocomplete="off"> </label> <label> <span>运行 ID</span> - <input id="run-id-input" value="run-001" autocomplete="off"> + <input id="run-id-input" value="run-probe-real-2" autocomplete="off"> </label> <label> <span>基准 ID</span> - <input id="base-id-input" value="base-000" autocomplete="off"> + <input id="base-id-input" value="probe-base-000" autocomplete="off"> </label> <label> <span>目标 ID</span> - <input id="target-id-input" value="target-003" autocomplete="off"> + <input id="target-id-input" value="probe-target-007" autocomplete="off"> </label> </div> <div class="control-actions"> @@ -85,7 +85,7 @@ <div class="version-block"> <div class="label-row"> <span>设计版本</span> - <strong id="version-readout">00 / 03</strong> + <strong id="version-readout">07 / 07</strong> </div> <div class="progress-track" aria-hidden="true"> <span id="progress-fill" class="progress-fill" style="width: 0%"></span> @@ -192,8 +192,8 @@ </section> <footer class="footer-note"> - <span>状态快照 · 原子发布 · 心跳监视</span> - <span>OPEN CODE / F# FIRST</span> + <span>首页构建重演:预发布历史透视探针(非飞行设计 · 盘式天线 / RTG / 科学吊臂 简化几何)</span> + <span>heritage 参考线保留占位演示 · F# / OPEN CODE</span> </footer> </main> <script type="module" src="/App.js"></script> |
