feat(k1): wire canonical control session to UI
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
||||
openEventSocket,
|
||||
type ConnectRequest,
|
||||
type EventSocketStatus,
|
||||
type OpenApplicationControlSessionRequest,
|
||||
type OperatorPresenceConfirmation,
|
||||
type PrepareAcquisitionRequest,
|
||||
type ReplayRequest,
|
||||
type XgridsK1State,
|
||||
@@ -25,6 +27,7 @@ import { selectMonotonicXgridsState } from "./stateOrdering";
|
||||
export type PendingAction =
|
||||
| "scan"
|
||||
| "connect"
|
||||
| "control"
|
||||
| "live"
|
||||
| "replay"
|
||||
| "stop"
|
||||
@@ -167,7 +170,26 @@ export function useXgridsK1Runtime(enabled: boolean) {
|
||||
[run, state],
|
||||
);
|
||||
|
||||
const prepareAndStartAcquisition = useCallback(
|
||||
const openApplicationControlSession = useCallback(
|
||||
(request: OpenApplicationControlSessionRequest) =>
|
||||
run("control", () => xgridsK1Api.openApplicationControlSession(request)),
|
||||
[run],
|
||||
);
|
||||
|
||||
const enterApplicationWorkspace = useCallback(
|
||||
() =>
|
||||
run("control", () =>
|
||||
xgridsK1Api.enterApplicationWorkspace({ operator_confirmed: true }),
|
||||
),
|
||||
[run],
|
||||
);
|
||||
|
||||
const closeApplicationControlSession = useCallback(
|
||||
() => run("control", () => xgridsK1Api.closeApplicationControlSession()),
|
||||
[run],
|
||||
);
|
||||
|
||||
const prepareAcquisition = useCallback(
|
||||
(request: PrepareAcquisitionRequest) =>
|
||||
run("live", async () => {
|
||||
const plan = liveStartPlan(state);
|
||||
@@ -178,17 +200,26 @@ export function useXgridsK1Runtime(enabled: boolean) {
|
||||
}
|
||||
if (plan === "already-running" && state) return state;
|
||||
|
||||
const prepared =
|
||||
return (
|
||||
plan === "resume-prepared" && state
|
||||
? state
|
||||
: await xgridsK1Api.prepareAcquisition(request);
|
||||
const acquisition = prepared.acquisition;
|
||||
if (!acquisition?.acquisition_id) {
|
||||
throw new ApiError("Локальный сервис не вернул идентификатор подготовленного приёма.");
|
||||
: await xgridsK1Api.prepareAcquisition(request)
|
||||
);
|
||||
}),
|
||||
[run, state],
|
||||
);
|
||||
|
||||
const startPreparedAcquisition = useCallback(
|
||||
(physicalAcceptance: OperatorPresenceConfirmation) =>
|
||||
run("live", async () => {
|
||||
const acquisition = state?.acquisition;
|
||||
if (!acquisition?.acquisition_id || acquisition.state !== "prepared") {
|
||||
throw new ApiError("Сначала сохраните проект и подготовьте локальный приём.");
|
||||
}
|
||||
return xgridsK1Api.startAcquisition({
|
||||
acquisition_id: acquisition.acquisition_id,
|
||||
expected_state_revision: acquisition.state_revision,
|
||||
physical_acceptance: physicalAcceptance,
|
||||
});
|
||||
}),
|
||||
[run, state],
|
||||
@@ -200,22 +231,57 @@ export function useXgridsK1Runtime(enabled: boolean) {
|
||||
);
|
||||
|
||||
const stop = useCallback(
|
||||
() =>
|
||||
(physicalAcceptance?: OperatorPresenceConfirmation) =>
|
||||
run("stop", () => {
|
||||
const acquisition = state?.acquisition;
|
||||
const acquisitionTerminal = isTerminalAcquisitionState(acquisition?.state);
|
||||
if (acquisition && !acquisitionTerminal) {
|
||||
const softwareCommanded = isSoftwareCommandedAcquisition(state);
|
||||
if (softwareCommanded && !physicalAcceptance) {
|
||||
throw new ApiError(
|
||||
"Подтвердите присутствие рядом с K1 перед каноническим STOP.",
|
||||
);
|
||||
}
|
||||
return xgridsK1Api.stopAcquisition({
|
||||
acquisition_id: acquisition.acquisition_id,
|
||||
mode: isSoftwareCommandedAcquisition(state) ? "graceful" : "capture-only",
|
||||
mode: softwareCommanded ? "graceful" : "capture-only",
|
||||
...(physicalAcceptance
|
||||
? { physical_acceptance: physicalAcceptance }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
// Replay and pre-v1alpha2 sessions remain a compatibility-only path.
|
||||
return xgridsK1Api.stopSessionCompatibility();
|
||||
}),
|
||||
[run, state],
|
||||
);
|
||||
|
||||
const confirmStoppedAtSteadyGreen = useCallback(
|
||||
() =>
|
||||
run("stop", () => {
|
||||
const acquisition = state?.acquisition;
|
||||
if (!acquisition || acquisition.state !== "awaiting_external_stop") {
|
||||
throw new ApiError("K1 сейчас не ожидает подтверждения завершённого STOP.");
|
||||
}
|
||||
const stopOperation = [...(state?.operations ?? [])]
|
||||
.reverse()
|
||||
.find(
|
||||
(operation) =>
|
||||
operation.action === "acquisition.stop" &&
|
||||
operation.status === "operator_action_required",
|
||||
);
|
||||
if (!stopOperation) {
|
||||
throw new ApiError("Не найдена исходная операция STOP; повтор команды запрещён.");
|
||||
}
|
||||
return xgridsK1Api.stopAcquisition({
|
||||
acquisition_id: acquisition.acquisition_id,
|
||||
mode: "graceful",
|
||||
operator_confirmed: true,
|
||||
operation_id: stopOperation.operation_id,
|
||||
});
|
||||
}),
|
||||
[run, state],
|
||||
);
|
||||
|
||||
const abort = useCallback(() => {
|
||||
const acquisition = state?.acquisition;
|
||||
if (!acquisition || isTerminalAcquisitionState(acquisition.state)) {
|
||||
@@ -348,9 +414,14 @@ export function useXgridsK1Runtime(enabled: boolean) {
|
||||
clearError: () => setError(null),
|
||||
scan,
|
||||
connect,
|
||||
prepareAndStartAcquisition,
|
||||
openApplicationControlSession,
|
||||
enterApplicationWorkspace,
|
||||
closeApplicationControlSession,
|
||||
prepareAcquisition,
|
||||
startPreparedAcquisition,
|
||||
startReplay,
|
||||
stop,
|
||||
confirmStoppedAtSteadyGreen,
|
||||
abort,
|
||||
setObservationSourceActive,
|
||||
updateViewerSettings,
|
||||
|
||||
Reference in New Issue
Block a user