90 lines
3.8 KiB
TypeScript
90 lines
3.8 KiB
TypeScript
import { Button, StatusBadge, type StatusTone } from "@nodedc/ui-react";
|
||
|
||
import type { DevicePluginConnectionProps } from "@mission-core/plugin-sdk";
|
||
import { K1AcquisitionPipeline } from "./components/K1AcquisitionPipeline";
|
||
import { K1Diagnostics } from "./components/K1Diagnostics";
|
||
import { K1Metrics } from "./components/K1Metrics";
|
||
import { K1ProvisioningPipeline } from "./components/K1ProvisioningPipeline";
|
||
import {
|
||
isConfirmedLiveState,
|
||
isSourceRuntimeBusy,
|
||
recoverableAcquisition,
|
||
sourceStatusLabel,
|
||
} from "./lifecycle";
|
||
import { localizeRuntimeMessage } from "./messages";
|
||
import { phaseLabel, phaseTone } from "./presentation";
|
||
import { useXgridsK1Controller } from "./runtimeContext";
|
||
|
||
export function XgridsK1Connection({ model, host }: DevicePluginConnectionProps) {
|
||
const controller = useXgridsK1Controller();
|
||
const { state, error, refresh, clearError } = controller;
|
||
|
||
const confirmedLive = isConfirmedLiveState(state);
|
||
const sourceRuntimeBusy = isSourceRuntimeBusy(state);
|
||
const preparedAcquisition = recoverableAcquisition(state)?.state === "prepared";
|
||
const sourceLabel = sourceStatusLabel(state);
|
||
const relevantAcquisitionFailed = state?.source_mode !== "replay" && state?.acquisition?.state === "failed";
|
||
const sourceTone: StatusTone =
|
||
state?.phase === "error" || relevantAcquisitionFailed
|
||
? "danger"
|
||
: confirmedLive || state?.source_mode === "replay"
|
||
? "success"
|
||
: sourceRuntimeBusy || preparedAcquisition
|
||
? "warning"
|
||
: "neutral";
|
||
const connectionPhaseLabel = sourceRuntimeBusy || preparedAcquisition
|
||
? sourceLabel
|
||
: phaseLabel(state?.phase);
|
||
const connectionPhaseTone = sourceRuntimeBusy || preparedAcquisition
|
||
? sourceTone
|
||
: phaseTone(state?.phase);
|
||
|
||
return (
|
||
<div className="device-workspace xgrids-k1-plugin">
|
||
{error ? (
|
||
<aside className="error-banner" role="alert">
|
||
<span className="error-banner__dot" aria-hidden="true" />
|
||
<div>
|
||
<strong>Локальная операция завершилась ошибкой</strong>
|
||
<p>{error}</p>
|
||
</div>
|
||
<div className="error-banner__actions">
|
||
<Button size="compact" variant="secondary" onClick={() => void refresh()}>Обновить состояние</Button>
|
||
<Button size="compact" variant="ghost" onClick={clearError}>Закрыть</Button>
|
||
</div>
|
||
</aside>
|
||
) : null}
|
||
|
||
<section className="workspace-lead workspace-lead--compact">
|
||
<div>
|
||
<span className="section-eyebrow">XGRIDS K1 · PLUGIN UI</span>
|
||
<h2>Подключение {model.displayName}</h2>
|
||
<p>BLE/Wi‑Fi provisioning и acquisition pipeline принадлежат этому device plugin; Control Station предоставляет только host slot и переход в пространственную сцену.</p>
|
||
</div>
|
||
<div className="workspace-lead__status">
|
||
<StatusBadge tone={connectionPhaseTone}>{connectionPhaseLabel}</StatusBadge>
|
||
<span>{localizeRuntimeMessage(state?.message) || "Ожидаем состояние локального контура."}</span>
|
||
</div>
|
||
</section>
|
||
|
||
<K1Metrics controller={controller} />
|
||
|
||
<div className="device-workspace__grid">
|
||
<K1ProvisioningPipeline
|
||
controller={controller}
|
||
phaseLabel={connectionPhaseLabel}
|
||
phaseTone={connectionPhaseTone}
|
||
/>
|
||
<div className="device-workspace__side">
|
||
<K1AcquisitionPipeline
|
||
controller={controller}
|
||
openSpatialScene={host.openSpatialScene}
|
||
activateAutomaticSpatialSource={host.activateAutomaticSpatialSource}
|
||
/>
|
||
<K1Diagnostics controller={controller} sourceLabel={sourceLabel} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|