fix(replay): recover failed archives and release deleted sessions
This commit is contained in:
@@ -199,6 +199,7 @@ export default function App() {
|
||||
const livePerceptionLayersRef = useRef<LivePerceptionLayers>(defaultLivePerceptionLayers);
|
||||
const livePerceptionRevisionRef = useRef(0);
|
||||
const replayActiveRef = useRef(false);
|
||||
const selectedRecordedSessionIdRef = useRef<string | null>(null);
|
||||
const sceneSettingsCommitterActiveRef = useRef(true);
|
||||
const sceneSettingsCommitterRef = useRef<LatestAsyncCommitter<SceneSettings> | null>(null);
|
||||
const polygonDatasetRouteOpenedRef = useRef(false);
|
||||
@@ -536,6 +537,7 @@ export default function App() {
|
||||
// produced a validated launch descriptor. Keep the old scene mounted
|
||||
// before this point; now perform one controlled receiver teardown before
|
||||
// accepting the already-ready archive.
|
||||
selectedRecordedSessionIdRef.current = null;
|
||||
setReplayTransitioning(true);
|
||||
setRecordedReplay(null);
|
||||
setRecordedReplayLabel(null);
|
||||
@@ -553,6 +555,7 @@ export default function App() {
|
||||
if (sourceSwitchBlockedRef.current) {
|
||||
throw new Error(SPATIAL_SOURCE_SWITCH_BLOCKED_REASON);
|
||||
}
|
||||
selectedRecordedSessionIdRef.current = session.id;
|
||||
setRecordedReplay(launch);
|
||||
setRecordedReplayLabel(session.label);
|
||||
setSourceUrl(launch.sourceUrl);
|
||||
@@ -564,11 +567,28 @@ export default function App() {
|
||||
if (outcome !== "accepted") setReplayTransitioning(false);
|
||||
}, []);
|
||||
|
||||
const releaseRecordedReplayForDelete = useCallback(async (sessionId: string) => {
|
||||
if (selectedRecordedSessionIdRef.current !== sessionId) return;
|
||||
// Deleting the selected archive is a source transition. Unmount Rerun and
|
||||
// recorded media first so no admission request can outlive the evidence.
|
||||
selectedRecordedSessionIdRef.current = null;
|
||||
setReplayTransitioning(true);
|
||||
setRecordedReplay(null);
|
||||
setRecordedReplayLabel(null);
|
||||
setSourceUrl("");
|
||||
setSourceDraft("");
|
||||
await new Promise<void>((resolve) => {
|
||||
window.requestAnimationFrame(() => window.setTimeout(resolve, 0));
|
||||
});
|
||||
if (selectedRecordedSessionIdRef.current === null) setReplayTransitioning(false);
|
||||
}, []);
|
||||
|
||||
const activateAutomaticSpatialSource = useCallback(() => {
|
||||
// A plugin-owned live/file-replay start must release any host-selected
|
||||
// archive or manual URL before the new acquisition becomes non-terminal.
|
||||
// This transition is an internal start boundary, not an operator source
|
||||
// switch, so it intentionally does not consult the acquisition guard.
|
||||
selectedRecordedSessionIdRef.current = null;
|
||||
setReplayTransitioning(false);
|
||||
setRecordedReplay(null);
|
||||
setRecordedReplayLabel(null);
|
||||
@@ -786,6 +806,7 @@ export default function App() {
|
||||
onReplayAccepted={acceptRecordedReplay}
|
||||
onReplaySettled={(_session, outcome) =>
|
||||
settleRecordedReplaySwitch(outcome)}
|
||||
onDeleteBegin={releaseRecordedReplayForDelete}
|
||||
/>
|
||||
) : activeDefinition.kind === "datasets" ? (
|
||||
<StatusBadge tone="neutral">Offline evaluation</StatusBadge>
|
||||
@@ -838,6 +859,7 @@ export default function App() {
|
||||
onReplayAccepted: acceptRecordedReplay,
|
||||
onReplaySettled: (_session, outcome) =>
|
||||
settleRecordedReplaySwitch(outcome),
|
||||
onDeleteBegin: releaseRecordedReplayForDelete,
|
||||
}}
|
||||
navigation={{
|
||||
openView,
|
||||
@@ -886,6 +908,7 @@ export default function App() {
|
||||
title={sourceSwitchBlockedReason ?? undefined}
|
||||
onClick={() => {
|
||||
if (sourceSwitchBlockedRef.current) return;
|
||||
selectedRecordedSessionIdRef.current = null;
|
||||
setSourceDraft("");
|
||||
setSourceUrl("");
|
||||
setRecordedReplay(null);
|
||||
@@ -901,6 +924,7 @@ export default function App() {
|
||||
title={sourceSwitchBlockedReason ?? undefined}
|
||||
onClick={() => {
|
||||
if (sourceSwitchBlockedRef.current) return;
|
||||
selectedRecordedSessionIdRef.current = null;
|
||||
setSourceUrl(sourceDraft.trim());
|
||||
setRecordedReplay(null);
|
||||
setRecordedReplayLabel(null);
|
||||
|
||||
Reference in New Issue
Block a user