Add versioned project settings modal

This commit is contained in:
2026-07-28 18:16:22 +02:00
parent e1fc81a083
commit d77cfbeb49
22 changed files with 2563 additions and 111 deletions
@@ -1,12 +1,13 @@
import { z } from "zod";
export const projectStateSnapshotSchemaVersion = 1 as const;
export const legacyProjectStateSnapshotSchemaVersion = 1 as const;
export const projectStateSnapshotSchemaVersion = 2 as const;
const idSchema = z.string().trim().min(1);
const nullableStringSchema = z.string().nullable();
const finiteNumberSchema = z.number().finite();
const projectSchema = z
const legacyProjectSchema = z
.object({
id: idSchema,
name: z.string().trim().min(1),
@@ -15,6 +16,13 @@ const projectSchema = z
})
.strict();
const projectSchema = legacyProjectSchema.extend({
internalProjectNumber: z.string().trim().min(1).max(100).nullable(),
externalProjectNumber: z.string().trim().min(1).max(100).nullable(),
buildingOwner: z.string().trim().min(1).max(200).nullable(),
description: z.string().trim().min(1).max(2000).nullable(),
});
const distributionBoardSchema = z
.object({
id: idSchema,
@@ -132,17 +140,29 @@ const roomSchema = z
})
.strict();
const projectStateSnapshotContents = {
distributionBoards: z.array(distributionBoardSchema),
circuitLists: z.array(circuitListSchema),
circuitSections: z.array(circuitSectionSchema),
circuits: z.array(circuitSchema),
projectDevices: z.array(projectDeviceSchema),
floors: z.array(floorSchema),
rooms: z.array(roomSchema),
};
const legacyProjectStateSnapshotSchema = z
.object({
schemaVersion: z.literal(legacyProjectStateSnapshotSchemaVersion),
project: legacyProjectSchema,
...projectStateSnapshotContents,
})
.strict();
export const projectStateSnapshotSchema = z
.object({
schemaVersion: z.literal(projectStateSnapshotSchemaVersion),
project: projectSchema,
distributionBoards: z.array(distributionBoardSchema),
circuitLists: z.array(circuitListSchema),
circuitSections: z.array(circuitSectionSchema),
circuits: z.array(circuitSchema),
projectDevices: z.array(projectDeviceSchema),
floors: z.array(floorSchema),
rooms: z.array(roomSchema),
...projectStateSnapshotContents,
})
.strict();
@@ -153,11 +173,37 @@ export type ProjectStateSnapshot = z.infer<
export function parseProjectStateSnapshot(
value: unknown
): ProjectStateSnapshot {
const snapshot = projectStateSnapshotSchema.parse(value);
const version = isPlainObject(value) ? value.schemaVersion : undefined;
const snapshot =
version === legacyProjectStateSnapshotSchemaVersion
? upgradeLegacyProjectStateSnapshot(
legacyProjectStateSnapshotSchema.parse(value)
)
: projectStateSnapshotSchema.parse(value);
assertProjectStateSnapshotRelations(snapshot);
return snapshot;
}
function upgradeLegacyProjectStateSnapshot(
snapshot: z.infer<typeof legacyProjectStateSnapshotSchema>
): ProjectStateSnapshot {
return {
...snapshot,
schemaVersion: projectStateSnapshotSchemaVersion,
project: {
...snapshot.project,
internalProjectNumber: null,
externalProjectNumber: null,
buildingOwner: null,
description: null,
},
};
}
function isPlainObject(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
export function serializeProjectStateSnapshot(
snapshot: ProjectStateSnapshot
): string {