feat(archive): complete recorded session lifecycle

This commit is contained in:
DCCONSTRUCTIONS
2026-07-19 01:07:21 +03:00
parent ffffee1879
commit 71c85e9894
22 changed files with 922 additions and 144 deletions
@@ -323,11 +323,19 @@ function SpatialWorkspace({
const floatingSourceMaximized = Boolean(observationLayout.maximizedFloatingSourceId);
const timeline = state?.observationTimeline;
const viewportRef = useRef<HTMLDivElement>(null);
const presentedViewerStatus = rerunPresentationStatus(
viewerStatus,
recordedSessionGate,
recordedSource,
);
const intentionalSourceEnd = !recordedSource && [
"awaiting_external_stop",
"stopping",
"finalizing",
"completed",
].includes(state?.acquisition?.state ?? "");
const presentedViewerStatus = intentionalSourceEnd
? "idle"
: rerunPresentationStatus(
viewerStatus,
recordedSessionGate,
recordedSource,
);
const onStatusChange = useCallback((status: RerunViewportStatus, message?: string) => {
setViewerStatus(status);
@@ -389,7 +397,7 @@ function SpatialWorkspace({
}, [observationLayout.setViewportSize]);
const viewerStatusLabel = {
idle: "Источник не назначен",
idle: intentionalSourceEnd ? "Источник отключён" : "Источник не назначен",
loading: "Подключение",
ready: "Визуализатор готов",
error: "Ошибка источника",
@@ -500,7 +508,7 @@ function SpatialWorkspace({
>
<span className="section-eyebrow">ВИЗУАЛЬНЫЙ ДВИЖОК</span>
<StatusBadge tone={viewerStatusTone}>{viewerStatusLabel}</StatusBadge>
{viewerMessage ? <small>{viewerMessage}</small> : null}
{!intentionalSourceEnd && viewerMessage ? <small>{viewerMessage}</small> : null}
</div>
<div
@@ -679,6 +687,7 @@ function CameraSourceCard({
: selectedPeer
? "Переключить"
: "Открыть канал";
const sourceDisconnected = Boolean(source.activation && !source.activation.selected && visible);
return (
<article className="camera-slot" data-focused={focused ? "true" : undefined}>
@@ -686,8 +695,11 @@ function CameraSourceCard({
<span>{source.label}</span>
<div className="camera-slot__head-actions">
<span className="camera-slot__status">
<i data-availability={source.availability} aria-hidden="true" />
{observationSourceStatusLabel(source)}
<i
data-availability={sourceDisconnected ? "unverified" : source.availability}
aria-hidden="true"
/>
{sourceDisconnected ? "Источник отключён" : observationSourceStatusLabel(source)}
</span>
{source.activation && !focused ? (
<button