summaryrefslogtreecommitdiff
path: root/src/SomhairlesDream.Frontend/App.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 06:05:15 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 06:05:15 +0800
commit13479cd194cd992c67805093e59f8b1dd1b5f3a2 (patch)
tree2918d1d408a65e694c49c081ce288566b8bcf5d5 /src/SomhairlesDream.Frontend/App.fs
parent822c092790bad4b1c0d780c1fafee063d70c91f6 (diff)
downloadsomhairles-dream-fsharp-13479cd194cd992c67805093e59f8b1dd1b5f3a2.tar.gz
feat(viewer): add user retry for failed step loads and regressions for same-run ordering and replay invalidation
Diffstat (limited to 'src/SomhairlesDream.Frontend/App.fs')
-rw-r--r--src/SomhairlesDream.Frontend/App.fs21
1 files changed, 21 insertions, 0 deletions
diff --git a/src/SomhairlesDream.Frontend/App.fs b/src/SomhairlesDream.Frontend/App.fs
index 6e07798..549b695 100644
--- a/src/SomhairlesDream.Frontend/App.fs
+++ b/src/SomhairlesDream.Frontend/App.fs
@@ -60,6 +60,7 @@ let mutable loadGeneration = 0
let mutable pendingLoad: (int * LoadOwner) option = None
let mutable loadedStep: LoadOwner option = None
let mutable viewMode = FrameMode
+let mutable failedLoad: LoadOwner option = None
let mutable displayedNode: ThreeNode option = None
let mutable freezeRotation = false
@@ -132,6 +133,7 @@ let clearGroup (group: ThreeNode) =
let invalidateLoads () =
loadGeneration <- loadGeneration + 1
pendingLoad <- None
+ failedLoad <- None
let renderFrame (frame: ReplayFrame) =
selectedFrame <- frame
@@ -242,6 +244,14 @@ let fallbackView () =
setText "viewport-note" "WebGL 视图待命 · 已保留重建数据"
(element "viewport-panel").classList.add("viewport-fallback")
+let setNoteRetryable (retryable: bool) =
+ let note = element "viewport-note"
+
+ if retryable then
+ note.classList.add("is-retryable")
+ else
+ note.classList.remove("is-retryable")
+
let showFrameMetadata (frame: ReplayFrame) =
setText "mesh-label" frame.Label
setText "timeline-current" (sprintf "V%02d · %s" frame.Version frame.Label)
@@ -262,6 +272,8 @@ let startStepLoad (view: ViewState) (owner: LoadOwner) =
loadGeneration <- generation
pendingLoad <- Some(generation, owner)
viewMode <- StepMode
+ failedLoad <- None
+ setNoteRetryable false
let loader = createGLTFLoader ()
let projectId = JS.encodeURIComponent owner.ProjectId
let runId = JS.encodeURIComponent owner.RunId
@@ -285,6 +297,8 @@ let startStepLoad (view: ViewState) (owner: LoadOwner) =
if pendingLoad = Some(generation, owner) then
pendingLoad <- None
loadedStep <- None
+ failedLoad <- Some owner
+ setNoteRetryable true
setText "viewport-note" (sprintf "管线几何加载失败 · %s" owner.Path))
let loadStepArtifact (view: ViewState) (stepPath: string) =
@@ -297,6 +311,12 @@ let loadStepArtifact (view: ViewState) (stepPath: string) =
| Some (_, pending) when pending = owner -> ()
| _ -> startStepLoad view owner
+let retryFailedLoad () =
+ match viewState, failedLoad with
+ | Some view, Some owner when owner.ProjectId = currentProjectId && owner.RunId = currentRunId ->
+ loadStepArtifact view owner.Path
+ | _ -> ()
+
let updateState (payload: SnapshotPayload) =
let status = statusName payload
setStatusClass status
@@ -474,6 +494,7 @@ let boot () =
fallbackView ()
(element "replay-button").addEventListener("click", fun _ -> toggleReplay ())
+ (element "viewport-note").addEventListener("click", fun _ -> retryFailedLoad ())
(element "run-controls").addEventListener("submit", fun event ->
event.preventDefault()
startRun (selectedRun ()))