Persist project device synchronization

This commit is contained in:
2026-07-24 11:47:03 +02:00
parent e930cb75b8
commit 3977a6e6e1
20 changed files with 300 additions and 747 deletions
+51 -28
View File
@@ -20,9 +20,8 @@ import {
listProjectDevices,
listProjects,
listRooms,
reconnectProjectDeviceRows,
restoreProjectDeviceRows,
synchronizeProjectDeviceRows,
undoProjectCommand,
updateProjectDevice,
updateProjectSettings,
} from "../../../frontend/utils/api";
@@ -34,7 +33,6 @@ import type {
GlobalDeviceDto,
ProjectDeviceDto,
ProjectDeviceSyncPreviewDto,
ProjectDeviceSyncRestoreRowDto,
ProjectDto,
RoomDto,
} from "../../../frontend/types";
@@ -57,9 +55,10 @@ const projectDeviceSyncFieldLabels: Record<ProjectDeviceSyncField, string> = {
remark: "Bemerkung",
};
type ProjectDeviceUndoState =
| { kind: "synchronize"; projectDeviceId: string; rows: ProjectDeviceSyncRestoreRowDto[] }
| { kind: "disconnect"; projectDeviceId: string; rowIds: string[] };
type ProjectDeviceUndoState = {
projectDeviceId: string;
revisionNumber: number;
};
const emptyProjectDevice: CreateProjectDeviceInput = {
name: "",
@@ -180,6 +179,7 @@ export default function ProjectDetailPage() {
setProject((current) =>
current ? { ...current, currentRevision } : current
);
setProjectDeviceUndo(null);
}
async function handleCreateBoard(event: FormEvent<HTMLFormElement>) {
@@ -409,7 +409,13 @@ export default function ProjectDetailPage() {
}
async function handleSynchronizeProjectDeviceRows() {
if (!projectId || !syncPreview || selectedSyncRowIds.length === 0 || selectedSyncFields.length === 0) {
if (
!projectId ||
!project ||
!syncPreview ||
selectedSyncRowIds.length === 0 ||
selectedSyncFields.length === 0
) {
return;
}
setIsSaving(true);
@@ -419,16 +425,17 @@ export default function ProjectDetailPage() {
projectId,
syncPreview.projectDevice.id,
selectedSyncRowIds,
selectedSyncFields
selectedSyncFields,
project.currentRevision
);
setSyncPreview(result.preview);
applyProjectRevision(result.history.currentRevision);
setSelectedSyncRowIds(
result.preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId)
);
setProjectDeviceUndo({
kind: "synchronize",
projectDeviceId: syncPreview.projectDevice.id,
rows: result.undo.rows,
revisionNumber: result.revision.revisionNumber,
});
} catch (err) {
setError(err instanceof Error ? err.message : "Gerätezeilen konnten nicht synchronisiert werden.");
@@ -438,7 +445,12 @@ export default function ProjectDetailPage() {
}
async function handleDisconnectProjectDeviceRows() {
if (!projectId || !syncPreview || selectedSyncRowIds.length === 0) {
if (
!projectId ||
!project ||
!syncPreview ||
selectedSyncRowIds.length === 0
) {
return;
}
setIsSaving(true);
@@ -447,13 +459,19 @@ export default function ProjectDetailPage() {
const result = await disconnectProjectDeviceRows(
projectId,
syncPreview.projectDevice.id,
selectedSyncRowIds
selectedSyncRowIds,
project.currentRevision
);
await openProjectDeviceSyncPreview(syncPreview.projectDevice.id);
setSyncPreview(result.preview);
setSelectedSyncRowIds(
result.preview.rows
.filter((row) => row.differences.length > 0)
.map((row) => row.rowId)
);
applyProjectRevision(result.history.currentRevision);
setProjectDeviceUndo({
kind: "disconnect",
projectDeviceId: syncPreview.projectDevice.id,
rowIds: result.undo.rowIds,
revisionNumber: result.revision.revisionNumber,
});
} catch (err) {
setError(err instanceof Error ? err.message : "Verknüpfungen konnten nicht getrennt werden.");
@@ -463,24 +481,29 @@ export default function ProjectDetailPage() {
}
async function handleUndoProjectDeviceOperation() {
if (!projectId || !projectDeviceUndo) {
if (!projectId || !project || !projectDeviceUndo) {
return;
}
setIsSaving(true);
setError(null);
try {
const preview =
projectDeviceUndo.kind === "synchronize"
? await restoreProjectDeviceRows(
projectId,
projectDeviceUndo.projectDeviceId,
projectDeviceUndo.rows
)
: await reconnectProjectDeviceRows(
projectId,
projectDeviceUndo.projectDeviceId,
projectDeviceUndo.rowIds
);
if (
project.currentRevision !==
projectDeviceUndo.revisionNumber
) {
throw new Error(
"Eine neuere Projektänderung verhindert dieses Rückgängig."
);
}
const result = await undoProjectCommand(
projectId,
project.currentRevision
);
const preview = await getProjectDeviceSyncPreview(
projectId,
projectDeviceUndo.projectDeviceId
);
applyProjectRevision(result.history.currentRevision);
setSyncPreview(preview);
setSelectedSyncRowIds(preview.rows.filter((row) => row.differences.length > 0).map((row) => row.rowId));
setProjectDeviceUndo(null);