Replace Revit CSV backend with Linear XLSX
This commit is contained in:
parent
52d3b1a270
commit
1cfeb06ec7
65 changed files with 4764 additions and 3717 deletions
|
|
@ -1,94 +0,0 @@
|
|||
import { assertExternalCsvConfiguration } from "../../external-model/csv/external-csv-configuration.js";
|
||||
import type { ExternalCsvConfiguration } from "../../external-model/csv/external-csv-contracts.js";
|
||||
import type { SerializedProjectCommand } from "./project-command.model.js";
|
||||
|
||||
export const externalCsvConfigurationUpdateCommandType =
|
||||
"external-csv-configuration.update" as const;
|
||||
export const externalCsvConfigurationCommandSchemaVersion = 1 as const;
|
||||
|
||||
export interface ExternalCsvConfigurationSnapshot {
|
||||
id: string;
|
||||
projectId: string;
|
||||
configurationVersion: number;
|
||||
configuration: ExternalCsvConfiguration;
|
||||
}
|
||||
|
||||
export interface ExternalCsvConfigurationUpdatePayload {
|
||||
expected: ExternalCsvConfigurationSnapshot | null;
|
||||
target: ExternalCsvConfigurationSnapshot | null;
|
||||
}
|
||||
|
||||
export interface ExternalCsvConfigurationUpdateProjectCommand
|
||||
extends SerializedProjectCommand<ExternalCsvConfigurationUpdatePayload> {
|
||||
schemaVersion: typeof externalCsvConfigurationCommandSchemaVersion;
|
||||
type: typeof externalCsvConfigurationUpdateCommandType;
|
||||
}
|
||||
|
||||
export function createExternalCsvConfigurationUpdateProjectCommand(
|
||||
expected: ExternalCsvConfigurationSnapshot | null,
|
||||
target: ExternalCsvConfigurationSnapshot | null
|
||||
): ExternalCsvConfigurationUpdateProjectCommand {
|
||||
const command: ExternalCsvConfigurationUpdateProjectCommand = {
|
||||
schemaVersion: externalCsvConfigurationCommandSchemaVersion,
|
||||
type: externalCsvConfigurationUpdateCommandType,
|
||||
payload: { expected, target },
|
||||
};
|
||||
assertExternalCsvConfigurationUpdateProjectCommand(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
export function assertExternalCsvConfigurationUpdateProjectCommand(
|
||||
command: SerializedProjectCommand<unknown>
|
||||
): asserts command is ExternalCsvConfigurationUpdateProjectCommand {
|
||||
if (
|
||||
command.schemaVersion !== externalCsvConfigurationCommandSchemaVersion ||
|
||||
command.type !== externalCsvConfigurationUpdateCommandType ||
|
||||
!isRecord(command.payload)
|
||||
) {
|
||||
throw new Error("Unsupported external CSV configuration update command.");
|
||||
}
|
||||
assertSnapshot(command.payload.expected, "expected");
|
||||
assertSnapshot(command.payload.target, "target");
|
||||
if (command.payload.expected === null && command.payload.target === null) {
|
||||
throw new Error("External CSV configuration command must change state.");
|
||||
}
|
||||
if (
|
||||
command.payload.expected !== null &&
|
||||
command.payload.target !== null &&
|
||||
(command.payload.expected.id !== command.payload.target.id ||
|
||||
command.payload.expected.projectId !== command.payload.target.projectId)
|
||||
) {
|
||||
throw new Error("External CSV configuration identity must remain stable.");
|
||||
}
|
||||
}
|
||||
|
||||
function assertSnapshot(
|
||||
value: unknown,
|
||||
field: string
|
||||
): asserts value is ExternalCsvConfigurationSnapshot | null {
|
||||
if (value === null) {
|
||||
return;
|
||||
}
|
||||
if (!isRecord(value)) {
|
||||
throw new Error(`${field} external CSV configuration must be an object or null.`);
|
||||
}
|
||||
assertId(value.id, `${field}.id`);
|
||||
assertId(value.projectId, `${field}.projectId`);
|
||||
if (!Number.isSafeInteger(value.configurationVersion) || (value.configurationVersion as number) < 1) {
|
||||
throw new Error(`${field}.configurationVersion must be a positive integer.`);
|
||||
}
|
||||
assertExternalCsvConfiguration(value.configuration);
|
||||
if (Object.keys(value).length !== 4) {
|
||||
throw new Error(`${field} external CSV configuration contains unknown fields.`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertId(value: unknown, field: string) {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new Error(`${field} must be a non-empty string.`);
|
||||
}
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
import type { ExternalModelStateSnapshot } from "../../external-model/domain/external-model-contracts.js";
|
||||
import { parseExternalModelStateSnapshot } from "./project-state-snapshot.model.js";
|
||||
import type { SerializedProjectCommand } from "./project-command.model.js";
|
||||
|
||||
export const externalInitialImportCommandType =
|
||||
"external-import.apply-initial" as const;
|
||||
export const externalInitialImportCommandSchemaVersion = 1 as const;
|
||||
|
||||
export interface ExternalInitialImportPayload {
|
||||
expected: ExternalModelStateSnapshot;
|
||||
target: ExternalModelStateSnapshot;
|
||||
}
|
||||
|
||||
export interface ExternalInitialImportProjectCommand
|
||||
extends SerializedProjectCommand<ExternalInitialImportPayload> {
|
||||
schemaVersion: typeof externalInitialImportCommandSchemaVersion;
|
||||
type: typeof externalInitialImportCommandType;
|
||||
}
|
||||
|
||||
export function createExternalInitialImportProjectCommand(
|
||||
expected: ExternalModelStateSnapshot,
|
||||
target: ExternalModelStateSnapshot
|
||||
): ExternalInitialImportProjectCommand {
|
||||
const command: ExternalInitialImportProjectCommand = {
|
||||
schemaVersion: externalInitialImportCommandSchemaVersion,
|
||||
type: externalInitialImportCommandType,
|
||||
payload: { expected, target },
|
||||
};
|
||||
assertExternalInitialImportProjectCommand(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
export function assertExternalInitialImportProjectCommand(
|
||||
command: SerializedProjectCommand<unknown>
|
||||
): asserts command is ExternalInitialImportProjectCommand {
|
||||
if (
|
||||
command.schemaVersion !== externalInitialImportCommandSchemaVersion ||
|
||||
command.type !== externalInitialImportCommandType ||
|
||||
!isRecord(command.payload) ||
|
||||
Object.keys(command.payload).length !== 2
|
||||
) {
|
||||
throw new Error("Unsupported external initial import command.");
|
||||
}
|
||||
const expected = parseExternalModelStateSnapshot(command.payload.expected);
|
||||
const target = parseExternalModelStateSnapshot(command.payload.target);
|
||||
const expectedIsEmpty = isEmptyExternalModelState(expected);
|
||||
const targetIsEmpty = isEmptyExternalModelState(target);
|
||||
if (expectedIsEmpty === targetIsEmpty) {
|
||||
throw new Error("External initial import must transition between empty and populated state.");
|
||||
}
|
||||
assertPopulatedInitialState(expectedIsEmpty ? target : expected);
|
||||
}
|
||||
|
||||
export function createEmptyExternalModelState(): ExternalModelStateSnapshot {
|
||||
return { source: null, importBatches: [], roomMappings: [], objects: [] };
|
||||
}
|
||||
|
||||
export function isEmptyExternalModelState(state: ExternalModelStateSnapshot) {
|
||||
return (
|
||||
state.source === null &&
|
||||
state.importBatches.length === 0 &&
|
||||
state.roomMappings.length === 0 &&
|
||||
state.objects.length === 0
|
||||
);
|
||||
}
|
||||
|
||||
function assertPopulatedInitialState(state: ExternalModelStateSnapshot) {
|
||||
if (state.source === null || state.importBatches.length !== 1 || state.objects.length === 0) {
|
||||
throw new Error("External initial import requires one source, one batch and at least one object.");
|
||||
}
|
||||
const source = state.source;
|
||||
const batch = state.importBatches[0];
|
||||
if (
|
||||
batch.importKind !== "initial" ||
|
||||
batch.projectId !== source.projectId ||
|
||||
batch.sourceId !== source.id
|
||||
) {
|
||||
throw new Error("External initial import batch identity is invalid.");
|
||||
}
|
||||
const mappingIds = uniqueIds(state.roomMappings, "room mapping");
|
||||
const roomKeys = new Set<string>();
|
||||
for (const mapping of state.roomMappings) {
|
||||
if (mapping.projectId !== source.projectId || mapping.sourceId !== source.id) {
|
||||
throw new Error("External initial room mapping identity is invalid.");
|
||||
}
|
||||
if (roomKeys.has(mapping.normalizedSourceRoomKey)) {
|
||||
throw new Error("External initial import contains duplicate room keys.");
|
||||
}
|
||||
roomKeys.add(mapping.normalizedSourceRoomKey);
|
||||
}
|
||||
uniqueIds(state.objects, "object");
|
||||
const ifcGuids = new Set<string>();
|
||||
for (const object of state.objects) {
|
||||
if (
|
||||
object.projectId !== source.projectId ||
|
||||
object.sourceId !== source.id ||
|
||||
object.lastSeenImportBatchId !== batch.id ||
|
||||
object.lastAcceptedImportBatchId !== batch.id
|
||||
) {
|
||||
throw new Error("External initial object identity is invalid.");
|
||||
}
|
||||
if (ifcGuids.has(object.ifcGuid)) {
|
||||
throw new Error("External initial import contains duplicate IFCGUIDs.");
|
||||
}
|
||||
ifcGuids.add(object.ifcGuid);
|
||||
if (
|
||||
object.externalRoomMappingId !== null &&
|
||||
!mappingIds.has(object.externalRoomMappingId)
|
||||
) {
|
||||
throw new Error("External initial object room mapping is invalid.");
|
||||
}
|
||||
if (object.circuitDeviceRowId !== null) {
|
||||
throw new Error("External initial import must not assign circuit device rows.");
|
||||
}
|
||||
if (object.presenceStatus !== "present") {
|
||||
throw new Error("External initial import objects must be present.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uniqueIds(entries: ReadonlyArray<{ id: string }>, label: string) {
|
||||
const ids = new Set<string>();
|
||||
for (const entry of entries) {
|
||||
if (ids.has(entry.id)) {
|
||||
throw new Error(`External initial import contains duplicate ${label} ids.`);
|
||||
}
|
||||
ids.add(entry.id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import {
|
||||
assertExternalModelConfiguration,
|
||||
type ExternalModelConfiguration,
|
||||
} from "../../external-model/configuration/external-model-configuration.js";
|
||||
import type { SerializedProjectCommand } from "./project-command.model.js";
|
||||
|
||||
export const externalModelConfigurationUpdateCommandType =
|
||||
"external-model-configuration.update" as const;
|
||||
export const externalModelConfigurationCommandSchemaVersion = 1 as const;
|
||||
|
||||
export interface ExternalModelConfigurationSnapshot {
|
||||
id: string;
|
||||
projectId: string;
|
||||
configuration: ExternalModelConfiguration;
|
||||
}
|
||||
|
||||
export interface ExternalModelConfigurationUpdatePayload {
|
||||
expected: ExternalModelConfigurationSnapshot | null;
|
||||
target: ExternalModelConfigurationSnapshot | null;
|
||||
}
|
||||
|
||||
export interface ExternalModelConfigurationUpdateProjectCommand
|
||||
extends SerializedProjectCommand<ExternalModelConfigurationUpdatePayload> {
|
||||
schemaVersion: typeof externalModelConfigurationCommandSchemaVersion;
|
||||
type: typeof externalModelConfigurationUpdateCommandType;
|
||||
}
|
||||
|
||||
export function createExternalModelConfigurationUpdateProjectCommand(
|
||||
expected: ExternalModelConfigurationSnapshot | null,
|
||||
target: ExternalModelConfigurationSnapshot | null
|
||||
): ExternalModelConfigurationUpdateProjectCommand {
|
||||
const command: ExternalModelConfigurationUpdateProjectCommand = {
|
||||
schemaVersion: externalModelConfigurationCommandSchemaVersion,
|
||||
type: externalModelConfigurationUpdateCommandType,
|
||||
payload: { expected, target },
|
||||
};
|
||||
assertExternalModelConfigurationUpdateProjectCommand(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
export function assertExternalModelConfigurationUpdateProjectCommand(
|
||||
command: SerializedProjectCommand<unknown>
|
||||
): asserts command is ExternalModelConfigurationUpdateProjectCommand {
|
||||
if (
|
||||
command.schemaVersion !== externalModelConfigurationCommandSchemaVersion ||
|
||||
command.type !== externalModelConfigurationUpdateCommandType ||
|
||||
!isRecord(command.payload) ||
|
||||
Object.keys(command.payload).length !== 2
|
||||
) {
|
||||
throw new Error("Nicht unterstützter Revit-XLSX-Konfigurationscommand.");
|
||||
}
|
||||
assertSnapshot(command.payload.expected, "expected");
|
||||
assertSnapshot(command.payload.target, "target");
|
||||
if (command.payload.expected === null && command.payload.target === null) {
|
||||
throw new Error("Der Konfigurationscommand muss den Zustand ändern.");
|
||||
}
|
||||
if (
|
||||
command.payload.expected !== null &&
|
||||
command.payload.target !== null &&
|
||||
(command.payload.expected.id !== command.payload.target.id ||
|
||||
command.payload.expected.projectId !== command.payload.target.projectId)
|
||||
) {
|
||||
throw new Error("Die Identität der Revit-XLSX-Konfiguration muss stabil bleiben.");
|
||||
}
|
||||
}
|
||||
|
||||
function assertSnapshot(
|
||||
value: unknown,
|
||||
field: string
|
||||
): asserts value is ExternalModelConfigurationSnapshot | null {
|
||||
if (value === null) return;
|
||||
if (!isRecord(value) || Object.keys(value).length !== 3) {
|
||||
throw new Error(`${field} muss eine vollständige Konfiguration oder null sein.`);
|
||||
}
|
||||
assertId(value.id, `${field}.id`);
|
||||
assertId(value.projectId, `${field}.projectId`);
|
||||
assertExternalModelConfiguration(value.configuration);
|
||||
}
|
||||
|
||||
function assertId(value: unknown, field: string) {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new Error(`${field} muss eine nichtleere ID sein.`);
|
||||
}
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return value !== null && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
|
@ -28,6 +28,10 @@ import {
|
|||
} from "../services/project-voltage.service.js";
|
||||
import { validateExternalCsvConfiguration } from "../../external-model/csv/external-csv-configuration.js";
|
||||
import type { ExternalCsvConfiguration } from "../../external-model/csv/external-csv-contracts.js";
|
||||
import {
|
||||
validateExternalModelConfiguration,
|
||||
type ExternalModelConfiguration,
|
||||
} from "../../external-model/configuration/external-model-configuration.js";
|
||||
import {
|
||||
externalImportKinds,
|
||||
externalModelSourceTypes,
|
||||
|
|
@ -35,7 +39,8 @@ import {
|
|||
type ExternalModelStateSnapshot,
|
||||
} from "../../external-model/domain/external-model-contracts.js";
|
||||
|
||||
export const projectStateSnapshotSchemaVersion = 9 as const;
|
||||
export const projectStateSnapshotSchemaVersion = 10 as const;
|
||||
const legacyCsvProjectStateSnapshotSchemaVersion = 9 as const;
|
||||
const roomAreaProjectStateSnapshotSchemaVersion = 8 as const;
|
||||
const buildingProjectStateSnapshotSchemaVersion = 7 as const;
|
||||
const coverProjectStateSnapshotSchemaVersion = 6 as const;
|
||||
|
|
@ -423,14 +428,14 @@ const externalCsvDocumentSchema = z.object({
|
|||
});
|
||||
});
|
||||
|
||||
const externalModelSourceSchema = z.object({
|
||||
const legacyExternalModelSourceSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
name: z.string().trim().min(1),
|
||||
sourceType: z.enum(externalModelSourceTypes),
|
||||
sourceType: z.literal("revit_csv"),
|
||||
}).strict();
|
||||
|
||||
const externalImportBatchSchema = z.object({
|
||||
const legacyExternalImportBatchSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
sourceId: idSchema,
|
||||
|
|
@ -461,7 +466,7 @@ const externalRoomMappingSchema = z.object({
|
|||
defaultDistributionBoardId: idSchema.nullable(),
|
||||
}).strict();
|
||||
|
||||
const externalPlanningFieldNames = [
|
||||
const legacyExternalPlanningFieldNames = [
|
||||
"displayName",
|
||||
"internalDeviceType",
|
||||
"category",
|
||||
|
|
@ -474,7 +479,7 @@ const externalPlanningFieldNames = [
|
|||
"remark",
|
||||
] as const;
|
||||
|
||||
const externalModelObjectSchema = z.object({
|
||||
const legacyExternalModelObjectSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
sourceId: idSchema,
|
||||
|
|
@ -504,6 +509,170 @@ const externalModelObjectSchema = z.object({
|
|||
costGroup: nullableStringSchema,
|
||||
remark: nullableStringSchema,
|
||||
}).strict(),
|
||||
overriddenFields: z.array(z.enum(legacyExternalPlanningFieldNames)).refine(
|
||||
(values) => new Set(values).size === values.length
|
||||
),
|
||||
externalRoomMappingId: idSchema.nullable(),
|
||||
distributionBoardId: idSchema.nullable(),
|
||||
linkedProjectDeviceId: idSchema.nullable(),
|
||||
circuitDeviceRowId: idSchema.nullable(),
|
||||
presenceStatus: z.enum(externalObjectPresenceStatuses),
|
||||
}).strict();
|
||||
|
||||
const legacyExternalModelStateSchema = z.object({
|
||||
source: legacyExternalModelSourceSchema.nullable(),
|
||||
importBatches: z.array(legacyExternalImportBatchSchema),
|
||||
roomMappings: z.array(externalRoomMappingSchema),
|
||||
objects: z.array(legacyExternalModelObjectSchema),
|
||||
}).strict();
|
||||
|
||||
const externalModelConfigurationSnapshotSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
configuration: z.custom<ExternalModelConfiguration>(
|
||||
(value) => validateExternalModelConfiguration(value).success
|
||||
),
|
||||
}).strict();
|
||||
|
||||
const externalXlsxScalarSchema = z.union([
|
||||
z.string(),
|
||||
finiteNumberSchema,
|
||||
z.boolean(),
|
||||
z.null(),
|
||||
]);
|
||||
|
||||
const externalXlsxDocumentSchema = z.object({
|
||||
sheetName: z.string().min(1).max(31),
|
||||
headerRowNumber: z.number().int().positive(),
|
||||
firstDataRowNumber: z.number().int().positive(),
|
||||
firstDataColumnNumber: z.number().int().positive(),
|
||||
columns: z.array(z.object({
|
||||
columnNumber: z.number().int().positive(),
|
||||
header: z.string(),
|
||||
comment: z.string().nullable(),
|
||||
width: finiteNumberSchema.positive().nullable(),
|
||||
}).strict()),
|
||||
rows: z.array(z.object({
|
||||
rowNumber: z.number().int().positive(),
|
||||
classification: z.enum(["object", "suspect-object", "passthrough"]),
|
||||
cells: z.array(z.object({
|
||||
columnNumber: z.number().int().positive(),
|
||||
value: externalXlsxScalarSchema,
|
||||
valueType: z.enum(["empty", "string", "number", "boolean"]),
|
||||
numberFormat: z.string().nullable(),
|
||||
formula: z.string().nullable(),
|
||||
usedCachedFormulaValue: z.boolean(),
|
||||
}).strict()),
|
||||
}).strict()),
|
||||
issues: z.array(z.object({
|
||||
code: z.enum([
|
||||
"cached-formula-value-used",
|
||||
"formula-without-cached-value",
|
||||
"suspect-object-skipped",
|
||||
"duplicate-ifc-guid",
|
||||
"optional-return-column-missing",
|
||||
]),
|
||||
message: z.string().min(1),
|
||||
rowNumber: z.number().int().positive().optional(),
|
||||
columnNumber: z.number().int().positive().optional(),
|
||||
field: z.enum([
|
||||
"worksharingId", "ifcGuid", "roomNumber", "roomName",
|
||||
"familyAndType", "selectionMarker", "socketCount", "sourceRemark",
|
||||
"circuitCombined", "boardName", "circuitIdentifier", "designation",
|
||||
"electricalPowerW", "voltageV", "currentA",
|
||||
]).optional(),
|
||||
}).strict()),
|
||||
}).strict();
|
||||
|
||||
const externalModelSourceSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
name: z.string().trim().min(1),
|
||||
sourceType: z.enum(externalModelSourceTypes),
|
||||
}).strict();
|
||||
|
||||
const externalImportBatchSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
sourceId: idSchema,
|
||||
importKind: z.enum(externalImportKinds),
|
||||
importedAtIso: z.string().refine((value) => Number.isFinite(Date.parse(value))),
|
||||
fileName: z.string().trim().min(1),
|
||||
sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
||||
objectCount: z.number().int().nonnegative(),
|
||||
appliedProjectRevision: z.number().int().nonnegative().nullable(),
|
||||
configurationSnapshot: z.custom<ExternalModelConfiguration>(
|
||||
(value) => value === null || validateExternalModelConfiguration(value).success
|
||||
).nullable(),
|
||||
originalContentBase64: z.string().min(1).regex(
|
||||
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/
|
||||
).nullable(),
|
||||
document: externalXlsxDocumentSchema.nullable(),
|
||||
}).strict().superRefine((batch, context) => {
|
||||
const complete = [
|
||||
batch.appliedProjectRevision,
|
||||
batch.configurationSnapshot,
|
||||
batch.originalContentBase64,
|
||||
batch.document,
|
||||
].map((value) => value !== null);
|
||||
if (!complete.every((value) => value === complete[0])) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
message: "Importbatch muss vollständig oder auf Metadaten reduziert sein.",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const externalPlanningFieldNames = [
|
||||
"displayName",
|
||||
"category",
|
||||
"connectionKind",
|
||||
"effectiveQuantity",
|
||||
"powerPerUnitW",
|
||||
"simultaneityFactor",
|
||||
"cosPhi",
|
||||
"costGroup",
|
||||
"remark",
|
||||
] as const;
|
||||
|
||||
const externalModelObjectSchema = z.object({
|
||||
id: idSchema,
|
||||
projectId: idSchema,
|
||||
sourceId: idSchema,
|
||||
worksharingId: z.string().regex(
|
||||
/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}-[0-9A-Fa-f]{8}$/
|
||||
),
|
||||
ifcGuid: externalIfcGuidSchema.nullable(),
|
||||
deviceTypeId: idSchema,
|
||||
lastSeenImportBatchId: idSchema,
|
||||
lastAcceptedImportBatchId: idSchema,
|
||||
acceptedSourceValues: z.object({
|
||||
rowNumber: z.number().int().positive(),
|
||||
roomNumber: externalXlsxScalarSchema,
|
||||
roomName: externalXlsxScalarSchema,
|
||||
familyAndType: z.string().min(1),
|
||||
selectionMarker: externalXlsxScalarSchema,
|
||||
socketCount: externalXlsxScalarSchema,
|
||||
sourceRemark: externalXlsxScalarSchema,
|
||||
circuitCombined: externalXlsxScalarSchema,
|
||||
boardName: externalXlsxScalarSchema,
|
||||
circuitIdentifier: externalXlsxScalarSchema,
|
||||
designation: externalXlsxScalarSchema,
|
||||
electricalPowerW: externalXlsxScalarSchema,
|
||||
voltageV: externalXlsxScalarSchema,
|
||||
currentA: externalXlsxScalarSchema,
|
||||
}).strict(),
|
||||
planningValues: z.object({
|
||||
displayName: nullableStringSchema,
|
||||
category: z.enum(circuitGroupCategories).nullable(),
|
||||
connectionKind: nullableStringSchema,
|
||||
effectiveQuantity: finiteNumberSchema.positive(),
|
||||
powerPerUnitW: finiteNumberSchema.nonnegative().nullable(),
|
||||
simultaneityFactor: finiteNumberSchema.min(0).max(1).nullable(),
|
||||
cosPhi: finiteNumberSchema.positive().max(1).nullable(),
|
||||
costGroup: nullableStringSchema,
|
||||
remark: nullableStringSchema,
|
||||
}).strict(),
|
||||
overriddenFields: z.array(z.enum(externalPlanningFieldNames)).refine(
|
||||
(values) => new Set(values).size === values.length
|
||||
),
|
||||
|
|
@ -519,7 +688,21 @@ const externalModelStateSchema = z.object({
|
|||
importBatches: z.array(externalImportBatchSchema),
|
||||
roomMappings: z.array(externalRoomMappingSchema),
|
||||
objects: z.array(externalModelObjectSchema),
|
||||
}).strict();
|
||||
}).strict().superRefine((state, context) => {
|
||||
const fullBatchIndexes = state.importBatches.flatMap((batch, index) =>
|
||||
batch.originalContentBase64 === null ? [] : [index]
|
||||
);
|
||||
if (
|
||||
state.importBatches.length > 0 &&
|
||||
(fullBatchIndexes.length !== 1 ||
|
||||
fullBatchIndexes[0] !== state.importBatches.length - 1)
|
||||
) {
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
message: "Nur der letzte Importbatch darf vollständig gespeichert sein.",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export function parseExternalModelStateSnapshot(
|
||||
value: unknown
|
||||
|
|
@ -565,19 +748,30 @@ export const projectStateSnapshotSchema = z
|
|||
schemaVersion: z.literal(projectStateSnapshotSchemaVersion),
|
||||
project: projectSchema,
|
||||
distributionBoards: z.array(distributionBoardSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModelConfiguration: externalModelConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
...projectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
||||
const legacyCsvProjectStateSnapshotSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(legacyCsvProjectStateSnapshotSchemaVersion),
|
||||
project: projectSchema,
|
||||
distributionBoards: z.array(distributionBoardSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...projectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
||||
const roomAreaProjectStateSnapshotSchema = z
|
||||
.object({
|
||||
schemaVersion: z.literal(roomAreaProjectStateSnapshotSchemaVersion),
|
||||
project: projectSchema,
|
||||
distributionBoards: z.array(distributionBoardWithoutFeedingSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...projectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
|
@ -588,7 +782,7 @@ const buildingProjectStateSnapshotSchema = z
|
|||
project: projectSchema,
|
||||
distributionBoards: z.array(distributionBoardWithoutFeedingSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...buildingProjectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
|
@ -599,7 +793,7 @@ const coverProjectStateSnapshotSchema = z
|
|||
project: projectSchema,
|
||||
distributionBoards: z.array(distributionBoardWithoutFeedingSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...previousProjectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
|
@ -610,7 +804,7 @@ const boardInfoProjectStateSnapshotSchema = z
|
|||
project: publicBuildingProjectSchema,
|
||||
distributionBoards: z.array(legacyDistributionBoardSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...previousProjectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
|
@ -621,7 +815,7 @@ const previousProjectStateSnapshotSchema = z
|
|||
project: publicBuildingProjectSchema,
|
||||
distributionBoards: z.array(legacyDistributionBoardSchema),
|
||||
externalCsvConfiguration: externalCsvConfigurationSnapshotSchema.nullable(),
|
||||
externalModel: externalModelStateSchema,
|
||||
externalModel: legacyExternalModelStateSchema,
|
||||
...previousProjectStateSnapshotContents,
|
||||
})
|
||||
.strict();
|
||||
|
|
@ -684,6 +878,39 @@ export function parseProjectStateSnapshot(
|
|||
}
|
||||
|
||||
function upgradePreviousProjectStateSnapshot(value: unknown): unknown {
|
||||
const legacyCsv = upgradeToLegacyCsvProjectStateSnapshot(value);
|
||||
if (
|
||||
legacyCsv !== null &&
|
||||
typeof legacyCsv === "object" &&
|
||||
!Array.isArray(legacyCsv) &&
|
||||
(legacyCsv as { schemaVersion?: unknown }).schemaVersion ===
|
||||
legacyCsvProjectStateSnapshotSchemaVersion
|
||||
) {
|
||||
const previous = legacyCsvProjectStateSnapshotSchema.parse(legacyCsv);
|
||||
if (
|
||||
previous.externalCsvConfiguration !== null ||
|
||||
!isEmptyExternalModelState(previous.externalModel)
|
||||
) {
|
||||
throw new Error(
|
||||
"Dieser alte Projektstand enthält Revit-CSV-Daten und kann nicht auf die Revit-XLSX-Struktur aktualisiert werden."
|
||||
);
|
||||
}
|
||||
const {
|
||||
externalCsvConfiguration: _externalCsvConfiguration,
|
||||
externalModel: _legacyExternalModel,
|
||||
...remaining
|
||||
} = previous;
|
||||
return {
|
||||
...remaining,
|
||||
schemaVersion: projectStateSnapshotSchemaVersion,
|
||||
externalModelConfiguration: null,
|
||||
externalModel: emptyExternalModelState(),
|
||||
};
|
||||
}
|
||||
return legacyCsv;
|
||||
}
|
||||
|
||||
function upgradeToLegacyCsvProjectStateSnapshot(value: unknown): unknown {
|
||||
const roomArea = upgradeToRoomAreaProjectStateSnapshot(value);
|
||||
if (
|
||||
roomArea !== null &&
|
||||
|
|
@ -695,7 +922,7 @@ function upgradePreviousProjectStateSnapshot(value: unknown): unknown {
|
|||
const previous = roomAreaProjectStateSnapshotSchema.parse(roomArea);
|
||||
return {
|
||||
...previous,
|
||||
schemaVersion: projectStateSnapshotSchemaVersion,
|
||||
schemaVersion: legacyCsvProjectStateSnapshotSchemaVersion,
|
||||
distributionBoards: withEmptyDistributionBoardFeeding(
|
||||
previous.distributionBoards
|
||||
),
|
||||
|
|
@ -830,6 +1057,20 @@ function emptyExternalModelState() {
|
|||
};
|
||||
}
|
||||
|
||||
function isEmptyExternalModelState(state: {
|
||||
source: unknown;
|
||||
importBatches: unknown[];
|
||||
roomMappings: unknown[];
|
||||
objects: unknown[];
|
||||
}) {
|
||||
return (
|
||||
state.source === null &&
|
||||
state.importBatches.length === 0 &&
|
||||
state.roomMappings.length === 0 &&
|
||||
state.objects.length === 0
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeSnapshotPhaseTypes(
|
||||
snapshot: ProjectStateSnapshot
|
||||
): ProjectStateSnapshot {
|
||||
|
|
@ -891,10 +1132,10 @@ function assertProjectStateSnapshotRelations(
|
|||
) {
|
||||
const projectId = snapshot.project.id;
|
||||
if (
|
||||
snapshot.externalCsvConfiguration !== null &&
|
||||
snapshot.externalCsvConfiguration.projectId !== projectId
|
||||
snapshot.externalModelConfiguration !== null &&
|
||||
snapshot.externalModelConfiguration.projectId !== projectId
|
||||
) {
|
||||
throw new Error("Snapshot external CSV configuration belongs to a different project.");
|
||||
throw new Error("Snapshot Revit-XLSX configuration belongs to a different project.");
|
||||
}
|
||||
const boardIds = uniqueIds(
|
||||
snapshot.distributionBoards,
|
||||
|
|
@ -1235,6 +1476,12 @@ function assertExternalModelRelations(
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (snapshot.externalModelConfiguration === null) {
|
||||
throw new Error("Snapshot external model requires a Revit-XLSX configuration.");
|
||||
}
|
||||
if (importBatches.length === 0) {
|
||||
throw new Error("Snapshot external model source requires an import batch.");
|
||||
}
|
||||
assertProjectOwnership(source.projectId, references.projectId, "external model source");
|
||||
const batchIds = uniqueIds(importBatches, "external import batch");
|
||||
const mappingIds = uniqueIds(roomMappings, "external room mapping");
|
||||
|
|
@ -1270,17 +1517,23 @@ function assertExternalModelRelations(
|
|||
}
|
||||
}
|
||||
|
||||
const ifcGuids = new Set<string>();
|
||||
const worksharingIds = new Set<string>();
|
||||
const deviceTypeIds = new Set(
|
||||
snapshot.externalModelConfiguration.configuration.deviceTypes.map(
|
||||
(deviceType) => deviceType.id
|
||||
)
|
||||
);
|
||||
for (const object of objects) {
|
||||
assertProjectOwnership(object.projectId, references.projectId, "external model object");
|
||||
if (object.sourceId !== source.id) {
|
||||
throw new Error("Snapshot external model object belongs to a different source.");
|
||||
}
|
||||
assertUniqueKey(
|
||||
ifcGuids,
|
||||
object.ifcGuid,
|
||||
"Snapshot contains duplicate external IFCGUIDs."
|
||||
worksharingIds,
|
||||
object.worksharingId,
|
||||
"Snapshot contains duplicate external Worksharing-IDs."
|
||||
);
|
||||
assertReference(deviceTypeIds, object.deviceTypeId, "external object device type");
|
||||
assertReference(batchIds, object.lastSeenImportBatchId, "external object last-seen batch");
|
||||
assertReference(batchIds, object.lastAcceptedImportBatchId, "external object accepted batch");
|
||||
if (object.externalRoomMappingId !== null) {
|
||||
|
|
|
|||
|
|
@ -146,16 +146,35 @@ export function remapProjectState(
|
|||
createId
|
||||
);
|
||||
const externalObjectIds = idMap(source.externalModel.objects, createId);
|
||||
const configurations = [
|
||||
source.externalModelConfiguration?.configuration ?? null,
|
||||
...source.externalModel.importBatches.map(
|
||||
(batch) => batch.configurationSnapshot
|
||||
),
|
||||
].filter((configuration) => configuration !== null);
|
||||
const deviceTypeIds = uniqueIdMap(
|
||||
configurations.flatMap((configuration) => configuration.deviceTypes),
|
||||
createId
|
||||
);
|
||||
const familyRuleIds = uniqueIdMap(
|
||||
configurations.flatMap((configuration) => configuration.familyTypeRules),
|
||||
createId
|
||||
);
|
||||
return parseProjectStateSnapshot({
|
||||
...source,
|
||||
project: { ...source.project, id: targetProjectId, name },
|
||||
externalCsvConfiguration:
|
||||
source.externalCsvConfiguration === null
|
||||
externalModelConfiguration:
|
||||
source.externalModelConfiguration === null
|
||||
? null
|
||||
: {
|
||||
...source.externalCsvConfiguration,
|
||||
...source.externalModelConfiguration,
|
||||
id: createId(),
|
||||
projectId: targetProjectId,
|
||||
configuration: remapExternalModelConfiguration(
|
||||
source.externalModelConfiguration.configuration,
|
||||
deviceTypeIds,
|
||||
familyRuleIds
|
||||
),
|
||||
},
|
||||
externalModel: {
|
||||
source: source.externalModel.source === null
|
||||
|
|
@ -170,6 +189,14 @@ export function remapProjectState(
|
|||
id: requiredId(externalBatchIds, batch.id),
|
||||
projectId: targetProjectId,
|
||||
sourceId: externalSourceId!,
|
||||
configurationSnapshot:
|
||||
batch.configurationSnapshot === null
|
||||
? null
|
||||
: remapExternalModelConfiguration(
|
||||
batch.configurationSnapshot,
|
||||
deviceTypeIds,
|
||||
familyRuleIds
|
||||
),
|
||||
})),
|
||||
roomMappings: source.externalModel.roomMappings.map((mapping) => ({
|
||||
...mapping,
|
||||
|
|
@ -190,6 +217,7 @@ export function remapProjectState(
|
|||
id: requiredId(externalObjectIds, object.id),
|
||||
projectId: targetProjectId,
|
||||
sourceId: externalSourceId!,
|
||||
deviceTypeId: requiredId(deviceTypeIds, object.deviceTypeId),
|
||||
lastSeenImportBatchId: requiredId(
|
||||
externalBatchIds,
|
||||
object.lastSeenImportBatchId
|
||||
|
|
@ -322,6 +350,36 @@ export function remapProjectState(
|
|||
});
|
||||
}
|
||||
|
||||
function remapExternalModelConfiguration(
|
||||
configuration: NonNullable<
|
||||
ProjectStateSnapshot["externalModelConfiguration"]
|
||||
>["configuration"],
|
||||
deviceTypeIds: ReadonlyMap<string, string>,
|
||||
familyRuleIds: ReadonlyMap<string, string>
|
||||
) {
|
||||
return {
|
||||
...configuration,
|
||||
deviceTypes: configuration.deviceTypes.map((deviceType) => ({
|
||||
...deviceType,
|
||||
id: requiredId(deviceTypeIds, deviceType.id),
|
||||
})),
|
||||
familyTypeRules: configuration.familyTypeRules.map((rule) => ({
|
||||
...rule,
|
||||
id: requiredId(familyRuleIds, rule.id),
|
||||
deviceTypeId: requiredId(deviceTypeIds, rule.deviceTypeId),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function uniqueIdMap(
|
||||
entries: ReadonlyArray<{ id: string }>,
|
||||
createId: () => string
|
||||
) {
|
||||
return new Map(
|
||||
[...new Set(entries.map((entry) => entry.id))].map((id) => [id, createId()])
|
||||
);
|
||||
}
|
||||
|
||||
function idMap(
|
||||
entries: ReadonlyArray<{ id: string }>,
|
||||
createId: () => string
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
import type { ExternalCsvConfigurationUpdateProjectCommand } from "../models/external-csv-configuration-project-command.model.js";
|
||||
import type { AppendedProjectRevision, ProjectRevisionSource } from "./project-revision.store.js";
|
||||
|
||||
export interface ExecuteExternalCsvConfigurationCommandInput {
|
||||
projectId: string;
|
||||
expectedRevision: number;
|
||||
source: ProjectRevisionSource;
|
||||
description?: string;
|
||||
actorId?: string;
|
||||
historyTargetChangeSetId?: string;
|
||||
command: ExternalCsvConfigurationUpdateProjectCommand;
|
||||
}
|
||||
|
||||
export interface ExternalCsvConfigurationProjectCommandStore {
|
||||
execute(input: ExecuteExternalCsvConfigurationCommandInput): {
|
||||
revision: AppendedProjectRevision;
|
||||
inverse: ExternalCsvConfigurationUpdateProjectCommand;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import type { ExternalCsvConfigurationSnapshot } from "../models/external-csv-configuration-project-command.model.js";
|
||||
|
||||
export interface ExternalCsvConfigurationReadResult {
|
||||
projectExists: boolean;
|
||||
configuration: ExternalCsvConfigurationSnapshot | null;
|
||||
}
|
||||
|
||||
export interface ExternalCsvConfigurationReader {
|
||||
getByProject(projectId: string): ExternalCsvConfigurationReadResult;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import type { ExternalInitialImportProjectCommand } from "../models/external-initial-import-project-command.model.js";
|
||||
import type { AppendedProjectRevision, ProjectRevisionSource } from "./project-revision.store.js";
|
||||
|
||||
export interface ExecuteExternalInitialImportCommandInput {
|
||||
projectId: string;
|
||||
expectedRevision: number;
|
||||
source: ProjectRevisionSource;
|
||||
description?: string;
|
||||
actorId?: string;
|
||||
historyTargetChangeSetId?: string;
|
||||
command: ExternalInitialImportProjectCommand;
|
||||
}
|
||||
|
||||
export interface ExternalInitialImportProjectCommandStore {
|
||||
execute(input: ExecuteExternalInitialImportCommandInput): {
|
||||
revision: AppendedProjectRevision;
|
||||
inverse: ExternalInitialImportProjectCommand;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import type { ExternalModelConfigurationUpdateProjectCommand } from "../models/external-model-configuration-project-command.model.js";
|
||||
import type { AppendedProjectRevision, ProjectRevisionSource } from "./project-revision.store.js";
|
||||
|
||||
export interface ExecuteExternalModelConfigurationCommandInput {
|
||||
projectId: string;
|
||||
expectedRevision: number;
|
||||
source: ProjectRevisionSource;
|
||||
description?: string;
|
||||
actorId?: string;
|
||||
historyTargetChangeSetId?: string;
|
||||
command: ExternalModelConfigurationUpdateProjectCommand;
|
||||
}
|
||||
|
||||
export interface ExternalModelConfigurationProjectCommandStore {
|
||||
execute(input: ExecuteExternalModelConfigurationCommandInput): {
|
||||
revision: AppendedProjectRevision;
|
||||
inverse: ExternalModelConfigurationUpdateProjectCommand;
|
||||
};
|
||||
}
|
||||
10
src/domain/ports/external-model-configuration.reader.ts
Normal file
10
src/domain/ports/external-model-configuration.reader.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import type { ExternalModelConfigurationSnapshot } from "../models/external-model-configuration-project-command.model.js";
|
||||
|
||||
export interface ExternalModelConfigurationReadResult {
|
||||
projectExists: boolean;
|
||||
configuration: ExternalModelConfigurationSnapshot | null;
|
||||
}
|
||||
|
||||
export interface ExternalModelConfigurationReader {
|
||||
getByProject(projectId: string): ExternalModelConfigurationReadResult;
|
||||
}
|
||||
|
|
@ -173,15 +173,10 @@ import type { ProjectRevisionSource } from "../ports/project-revision.store.js";
|
|||
import type { ProjectSettingsProjectCommandStore } from "../ports/project-settings-project-command.store.js";
|
||||
import type { ProjectStateRestoreCommandStore } from "../ports/project-state-restore-command.store.js";
|
||||
import {
|
||||
assertExternalCsvConfigurationUpdateProjectCommand,
|
||||
externalCsvConfigurationUpdateCommandType,
|
||||
} from "../models/external-csv-configuration-project-command.model.js";
|
||||
import type { ExternalCsvConfigurationProjectCommandStore } from "../ports/external-csv-configuration-project-command.store.js";
|
||||
import {
|
||||
assertExternalInitialImportProjectCommand,
|
||||
externalInitialImportCommandType,
|
||||
} from "../models/external-initial-import-project-command.model.js";
|
||||
import type { ExternalInitialImportProjectCommandStore } from "../ports/external-initial-import-project-command.store.js";
|
||||
assertExternalModelConfigurationUpdateProjectCommand,
|
||||
externalModelConfigurationUpdateCommandType,
|
||||
} from "../models/external-model-configuration-project-command.model.js";
|
||||
import type { ExternalModelConfigurationProjectCommandStore } from "../ports/external-model-configuration-project-command.store.js";
|
||||
import {
|
||||
assertExternalObjectRowAssignmentProjectCommand,
|
||||
externalObjectRowAssignmentCommandType,
|
||||
|
|
@ -243,8 +238,7 @@ export class ProjectCommandService implements ProjectCommandExecutor {
|
|||
private readonly circuitGroupSubtreeStore: CircuitGroupSubtreeProjectCommandStore,
|
||||
private readonly circuitProtectionStore: CircuitProtectionProjectCommandStore,
|
||||
private readonly historyStore: ProjectHistoryStore,
|
||||
private readonly externalCsvConfigurationStore?: ExternalCsvConfigurationProjectCommandStore,
|
||||
private readonly externalInitialImportStore?: ExternalInitialImportProjectCommandStore,
|
||||
private readonly externalModelConfigurationStore?: ExternalModelConfigurationProjectCommandStore,
|
||||
private readonly externalObjectRowAssignmentStore?: ExternalObjectRowAssignmentProjectCommandStore,
|
||||
private readonly externalObjectNewRowStore?: ExternalObjectNewRowProjectCommandStore,
|
||||
private readonly externalObjectNewCircuitStore?: ExternalObjectNewCircuitProjectCommandStore,
|
||||
|
|
@ -308,6 +302,8 @@ export class ProjectCommandService implements ProjectCommandExecutor {
|
|||
);
|
||||
}
|
||||
|
||||
assertNoLegacyExternalCsvHistoryCommand(step.command);
|
||||
|
||||
return this.dispatch({
|
||||
...input,
|
||||
source: direction,
|
||||
|
|
@ -625,22 +621,12 @@ export class ProjectCommandService implements ProjectCommandExecutor {
|
|||
command: input.command,
|
||||
}).revision;
|
||||
}
|
||||
case externalCsvConfigurationUpdateCommandType: {
|
||||
assertExternalCsvConfigurationUpdateProjectCommand(input.command);
|
||||
if (!this.externalCsvConfigurationStore) {
|
||||
throw new Error("External CSV configuration store is not available.");
|
||||
case externalModelConfigurationUpdateCommandType: {
|
||||
assertExternalModelConfigurationUpdateProjectCommand(input.command);
|
||||
if (!this.externalModelConfigurationStore) {
|
||||
throw new Error("External model configuration store is not available.");
|
||||
}
|
||||
return this.externalCsvConfigurationStore.execute({
|
||||
...input,
|
||||
command: input.command,
|
||||
}).revision;
|
||||
}
|
||||
case externalInitialImportCommandType: {
|
||||
assertExternalInitialImportProjectCommand(input.command);
|
||||
if (!this.externalInitialImportStore) {
|
||||
throw new Error("External initial import store is not available.");
|
||||
}
|
||||
return this.externalInitialImportStore.execute({
|
||||
return this.externalModelConfigurationStore.execute({
|
||||
...input,
|
||||
command: input.command,
|
||||
}).revision;
|
||||
|
|
@ -720,3 +706,16 @@ function assertExpectedRevision(expectedRevision: number) {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertNoLegacyExternalCsvHistoryCommand(
|
||||
command: SerializedProjectCommand<unknown>
|
||||
) {
|
||||
if (
|
||||
command.type === "external-csv-configuration.update" ||
|
||||
command.type === "external-import.apply-initial"
|
||||
) {
|
||||
throw new Error(
|
||||
"Dieser Verlaufseintrag stammt aus der alten Revit-CSV-Anbindung und kann nach der Umstellung auf Linear-XLSX nicht mehr ausgef\u00fchrt werden."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue