diff --git a/docs/spec/revit-excel-integration-requirements.md b/docs/spec/revit-excel-integration-requirements.md index ce80c46..29a4aaf 100644 --- a/docs/spec/revit-excel-integration-requirements.md +++ b/docs/spec/revit-excel-integration-requirements.md @@ -306,16 +306,6 @@ aktuellen Row-Werte als Planungswerte und entsprechende Overrides. ## 11. Editor-Zuordnung und Löschen -Umsetzungsstand R7: Der Stromkreislisteneditor lädt die kompakte Projektliste -gemeinsam mit dem Baum, gruppiert unzugeordnete Objekte des aktuellen -Verteilers im Client und bietet Gruppen sowie einzelne Worksharing-IDs als -Drag-Quelle an. Drop auf Row, Circuit und freien Gruppenbereich verwendet die -drei persistenten Zuordnungscommands. Row-Badges zeigen die Linkzahl; Lösen -kopiert die aktuellen Row-Planungswerte als Overrides. Row-, Circuit- und -Gruppenlöschungen speichern die vollständigen Linkübergänge im Forward- und -Inverse-Command. Raum- und Verteilerlöschungen prüfen externe Referenzen -explizit. - Der rechte, überlagernde Editorbereich zeigt unzugeordnete konfliktfreie Objekte des aktuellen Verteilers. Gruppierungsschlüssel sind interner Raum, Auswahlkenner, Geräteart, Kategorie, identische Planungswerte und kompatibler @@ -348,14 +338,6 @@ Pfade. ## 12. Rückgabe-Excel -Umsetzungsstand R8: Die Revit-Objekttabelle bietet alle drei Rückgabeumfänge -an und lädt eine aus dem letzten vollständigen Import erzeugte XLSX herunter. -Die Serverprojektion verwendet für verknüpfte Objekte die aktuellen Row- und -Circuit-Werte, für freie Objekte die Planungswerte und schreibt Zahlen als -Excel-Zahlen. Hinweise zu nicht berechenbaren Werten und fehlenden optionalen -Spalten werden nach dem Download angezeigt. Der append-only Exportnachweis -liegt außerhalb von Projektrevision, Undo/Redo, Snapshots und Transfer. - Der Export ist eine Leseoperation ohne Projektrevision. Ein append-only Nachweis speichert Projektrevision, zugrunde liegenden letzten Import, Zeitpunkt, Dateiname, SHA-256, Konfigurationskopie beziehungsweise ihren Hash diff --git a/docs/spec/revit-excel-phase-14-plan.md b/docs/spec/revit-excel-phase-14-plan.md index 61d8f2d..9b43c4f 100644 --- a/docs/spec/revit-excel-phase-14-plan.md +++ b/docs/spec/revit-excel-phase-14-plan.md @@ -15,8 +15,8 @@ Der alte CSV-Plan 14.0–14.6 ist abgelöst und wird nicht fortgeschrieben. | R4 | abgeschlossen | Revit-Seite, Navigation und revisionierte XLSX-Einstellungen mit Musterdateiprüfung sind umgesetzt; das alte Projektseitenmodal ist entfernt. | | R5 | abgeschlossen | Zustandslose XLSX-Vorschau, sechsstufiger Erstimportwizard und atomarer Importcommand mit parserfreiem Undo/Redo. | | R6 | abgeschlossen | Projektweite kompakte Objektliste, clientseitige Filter/Sortierung, Virtualisierung und revisionierte Sammeländerungen. | -| R7 | abgeschlossen | Gruppierter Editorbereich, drei Drag-and-drop-Ziele, Row-Indikator, ausdrückliches Lösen und atomare Löschübergänge mit exaktem Undo/Redo. | -| R8 | abgeschlossen | Rückgabe-Excel für alle, abweichende oder ausgewählte Objekte und append-only Exportnachweis sind umgesetzt. | +| R7 | offen | Editorbereich, Gruppierung, Drag-and-drop, Lösen und integrierte Löschübergänge. | +| R8 | offen | Rückgabe-Excel und append-only Exportnachweis. | | R9 | offen | Vollständiger Folgeimport nach Worksharing-ID. | | R10 | offen | Ende-zu-Ende-Härtung, große Datenmengen und Abschlussdokumentation. | @@ -173,13 +173,6 @@ Sammelaktionen gesperrt und folgen weiterhin ausschließlich ihrer Row. R8 baut auf der in R2 durch Linear bestätigten Transportstrategie auf. -Umsetzungsstand: Die Revit-Objekttabelle erzeugt die Rückgabe revisionssicher -aus dem letzten vollständigen Import. Die gemeinsame Projektion berechnet -Stromkreis, Bezeichnung, Leistung, Spannung und Strom; der XLSX-Adapter erhält -Struktur und Formate und meldet fehlende optionale Spalten. Jeder erfolgreiche -Download wird außerhalb von Projektcommands, Snapshots und Transfers mit -Revision, Importbatch, Konfigurationskopie und Prüfsummen protokolliert. - ## R9 – Folgeimport - exaktes, case-sensitives Matching nach Worksharing-ID; diff --git a/src/app/globals.css b/src/app/globals.css index 67985f4..8b55c75 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1128,17 +1128,6 @@ a.kpi:hover { border-style: dashed; } -.project-device-item > summary { - display: flex; - flex-direction: column; - gap: 0.1rem; - cursor: grab; -} - -.project-device-item > summary::marker { - color: var(--text-faint); -} - .sidebar-actions { display: flex; flex-direction: column; diff --git a/src/app/projects/[projectId]/revit/page.tsx b/src/app/projects/[projectId]/revit/page.tsx index 46c3d5d..fc8b85e 100644 --- a/src/app/projects/[projectId]/revit/page.tsx +++ b/src/app/projects/[projectId]/revit/page.tsx @@ -45,7 +45,7 @@ export default function RevitPage() { {error ?
{error}
: null}

XLSX-Konfiguration

{snapshot ? "Die Linear-Spalten und das Tabellenlayout sind konfiguriert." : "Noch keine XLSX-Konfiguration gespeichert."}

{snapshot ? "Konfiguriert" : "Offen"}

Importstatus

{importStatus?.imported ? <>

{importStatus.objectCount} Revit-Objekte{importStatus.fileName ? ` aus ${importStatus.fileName}` : ""}

Quelle: {importStatus.sourceName}

:

Noch kein Linear-XLSX-Import vorhanden.

}
{importStatus?.imported ? setProject((current) => current ? { ...current, currentRevision: revision } : current)} /> : null} - {settingsOpen ? setSettingsOpen(false)} onInspectSample={async (file, configuration) => { const result = await detectExternalModelWorkbook(projectId, file, configuration); return `Muster erkannt: ${result.sheetName}, ${result.columnCount} Spalten, ${result.objectCount} Objekte.`; }} onSave={save} /> : null} + {settingsOpen ? setSettingsOpen(false)} onInspectSample={async (file, configuration) => { const result = await detectExternalModelWorkbook(projectId, file, configuration); return `Muster erkannt: ${result.sheetName}, ${result.columnCount} Spalten, ${result.objectCount} Objekte.`; }} onSave={save} /> : null} {importOpen && project && snapshot ? setImportOpen(false)} onImported={({ history }) => { setProject({ ...project, currentRevision: history.currentRevision }); setImportOpen(false); void Promise.all([getExternalInitialImportStatus(projectId), getExternalModelConfiguration(projectId)]).then(([status, configuration]) => { setImportStatus(status); setSnapshot(configuration.configuration); }); }} /> : null} ; } diff --git a/src/db/migrations/0015_wide_night_thrasher.sql b/src/db/migrations/0015_wide_night_thrasher.sql deleted file mode 100644 index fcd376b..0000000 --- a/src/db/migrations/0015_wide_night_thrasher.sql +++ /dev/null @@ -1,16 +0,0 @@ -CREATE TABLE `external_export_batches` ( - `id` text PRIMARY KEY NOT NULL, - `project_id` text NOT NULL, - `project_revision` integer NOT NULL, - `import_batch_id` text NOT NULL, - `exported_at_iso` text NOT NULL, - `file_name` text NOT NULL, - `sha256` text NOT NULL, - `configuration_snapshot` text NOT NULL, - `configuration_sha256` text NOT NULL, - `scope` text NOT NULL, - `object_count` integer NOT NULL, - FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE cascade -); ---> statement-breakpoint -CREATE INDEX `external_export_batches_project_exported_idx` ON `external_export_batches` (`project_id`,`exported_at_iso`); \ No newline at end of file diff --git a/src/db/migrations/meta/0015_snapshot.json b/src/db/migrations/meta/0015_snapshot.json deleted file mode 100644 index 9c00cc3..0000000 --- a/src/db/migrations/meta/0015_snapshot.json +++ /dev/null @@ -1,3210 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "eab4abfa-dc46-4330-9ddd-b4676343d610", - "prevId": "b443af16-e0aa-459a-9443-62a7f8c6b6dd", - "tables": { - "buildings": { - "name": "buildings", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": { - "buildings_project_id_projects_id_fk": { - "name": "buildings_project_id_projects_id_fk", - "tableFrom": "buildings", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuit_device_rows": { - "name": "circuit_device_rows", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "circuit_id": { - "name": "circuit_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "linked_project_device_id": { - "name": "linked_project_device_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phase_type": { - "name": "phase_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "connection_kind": { - "name": "connection_kind", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost_group": { - "name": "cost_group", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "level": { - "name": "level", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "room_id": { - "name": "room_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "room_number_snapshot": { - "name": "room_number_snapshot", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "room_name_snapshot": { - "name": "room_name_snapshot", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "quantity": { - "name": "quantity", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "manual_quantity": { - "name": "manual_quantity", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "power_per_unit": { - "name": "power_per_unit", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "simultaneity_factor": { - "name": "simultaneity_factor", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cos_phi": { - "name": "cos_phi", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "remark": { - "name": "remark", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "overridden_fields": { - "name": "overridden_fields", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "circuit_device_rows_circuit_id_idx": { - "name": "circuit_device_rows_circuit_id_idx", - "columns": [ - "circuit_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "circuit_device_rows_circuit_id_circuits_id_fk": { - "name": "circuit_device_rows_circuit_id_circuits_id_fk", - "tableFrom": "circuit_device_rows", - "tableTo": "circuits", - "columnsFrom": [ - "circuit_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_device_rows_linked_project_device_id_project_devices_id_fk": { - "name": "circuit_device_rows_linked_project_device_id_project_devices_id_fk", - "tableFrom": "circuit_device_rows", - "tableTo": "project_devices", - "columnsFrom": [ - "linked_project_device_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "circuit_device_rows_room_id_rooms_id_fk": { - "name": "circuit_device_rows_room_id_rooms_id_fk", - "tableFrom": "circuit_device_rows", - "tableTo": "rooms", - "columnsFrom": [ - "room_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuit_list_equipment_identifiers": { - "name": "circuit_list_equipment_identifiers", - "columns": { - "owner_type": { - "name": "owner_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "owner_id": { - "name": "owner_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "circuit_list_id": { - "name": "circuit_list_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "equipment_identifier": { - "name": "equipment_identifier", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "circuit_list_equipment_identifiers_owner_unique": { - "name": "circuit_list_equipment_identifiers_owner_unique", - "columns": [ - "owner_type", - "owner_id" - ], - "isUnique": true - }, - "circuit_list_equipment_identifiers_list_identifier_unique": { - "name": "circuit_list_equipment_identifiers_list_identifier_unique", - "columns": [ - "circuit_list_id", - "equipment_identifier" - ], - "isUnique": true - } - }, - "foreignKeys": { - "circuit_list_equipment_identifiers_circuit_list_id_circuit_lists_id_fk": { - "name": "circuit_list_equipment_identifiers_circuit_list_id_circuit_lists_id_fk", - "tableFrom": "circuit_list_equipment_identifiers", - "tableTo": "circuit_lists", - "columnsFrom": [ - "circuit_list_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuit_lists": { - "name": "circuit_lists", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "distribution_board_id": { - "name": "distribution_board_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "circuit_lists_distribution_board_id_unique": { - "name": "circuit_lists_distribution_board_id_unique", - "columns": [ - "distribution_board_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "circuit_lists_project_id_projects_id_fk": { - "name": "circuit_lists_project_id_projects_id_fk", - "tableFrom": "circuit_lists", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuit_lists_distribution_board_id_distribution_boards_id_fk": { - "name": "circuit_lists_distribution_board_id_distribution_boards_id_fk", - "tableFrom": "circuit_lists", - "tableTo": "distribution_boards", - "columnsFrom": [ - "distribution_board_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuit_protection_devices": { - "name": "circuit_protection_devices", - "columns": { - "circuit_id": { - "name": "circuit_id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rated_current_a": { - "name": "rated_current_a", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "fuse_utilization_category": { - "name": "fuse_utilization_category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "trip_characteristic": { - "name": "trip_characteristic", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rcd_type": { - "name": "rcd_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rated_residual_current_ma": { - "name": "rated_residual_current_ma", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "circuit_protection_devices_circuit_id_circuits_id_fk": { - "name": "circuit_protection_devices_circuit_id_circuits_id_fk", - "tableFrom": "circuit_protection_devices", - "tableTo": "circuits", - "columnsFrom": [ - "circuit_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuit_sections": { - "name": "circuit_sections", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "circuit_list_id": { - "name": "circuit_list_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "prefix": { - "name": "prefix", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "group_number": { - "name": "group_number", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "circuit_sections_list_key_unique": { - "name": "circuit_sections_list_key_unique", - "columns": [ - "circuit_list_id", - "key" - ], - "isUnique": true - }, - "circuit_sections_list_prefix_unique": { - "name": "circuit_sections_list_prefix_unique", - "columns": [ - "circuit_list_id", - "prefix" - ], - "isUnique": true - }, - "circuit_sections_list_category_group_unique": { - "name": "circuit_sections_list_category_group_unique", - "columns": [ - "circuit_list_id", - "category", - "group_number" - ], - "isUnique": true - } - }, - "foreignKeys": { - "circuit_sections_circuit_list_id_circuit_lists_id_fk": { - "name": "circuit_sections_circuit_list_id_circuit_lists_id_fk", - "tableFrom": "circuit_sections", - "tableTo": "circuit_lists", - "columnsFrom": [ - "circuit_list_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "circuits": { - "name": "circuits", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "circuit_list_id": { - "name": "circuit_list_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "section_id": { - "name": "section_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "equipment_identifier": { - "name": "equipment_identifier", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "cable_type": { - "name": "cable_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cable_cross_section": { - "name": "cable_cross_section", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cable_length": { - "name": "cable_length", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rcd_assignment": { - "name": "rcd_assignment", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "terminal_designation": { - "name": "terminal_designation", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "voltage": { - "name": "voltage", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "control_requirement": { - "name": "control_requirement", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "is_reserve": { - "name": "is_reserve", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "remark": { - "name": "remark", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "circuits_section_id_idx": { - "name": "circuits_section_id_idx", - "columns": [ - "section_id" - ], - "isUnique": false - }, - "circuits_list_equipment_identifier_unique": { - "name": "circuits_list_equipment_identifier_unique", - "columns": [ - "circuit_list_id", - "equipment_identifier" - ], - "isUnique": true - } - }, - "foreignKeys": { - "circuits_circuit_list_id_circuit_lists_id_fk": { - "name": "circuits_circuit_list_id_circuit_lists_id_fk", - "tableFrom": "circuits", - "tableTo": "circuit_lists", - "columnsFrom": [ - "circuit_list_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "circuits_section_id_circuit_sections_id_fk": { - "name": "circuits_section_id_circuit_sections_id_fk", - "tableFrom": "circuits", - "tableTo": "circuit_sections", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "distribution_board_component_protection_devices": { - "name": "distribution_board_component_protection_devices", - "columns": { - "component_id": { - "name": "component_id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "rated_current_a": { - "name": "rated_current_a", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "fuse_utilization_category": { - "name": "fuse_utilization_category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "trip_characteristic": { - "name": "trip_characteristic", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rcd_type": { - "name": "rcd_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "rated_residual_current_ma": { - "name": "rated_residual_current_ma", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "distribution_board_component_protection_devices_component_id_distribution_board_components_id_fk": { - "name": "distribution_board_component_protection_devices_component_id_distribution_board_components_id_fk", - "tableFrom": "distribution_board_component_protection_devices", - "tableTo": "distribution_board_components", - "columnsFrom": [ - "component_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "distribution_board_components": { - "name": "distribution_board_components", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "circuit_list_id": { - "name": "circuit_list_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "section_id": { - "name": "section_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "equipment_identifier": { - "name": "equipment_identifier", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "placement": { - "name": "placement", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - } - }, - "indexes": { - "distribution_board_components_list_identifier_unique": { - "name": "distribution_board_components_list_identifier_unique", - "columns": [ - "circuit_list_id", - "equipment_identifier" - ], - "isUnique": true - }, - "distribution_board_components_section_role_unique": { - "name": "distribution_board_components_section_role_unique", - "columns": [ - "section_id", - "role" - ], - "isUnique": true - } - }, - "foreignKeys": { - "distribution_board_components_circuit_list_id_circuit_lists_id_fk": { - "name": "distribution_board_components_circuit_list_id_circuit_lists_id_fk", - "tableFrom": "distribution_board_components", - "tableTo": "circuit_lists", - "columnsFrom": [ - "circuit_list_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "distribution_board_components_section_id_circuit_sections_id_fk": { - "name": "distribution_board_components_section_id_circuit_sections_id_fk", - "tableFrom": "distribution_board_components", - "tableTo": "circuit_sections", - "columnsFrom": [ - "section_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "distribution_boards": { - "name": "distribution_boards", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "floor_id": { - "name": "floor_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "supply_type": { - "name": "supply_type", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "simultaneity_factor": { - "name": "simultaneity_factor", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "board_number": { - "name": "board_number", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "location": { - "name": "location", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "fed_from": { - "name": "fed_from", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "remark": { - "name": "remark", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "feeding_distribution_board_id": { - "name": "feeding_distribution_board_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "feeding_circuit_id": { - "name": "feeding_circuit_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "distribution_boards_feeding_board_idx": { - "name": "distribution_boards_feeding_board_idx", - "columns": [ - "feeding_distribution_board_id" - ], - "isUnique": false - }, - "distribution_boards_feeding_circuit_idx": { - "name": "distribution_boards_feeding_circuit_idx", - "columns": [ - "feeding_circuit_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "distribution_boards_project_id_projects_id_fk": { - "name": "distribution_boards_project_id_projects_id_fk", - "tableFrom": "distribution_boards", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "distribution_boards_floor_id_floors_id_fk": { - "name": "distribution_boards_floor_id_floors_id_fk", - "tableFrom": "distribution_boards", - "tableTo": "floors", - "columnsFrom": [ - "floor_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "distribution_boards_feeding_distribution_board_id_distribution_boards_id_fk": { - "name": "distribution_boards_feeding_distribution_board_id_distribution_boards_id_fk", - "tableFrom": "distribution_boards", - "tableTo": "distribution_boards", - "columnsFrom": [ - "feeding_distribution_board_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "restrict", - "onUpdate": "no action" - }, - "distribution_boards_feeding_circuit_id_circuits_id_fk": { - "name": "distribution_boards_feeding_circuit_id_circuits_id_fk", - "tableFrom": "distribution_boards", - "tableTo": "circuits", - "columnsFrom": [ - "feeding_circuit_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "restrict", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "document_branding_assets": { - "name": "document_branding_assets", - "columns": { - "key": { - "name": "key", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "mime_type": { - "name": "mime_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "file_name": { - "name": "file_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "data": { - "name": "data", - "type": "blob", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(unixepoch())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "document_branding_settings": { - "name": "document_branding_settings", - "columns": { - "key": { - "name": "key", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(unixepoch())" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "estimate_balances": { - "name": "estimate_balances", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "work_stage": { - "name": "work_stage", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "date_iso": { - "name": "date_iso", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reserve_av_percent": { - "name": "reserve_av_percent", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "reserve_sv_percent": { - "name": "reserve_sv_percent", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - } - }, - "indexes": { - "estimate_balances_project_id_idx": { - "name": "estimate_balances_project_id_idx", - "columns": [ - "project_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "estimate_balances_project_id_projects_id_fk": { - "name": "estimate_balances_project_id_projects_id_fk", - "tableFrom": "estimate_balances", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "estimate_groups": { - "name": "estimate_groups", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "balance_id": { - "name": "balance_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "cost_group": { - "name": "cost_group", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "''" - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "editor": { - "name": "editor", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - } - }, - "indexes": { - "estimate_groups_balance_id_idx": { - "name": "estimate_groups_balance_id_idx", - "columns": [ - "balance_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "estimate_groups_balance_id_estimate_balances_id_fk": { - "name": "estimate_groups_balance_id_estimate_balances_id_fk", - "tableFrom": "estimate_groups", - "tableTo": "estimate_balances", - "columnsFrom": [ - "balance_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "estimate_rows": { - "name": "estimate_rows", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "group_id": { - "name": "group_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "supply": { - "name": "supply", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "''" - }, - "quantity": { - "name": "quantity", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "unit": { - "name": "unit", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'piece'" - }, - "connection": { - "name": "connection", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "power_per_unit_w": { - "name": "power_per_unit_w", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "simultaneity_factor": { - "name": "simultaneity_factor", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "cos_phi": { - "name": "cos_phi", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "safety_supply": { - "name": "safety_supply", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "remark": { - "name": "remark", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "estimate_rows_group_id_idx": { - "name": "estimate_rows_group_id_idx", - "columns": [ - "group_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "estimate_rows_group_id_estimate_groups_id_fk": { - "name": "estimate_rows_group_id_estimate_groups_id_fk", - "tableFrom": "estimate_rows", - "tableTo": "estimate_groups", - "columnsFrom": [ - "group_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_export_batches": { - "name": "external_export_batches", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "project_revision": { - "name": "project_revision", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "import_batch_id": { - "name": "import_batch_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "exported_at_iso": { - "name": "exported_at_iso", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "file_name": { - "name": "file_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sha256": { - "name": "sha256", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "configuration_snapshot": { - "name": "configuration_snapshot", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "configuration_sha256": { - "name": "configuration_sha256", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "object_count": { - "name": "object_count", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "external_export_batches_project_exported_idx": { - "name": "external_export_batches_project_exported_idx", - "columns": [ - "project_id", - "exported_at_iso" - ], - "isUnique": false - } - }, - "foreignKeys": { - "external_export_batches_project_id_projects_id_fk": { - "name": "external_export_batches_project_id_projects_id_fk", - "tableFrom": "external_export_batches", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_import_batches": { - "name": "external_import_batches", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_id": { - "name": "source_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "import_kind": { - "name": "import_kind", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "imported_at_iso": { - "name": "imported_at_iso", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "file_name": { - "name": "file_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sha256": { - "name": "sha256", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "object_count": { - "name": "object_count", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "applied_project_revision": { - "name": "applied_project_revision", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "configuration_snapshot": { - "name": "configuration_snapshot", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "original_bytes": { - "name": "original_bytes", - "type": "blob", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "document": { - "name": "document", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "external_import_batches_project_revision_idx": { - "name": "external_import_batches_project_revision_idx", - "columns": [ - "project_id", - "applied_project_revision" - ], - "isUnique": false - }, - "external_import_batches_source_imported_idx": { - "name": "external_import_batches_source_imported_idx", - "columns": [ - "source_id", - "imported_at_iso" - ], - "isUnique": false - } - }, - "foreignKeys": { - "external_import_batches_project_id_projects_id_fk": { - "name": "external_import_batches_project_id_projects_id_fk", - "tableFrom": "external_import_batches", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "external_import_batches_source_id_external_model_sources_id_fk": { - "name": "external_import_batches_source_id_external_model_sources_id_fk", - "tableFrom": "external_import_batches", - "tableTo": "external_model_sources", - "columnsFrom": [ - "source_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_model_configurations": { - "name": "external_model_configurations", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "configuration": { - "name": "configuration", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "external_model_configurations_project_id_unique": { - "name": "external_model_configurations_project_id_unique", - "columns": [ - "project_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "external_model_configurations_project_id_projects_id_fk": { - "name": "external_model_configurations_project_id_projects_id_fk", - "tableFrom": "external_model_configurations", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_model_objects": { - "name": "external_model_objects", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_id": { - "name": "source_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "worksharing_id": { - "name": "worksharing_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "ifc_guid": { - "name": "ifc_guid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "device_type_id": { - "name": "device_type_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "last_seen_import_batch_id": { - "name": "last_seen_import_batch_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "last_accepted_import_batch_id": { - "name": "last_accepted_import_batch_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "accepted_source_values": { - "name": "accepted_source_values", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "planning_values": { - "name": "planning_values", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "overridden_fields": { - "name": "overridden_fields", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "external_room_mapping_id": { - "name": "external_room_mapping_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "distribution_board_id": { - "name": "distribution_board_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "linked_project_device_id": { - "name": "linked_project_device_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "circuit_device_row_id": { - "name": "circuit_device_row_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "presence_status": { - "name": "presence_status", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'present'" - } - }, - "indexes": { - "external_model_objects_source_worksharing_id_unique": { - "name": "external_model_objects_source_worksharing_id_unique", - "columns": [ - "source_id", - "worksharing_id" - ], - "isUnique": true - }, - "external_model_objects_project_presence_idx": { - "name": "external_model_objects_project_presence_idx", - "columns": [ - "project_id", - "presence_status" - ], - "isUnique": false - }, - "external_model_objects_project_device_type_idx": { - "name": "external_model_objects_project_device_type_idx", - "columns": [ - "project_id", - "device_type_id" - ], - "isUnique": false - }, - "external_model_objects_external_room_mapping_idx": { - "name": "external_model_objects_external_room_mapping_idx", - "columns": [ - "external_room_mapping_id" - ], - "isUnique": false - }, - "external_model_objects_distribution_board_idx": { - "name": "external_model_objects_distribution_board_idx", - "columns": [ - "distribution_board_id" - ], - "isUnique": false - }, - "external_model_objects_linked_project_device_idx": { - "name": "external_model_objects_linked_project_device_idx", - "columns": [ - "linked_project_device_id" - ], - "isUnique": false - }, - "external_model_objects_circuit_device_row_idx": { - "name": "external_model_objects_circuit_device_row_idx", - "columns": [ - "circuit_device_row_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "external_model_objects_project_id_projects_id_fk": { - "name": "external_model_objects_project_id_projects_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "external_model_objects_source_id_external_model_sources_id_fk": { - "name": "external_model_objects_source_id_external_model_sources_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "external_model_sources", - "columnsFrom": [ - "source_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "external_model_objects_last_seen_import_batch_id_external_import_batches_id_fk": { - "name": "external_model_objects_last_seen_import_batch_id_external_import_batches_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "external_import_batches", - "columnsFrom": [ - "last_seen_import_batch_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "restrict", - "onUpdate": "no action" - }, - "external_model_objects_last_accepted_import_batch_id_external_import_batches_id_fk": { - "name": "external_model_objects_last_accepted_import_batch_id_external_import_batches_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "external_import_batches", - "columnsFrom": [ - "last_accepted_import_batch_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "restrict", - "onUpdate": "no action" - }, - "external_model_objects_external_room_mapping_id_external_room_mappings_id_fk": { - "name": "external_model_objects_external_room_mapping_id_external_room_mappings_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "external_room_mappings", - "columnsFrom": [ - "external_room_mapping_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "external_model_objects_distribution_board_id_distribution_boards_id_fk": { - "name": "external_model_objects_distribution_board_id_distribution_boards_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "distribution_boards", - "columnsFrom": [ - "distribution_board_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "external_model_objects_linked_project_device_id_project_devices_id_fk": { - "name": "external_model_objects_linked_project_device_id_project_devices_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "project_devices", - "columnsFrom": [ - "linked_project_device_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "external_model_objects_circuit_device_row_id_circuit_device_rows_id_fk": { - "name": "external_model_objects_circuit_device_row_id_circuit_device_rows_id_fk", - "tableFrom": "external_model_objects", - "tableTo": "circuit_device_rows", - "columnsFrom": [ - "circuit_device_row_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_model_sources": { - "name": "external_model_sources", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_type": { - "name": "source_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'revit_xlsx'" - } - }, - "indexes": { - "external_model_sources_project_unique": { - "name": "external_model_sources_project_unique", - "columns": [ - "project_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "external_model_sources_project_id_projects_id_fk": { - "name": "external_model_sources_project_id_projects_id_fk", - "tableFrom": "external_model_sources", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "external_room_mappings": { - "name": "external_room_mappings", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_id": { - "name": "source_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "normalized_source_room_key": { - "name": "normalized_source_room_key", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_floor_name": { - "name": "source_floor_name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "source_room_number": { - "name": "source_room_number", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_room_name": { - "name": "source_room_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "room_id": { - "name": "room_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "default_distribution_board_id": { - "name": "default_distribution_board_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "external_room_mappings_source_key_unique": { - "name": "external_room_mappings_source_key_unique", - "columns": [ - "source_id", - "normalized_source_room_key" - ], - "isUnique": true - }, - "external_room_mappings_project_room_idx": { - "name": "external_room_mappings_project_room_idx", - "columns": [ - "project_id", - "room_id" - ], - "isUnique": false - } - }, - "foreignKeys": { - "external_room_mappings_project_id_projects_id_fk": { - "name": "external_room_mappings_project_id_projects_id_fk", - "tableFrom": "external_room_mappings", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "external_room_mappings_source_id_external_model_sources_id_fk": { - "name": "external_room_mappings_source_id_external_model_sources_id_fk", - "tableFrom": "external_room_mappings", - "tableTo": "external_model_sources", - "columnsFrom": [ - "source_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "external_room_mappings_room_id_rooms_id_fk": { - "name": "external_room_mappings_room_id_rooms_id_fk", - "tableFrom": "external_room_mappings", - "tableTo": "rooms", - "columnsFrom": [ - "room_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "external_room_mappings_default_distribution_board_id_distribution_boards_id_fk": { - "name": "external_room_mappings_default_distribution_board_id_distribution_boards_id_fk", - "tableFrom": "external_room_mappings", - "tableTo": "distribution_boards", - "columnsFrom": [ - "default_distribution_board_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "floors": { - "name": "floors", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sort_order": { - "name": "sort_order", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "building_id": { - "name": "building_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "floors_project_id_projects_id_fk": { - "name": "floors_project_id_projects_id_fk", - "tableFrom": "floors", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "floors_building_id_buildings_id_fk": { - "name": "floors_building_id_buildings_id_fk", - "tableFrom": "floors", - "tableTo": "buildings", - "columnsFrom": [ - "building_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "global_devices": { - "name": "global_devices", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "quantity": { - "name": "quantity", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "installed_power_per_unit_kw": { - "name": "installed_power_per_unit_kw", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "demand_factor": { - "name": "demand_factor", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "voltage_v": { - "name": "voltage_v", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "phase_count": { - "name": "phase_count", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "power_factor": { - "name": "power_factor", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "note": { - "name": "note", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "project_change_sets": { - "name": "project_change_sets", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_revision_id": { - "name": "project_revision_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "command_type": { - "name": "command_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "payload_schema_version": { - "name": "payload_schema_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "forward_payload_json": { - "name": "forward_payload_json", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "inverse_payload_json": { - "name": "inverse_payload_json", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "project_change_sets_revision_unique": { - "name": "project_change_sets_revision_unique", - "columns": [ - "project_revision_id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "project_change_sets_project_revision_id_project_revisions_id_fk": { - "name": "project_change_sets_project_revision_id_project_revisions_id_fk", - "tableFrom": "project_change_sets", - "tableTo": "project_revisions", - "columnsFrom": [ - "project_revision_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "project_devices": { - "name": "project_devices", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "phase_type": { - "name": "phase_type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'single_phase'" - }, - "connection_kind": { - "name": "connection_kind", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "cost_group": { - "name": "cost_group", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "category": { - "name": "category", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "quantity": { - "name": "quantity", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "power_per_unit": { - "name": "power_per_unit", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "simultaneity_factor": { - "name": "simultaneity_factor", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 1 - }, - "cos_phi": { - "name": "cos_phi", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "remark": { - "name": "remark", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "voltage_v": { - "name": "voltage_v", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "project_devices_project_id_projects_id_fk": { - "name": "project_devices_project_id_projects_id_fk", - "tableFrom": "project_devices", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "project_history_stack_entries": { - "name": "project_history_stack_entries", - "columns": { - "change_set_id": { - "name": "change_set_id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "stack": { - "name": "stack", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "position": { - "name": "position", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "project_history_stack_entries_position_unique": { - "name": "project_history_stack_entries_position_unique", - "columns": [ - "project_id", - "stack", - "position" - ], - "isUnique": true - } - }, - "foreignKeys": { - "project_history_stack_entries_change_set_id_project_change_sets_id_fk": { - "name": "project_history_stack_entries_change_set_id_project_change_sets_id_fk", - "tableFrom": "project_history_stack_entries", - "tableTo": "project_change_sets", - "columnsFrom": [ - "change_set_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "project_history_stack_entries_project_id_projects_id_fk": { - "name": "project_history_stack_entries_project_id_projects_id_fk", - "tableFrom": "project_history_stack_entries", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": { - "project_history_stack_entries_stack_check": { - "name": "project_history_stack_entries_stack_check", - "value": "\"project_history_stack_entries\".\"stack\" in ('undo', 'redo')" - } - } - }, - "project_revisions": { - "name": "project_revisions", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "revision_number": { - "name": "revision_number", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at_iso": { - "name": "created_at_iso", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "actor_id": { - "name": "actor_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "source": { - "name": "source", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "project_revisions_project_number_unique": { - "name": "project_revisions_project_number_unique", - "columns": [ - "project_id", - "revision_number" - ], - "isUnique": true - } - }, - "foreignKeys": { - "project_revisions_project_id_projects_id_fk": { - "name": "project_revisions_project_id_projects_id_fk", - "tableFrom": "project_revisions", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "project_snapshots": { - "name": "project_snapshots", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "source_revision": { - "name": "source_revision", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "schema_version": { - "name": "schema_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "kind": { - "name": "kind", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'named'" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "payload_json": { - "name": "payload_json", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "payload_sha256": { - "name": "payload_sha256", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_at_iso": { - "name": "created_at_iso", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "created_by_actor_id": { - "name": "created_by_actor_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "project_snapshots_project_created_idx": { - "name": "project_snapshots_project_created_idx", - "columns": [ - "project_id", - "created_at_iso" - ], - "isUnique": false - }, - "project_snapshots_project_kind_revision_idx": { - "name": "project_snapshots_project_kind_revision_idx", - "columns": [ - "project_id", - "kind", - "source_revision" - ], - "isUnique": false - }, - "project_snapshots_project_name_unique": { - "name": "project_snapshots_project_name_unique", - "columns": [ - "project_id", - "name" - ], - "isUnique": true - } - }, - "foreignKeys": { - "project_snapshots_project_id_projects_id_fk": { - "name": "project_snapshots_project_id_projects_id_fk", - "tableFrom": "project_snapshots", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "projects": { - "name": "projects", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "internal_project_number": { - "name": "internal_project_number", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "external_project_number": { - "name": "external_project_number", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "building_owner": { - "name": "building_owner", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "is_public_building": { - "name": "is_public_building", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "single_phase_voltage_v": { - "name": "single_phase_voltage_v", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 230 - }, - "three_phase_voltage_v": { - "name": "three_phase_voltage_v", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 400 - }, - "enabled_distribution_board_supply_types": { - "name": "enabled_distribution_board_supply_types", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'[\"AV\",\"SV\",\"EV\",\"USV\",\"MSR\",\"SiBe\"]'" - }, - "site_address": { - "name": "site_address", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "work_stage": { - "name": "work_stage", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "project_lead": { - "name": "project_lead", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "project_editor": { - "name": "project_editor", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "current_revision": { - "name": "current_revision", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "rooms": { - "name": "rooms", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "project_id": { - "name": "project_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "floor_id": { - "name": "floor_id", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "room_number": { - "name": "room_number", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "room_name": { - "name": "room_name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "area_m2": { - "name": "area_m2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "rooms_project_id_projects_id_fk": { - "name": "rooms_project_id_projects_id_fk", - "tableFrom": "rooms", - "tableTo": "projects", - "columnsFrom": [ - "project_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "rooms_floor_id_floors_id_fk": { - "name": "rooms_floor_id_floors_id_fk", - "tableFrom": "rooms", - "tableTo": "floors", - "columnsFrom": [ - "floor_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "password_hash": { - "name": "password_hash", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "'user'" - }, - "active": { - "name": "active", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "must_change_password": { - "name": "must_change_password", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": true - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(unixepoch())" - }, - "updated_at": { - "name": "updated_at", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(unixepoch())" - } - }, - "indexes": { - "users_username_unique": { - "name": "users_username_unique", - "columns": [ - "username" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/src/db/migrations/meta/_journal.json b/src/db/migrations/meta/_journal.json index 0ab138e..0f6c303 100644 --- a/src/db/migrations/meta/_journal.json +++ b/src/db/migrations/meta/_journal.json @@ -106,13 +106,6 @@ "when": 1790748107566, "tag": "0014_linear_xlsx_external_model", "breakpoints": true - }, - { - "idx": 15, - "version": "6", - "when": 1790773066696, - "tag": "0015_wide_night_thrasher", - "breakpoints": true } ] } \ No newline at end of file diff --git a/src/db/repositories/circuit-device-row-structure-project-command.repository.ts b/src/db/repositories/circuit-device-row-structure-project-command.repository.ts index f69dc78..6919d20 100644 --- a/src/db/repositories/circuit-device-row-structure-project-command.repository.ts +++ b/src/db/repositories/circuit-device-row-structure-project-command.repository.ts @@ -23,15 +23,8 @@ import { toCircuitDeviceRowInsertValues, toCircuitDeviceRowSnapshot, } from "./circuit-device-row-structure.persistence.js"; -import { executeProjectCommandTransactionWithAppliedForward, type AppliedProjectCommand } from "./project-command-transaction.persistence.js"; +import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; import { updateDerivedCircuitVoltage } from "./project-voltage.persistence.js"; -import { - applyExternalObjectLinks, - captureExternalObjectDetachTransitions, - invertExternalObjectLinkTransitions, - loadExpectedExternalObjectTransitions, - type ExternalObjectLinkTransition, -} from "./external-object-assignment.persistence.js"; export class CircuitDeviceRowStructureProjectCommandRepository implements CircuitDeviceRowStructureProjectCommandStore @@ -39,11 +32,7 @@ export class CircuitDeviceRowStructureProjectCommandRepository constructor(private readonly database: AppDatabase) {} execute(input: ExecuteCircuitDeviceRowStructureCommandInput) { - return executeProjectCommandTransactionWithAppliedForward< - CircuitDeviceRowStructureProjectCommand, - CircuitDeviceRowStructureProjectCommand, - CircuitDeviceRowStructureProjectCommand - >( + return executeProjectCommandTransaction( this.database, input, (tx) => @@ -61,15 +50,14 @@ export class CircuitDeviceRowStructureProjectCommandRepository projectId: string, source: ExecuteCircuitDeviceRowStructureCommandInput["source"], command: CircuitDeviceRowStructureProjectCommand - ): AppliedProjectCommand { + ): CircuitDeviceRowStructureProjectCommand { if (command.type === circuitDeviceRowInsertCommandType) { assertCircuitDeviceRowInsertProjectCommand(command); return this.insert( database, projectId, source, - command.payload.row, - command.payload.externalObjects ?? [] + command.payload.row ); } if (command.type === circuitDeviceRowDeleteCommandType) { @@ -78,8 +66,7 @@ export class CircuitDeviceRowStructureProjectCommandRepository database, projectId, command.payload.rowId, - command.payload.expectedCircuitId, - command.payload.externalObjects + command.payload.expectedCircuitId ); } throw new Error("Unsupported circuit device-row structure command."); @@ -89,8 +76,7 @@ export class CircuitDeviceRowStructureProjectCommandRepository database: AppDatabase, projectId: string, source: ExecuteCircuitDeviceRowStructureCommandInput["source"], - row: CircuitDeviceRowSnapshot, - externalObjects: ExternalObjectLinkTransition[] + row: CircuitDeviceRowSnapshot ) { if (source === "user" && !isElectricalPhaseType(row.phaseType)) { throw new Error("Device-row phase type is invalid."); @@ -121,23 +107,17 @@ export class CircuitDeviceRowStructureProjectCommandRepository } updateDerivedCircuitVoltage(database, projectId, row.circuitId); - if (externalObjects.length > 0) { - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Wiederherstellen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Wiederherstellen geändert."); - } - - return { - forward: createCircuitDeviceRowInsertProjectCommand(row, externalObjects), - inverse: createCircuitDeviceRowDeleteProjectCommand(row.id, row.circuitId, invertExternalObjectLinkTransitions(externalObjects)), - }; + return createCircuitDeviceRowDeleteProjectCommand( + row.id, + row.circuitId + ); } private delete( database: AppDatabase, projectId: string, rowId: string, - expectedCircuitId: string, - suppliedExternalObjects?: ExternalObjectLinkTransition[] + expectedCircuitId: string ) { const row = database .select() @@ -150,10 +130,6 @@ export class CircuitDeviceRowStructureProjectCommandRepository ); } this.assertCircuitInProject(database, projectId, row.circuitId); - const externalObjects = suppliedExternalObjects ?? - captureExternalObjectDetachTransitions(database, projectId, [rowId]); - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Löschen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Löschen geändert."); const result = database .delete(circuitDeviceRows) @@ -188,10 +164,9 @@ export class CircuitDeviceRowStructureProjectCommandRepository expectedCircuitId ); - return { - forward: createCircuitDeviceRowDeleteProjectCommand(rowId, expectedCircuitId, externalObjects), - inverse: createCircuitDeviceRowInsertProjectCommand(toCircuitDeviceRowSnapshot(row), invertExternalObjectLinkTransitions(externalObjects)), - }; + return createCircuitDeviceRowInsertProjectCommand( + toCircuitDeviceRowSnapshot(row) + ); } private assertCircuitInProject( diff --git a/src/db/repositories/circuit-group-subtree-project-command.repository.ts b/src/db/repositories/circuit-group-subtree-project-command.repository.ts index b4baeb6..9bf27a0 100644 --- a/src/db/repositories/circuit-group-subtree-project-command.repository.ts +++ b/src/db/repositories/circuit-group-subtree-project-command.repository.ts @@ -25,14 +25,8 @@ import { circuits } from "../schema/circuits.js"; import { distributionBoardComponentProtectionDevices } from "../schema/distribution-board-component-protection-devices.js"; import { distributionBoardComponents } from "../schema/distribution-board-components.js"; import { toCircuitDeviceRowInsertValues } from "./circuit-device-row-structure.persistence.js"; -import { executeProjectCommandTransactionWithAppliedForward, type AppliedProjectCommand } from "./project-command-transaction.persistence.js"; +import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; import { assertCircuitsAreNotReferencedAsFeeders } from "./distribution-board-feeding-deletion-guard.persistence.js"; -import { - applyExternalObjectLinks, - captureExternalObjectDetachTransitions, - invertExternalObjectLinkTransitions, - loadExpectedExternalObjectTransitions, -} from "./external-object-assignment.persistence.js"; export class CircuitGroupSubtreeProjectCommandRepository implements CircuitGroupSubtreeProjectCommandStore @@ -49,11 +43,7 @@ export class CircuitGroupSubtreeProjectCommandRepository } else { assertCircuitGroupRestoreSubtreeProjectCommand(input.command); } - return executeProjectCommandTransactionWithAppliedForward< - CircuitGroupSubtreeProjectCommand, - CircuitGroupSubtreeProjectCommand, - CircuitGroupSubtreeProjectCommand - >( + return executeProjectCommandTransaction( this.database, input, (tx) => this.applyCommand(tx, input.projectId, input.command) @@ -64,7 +54,7 @@ export class CircuitGroupSubtreeProjectCommandRepository database: AppDatabase, projectId: string, command: CircuitGroupSubtreeProjectCommand - ): AppliedProjectCommand { + ) { if (command.type === circuitGroupDeleteSubtreeCommandType) { const current = this.captureFrom( database, @@ -81,14 +71,6 @@ export class CircuitGroupSubtreeProjectCommandRepository projectId, current.circuits.map((entry) => entry.circuit.id) ); - const externalObjects = command.payload.externalObjects ?? - captureExternalObjectDetachTransitions( - database, - projectId, - current.circuits.flatMap((entry) => entry.circuit.deviceRows.map((row) => row.id)) - ); - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Löschen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Löschen geändert."); const deleted = database .delete(circuitSections) .where(eq(circuitSections.id, current.group.id)) @@ -96,20 +78,15 @@ export class CircuitGroupSubtreeProjectCommandRepository if (deleted.changes !== 1) { throw new Error("Circuit-group subtree could not be deleted."); } - return { - forward: createCircuitGroupDeleteSubtreeProjectCommand(command.payload.snapshot, externalObjects), - inverse: createCircuitGroupRestoreSubtreeProjectCommand(command.payload.snapshot, invertExternalObjectLinkTransitions(externalObjects)), - }; + return createCircuitGroupRestoreSubtreeProjectCommand( + command.payload.snapshot + ); } if (command.type === circuitGroupRestoreSubtreeCommandType) { this.restore(database, projectId, command.payload.snapshot); - const externalObjects = command.payload.externalObjects ?? []; - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Wiederherstellen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Wiederherstellen geändert."); - return { - forward: createCircuitGroupRestoreSubtreeProjectCommand(command.payload.snapshot, externalObjects), - inverse: createCircuitGroupDeleteSubtreeProjectCommand(command.payload.snapshot, invertExternalObjectLinkTransitions(externalObjects)), - }; + return createCircuitGroupDeleteSubtreeProjectCommand( + command.payload.snapshot + ); } throw new Error("Unsupported circuit-group subtree command."); } diff --git a/src/db/repositories/circuit-structure-project-command.repository.ts b/src/db/repositories/circuit-structure-project-command.repository.ts index f4fc420..4841616 100644 --- a/src/db/repositories/circuit-structure-project-command.repository.ts +++ b/src/db/repositories/circuit-structure-project-command.repository.ts @@ -25,17 +25,10 @@ import { toCircuitDeviceRowInsertValues, toCircuitDeviceRowSnapshot, } from "./circuit-device-row-structure.persistence.js"; -import { executeProjectCommandTransactionWithAppliedForward, type AppliedProjectCommand } from "./project-command-transaction.persistence.js"; +import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; import { assertCircuitsAreNotReferencedAsFeeders } from "./distribution-board-feeding-deletion-guard.persistence.js"; import { resolveCircuitVoltage } from "./project-voltage.persistence.js"; import { assertEquipmentIdentifierAvailable } from "./equipment-identifier-uniqueness.persistence.js"; -import { - applyExternalObjectLinks, - captureExternalObjectDetachTransitions, - invertExternalObjectLinkTransitions, - loadExpectedExternalObjectTransitions, - type ExternalObjectLinkTransition, -} from "./external-object-assignment.persistence.js"; export class CircuitStructureProjectCommandRepository implements CircuitStructureProjectCommandStore @@ -43,15 +36,11 @@ export class CircuitStructureProjectCommandRepository constructor(private readonly database: AppDatabase) {} execute(input: ExecuteCircuitStructureCommandInput) { - return executeProjectCommandTransactionWithAppliedForward< - CircuitStructureProjectCommand, - CircuitStructureProjectCommand, - CircuitStructureProjectCommand - >( + return executeProjectCommandTransaction( this.database, input, (tx) => - this.applyWithForward( + this.applyInTransaction( tx, input.projectId, input.source, @@ -70,23 +59,13 @@ export class CircuitStructureProjectCommandRepository source: ExecuteCircuitStructureCommandInput["source"], command: CircuitStructureProjectCommand ): CircuitStructureProjectCommand { - return this.applyWithForward(database, projectId, source, command).inverse; - } - - private applyWithForward( - database: AppDatabase, - projectId: string, - source: ExecuteCircuitStructureCommandInput["source"], - command: CircuitStructureProjectCommand - ): AppliedProjectCommand { if (command.type === circuitInsertCommandType) { assertCircuitInsertProjectCommand(command); return this.insert( database, projectId, source, - command.payload.circuit, - command.payload.externalObjects ?? [] + command.payload.circuit ); } if (command.type === circuitDeleteCommandType) { @@ -95,8 +74,7 @@ export class CircuitStructureProjectCommandRepository database, projectId, command.payload.circuitId, - command.payload.expectedCircuitListId, - command.payload.externalObjects + command.payload.expectedCircuitListId ); } throw new Error("Unsupported circuit structure command."); @@ -106,8 +84,7 @@ export class CircuitStructureProjectCommandRepository database: AppDatabase, projectId: string, source: ExecuteCircuitStructureCommandInput["source"], - snapshot: CircuitSnapshot, - externalObjects: ExternalObjectLinkTransition[] + snapshot: CircuitSnapshot ) { this.assertCircuitLocation(database, projectId, snapshot); if (source === "user") { @@ -195,23 +172,17 @@ export class CircuitStructureProjectCommandRepository .run(); } - if (externalObjects.length > 0) { - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Wiederherstellen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Wiederherstellen geändert."); - } - - return { - forward: createCircuitInsertProjectCommand(snapshot, externalObjects), - inverse: createCircuitDeleteProjectCommand(snapshot.id, snapshot.circuitListId, invertExternalObjectLinkTransitions(externalObjects)), - }; + return createCircuitDeleteProjectCommand( + snapshot.id, + snapshot.circuitListId + ); } private delete( database: AppDatabase, projectId: string, circuitId: string, - expectedCircuitListId: string, - suppliedExternalObjects?: ExternalObjectLinkTransition[] + expectedCircuitListId: string ) { const circuit = database .select() @@ -249,12 +220,7 @@ export class CircuitStructureProjectCommandRepository .from(circuitProtectionDevices) .where(eq(circuitProtectionDevices.circuitId, circuit.id)) .get(); - const externalObjects = suppliedExternalObjects ?? captureExternalObjectDetachTransitions( - database, projectId, rows.map((row) => row.id) - ); - loadExpectedExternalObjectTransitions(database, projectId, externalObjects, "Revit-Objekt wurde vor dem Löschen geändert."); - applyExternalObjectLinks(database, externalObjects, "Revit-Objekt wurde beim Löschen geändert."); - const circuitSnapshot: CircuitSnapshot = { + const inverse = createCircuitInsertProjectCommand({ id: circuit.id, circuitListId: circuit.circuitListId, sectionId: circuit.sectionId, @@ -273,7 +239,7 @@ export class CircuitStructureProjectCommandRepository remark: circuit.remark, deviceRows: rows.map(toCircuitDeviceRowSnapshot), protectionDevice: protectionDevice ?? null, - }; + }); assertCircuitsAreNotReferencedAsFeeders(database, projectId, [circuit.id]); @@ -289,10 +255,7 @@ export class CircuitStructureProjectCommandRepository if (result.changes !== 1) { throw new Error("Circuit could not be deleted."); } - return { - forward: createCircuitDeleteProjectCommand(circuitId, expectedCircuitListId, externalObjects), - inverse: createCircuitInsertProjectCommand(circuitSnapshot, invertExternalObjectLinkTransitions(externalObjects)), - }; + return inverse; } private assertCircuitLocation( diff --git a/src/db/repositories/distribution-board-structure-project-command.repository.ts b/src/db/repositories/distribution-board-structure-project-command.repository.ts index f7003c5..115705b 100644 --- a/src/db/repositories/distribution-board-structure-project-command.repository.ts +++ b/src/db/repositories/distribution-board-structure-project-command.repository.ts @@ -46,7 +46,6 @@ import { floors } from "../schema/floors.js"; import { projects } from "../schema/projects.js"; import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; import { assertBoardsAreNotReferencedAsFeeders } from "./distribution-board-feeding-deletion-guard.persistence.js"; -import { assertDistributionBoardHasNoExternalObjects } from "./external-object-deletion-guard.persistence.js"; import { CircuitStructureProjectCommandRepository } from "./circuit-structure-project-command.repository.js"; export class DistributionBoardStructureProjectCommandRepository @@ -291,7 +290,6 @@ export class DistributionBoardStructureProjectCommandRepository } assertBoardsAreNotReferencedAsFeeders(database, projectId, [board.id]); - assertDistributionBoardHasNoExternalObjects(database, projectId, board.id); const deleted = database .delete(distributionBoards) diff --git a/src/db/repositories/distribution-board-subtree-project-command.repository.ts b/src/db/repositories/distribution-board-subtree-project-command.repository.ts index b32fee5..969c287 100644 --- a/src/db/repositories/distribution-board-subtree-project-command.repository.ts +++ b/src/db/repositories/distribution-board-subtree-project-command.repository.ts @@ -33,7 +33,6 @@ import { rooms } from "../schema/rooms.js"; import { toCircuitDeviceRowInsertValues } from "./circuit-device-row-structure.persistence.js"; import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; import { assertBoardsAreNotReferencedAsFeeders } from "./distribution-board-feeding-deletion-guard.persistence.js"; -import { assertDistributionBoardHasNoExternalObjects } from "./external-object-deletion-guard.persistence.js"; export class DistributionBoardSubtreeProjectCommandRepository implements DistributionBoardSubtreeProjectCommandStore @@ -87,7 +86,6 @@ export class DistributionBoardSubtreeProjectCommandRepository assertBoardsAreNotReferencedAsFeeders(database, projectId, [ current.distributionBoard.id, ]); - assertDistributionBoardHasNoExternalObjects(database, projectId, current.distributionBoard.id); const deleted = database .delete(distributionBoards) .where( diff --git a/src/db/repositories/external-export-batch.repository.ts b/src/db/repositories/external-export-batch.repository.ts deleted file mode 100644 index c8f7a7d..0000000 --- a/src/db/repositories/external-export-batch.repository.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { desc, eq } from "drizzle-orm"; -import type { AppDatabase } from "../database-context.js"; -import { externalExportBatches } from "../schema/external-export-batches.js"; - -export class ExternalExportBatchRepository { - constructor(private readonly database: AppDatabase) {} - - append(batch: typeof externalExportBatches.$inferInsert) { - this.database.insert(externalExportBatches).values(batch).run(); - return batch; - } - - listByProject(projectId: string) { - return this.database.select().from(externalExportBatches) - .where(eq(externalExportBatches.projectId, projectId)) - .orderBy(desc(externalExportBatches.exportedAtIso), desc(externalExportBatches.id)).all(); - } -} diff --git a/src/db/repositories/external-object-assignment.persistence.ts b/src/db/repositories/external-object-assignment.persistence.ts index 505481d..1111730 100644 --- a/src/db/repositories/external-object-assignment.persistence.ts +++ b/src/db/repositories/external-object-assignment.persistence.ts @@ -11,27 +11,6 @@ export interface ExternalObjectLinkTransition { target: ExternalModelObjectSnapshot; } -export function captureExternalObjectDetachTransitions( - database: AppDatabase, - projectId: string, - rowIds: string[] -): ExternalObjectLinkTransition[] { - if (rowIds.length === 0) return []; - return database.select().from(externalModelObjects) - .where(and( - eq(externalModelObjects.projectId, projectId), - inArray(externalModelObjects.circuitDeviceRowId, rowIds) - )).all() - .map(toExternalObjectSnapshot) - .map((expected) => ({ expected, target: { ...expected, circuitDeviceRowId: null } })); -} - -export function invertExternalObjectLinkTransitions( - transitions: ExternalObjectLinkTransition[] -): ExternalObjectLinkTransition[] { - return transitions.map(({ expected, target }) => ({ expected: target, target: expected })); -} - export function loadExpectedExternalObjectTransitions( database: AppDatabase, projectId: string, @@ -107,13 +86,7 @@ export function applyExternalObjectLinks( ) { for (const { expected, target } of transitions) { const updated = database.update(externalModelObjects) - .set({ - circuitDeviceRowId: target.circuitDeviceRowId, - distributionBoardId: target.distributionBoardId, - linkedProjectDeviceId: target.linkedProjectDeviceId, - planningValues: target.planningValues, - overriddenFields: target.overriddenFields, - }) + .set({ circuitDeviceRowId: target.circuitDeviceRowId }) .where(and( eq(externalModelObjects.id, expected.id), expected.circuitDeviceRowId === null diff --git a/src/db/repositories/external-object-deletion-guard.persistence.ts b/src/db/repositories/external-object-deletion-guard.persistence.ts deleted file mode 100644 index 45fdac7..0000000 --- a/src/db/repositories/external-object-deletion-guard.persistence.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { and, eq } from "drizzle-orm"; -import type { AppDatabase } from "../database-context.js"; -import { externalModelObjects } from "../schema/external-model-objects.js"; -import { externalRoomMappings } from "../schema/external-room-mappings.js"; - -export function assertDistributionBoardHasNoExternalObjects( - database: AppDatabase, - projectId: string, - distributionBoardId: string -) { - const reference = database.select({ id: externalModelObjects.id }) - .from(externalModelObjects) - .where(and( - eq(externalModelObjects.projectId, projectId), - eq(externalModelObjects.distributionBoardId, distributionBoardId) - )).limit(1).get(); - if (reference) { - throw new Error("Der Verteiler kann nicht gelöscht werden, solange Revit-Objekte auf ihn verweisen."); - } -} - -export function assertRoomHasNoExternalObjects( - database: AppDatabase, - projectId: string, - roomId: string -) { - const reference = database.select({ id: externalModelObjects.id }) - .from(externalModelObjects) - .innerJoin(externalRoomMappings, eq(externalRoomMappings.id, externalModelObjects.externalRoomMappingId)) - .where(and( - eq(externalModelObjects.projectId, projectId), - eq(externalRoomMappings.roomId, roomId) - )).limit(1).get(); - if (reference) { - throw new Error("Der Raum kann nicht gelöscht werden, solange Revit-Objekte auf ihn verweisen."); - } -} diff --git a/src/db/repositories/project-location-structure-project-command.repository.ts b/src/db/repositories/project-location-structure-project-command.repository.ts index 40a1743..51edb3b 100644 --- a/src/db/repositories/project-location-structure-project-command.repository.ts +++ b/src/db/repositories/project-location-structure-project-command.repository.ts @@ -46,7 +46,6 @@ import { distributionBoards } from "../schema/distribution-boards.js"; import { projects } from "../schema/projects.js"; import { rooms } from "../schema/rooms.js"; import { executeProjectCommandTransaction } from "./project-command-transaction.persistence.js"; -import { assertRoomHasNoExternalObjects } from "./external-object-deletion-guard.persistence.js"; export class ProjectLocationStructureProjectCommandRepository implements ProjectLocationStructureProjectCommandStore @@ -440,7 +439,6 @@ export class ProjectLocationStructureProjectCommandRepository "Der Raum kann nicht gelöscht werden, solange er in einem Stromkreis verwendet wird." ); } - assertRoomHasNoExternalObjects(database, projectId, expected.id); const deleted = database .delete(rooms) .where( diff --git a/src/db/schema/external-export-batches.ts b/src/db/schema/external-export-batches.ts deleted file mode 100644 index 37e94d8..0000000 --- a/src/db/schema/external-export-batches.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { index, integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; -import type { ExternalModelConfiguration } from "../../external-model/configuration/external-model-configuration.js"; -import { projects } from "./projects.js"; - -export const externalExportScopes = ["all", "deviating", "selected"] as const; -export type ExternalExportScope = (typeof externalExportScopes)[number]; - -export const externalExportBatches = sqliteTable( - "external_export_batches", - { - id: text("id").primaryKey(), - projectId: text("project_id").notNull().references(() => projects.id, { onDelete: "cascade" }), - projectRevision: integer("project_revision").notNull(), - importBatchId: text("import_batch_id").notNull(), - exportedAtIso: text("exported_at_iso").notNull(), - fileName: text("file_name").notNull(), - sha256: text("sha256").notNull(), - configurationSnapshot: text("configuration_snapshot", { mode: "json" }).$type().notNull(), - configurationSha256: text("configuration_sha256").notNull(), - scope: text("scope", { enum: externalExportScopes }).notNull(), - objectCount: integer("object_count").notNull(), - }, - (table) => [index("external_export_batches_project_exported_idx").on(table.projectId, table.exportedAtIso)] -); diff --git a/src/domain/models/circuit-device-row-structure-project-command.model.ts b/src/domain/models/circuit-device-row-structure-project-command.model.ts index ebba5ac..2464a27 100644 --- a/src/domain/models/circuit-device-row-structure-project-command.model.ts +++ b/src/domain/models/circuit-device-row-structure-project-command.model.ts @@ -1,11 +1,4 @@ import type { SerializedProjectCommand } from "./project-command.model.js"; -import type { ExternalModelObjectSnapshot } from "../../external-model/domain/external-model-contracts.js"; -import { parseExternalModelStateSnapshot } from "./project-state-snapshot.model.js"; - -export interface ExternalObjectLinkSnapshotTransition { - expected: ExternalModelObjectSnapshot; - target: ExternalModelObjectSnapshot; -} export const circuitDeviceRowInsertCommandType = "circuit-device-row.insert" as const; @@ -39,13 +32,11 @@ export interface CircuitDeviceRowSnapshot { export interface CircuitDeviceRowInsertCommandPayload { row: CircuitDeviceRowSnapshot; - externalObjects?: ExternalObjectLinkSnapshotTransition[]; } export interface CircuitDeviceRowDeleteCommandPayload { rowId: string; expectedCircuitId: string; - externalObjects?: ExternalObjectLinkSnapshotTransition[]; } export interface CircuitDeviceRowInsertProjectCommand @@ -65,8 +56,7 @@ export type CircuitDeviceRowStructureProjectCommand = | CircuitDeviceRowDeleteProjectCommand; export function createCircuitDeviceRowInsertProjectCommand( - row: CircuitDeviceRowSnapshot, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + row: CircuitDeviceRowSnapshot ): CircuitDeviceRowInsertProjectCommand { const normalizedRow = { ...row, @@ -75,7 +65,7 @@ export function createCircuitDeviceRowInsertProjectCommand( const command: CircuitDeviceRowInsertProjectCommand = { schemaVersion: circuitDeviceRowStructureCommandSchemaVersion, type: circuitDeviceRowInsertCommandType, - payload: { row: normalizedRow, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { row: normalizedRow }, }; assertCircuitDeviceRowInsertProjectCommand(command); return command; @@ -83,13 +73,12 @@ export function createCircuitDeviceRowInsertProjectCommand( export function createCircuitDeviceRowDeleteProjectCommand( rowId: string, - expectedCircuitId: string, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + expectedCircuitId: string ): CircuitDeviceRowDeleteProjectCommand { const command: CircuitDeviceRowDeleteProjectCommand = { schemaVersion: circuitDeviceRowStructureCommandSchemaVersion, type: circuitDeviceRowDeleteCommandType, - payload: { rowId, expectedCircuitId, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { rowId, expectedCircuitId }, }; assertCircuitDeviceRowDeleteProjectCommand(command); return command; @@ -154,7 +143,6 @@ export function assertCircuitDeviceRowInsertProjectCommand( throw new Error("row.cosPhi must be positive or null."); } } - assertExternalObjectLinkTransitions(command.payload.externalObjects); } export function assertCircuitDeviceRowDeleteProjectCommand( @@ -175,41 +163,6 @@ export function assertCircuitDeviceRowDeleteProjectCommand( command.payload.expectedCircuitId, "expectedCircuitId" ); - assertExternalObjectLinkTransitions(command.payload.externalObjects); -} - -export function assertExternalObjectLinkTransitions(value: unknown) { - if (value === undefined) return; - if (!Array.isArray(value)) throw new Error("externalObjects must be an array."); - const ids = new Set(); - for (const transition of value) { - if (!isPlainObject(transition) || !isPlainObject(transition.expected) || !isPlainObject(transition.target)) { - throw new Error("Invalid external object link transition."); - } - const expectedId = transition.expected.id; - const targetId = transition.target.id; - if (typeof expectedId !== "string" || expectedId !== targetId || ids.has(expectedId)) { - throw new Error("External object link transition has mismatched or duplicate ids."); - } - ids.add(expectedId); - const expectedRowId = transition.expected.circuitDeviceRowId; - const targetRowId = transition.target.circuitDeviceRowId; - if ((expectedRowId !== null && typeof expectedRowId !== "string") || (targetRowId !== null && typeof targetRowId !== "string")) { - throw new Error("Invalid external object row link."); - } - const parsed = parseExternalModelStateSnapshot({ source: null, importBatches: [], roomMappings: [], objects: [transition.expected, transition.target] }).objects; - const expectedRest = { ...parsed[0], circuitDeviceRowId: null }; - const targetRest = { ...parsed[1], circuitDeviceRowId: null }; - if (canonicalJson(expectedRest) !== canonicalJson(targetRest) || expectedRowId === targetRowId) { - throw new Error("External object transition may only change the row link."); - } - } -} - -function canonicalJson(value: unknown): string { - if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`; - if (isPlainObject(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`; - return JSON.stringify(value) ?? "null"; } function assertNonEmptyString(value: unknown, field: string) { diff --git a/src/domain/models/circuit-group-subtree-project-command.model.ts b/src/domain/models/circuit-group-subtree-project-command.model.ts index 4470cd2..a3e53b3 100644 --- a/src/domain/models/circuit-group-subtree-project-command.model.ts +++ b/src/domain/models/circuit-group-subtree-project-command.model.ts @@ -3,7 +3,6 @@ import { type CircuitGroupSubtreeSnapshot, } from "./circuit-group-subtree-snapshot.model.js"; import type { SerializedProjectCommand } from "./project-command.model.js"; -import { assertExternalObjectLinkTransitions, type ExternalObjectLinkSnapshotTransition } from "./circuit-device-row-structure-project-command.model.js"; export const circuitGroupDeleteSubtreeCommandType = "circuit-group.delete-subtree" as const; @@ -13,7 +12,6 @@ export const circuitGroupSubtreeCommandSchemaVersion = 1 as const; interface Payload { snapshot: CircuitGroupSubtreeSnapshot; - externalObjects?: ExternalObjectLinkSnapshotTransition[]; } export interface CircuitGroupDeleteSubtreeProjectCommand @@ -33,26 +31,24 @@ export type CircuitGroupSubtreeProjectCommand = | CircuitGroupRestoreSubtreeProjectCommand; export function createCircuitGroupDeleteSubtreeProjectCommand( - snapshot: CircuitGroupSubtreeSnapshot, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + snapshot: CircuitGroupSubtreeSnapshot ): CircuitGroupDeleteSubtreeProjectCommand { const command: CircuitGroupDeleteSubtreeProjectCommand = { schemaVersion: circuitGroupSubtreeCommandSchemaVersion, type: circuitGroupDeleteSubtreeCommandType, - payload: { snapshot, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { snapshot }, }; assertCircuitGroupDeleteSubtreeProjectCommand(command); return command; } export function createCircuitGroupRestoreSubtreeProjectCommand( - snapshot: CircuitGroupSubtreeSnapshot, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + snapshot: CircuitGroupSubtreeSnapshot ): CircuitGroupRestoreSubtreeProjectCommand { const command: CircuitGroupRestoreSubtreeProjectCommand = { schemaVersion: circuitGroupSubtreeCommandSchemaVersion, type: circuitGroupRestoreSubtreeCommandType, - payload: { snapshot, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { snapshot }, }; assertCircuitGroupRestoreSubtreeProjectCommand(command); return command; @@ -80,12 +76,11 @@ function assertCommand( command.schemaVersion !== circuitGroupSubtreeCommandSchemaVersion || command.type !== type || !isPlainObject(command.payload) || - Object.keys(command.payload).some((key) => key !== "snapshot" && key !== "externalObjects") + Object.keys(command.payload).length !== 1 ) { throw new Error("Unsupported circuit-group subtree command."); } assertCircuitGroupSubtreeSnapshot(command.payload.snapshot); - assertExternalObjectLinkTransitions(command.payload.externalObjects); } function isPlainObject(value: unknown): value is Record { diff --git a/src/domain/models/circuit-structure-project-command.model.ts b/src/domain/models/circuit-structure-project-command.model.ts index 292c776..5260c4b 100644 --- a/src/domain/models/circuit-structure-project-command.model.ts +++ b/src/domain/models/circuit-structure-project-command.model.ts @@ -3,8 +3,6 @@ import { circuitDeviceRowInsertCommandType, circuitDeviceRowStructureCommandSchemaVersion, type CircuitDeviceRowSnapshot, - type ExternalObjectLinkSnapshotTransition, - assertExternalObjectLinkTransitions, } from "./circuit-device-row-structure-project-command.model.js"; import type { SerializedProjectCommand } from "./project-command.model.js"; import { @@ -39,13 +37,11 @@ export interface CircuitSnapshot { export interface CircuitInsertCommandPayload { circuit: CircuitSnapshot; - externalObjects?: ExternalObjectLinkSnapshotTransition[]; } export interface CircuitDeleteCommandPayload { circuitId: string; expectedCircuitListId: string; - externalObjects?: ExternalObjectLinkSnapshotTransition[]; } export interface CircuitInsertProjectCommand @@ -65,13 +61,12 @@ export type CircuitStructureProjectCommand = | CircuitDeleteProjectCommand; export function createCircuitInsertProjectCommand( - circuit: CircuitSnapshot, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + circuit: CircuitSnapshot ): CircuitInsertProjectCommand { const command: CircuitInsertProjectCommand = { schemaVersion: circuitStructureCommandSchemaVersion, type: circuitInsertCommandType, - payload: { circuit, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { circuit }, }; assertCircuitInsertProjectCommand(command); return command; @@ -79,13 +74,12 @@ export function createCircuitInsertProjectCommand( export function createCircuitDeleteProjectCommand( circuitId: string, - expectedCircuitListId: string, - externalObjects?: ExternalObjectLinkSnapshotTransition[] + expectedCircuitListId: string ): CircuitDeleteProjectCommand { const command: CircuitDeleteProjectCommand = { schemaVersion: circuitStructureCommandSchemaVersion, type: circuitDeleteCommandType, - payload: { circuitId, expectedCircuitListId, ...(externalObjects?.length ? { externalObjects } : {}) }, + payload: { circuitId, expectedCircuitListId }, }; assertCircuitDeleteProjectCommand(command); return command; @@ -174,7 +168,6 @@ export function assertCircuitInsertProjectCommand( } rowIds.add(row.id); } - assertExternalObjectLinkTransitions(command.payload.externalObjects); } export function assertCircuitDeleteProjectCommand( @@ -194,7 +187,6 @@ export function assertCircuitDeleteProjectCommand( command.payload.expectedCircuitListId, "expectedCircuitListId" ); - assertExternalObjectLinkTransitions(command.payload.externalObjects); } function assertNonEmptyString(value: unknown, field: string) { diff --git a/src/domain/models/circuit-tree.model.ts b/src/domain/models/circuit-tree.model.ts index fd1bd2c..00a0c2d 100644 --- a/src/domain/models/circuit-tree.model.ts +++ b/src/domain/models/circuit-tree.model.ts @@ -20,7 +20,6 @@ export interface CircuitTreeDeviceRow { remark?: string; overriddenFields?: string; rowTotalPower: number; - externalObjectCount?: number; } export interface CircuitTreeCircuit { diff --git a/src/domain/models/external-object-new-circuit-project-command.model.ts b/src/domain/models/external-object-new-circuit-project-command.model.ts index e7a3e23..b34a449 100644 --- a/src/domain/models/external-object-new-circuit-project-command.model.ts +++ b/src/domain/models/external-object-new-circuit-project-command.model.ts @@ -146,8 +146,8 @@ function assertOnlyAssignmentChanged( expected: ExternalModelObjectSnapshot, target: ExternalModelObjectSnapshot ) { - const expectedRest = { ...expected, circuitDeviceRowId: null, distributionBoardId: null }; - const targetRest = { ...target, circuitDeviceRowId: null, distributionBoardId: null }; + const expectedRest = { ...expected, circuitDeviceRowId: null }; + const targetRest = { ...target, circuitDeviceRowId: null }; if (canonicalJson(expectedRest) !== canonicalJson(targetRest)) { throw new Error("New-circuit assignment may only change the external object row link."); } diff --git a/src/domain/models/external-object-new-row-project-command.model.ts b/src/domain/models/external-object-new-row-project-command.model.ts index 6bae039..d0416dd 100644 --- a/src/domain/models/external-object-new-row-project-command.model.ts +++ b/src/domain/models/external-object-new-row-project-command.model.ts @@ -141,8 +141,8 @@ function assertOnlyAssignmentChanged( expected: ExternalModelObjectSnapshot, target: ExternalModelObjectSnapshot ) { - const expectedRest = { ...expected, circuitDeviceRowId: null, distributionBoardId: null }; - const targetRest = { ...target, circuitDeviceRowId: null, distributionBoardId: null }; + const expectedRest = { ...expected, circuitDeviceRowId: null }; + const targetRest = { ...target, circuitDeviceRowId: null }; if (canonicalJson(expectedRest) !== canonicalJson(targetRest)) { throw new Error("New-row assignment may only change the external object row link."); } diff --git a/src/domain/models/external-object-row-assignment-project-command.model.ts b/src/domain/models/external-object-row-assignment-project-command.model.ts index cb4ae97..a45fe31 100644 --- a/src/domain/models/external-object-row-assignment-project-command.model.ts +++ b/src/domain/models/external-object-row-assignment-project-command.model.ts @@ -104,10 +104,10 @@ export function assertExternalObjectRowAssignmentProjectCommand( if (expected.circuitDeviceRowId === target.circuitDeviceRowId) { throw new Error("External object row assignment must change its row link."); } - assertOnlyFieldsChanged( + assertOnlyFieldChanged( expected as unknown as Record, target as unknown as Record, - new Set(["circuitDeviceRowId", "distributionBoardId", "linkedProjectDeviceId", "planningValues", "overriddenFields"]), + "circuitDeviceRowId", "external object" ); if (expected.circuitDeviceRowId) affectedRowIds.add(expected.circuitDeviceRowId); @@ -161,22 +161,11 @@ function assertOnlyFieldChanged( target: Record, allowedField: string, label: string -) { - assertOnlyFieldsChanged(expected, target, new Set([allowedField]), label); -} - -function assertOnlyFieldsChanged( - expected: Record, - target: Record, - allowedFields: ReadonlySet, - label: string ) { const expectedRest = { ...expected }; const targetRest = { ...target }; - for (const field of allowedFields) { - delete expectedRest[field]; - delete targetRest[field]; - } + delete expectedRest[allowedField]; + delete targetRest[allowedField]; if (canonicalJson(expectedRest) !== canonicalJson(targetRest)) { throw new Error(`Row assignment may only change the ${label} assignment state.`); } diff --git a/src/external-model/application/external-xlsx-return-projection.ts b/src/external-model/application/external-xlsx-return-projection.ts deleted file mode 100644 index a80125c..0000000 --- a/src/external-model/application/external-xlsx-return-projection.ts +++ /dev/null @@ -1,135 +0,0 @@ -import type { ExternalModelObjectSnapshot } from "../domain/external-model-contracts.js"; -import type { ExternalXlsxCircuitMode, ExternalXlsxReturnValues } from "../xlsx/external-xlsx-contracts.js"; -import type { CircuitGroupCategory } from "../../shared/constants/circuit-group.js"; - -export interface ExternalReturnRowContext { - rowId: string; - displayName: string; - powerPerUnitKw: number; - cosPhi: number | null; - phaseType: string | null; - category: CircuitGroupCategory | null; - circuitIdentifier: string; - circuitVoltageV: number | null; - distributionBoardName: string; -} - -export interface ExternalReturnProjection { - objectId: string; - worksharingId: string; - values: ExternalXlsxReturnValues; - differsFromImported: boolean; - warnings: string[]; -} - -export function getRevitBoardName(board: { name: string }) { - return board.name; -} - -export function projectExternalXlsxReturn(input: { - object: ExternalModelObjectSnapshot; - row: ExternalReturnRowContext | null; - circuitMode: ExternalXlsxCircuitMode; - singlePhaseVoltageV: number; - threePhaseVoltageV: number; -}): ExternalReturnProjection { - const { object, row } = input; - const planning = object.planningValues; - const warnings: string[] = []; - const category = row?.category ?? planning.category; - const phaseType = row?.phaseType ?? (category === "three_phase" ? "three_phase" : category ? "single_phase" : null); - const voltageV = row?.circuitVoltageV ?? defaultVoltage(category, input.singlePhaseVoltageV, input.threePhaseVoltageV); - const powerPerUnitW = row ? row.powerPerUnitKw * 1000 : planning.powerPerUnitW; - const electricalPowerW = powerPerUnitW === null - ? null - : roundNumber(planning.effectiveQuantity * powerPerUnitW, 6); - const cosPhi = row?.cosPhi ?? planning.cosPhi; - const currentA = calculateCurrent({ electricalPowerW, voltageV, cosPhi, phaseType }); - if (electricalPowerW === null) warnings.push("Elektrische Leistung ist nicht berechenbar."); - if (voltageV === null) warnings.push("Spannung ist nicht bestimmbar."); - if (currentA === null) warnings.push("Stromstärke ist nicht berechenbar."); - - const values: ExternalXlsxReturnValues = { - ...(input.circuitMode === "combined" - ? { circuitCombined: row ? `${getRevitBoardName({ name: row.distributionBoardName })}${row.circuitIdentifier}` : "" } - : { - boardName: row ? getRevitBoardName({ name: row.distributionBoardName }) : "", - circuitIdentifier: row?.circuitIdentifier ?? "", - }), - designation: row?.displayName ?? planning.displayName ?? "", - electricalPowerW, - voltageV, - currentA, - }; - const source = object.acceptedSourceValues; - const sourceValues: ExternalXlsxReturnValues = input.circuitMode === "combined" - ? { - circuitCombined: source.circuitCombined, - designation: source.designation, - electricalPowerW: source.electricalPowerW, - voltageV: source.voltageV, - currentA: source.currentA, - } - : { - boardName: source.boardName, - circuitIdentifier: source.circuitIdentifier, - designation: source.designation, - electricalPowerW: source.electricalPowerW, - voltageV: source.voltageV, - currentA: source.currentA, - }; - - return { - objectId: object.id, - worksharingId: object.worksharingId, - values, - differsFromImported: Object.keys(values).some((key) => - !sameScalar(values[key as keyof ExternalXlsxReturnValues], sourceValues[key as keyof ExternalXlsxReturnValues]) - ), - warnings, - }; -} - -function defaultVoltage(category: CircuitGroupCategory | null, singlePhase: number, threePhase: number) { - if (category === "three_phase") return threePhase; - if (category === "lighting" || category === "single_phase") return singlePhase; - return null; -} - -function calculateCurrent(input: { electricalPowerW: number | null; voltageV: number | null; cosPhi: number | null; phaseType: string | null }) { - if ( - input.electricalPowerW === null || - input.voltageV === null || input.voltageV <= 0 || - input.cosPhi === null || input.cosPhi <= 0 || - (input.phaseType !== "single_phase" && input.phaseType !== "three_phase") - ) return null; - const divisor = input.phaseType === "three_phase" - ? Math.sqrt(3) * input.voltageV * input.cosPhi - : input.voltageV * input.cosPhi; - return roundNumber(input.electricalPowerW / divisor, 2); -} - -function sameScalar(left: string | number | boolean | null | undefined, right: string | number | boolean | null | undefined) { - const normalizedLeft = normalizeScalar(left); - const normalizedRight = normalizeScalar(right); - if (typeof normalizedLeft === "number" && typeof normalizedRight === "number") { - return Math.abs(normalizedLeft - normalizedRight) < 1e-9; - } - return normalizedLeft === normalizedRight; -} - -function normalizeScalar(value: string | number | boolean | null | undefined): string | number | boolean { - if (value === null || value === undefined || value === "") return ""; - if (typeof value === "string") { - const trimmed = value.trim(); - if (!trimmed) return ""; - const numeric = Number(trimmed.replace(",", ".")); - return Number.isFinite(numeric) ? numeric : trimmed; - } - return value; -} - -function roundNumber(value: number, decimals: number) { - const factor = 10 ** decimals; - return Math.round((value + Number.EPSILON) * factor) / factor; -} diff --git a/src/frontend/components/circuit-tree-editor.tsx b/src/frontend/components/circuit-tree-editor.tsx index 5418922..f75b64e 100644 --- a/src/frontend/components/circuit-tree-editor.tsx +++ b/src/frontend/components/circuit-tree-editor.tsx @@ -120,11 +120,6 @@ import { deleteCircuitGroupCommand, deleteCircuitGroupSubtreeCommand, deleteDistributionBoardComponentCommand, - assignExternalProjectObjectsToRow, - assignExternalProjectObjectsToNewRow, - assignExternalProjectObjectsToNewCircuit, - detachExternalProjectObjectsFromRow, - getExternalProjectObjects, getCircuitTree, getNextCircuitIdentifier, getProjectHistory, @@ -159,7 +154,6 @@ import type { ProjectCommandResultDto, ProjectDeviceDto, ProjectHistoryStateDto, - ExternalProjectObjectsDto, } from "../types"; import type { CircuitDeviceRowSnapshot, @@ -336,9 +330,6 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str const [cableSizingEditorCircuit, setCableSizingEditorCircuit] = useState(null); const [projectDevices, setProjectDevices] = useState([]); - const [externalObjects, setExternalObjects] = useState(null); - const [isRevitDrawerOpen, setIsRevitDrawerOpen] = useState(false); - const [draggingExternalObjectIds, setDraggingExternalObjectIds] = useState([]); const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] = useState(false); const [projectDeviceSearch, setProjectDeviceSearch] = useState(""); @@ -390,26 +381,6 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str () => orderedColumns.filter((column) => visibleColumnKeys.includes(column.key)), [orderedColumns, visibleColumnKeys] ); - const externalObjectGroups = useMemo(() => { - if (!data || !externalObjects) return []; - const groups = new Map(); - for (const object of externalObjects.objects) { - if (object.presenceStatus !== "present" || object.circuitDeviceRowId !== null || object.distributionBoardId !== data.distributionBoardId) continue; - const key = JSON.stringify([ - object.roomId, object.selectionMarker, object.deviceTypeId, - object.planningValues.category, object.linkedProjectDeviceId, - object.planningValues, - ]); - const entries = groups.get(key) ?? []; - entries.push(object); - groups.set(key, entries); - } - return [...groups.values()].map((objects) => ({ - key: objects.map((object) => object.id).sort().join("|"), - objects, - quantity: objects.reduce((sum, object) => sum + object.planningValues.effectiveQuantity, 0), - })); - }, [data, externalObjects]); async function loadTree(options?: { showLoading?: boolean }) { const showLoading = options?.showLoading ?? false; @@ -418,17 +389,13 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str } setError(null); try { - const [{ tree, history }, external] = await Promise.all([ - loadCircuitEditorSnapshot( - () => getCircuitTree(projectId, circuitListId), - () => getProjectHistory(projectId) - ), - getExternalProjectObjects(projectId), - ]); + const { tree, history } = await loadCircuitEditorSnapshot( + () => getCircuitTree(projectId, circuitListId), + () => getProjectHistory(projectId) + ); projectRevisionRef.current = history.currentRevision; setHistoryState(history); setData(tree); - setExternalObjects(external); } catch (err) { setError(normalizeUiError(err)); } finally { @@ -1354,20 +1321,12 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str const summary = subtree ? summarizeCircuitGroupSubtree(subtree) : null; - const externalObjectCount = section.circuits.reduce( - (total, circuit) => total + circuit.deviceRows.reduce( - (rowTotal, row) => rowTotal + (row.externalObjectCount ?? 0), 0 - ), 0 - ); - const externalWarning = externalObjectCount > 0 - ? `\n\n${externalObjectCount} Revit-Objekte werden wieder unzugeordnet.` - : ""; const warning = isEmpty ? `Leere Stromkreisgruppe „${section.displayName}“ entfernen?` : `Stromkreisgruppe „${section.displayName}“ vollständig entfernen?\n\n` + `Dabei werden ${summary!.circuitCount} Stromkreis(e), ${summary!.deviceRowCount} Gerätezeile(n) und ${summary!.protectionComponentCount} Gruppenschutzgerät(e) gelöscht.\n\n` + "Die Änderung kann über die projektweite Versionshistorie rückgängig gemacht werden."; - if (!confirm(warning + externalWarning)) { + if (!confirm(warning)) { return; } await runCommand({ @@ -2919,15 +2878,11 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str setError("Die Gerätezeile ist ungültig."); return; } - const externalWarning = (rowSnapshot.externalObjectCount ?? 0) > 0 - ? `\n\n${rowSnapshot.externalObjectCount} Revit-Objekte werden wieder unzugeordnet.` - : ""; if (sourceCircuit.deviceRows.length === 1) { const keepAsReserve = confirm( `„${rowSnapshot.displayName}“ ist das letzte Gerät in ${sourceCircuit.equipmentIdentifier}.\n\n` + "OK: Gerät löschen und den leeren Stromkreis als Reserve behalten.\n" + - "Abbrechen: anschließend entscheiden, ob stattdessen der gesamte Stromkreis gelöscht werden soll." + - externalWarning + "Abbrechen: anschließend entscheiden, ob stattdessen der gesamte Stromkreis gelöscht werden soll." ); if (!keepAsReserve) { const deleteCircuit = confirm( @@ -2939,7 +2894,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str } return; } - } else if (!confirm(`Gerätezeile „${rowSnapshot.displayName}“ löschen?${externalWarning}`)) { + } else if (!confirm(`Gerätezeile „${rowSnapshot.displayName}“ löschen?`)) { return; } await runCommand({ @@ -2962,18 +2917,11 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str setError("Der Stromkreis ist ungültig."); return; } - const externalObjectCount = circuit.deviceRows.reduce( - (total, row) => total + (row.externalObjectCount ?? 0), 0 - ); - const externalWarning = externalObjectCount > 0 - ? `\n\n${externalObjectCount} Revit-Objekte werden wieder unzugeordnet.` - : ""; if ( askForConfirmation && !confirm( `Stromkreis ${circuit.equipmentIdentifier} und ${circuit.deviceRows.length} zugeordnete Gerätezeile(n) löschen?\n\n` + - "Bestehende Betriebsmittelkennzeichen werden nicht neu nummeriert." + - externalWarning + "Bestehende Betriebsmittelkennzeichen werden nicht neu nummeriert." ) ) { return; @@ -3010,56 +2958,6 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str await handleDeleteCircuit(intent.circuitId); } - async function handleAssignExternalObjects(rowId: string, objectIds: string[]) { - if (!confirm(`${objectIds.length} Revit-Objekt(e) dieser Gerätezeile zuordnen?\n\nAbweichende Planungswerte werden ausdrücklich zugunsten der Gerätezeile bestätigt.`)) return; - await runCommand({ - label: "Revit-Objekte zuordnen", - redo: async () => { - const result = await assignExternalProjectObjectsToRow( - projectId, - getExpectedProjectRevision(), - objectIds, - rowId, - objectIds - ); - applyProjectCommandResult(result); - setDraggingExternalObjectIds([]); - return null; - }, - }); - } - - async function handleAssignExternalObjectsToNewRow(circuitId: string, objectIds: string[]) { - if (!confirm(`${objectIds.length} Revit-Objekt(e) als neue Gerätezeile anlegen?`)) return; - await runCommand({ label: "Revit-Objekte als Gerätezeile zuordnen", redo: async () => { - const result = await assignExternalProjectObjectsToNewRow(projectId, getExpectedProjectRevision(), objectIds, circuitId); - applyProjectCommandResult(result); setDraggingExternalObjectIds([]); return null; - }}); - } - - async function handleAssignExternalObjectsToNewCircuit(sectionId: string, objectIds: string[]) { - if (!confirm(`${objectIds.length} Revit-Objekt(e) als neuen Stromkreis anlegen?`)) return; - await runCommand({ label: "Revit-Objekte als Stromkreis zuordnen", redo: async () => { - const result = await assignExternalProjectObjectsToNewCircuit(projectId, getExpectedProjectRevision(), objectIds, sectionId); - applyProjectCommandResult(result); setDraggingExternalObjectIds([]); return null; - }}); - } - - async function handleDetachExternalObjects(rowId: string) { - const objectIds = externalObjects?.objects - .filter((object) => object.circuitDeviceRowId === rowId) - .map((object) => object.id) ?? []; - if (objectIds.length === 0 || !confirm(`${objectIds.length} Revit-Objekt(e) lösen?\n\nDie aktuellen Werte der Gerätezeile werden als Planungswerte und Overrides übernommen.`)) return; - await runCommand({ - label: "Revit-Objekte lösen", - redo: async () => { - const result = await detachExternalProjectObjectsFromRow(projectId, getExpectedProjectRevision(), objectIds); - applyProjectCommandResult(result); - return null; - }, - }); - } - // Explicit renumber action through project history. Sorting and device rows // remain unchanged; the server handles collision-safe identifier swaps. async function handleRenumberSection(sectionId: string) { @@ -3483,15 +3381,6 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str } showLabel /> - sum + group.objects.length, 0)})`} - onClick={() => setIsRevitDrawerOpen((current) => !current)} - showLabel - /> Wird gespeichert … : null}
- {isRevitDrawerOpen ? ( - - ) : null} {isProjectDeviceDrawerOpen ? (