Add public building project setting
This commit is contained in:
@@ -250,9 +250,11 @@ not change the project revision or undo/redo stacks. Restoring a server-stored
|
|||||||
snapshot verifies its checksum and the current-state hash, replaces supported
|
snapshot verifies its checksum and the current-state hash, replaces supported
|
||||||
project data atomically and records a new `restore` revision with a complete
|
project data atomically and records a new `restore` revision with a complete
|
||||||
inverse command. Restore can therefore be undone and redone after a restart.
|
inverse command. Restore can therefore be undone and redone after a restart.
|
||||||
Baseline snapshot schema version 1 contains circuit-group identity,
|
Current snapshot schema version 2 additionally stores whether the project is a
|
||||||
distribution-board components and the separate circuit/component protection
|
public building. Supported baseline version 1 snapshots are upgraded with
|
||||||
records. Pre-baseline snapshots are unsupported. Portable duplicate imports
|
`isPublicBuilding = false`; pre-baseline snapshots remain unsupported. Both
|
||||||
|
versions contain circuit-group identity, distribution-board components and the
|
||||||
|
separate circuit/component protection records. Portable duplicate imports
|
||||||
remap component ids and protection-owner references together with the existing
|
remap component ids and protection-owner references together with the existing
|
||||||
project graph.
|
project graph.
|
||||||
The central revision boundary creates an automatic logical snapshot after each
|
The central revision boundary creates an automatic logical snapshot after each
|
||||||
@@ -284,9 +286,11 @@ global-to-project copy API/UI paths use these persistent commands and track the
|
|||||||
returned project revision. ProjectDevice synchronization/disconnect API and UI
|
returned project revision. ProjectDevice synchronization/disconnect API and UI
|
||||||
paths do the same; their undo action uses the project-wide history endpoint.
|
paths do the same; their undo action uses the project-wide history endpoint.
|
||||||
Project settings use the persistent `project.update-settings` command. Project
|
Project settings use the persistent `project.update-settings` command. Project
|
||||||
metadata, both voltage defaults and the enabled distribution-board supply types
|
metadata, the public-building classification, both voltage defaults and the
|
||||||
change in one revision and Undo/Redo restores them together; the project PUT
|
enabled distribution-board supply types change in one revision and Undo/Redo
|
||||||
route requires `expectedRevision`. The system catalog is `AV`, `SV`, `EV`,
|
restores them together; the project PUT route requires `expectedRevision`.
|
||||||
|
The public-building flag is the future sizing input for requiring halogen-free
|
||||||
|
cables and lines. The system catalog is `AV`, `SV`, `EV`,
|
||||||
`USV`, `MSR`, `SiBe`; at least one must be enabled and a type used by a board
|
`USV`, `MSR`, `SiBe`; at least one must be enabled and a type used by a board
|
||||||
cannot be disabled.
|
cannot be disabled.
|
||||||
Distribution-board setup uses `distribution-board.insert` schema version 1
|
Distribution-board setup uses `distribution-board.insert` schema version 1
|
||||||
|
|||||||
@@ -108,9 +108,10 @@ npm run db:generate
|
|||||||
```
|
```
|
||||||
|
|
||||||
`db:backup` verwendet die SQLite-Online-Backup-API und prüft das Ergebnis auf
|
`db:backup` verwendet die SQLite-Online-Backup-API und prüft das Ergebnis auf
|
||||||
Integrität und Fremdschlüsselverletzungen. Die Migration `0000` ist die
|
Integrität und Fremdschlüsselverletzungen. Migration `0000` ist die
|
||||||
Release-Baseline und richtet ausschließlich eine neue, leere Datenbank ein.
|
Release-Baseline für eine leere Datenbank; nachfolgende nummerierte Migrationen
|
||||||
Datenbanken aus Entwicklungsständen vor dieser Baseline werden nicht unterstützt.
|
entwickeln diese Baseline additiv weiter. Datenbanken aus Entwicklungsständen
|
||||||
|
vor der Baseline werden nicht unterstützt.
|
||||||
|
|
||||||
## Dokumentation
|
## Dokumentation
|
||||||
|
|
||||||
|
|||||||
@@ -73,9 +73,11 @@ Protected-board structure uses
|
|||||||
`circuit-protection.update`. A subtree restore is normally emitted only as the
|
`circuit-protection.update`. A subtree restore is normally emitted only as the
|
||||||
persisted inverse of a delete. The dispatcher also supports the documented
|
persisted inverse of a delete. The dispatcher also supports the documented
|
||||||
project-device, project settings, distribution-board and project-location
|
project-device, project settings, distribution-board and project-location
|
||||||
commands. The generic editor commands listed here use schema version `1`;
|
commands. The generic editor commands listed here use schema version `1`.
|
||||||
the clean pre-release baseline does not accept older development formats.
|
`project.update-settings` uses version `2` and still accepts supported baseline
|
||||||
Unsupported types or schema versions are rejected. Insert commands contain the complete entity or circuit block
|
version `1` commands without changing the newer building classification.
|
||||||
|
Pre-baseline formats remain unsupported. Unsupported types or schema versions
|
||||||
|
are rejected. Insert commands contain the complete entity or circuit block
|
||||||
with stable ids; delete commands include the expected parent identity. Circuit
|
with stable ids; delete commands include the expected parent identity. Circuit
|
||||||
snapshots contain zero, one or multiple complete device rows. Move commands
|
snapshots contain zero, one or multiple complete device rows. Move commands
|
||||||
contain each row's expected and target circuit plus its exact expected and
|
contain each row's expected and target circuit plus its exact expected and
|
||||||
@@ -170,12 +172,12 @@ synchronizes linked circuit rows implicitly.
|
|||||||
|
|
||||||
- `PUT /projects/:projectId`
|
- `PUT /projects/:projectId`
|
||||||
- request:
|
- request:
|
||||||
`{ "expectedRevision": 12, "singlePhaseVoltageV": 230, "threePhaseVoltageV": 400, "enabledDistributionBoardSupplyTypes": ["AV", "MSR", "SiBe"], ...projectMetadata }`
|
`{ "expectedRevision": 12, "isPublicBuilding": true, "singlePhaseVoltageV": 230, "threePhaseVoltageV": 400, "enabledDistributionBoardSupplyTypes": ["AV", "MSR", "SiBe"], ...projectMetadata }`
|
||||||
- executes `project.update-settings` as one atomic revision
|
- executes `project.update-settings` as one atomic revision
|
||||||
- response:
|
- response:
|
||||||
`{ "project": { ... }, "revision": { ... }, "history": { ... } }`
|
`{ "project": { ... }, "revision": { ... }, "history": { ... } }`
|
||||||
- persistent Undo/Redo restores metadata, voltage values and the enabled
|
- persistent Undo/Redo restores metadata, the public-building flag, voltage
|
||||||
distribution-board supply types together; project-device and circuit
|
values and enabled distribution-board supply types together; project-device and circuit
|
||||||
voltages are recalculated from the restored project settings in the same
|
voltages are recalculated from the restored project settings in the same
|
||||||
transaction
|
transaction
|
||||||
- project-device and circuit voltage are derived values and are not accepted
|
- project-device and circuit voltage are derived values and are not accepted
|
||||||
|
|||||||
@@ -232,8 +232,10 @@ und Historienstapel teilen dieselbe Transaktion. Create, Import aus der globalen
|
|||||||
Gerätebibliothek und Delete laufen über dieselbe Command-Grenze; ihre Antworten
|
Gerätebibliothek und Delete laufen über dieselbe Command-Grenze; ihre Antworten
|
||||||
liefern Gerät und aktualisierten Historienstand an die Projektseite zurück.
|
liefern Gerät und aktualisierten Historienstand an die Projektseite zurück.
|
||||||
`project.update-settings` versioniert Projektname, interne und externe
|
`project.update-settings` versioniert Projektname, interne und externe
|
||||||
Projektnummer, Bauherr, Beschreibung, beide Standardspannungen sowie die im
|
Projektnummer, Bauherr, Beschreibung, die Kennzeichnung als öffentliches
|
||||||
Projekt freigeschalteten Verteiler-Netzarten als eine atomare Änderung. Der
|
Gebäude, beide Standardspannungen sowie die im Projekt freigeschalteten
|
||||||
|
Verteiler-Netzarten als eine atomare Änderung. Die Gebäudekennzeichnung ist
|
||||||
|
der spätere Eingang für die Auswahl halogenfreier Kabel und Leitungen. Der
|
||||||
Systemkatalog besteht aus `AV`, `SV`, `EV`, `USV`, `MSR` und `SiBe`; mindestens
|
Systemkatalog besteht aus `AV`, `SV`, `EV`, `USV`, `MSR` und `SiBe`; mindestens
|
||||||
eine Netzart muss aktiv bleiben und eine bereits von einer Verteilung
|
eine Netzart muss aktiv bleiben und eine bereits von einer Verteilung
|
||||||
verwendete Netzart kann nicht deaktiviert werden. Die Projektseite bearbeitet diese Angaben in einem
|
verwendete Netzart kann nicht deaktiviert werden. Die Projektseite bearbeitet diese Angaben in einem
|
||||||
@@ -414,12 +416,13 @@ wieder her.
|
|||||||
verteilerweiten Gleichzeitigkeitsfaktor gemeinsam und stellt alle Werte über
|
verteilerweiten Gleichzeitigkeitsfaktor gemeinsam und stellt alle Werte über
|
||||||
dauerhaftes Undo/Redo wieder her. Der Faktor liegt zwischen `0` und `1` und
|
dauerhaftes Undo/Redo wieder her. Der Faktor liegt zwischen `0` und `1` und
|
||||||
ist für bestehende sowie neu angelegte Verteilungen standardmäßig `1`.
|
ist für bestehende sowie neu angelegte Verteilungen standardmäßig `1`.
|
||||||
Das aktuelle Baseline-Snapshot-Schema enthält den Gleichzeitigkeitsfaktor,
|
Snapshot-Schema 2 enthält zusätzlich die Gebäudekennzeichnung sowie den Gleichzeitigkeitsfaktor,
|
||||||
Gruppenkategorie und -nummer, Verteilerkomponenten sowie die getrennten
|
Gruppenkategorie und -nummer, Verteilerkomponenten sowie die getrennten
|
||||||
1:1-Schutzgerätedaten. Capture,
|
1:1-Schutzgerätedaten. Capture,
|
||||||
benannte und automatische Snapshots, Wiederherstellung, Undo/Redo und beide
|
benannte und automatische Snapshots, Wiederherstellung, Undo/Redo und beide
|
||||||
JSON-Importmodi verwenden denselben vollständigen Zustand. Vorherige
|
JSON-Importmodi verwenden denselben vollständigen Zustand. Die unterstützte
|
||||||
Entwicklungsschemas werden nicht mehr eingelesen.
|
Baseline-Version 1 wird mit `isPublicBuilding = false` hochgestuft; Formate vor
|
||||||
|
dieser Baseline werden nicht eingelesen.
|
||||||
Persistente Insert-, Update- und Delete-Commands versionieren Anlage,
|
Persistente Insert-, Update- und Delete-Commands versionieren Anlage,
|
||||||
Bearbeitung und Löschung von Geschossen und Räumen mit stabilen UUIDs und
|
Bearbeitung und Löschung von Geschossen und Räumen mit stabilen UUIDs und
|
||||||
exakten Vorher-/Nachher-Snapshots. Ein Geschoss wird nur
|
exakten Vorher-/Nachher-Snapshots. Ein Geschoss wird nur
|
||||||
@@ -447,8 +450,8 @@ Kopieren in ein Projekt erzeugt ein eigenständiges Projektgerät.
|
|||||||
|
|
||||||
- SQLite ist die aktuell unterstützte Datenbank.
|
- SQLite ist die aktuell unterstützte Datenbank.
|
||||||
- Fremdschlüssel werden für jeden Datenbankkontext aktiviert.
|
- Fremdschlüssel werden für jeden Datenbankkontext aktiviert.
|
||||||
- `npm run db:migrate` richtet mit der einzelnen Migration `0000` das komplette
|
- `npm run db:migrate` richtet mit Baseline-Migration `0000` und den folgenden
|
||||||
aktuelle Schema einer leeren Datenbank ein.
|
additiven Migrationen das aktuelle Schema ein.
|
||||||
- `npm run db:verify:circuit-schema` prüft erforderliche und entfernte Spalten.
|
- `npm run db:verify:circuit-schema` prüft erforderliche und entfernte Spalten.
|
||||||
- `npm run db:backup` erzeugt ein konsistentes und verifiziertes Online-Backup.
|
- `npm run db:backup` erzeugt ein konsistentes und verifiziertes Online-Backup.
|
||||||
- `npm run typecheck:scripts` prüft die TypeScript-Wartungsskripte, ohne Code zu
|
- `npm run typecheck:scripts` prüft die TypeScript-Wartungsskripte, ohne Code zu
|
||||||
@@ -469,8 +472,8 @@ Kopieren in ein Projekt erzeugt ein eigenständiges Projektgerät.
|
|||||||
flachen Stromkreis-Schutzfelder sind aus der Baseline entfernt.
|
flachen Stromkreis-Schutzfelder sind aus der Baseline entfernt.
|
||||||
Ein triggergeführtes Register erzwingt bereits eine normalisierte,
|
Ein triggergeführtes Register erzwingt bereits eine normalisierte,
|
||||||
stromkreislistenweite BMK-Eindeutigkeit über Stromkreise und
|
stromkreislistenweite BMK-Eindeutigkeit über Stromkreise und
|
||||||
Verteilerkomponenten. Snapshot- und Transfer-Integration verwenden
|
Verteilerkomponenten. Snapshot- und Transfer-Integration verwenden aktuell
|
||||||
Snapshot-Schema 1 der Baseline. Persistente Insert/Delete/Update-Commands für
|
Snapshot-Schema 2. Persistente Insert/Delete/Update-Commands für
|
||||||
veränderliche Verteilerkomponenten, Gruppen einschließlich befüllter
|
veränderliche Verteilerkomponenten, Gruppen einschließlich befüllter
|
||||||
Unterbäume sowie vollständige Gruppensortierung sind integriert. Der Editor
|
Unterbäume sowie vollständige Gruppensortierung sind integriert. Der Editor
|
||||||
zeigt die geschützte Struktur an und bearbeitet veränderliche Gruppen- und
|
zeigt die geschützte Struktur an und bearbeitet veränderliche Gruppen- und
|
||||||
|
|||||||
@@ -262,8 +262,9 @@ Completed foundation:
|
|||||||
- `project-device.insert` and `project-device.delete` preserve stable device
|
- `project-device.insert` and `project-device.delete` preserve stable device
|
||||||
ids; delete undo restores links only from complete unchanged disconnected-row
|
ids; delete undo restores links only from complete unchanged disconnected-row
|
||||||
snapshots in the same transaction
|
snapshots in the same transaction
|
||||||
- `project.update-settings` persists both project voltage defaults, its exact
|
- `project.update-settings` persists the public-building classification and
|
||||||
inverse, revision and history transition atomically; the project page and
|
both project voltage defaults with their exact inverse, revision and history
|
||||||
|
transition atomically; the project page and
|
||||||
existing PUT route require the current expected revision; the same
|
existing PUT route require the current expected revision; the same
|
||||||
transaction derives every project-device and circuit voltage again, so
|
transaction derives every project-device and circuit voltage again, so
|
||||||
Undo/Redo cannot leave mixed voltage states
|
Undo/Redo cannot leave mixed voltage states
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ Wichtige fachliche Grenzen:
|
|||||||
Für einen späteren Revit-Austausch besonders relevante Daten sind:
|
Für einen späteren Revit-Austausch besonders relevante Daten sind:
|
||||||
|
|
||||||
- Projekt: Name, interne/externe Projektnummer, Bauherr, Beschreibung,
|
- Projekt: Name, interne/externe Projektnummer, Bauherr, Beschreibung,
|
||||||
Projektspannungen.
|
Kennzeichnung als öffentliches Gebäude und Projektspannungen.
|
||||||
- Geschoss und Raum: interne UUID, Name beziehungsweise Raumnummer und
|
- Geschoss und Raum: interne UUID, Name beziehungsweise Raumnummer und
|
||||||
Raumname.
|
Raumname.
|
||||||
- Verteilung: interne UUID, Name, Etage, Netzart und Gleichzeitigkeitsfaktor.
|
- Verteilung: interne UUID, Name, Etage, Netzart und Gleichzeitigkeitsfaktor.
|
||||||
|
|||||||
@@ -14,12 +14,18 @@ Future suggestions or checks may include:
|
|||||||
- cable type
|
- cable type
|
||||||
- number of cores
|
- number of cores
|
||||||
- cable cross-section
|
- cable cross-section
|
||||||
|
- halogen-free cable or line requirement for public buildings
|
||||||
- minimum cable cross-section based on current
|
- minimum cable cross-section based on current
|
||||||
- maximum permissible cable length based on voltage drop
|
- maximum permissible cable length based on voltage drop
|
||||||
- warning messages if cable length, cross-section or protection device do not match
|
- warning messages if cable length, cross-section or protection device do not match
|
||||||
|
|
||||||
Users must remain able to manually override suggestions.
|
Users must remain able to manually override suggestions.
|
||||||
|
|
||||||
|
The project-owned `isPublicBuilding` setting is the authoritative input for
|
||||||
|
the later halogen-free selection rule. The setting is persisted now; this
|
||||||
|
document does not yet define or implement the complete cable catalog or sizing
|
||||||
|
algorithm.
|
||||||
|
|
||||||
## Initial Design Rule Examples
|
## Initial Design Rule Examples
|
||||||
|
|
||||||
These are common planning defaults, not a replacement for full norm-compliant calculation.
|
These are common planning defaults, not a replacement for full norm-compliant calculation.
|
||||||
|
|||||||
@@ -465,9 +465,9 @@ Implemented foundation:
|
|||||||
- ProjectDevice synchronization and disconnect endpoints also require
|
- ProjectDevice synchronization and disconnect endpoints also require
|
||||||
`expectedRevision`; their UI undo uses project-wide persistent history and
|
`expectedRevision`; their UI undo uses project-wide persistent history and
|
||||||
the obsolete direct restore/reconnect write paths are removed
|
the obsolete direct restore/reconnect write paths are removed
|
||||||
- project voltage settings use `project.update-settings`; both values, inverse,
|
- project settings use `project.update-settings`; metadata, public-building
|
||||||
revision and history transition commit atomically and the former direct
|
classification, voltage values, inverse, revision and history transition
|
||||||
settings write is removed
|
commit atomically and the former direct settings write is removed
|
||||||
- distribution-board setup uses `distribution-board.insert` with a complete
|
- distribution-board setup uses `distribution-board.insert` with a complete
|
||||||
stable board/list/default-section snapshot; Undo removes only an unchanged
|
stable board/list/default-section snapshot; Undo removes only an unchanged
|
||||||
empty setup and the former direct controller write is removed
|
empty setup and the former direct controller write is removed
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ requirements and intended sequencing, not proof of implementation.
|
|||||||
|
|
||||||
The pre-release cleanup established the following compatibility boundary:
|
The pre-release cleanup established the following compatibility boundary:
|
||||||
|
|
||||||
- [x] Pre-release databases, portable JSON exports, logical snapshots and
|
- [x] Pre-baseline databases, portable JSON exports, logical snapshots and
|
||||||
persisted command histories are explicitly unsupported.
|
persisted command histories are explicitly unsupported.
|
||||||
- [x] Migration `0000` builds the complete supported schema on an empty
|
- [x] Migration `0000` builds the complete supported schema on an empty
|
||||||
database.
|
database.
|
||||||
@@ -109,9 +109,16 @@ The pre-release cleanup established the following compatibility boundary:
|
|||||||
device rows with a valid phase are three-phase.
|
device rows with a valid phase are three-phase.
|
||||||
- [x] Changing project voltage settings updates all project devices and circuits
|
- [x] Changing project voltage settings updates all project devices and circuits
|
||||||
atomically in the same persistent Undo/Redo step.
|
atomically in the same persistent Undo/Redo step.
|
||||||
- [x] Baseline migration `0000` and project-state schema version `1` store only
|
- [x] Baseline migration `0000` stores only canonical derived values.
|
||||||
the canonical derived values. Pre-release imports are intentionally
|
Pre-baseline imports are intentionally unsupported.
|
||||||
unsupported.
|
|
||||||
|
## Building Classification
|
||||||
|
|
||||||
|
- [x] Store whether a project represents a public building.
|
||||||
|
- [x] Edit the value in the project settings and preserve it through persistent
|
||||||
|
Undo/Redo, snapshots and portable project transfers.
|
||||||
|
- [x] Provide the value as an explicit future sizing input for selecting
|
||||||
|
halogen-free cables and lines; automatic sizing remains deferred.
|
||||||
|
|
||||||
## Circuit List Power Summary
|
## Circuit List Power Summary
|
||||||
|
|
||||||
|
|||||||
@@ -467,11 +467,11 @@ The supported logical project snapshot and portable JSON transfer must include:
|
|||||||
- circuit protection-device state
|
- circuit protection-device state
|
||||||
- all new component relationships and sort positions
|
- all new component relationships and sort positions
|
||||||
|
|
||||||
The clean pre-release baseline uses project-state schema version `1`. It
|
Current project-state schema version `2` contains the complete supported
|
||||||
contains the complete supported structure above and is shared by logical
|
structure above and the project building classification. It is shared by
|
||||||
snapshots, restore, Undo/Redo and portable JSON transfer. Payloads from earlier
|
logical snapshots, restore, Undo/Redo and portable JSON transfer. Supported
|
||||||
development schemas are intentionally unsupported and rejected before any
|
baseline version `1` is upgraded with the non-public default; payloads from
|
||||||
write.
|
before that baseline are rejected before any write.
|
||||||
|
|
||||||
Migration `0000` creates the complete relational model on an empty database.
|
Migration `0000` creates the complete relational model on an empty database.
|
||||||
New defaults apply when boards, groups or circuits are created; they never
|
New defaults apply when boards, groups or circuits are created; they never
|
||||||
@@ -545,7 +545,7 @@ Implemented persistence:
|
|||||||
one-to-one ownership boundaries
|
one-to-one ownership boundaries
|
||||||
- a trigger-maintained circuit-list registry rejects normalized BMK collisions
|
- a trigger-maintained circuit-list registry rejects normalized BMK collisions
|
||||||
across circuits and distribution-board components
|
across circuits and distribution-board components
|
||||||
- snapshot schema version `1` includes group identity, distribution-board
|
- snapshot schema version `2` includes group identity, distribution-board
|
||||||
components and both one-to-one protection collections
|
components and both one-to-one protection collections
|
||||||
- capture, named and automatic snapshots, restore, Undo/Redo and portable JSON
|
- capture, named and automatic snapshots, restore, Undo/Redo and portable JSON
|
||||||
transfers preserve the complete new relational state
|
transfers preserve the complete new relational state
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ const requiredProjectColumns = [
|
|||||||
"external_project_number",
|
"external_project_number",
|
||||||
"building_owner",
|
"building_owner",
|
||||||
"description",
|
"description",
|
||||||
|
"is_public_building",
|
||||||
"enabled_distribution_board_supply_types",
|
"enabled_distribution_board_supply_types",
|
||||||
];
|
];
|
||||||
const projectColumns = new Set(
|
const projectColumns = new Set(
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `projects` ADD `is_public_building` integer DEFAULT false NOT NULL;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,13 @@
|
|||||||
"when": 1785499119431,
|
"when": 1785499119431,
|
||||||
"tag": "0000_whole_surge",
|
"tag": "0000_whole_surge",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1785511894897,
|
||||||
|
"tag": "0001_add_public_building_setting",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -40,22 +40,33 @@ export class ProjectSettingsProjectCommandRepository
|
|||||||
if (!current) {
|
if (!current) {
|
||||||
throw new Error("Project not found.");
|
throw new Error("Project not found.");
|
||||||
}
|
}
|
||||||
const target = input.command.payload;
|
const target: ProjectSettingsValues =
|
||||||
|
input.command.schemaVersion === 1
|
||||||
|
? {
|
||||||
|
...input.command.payload,
|
||||||
|
isPublicBuilding: current.isPublicBuilding,
|
||||||
|
}
|
||||||
|
: input.command.payload;
|
||||||
if (projectSettingsEqual(current, target)) {
|
if (projectSettingsEqual(current, target)) {
|
||||||
throw new Error("Project settings did not change.");
|
throw new Error("Project settings did not change.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const inverse = createProjectSettingsUpdateProjectCommand({
|
const inverseValues: ProjectSettingsValues = {
|
||||||
name: current.name,
|
name: current.name,
|
||||||
internalProjectNumber: current.internalProjectNumber,
|
internalProjectNumber: current.internalProjectNumber,
|
||||||
externalProjectNumber: current.externalProjectNumber,
|
externalProjectNumber: current.externalProjectNumber,
|
||||||
buildingOwner: current.buildingOwner,
|
buildingOwner: current.buildingOwner,
|
||||||
description: current.description,
|
description: current.description,
|
||||||
|
isPublicBuilding: current.isPublicBuilding,
|
||||||
singlePhaseVoltageV: current.singlePhaseVoltageV,
|
singlePhaseVoltageV: current.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: current.threePhaseVoltageV,
|
threePhaseVoltageV: current.threePhaseVoltageV,
|
||||||
enabledDistributionBoardSupplyTypes:
|
enabledDistributionBoardSupplyTypes:
|
||||||
current.enabledDistributionBoardSupplyTypes,
|
current.enabledDistributionBoardSupplyTypes,
|
||||||
});
|
};
|
||||||
|
const inverse =
|
||||||
|
input.command.schemaVersion === 1
|
||||||
|
? createBaselineProjectSettingsUpdateCommand(inverseValues)
|
||||||
|
: createProjectSettingsUpdateProjectCommand(inverseValues);
|
||||||
assertDisabledSupplyTypesAreUnused(tx, input.projectId, target);
|
assertDisabledSupplyTypesAreUnused(tx, input.projectId, target);
|
||||||
const updated = tx
|
const updated = tx
|
||||||
.update(projects)
|
.update(projects)
|
||||||
@@ -71,6 +82,26 @@ export class ProjectSettingsProjectCommandRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBaselineProjectSettingsUpdateCommand(
|
||||||
|
values: ProjectSettingsValues
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
schemaVersion: 1 as const,
|
||||||
|
type: "project.update-settings" as const,
|
||||||
|
payload: {
|
||||||
|
name: values.name,
|
||||||
|
internalProjectNumber: values.internalProjectNumber,
|
||||||
|
externalProjectNumber: values.externalProjectNumber,
|
||||||
|
buildingOwner: values.buildingOwner,
|
||||||
|
description: values.description,
|
||||||
|
singlePhaseVoltageV: values.singlePhaseVoltageV,
|
||||||
|
threePhaseVoltageV: values.threePhaseVoltageV,
|
||||||
|
enabledDistributionBoardSupplyTypes:
|
||||||
|
values.enabledDistributionBoardSupplyTypes,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function projectSettingsEqual(
|
function projectSettingsEqual(
|
||||||
current: ProjectSettingsValues,
|
current: ProjectSettingsValues,
|
||||||
target: ProjectSettingsValues
|
target: ProjectSettingsValues
|
||||||
@@ -81,6 +112,7 @@ function projectSettingsEqual(
|
|||||||
current.externalProjectNumber === target.externalProjectNumber &&
|
current.externalProjectNumber === target.externalProjectNumber &&
|
||||||
current.buildingOwner === target.buildingOwner &&
|
current.buildingOwner === target.buildingOwner &&
|
||||||
current.description === target.description &&
|
current.description === target.description &&
|
||||||
|
current.isPublicBuilding === target.isPublicBuilding &&
|
||||||
current.singlePhaseVoltageV === target.singlePhaseVoltageV &&
|
current.singlePhaseVoltageV === target.singlePhaseVoltageV &&
|
||||||
current.threePhaseVoltageV === target.threePhaseVoltageV
|
current.threePhaseVoltageV === target.threePhaseVoltageV
|
||||||
&& sameSupplyTypes(
|
&& sameSupplyTypes(
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ function replaceProjectState(
|
|||||||
externalProjectNumber: state.project.externalProjectNumber,
|
externalProjectNumber: state.project.externalProjectNumber,
|
||||||
buildingOwner: state.project.buildingOwner,
|
buildingOwner: state.project.buildingOwner,
|
||||||
description: state.project.description,
|
description: state.project.description,
|
||||||
|
isPublicBuilding: state.project.isPublicBuilding,
|
||||||
singlePhaseVoltageV: state.project.singlePhaseVoltageV,
|
singlePhaseVoltageV: state.project.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: state.project.threePhaseVoltageV,
|
threePhaseVoltageV: state.project.threePhaseVoltageV,
|
||||||
enabledDistributionBoardSupplyTypes:
|
enabledDistributionBoardSupplyTypes:
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export function readProjectStateSnapshot(
|
|||||||
externalProjectNumber: projects.externalProjectNumber,
|
externalProjectNumber: projects.externalProjectNumber,
|
||||||
buildingOwner: projects.buildingOwner,
|
buildingOwner: projects.buildingOwner,
|
||||||
description: projects.description,
|
description: projects.description,
|
||||||
|
isPublicBuilding: projects.isPublicBuilding,
|
||||||
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: projects.threePhaseVoltageV,
|
threePhaseVoltageV: projects.threePhaseVoltageV,
|
||||||
enabledDistributionBoardSupplyTypes:
|
enabledDistributionBoardSupplyTypes:
|
||||||
@@ -233,6 +234,7 @@ export function readProjectStateSnapshot(
|
|||||||
externalProjectNumber: project.externalProjectNumber,
|
externalProjectNumber: project.externalProjectNumber,
|
||||||
buildingOwner: project.buildingOwner,
|
buildingOwner: project.buildingOwner,
|
||||||
description: project.description,
|
description: project.description,
|
||||||
|
isPublicBuilding: project.isPublicBuilding,
|
||||||
singlePhaseVoltageV: project.singlePhaseVoltageV,
|
singlePhaseVoltageV: project.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: project.threePhaseVoltageV,
|
threePhaseVoltageV: project.threePhaseVoltageV,
|
||||||
enabledDistributionBoardSupplyTypes:
|
enabledDistributionBoardSupplyTypes:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export class ProjectRepository {
|
|||||||
externalProjectNumber: input.externalProjectNumber ?? null,
|
externalProjectNumber: input.externalProjectNumber ?? null,
|
||||||
buildingOwner: input.buildingOwner ?? null,
|
buildingOwner: input.buildingOwner ?? null,
|
||||||
description: input.description ?? null,
|
description: input.description ?? null,
|
||||||
|
isPublicBuilding: input.isPublicBuilding ?? false,
|
||||||
singlePhaseVoltageV: input.singlePhaseVoltageV ?? 230,
|
singlePhaseVoltageV: input.singlePhaseVoltageV ?? 230,
|
||||||
threePhaseVoltageV: input.threePhaseVoltageV ?? 400,
|
threePhaseVoltageV: input.threePhaseVoltageV ?? 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ export const projects = sqliteTable("projects", {
|
|||||||
externalProjectNumber: text("external_project_number"),
|
externalProjectNumber: text("external_project_number"),
|
||||||
buildingOwner: text("building_owner"),
|
buildingOwner: text("building_owner"),
|
||||||
description: text("description"),
|
description: text("description"),
|
||||||
|
isPublicBuilding: integer("is_public_building", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
singlePhaseVoltageV: integer("single_phase_voltage_v").notNull().default(230),
|
singlePhaseVoltageV: integer("single_phase_voltage_v").notNull().default(230),
|
||||||
threePhaseVoltageV: integer("three_phase_voltage_v").notNull().default(400),
|
threePhaseVoltageV: integer("three_phase_voltage_v").notNull().default(400),
|
||||||
enabledDistributionBoardSupplyTypes: text(
|
enabledDistributionBoardSupplyTypes: text(
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
|
|
||||||
export const projectSettingsUpdateCommandType =
|
export const projectSettingsUpdateCommandType =
|
||||||
"project.update-settings" as const;
|
"project.update-settings" as const;
|
||||||
export const projectSettingsUpdateCommandSchemaVersion = 1 as const;
|
export const projectSettingsUpdateCommandSchemaVersion = 2 as const;
|
||||||
|
const previousProjectSettingsUpdateCommandSchemaVersion = 1 as const;
|
||||||
|
|
||||||
export interface ProjectSettingsValues {
|
export interface ProjectSettingsValues {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -14,21 +15,37 @@ export interface ProjectSettingsValues {
|
|||||||
externalProjectNumber: string | null;
|
externalProjectNumber: string | null;
|
||||||
buildingOwner: string | null;
|
buildingOwner: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
isPublicBuilding: boolean;
|
||||||
singlePhaseVoltageV: number;
|
singlePhaseVoltageV: number;
|
||||||
threePhaseVoltageV: number;
|
threePhaseVoltageV: number;
|
||||||
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProjectSettingsUpdateProjectCommand
|
type PreviousProjectSettingsValues = Omit<
|
||||||
|
ProjectSettingsValues,
|
||||||
|
"isPublicBuilding"
|
||||||
|
>;
|
||||||
|
|
||||||
|
export interface CurrentProjectSettingsUpdateProjectCommand
|
||||||
extends SerializedProjectCommand<ProjectSettingsValues> {
|
extends SerializedProjectCommand<ProjectSettingsValues> {
|
||||||
schemaVersion: typeof projectSettingsUpdateCommandSchemaVersion;
|
schemaVersion: typeof projectSettingsUpdateCommandSchemaVersion;
|
||||||
type: typeof projectSettingsUpdateCommandType;
|
type: typeof projectSettingsUpdateCommandType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PreviousProjectSettingsUpdateProjectCommand
|
||||||
|
extends SerializedProjectCommand<PreviousProjectSettingsValues> {
|
||||||
|
schemaVersion: typeof previousProjectSettingsUpdateCommandSchemaVersion;
|
||||||
|
type: typeof projectSettingsUpdateCommandType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProjectSettingsUpdateProjectCommand =
|
||||||
|
| CurrentProjectSettingsUpdateProjectCommand
|
||||||
|
| PreviousProjectSettingsUpdateProjectCommand;
|
||||||
|
|
||||||
export function createProjectSettingsUpdateProjectCommand(
|
export function createProjectSettingsUpdateProjectCommand(
|
||||||
values: ProjectSettingsValues
|
values: ProjectSettingsValues
|
||||||
): ProjectSettingsUpdateProjectCommand {
|
): CurrentProjectSettingsUpdateProjectCommand {
|
||||||
const command: ProjectSettingsUpdateProjectCommand = {
|
const command: CurrentProjectSettingsUpdateProjectCommand = {
|
||||||
schemaVersion: projectSettingsUpdateCommandSchemaVersion,
|
schemaVersion: projectSettingsUpdateCommandSchemaVersion,
|
||||||
type: projectSettingsUpdateCommandType,
|
type: projectSettingsUpdateCommandType,
|
||||||
payload: { ...values },
|
payload: { ...values },
|
||||||
@@ -42,7 +59,8 @@ export function assertProjectSettingsUpdateProjectCommand(
|
|||||||
): asserts command is ProjectSettingsUpdateProjectCommand {
|
): asserts command is ProjectSettingsUpdateProjectCommand {
|
||||||
if (
|
if (
|
||||||
command.type !== projectSettingsUpdateCommandType ||
|
command.type !== projectSettingsUpdateCommandType ||
|
||||||
command.schemaVersion !== projectSettingsUpdateCommandSchemaVersion
|
(command.schemaVersion !== projectSettingsUpdateCommandSchemaVersion &&
|
||||||
|
command.schemaVersion !== previousProjectSettingsUpdateCommandSchemaVersion)
|
||||||
) {
|
) {
|
||||||
throw new Error("Unsupported project settings update command.");
|
throw new Error("Unsupported project settings update command.");
|
||||||
}
|
}
|
||||||
@@ -58,8 +76,7 @@ export function assertProjectSettingsUpdateProjectCommand(
|
|||||||
!isNullableTrimmedString(command.payload.buildingOwner, 200) ||
|
!isNullableTrimmedString(command.payload.buildingOwner, 200) ||
|
||||||
!isNullableTrimmedString(command.payload.description, 2000) ||
|
!isNullableTrimmedString(command.payload.description, 2000) ||
|
||||||
!isPositiveFiniteNumber(command.payload.singlePhaseVoltageV) ||
|
!isPositiveFiniteNumber(command.payload.singlePhaseVoltageV) ||
|
||||||
!isPositiveFiniteNumber(command.payload.threePhaseVoltageV) ||
|
!isPositiveFiniteNumber(command.payload.threePhaseVoltageV)
|
||||||
Object.keys(command.payload).length !== 8
|
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Project settings update command contains invalid values."
|
"Project settings update command contains invalid values."
|
||||||
@@ -74,6 +91,18 @@ export function assertProjectSettingsUpdateProjectCommand(
|
|||||||
"Project settings update command contains invalid supply types."
|
"Project settings update command contains invalid supply types."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const isPreviousSchema =
|
||||||
|
command.schemaVersion === previousProjectSettingsUpdateCommandSchemaVersion;
|
||||||
|
if (
|
||||||
|
(isPreviousSchema && Object.keys(command.payload).length !== 8) ||
|
||||||
|
(!isPreviousSchema &&
|
||||||
|
(typeof command.payload.isPublicBuilding !== "boolean" ||
|
||||||
|
Object.keys(command.payload).length !== 9))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Project settings update command contains invalid values."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidSupplyTypes(
|
function isValidSupplyTypes(
|
||||||
|
|||||||
@@ -19,13 +19,14 @@ import {
|
|||||||
resolveProjectVoltage,
|
resolveProjectVoltage,
|
||||||
} from "../services/project-voltage.service.js";
|
} from "../services/project-voltage.service.js";
|
||||||
|
|
||||||
export const projectStateSnapshotSchemaVersion = 1 as const;
|
export const projectStateSnapshotSchemaVersion = 2 as const;
|
||||||
|
const previousProjectStateSnapshotSchemaVersion = 1 as const;
|
||||||
|
|
||||||
const idSchema = z.string().trim().min(1);
|
const idSchema = z.string().trim().min(1);
|
||||||
const nullableStringSchema = z.string().nullable();
|
const nullableStringSchema = z.string().nullable();
|
||||||
const finiteNumberSchema = z.number().finite();
|
const finiteNumberSchema = z.number().finite();
|
||||||
|
|
||||||
const projectSchema = z
|
const previousProjectSchema = z
|
||||||
.object({
|
.object({
|
||||||
id: idSchema,
|
id: idSchema,
|
||||||
name: z.string().trim().min(1),
|
name: z.string().trim().min(1),
|
||||||
@@ -42,6 +43,10 @@ const projectSchema = z
|
|||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
const projectSchema = previousProjectSchema
|
||||||
|
.extend({ isPublicBuilding: z.boolean() })
|
||||||
|
.strict();
|
||||||
|
|
||||||
const distributionBoardSchema = z
|
const distributionBoardSchema = z
|
||||||
.object({
|
.object({
|
||||||
id: idSchema,
|
id: idSchema,
|
||||||
@@ -267,6 +272,15 @@ export const projectStateSnapshotSchema = z
|
|||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
|
const previousProjectStateSnapshotSchema = z
|
||||||
|
.object({
|
||||||
|
schemaVersion: z.literal(previousProjectStateSnapshotSchemaVersion),
|
||||||
|
project: previousProjectSchema,
|
||||||
|
distributionBoards: z.array(distributionBoardSchema),
|
||||||
|
...projectStateSnapshotContents,
|
||||||
|
})
|
||||||
|
.strict();
|
||||||
|
|
||||||
export type ProjectStateSnapshot = z.infer<
|
export type ProjectStateSnapshot = z.infer<
|
||||||
typeof projectStateSnapshotSchema
|
typeof projectStateSnapshotSchema
|
||||||
>;
|
>;
|
||||||
@@ -274,12 +288,35 @@ export type ProjectStateSnapshot = z.infer<
|
|||||||
export function parseProjectStateSnapshot(
|
export function parseProjectStateSnapshot(
|
||||||
value: unknown
|
value: unknown
|
||||||
): ProjectStateSnapshot {
|
): ProjectStateSnapshot {
|
||||||
const parsedSnapshot = projectStateSnapshotSchema.parse(value);
|
const parsedSnapshot = projectStateSnapshotSchema.parse(
|
||||||
|
upgradePreviousProjectStateSnapshot(value)
|
||||||
|
);
|
||||||
const snapshot = normalizeSnapshotPhaseTypes(parsedSnapshot);
|
const snapshot = normalizeSnapshotPhaseTypes(parsedSnapshot);
|
||||||
assertProjectStateSnapshotRelations(snapshot);
|
assertProjectStateSnapshotRelations(snapshot);
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function upgradePreviousProjectStateSnapshot(value: unknown): unknown {
|
||||||
|
if (
|
||||||
|
value === null ||
|
||||||
|
typeof value !== "object" ||
|
||||||
|
Array.isArray(value) ||
|
||||||
|
(value as { schemaVersion?: unknown }).schemaVersion !==
|
||||||
|
previousProjectStateSnapshotSchemaVersion
|
||||||
|
) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const previous = previousProjectStateSnapshotSchema.parse(value);
|
||||||
|
return {
|
||||||
|
...previous,
|
||||||
|
schemaVersion: projectStateSnapshotSchemaVersion,
|
||||||
|
project: {
|
||||||
|
...previous.project,
|
||||||
|
isPublicBuilding: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeSnapshotPhaseTypes(
|
function normalizeSnapshotPhaseTypes(
|
||||||
snapshot: ProjectStateSnapshot
|
snapshot: ProjectStateSnapshot
|
||||||
): ProjectStateSnapshot {
|
): ProjectStateSnapshot {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export interface ProjectSettingsInput {
|
|||||||
externalProjectNumber: string | null;
|
externalProjectNumber: string | null;
|
||||||
buildingOwner: string | null;
|
buildingOwner: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
isPublicBuilding: boolean;
|
||||||
singlePhaseVoltageV: number;
|
singlePhaseVoltageV: number;
|
||||||
threePhaseVoltageV: number;
|
threePhaseVoltageV: number;
|
||||||
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
||||||
@@ -54,6 +55,9 @@ export function ProjectSettingsModal({
|
|||||||
const [description, setDescription] = useState(
|
const [description, setDescription] = useState(
|
||||||
project.description ?? ""
|
project.description ?? ""
|
||||||
);
|
);
|
||||||
|
const [isPublicBuilding, setIsPublicBuilding] = useState(
|
||||||
|
project.isPublicBuilding
|
||||||
|
);
|
||||||
const [singlePhaseVoltageV, setSinglePhaseVoltageV] = useState(
|
const [singlePhaseVoltageV, setSinglePhaseVoltageV] = useState(
|
||||||
String(project.singlePhaseVoltageV)
|
String(project.singlePhaseVoltageV)
|
||||||
);
|
);
|
||||||
@@ -82,6 +86,7 @@ export function ProjectSettingsModal({
|
|||||||
externalProjectNumber: toNullableString(externalProjectNumber),
|
externalProjectNumber: toNullableString(externalProjectNumber),
|
||||||
buildingOwner: toNullableString(buildingOwner),
|
buildingOwner: toNullableString(buildingOwner),
|
||||||
description: toNullableString(description),
|
description: toNullableString(description),
|
||||||
|
isPublicBuilding,
|
||||||
singlePhaseVoltageV: Number(singlePhaseVoltageV),
|
singlePhaseVoltageV: Number(singlePhaseVoltageV),
|
||||||
threePhaseVoltageV: Number(threePhaseVoltageV),
|
threePhaseVoltageV: Number(threePhaseVoltageV),
|
||||||
enabledDistributionBoardSupplyTypes,
|
enabledDistributionBoardSupplyTypes,
|
||||||
@@ -269,6 +274,27 @@ export function ProjectSettingsModal({
|
|||||||
value={description}
|
value={description}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<label className="form-check">
|
||||||
|
<input
|
||||||
|
checked={isPublicBuilding}
|
||||||
|
className="form-check-input"
|
||||||
|
id="public-building"
|
||||||
|
onChange={(event) =>
|
||||||
|
setIsPublicBuilding(event.target.checked)
|
||||||
|
}
|
||||||
|
type="checkbox"
|
||||||
|
/>
|
||||||
|
<span className="form-check-label">
|
||||||
|
Öffentliches Gebäude
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-text ms-4">
|
||||||
|
Wird bei der späteren Leitungsauslegung berücksichtigt,
|
||||||
|
insbesondere bei der Auswahl halogenfreier Kabel und
|
||||||
|
Leitungen.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<label className="form-label" htmlFor="single-phase-voltage">
|
<label className="form-label" htmlFor="single-phase-voltage">
|
||||||
Standardspannung 1-phasig [V]
|
Standardspannung 1-phasig [V]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface ProjectDto {
|
|||||||
externalProjectNumber: string | null;
|
externalProjectNumber: string | null;
|
||||||
buildingOwner: string | null;
|
buildingOwner: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
isPublicBuilding: boolean;
|
||||||
singlePhaseVoltageV: number;
|
singlePhaseVoltageV: number;
|
||||||
threePhaseVoltageV: number;
|
threePhaseVoltageV: number;
|
||||||
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
enabledDistributionBoardSupplyTypes: DistributionBoardSupplyType[];
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ export function updateProjectSettings(
|
|||||||
externalProjectNumber: string | null;
|
externalProjectNumber: string | null;
|
||||||
buildingOwner: string | null;
|
buildingOwner: string | null;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
isPublicBuilding: boolean;
|
||||||
singlePhaseVoltageV: number;
|
singlePhaseVoltageV: number;
|
||||||
threePhaseVoltageV: number;
|
threePhaseVoltageV: number;
|
||||||
enabledDistributionBoardSupplyTypes: ProjectDto["enabledDistributionBoardSupplyTypes"];
|
enabledDistributionBoardSupplyTypes: ProjectDto["enabledDistributionBoardSupplyTypes"];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export const createProjectSchema = z.object({
|
|||||||
externalProjectNumber: z.string().trim().max(100).optional(),
|
externalProjectNumber: z.string().trim().max(100).optional(),
|
||||||
buildingOwner: z.string().trim().max(200).optional(),
|
buildingOwner: z.string().trim().max(200).optional(),
|
||||||
description: z.string().trim().max(2000).optional(),
|
description: z.string().trim().max(2000).optional(),
|
||||||
|
isPublicBuilding: z.boolean().optional(),
|
||||||
singlePhaseVoltageV: z.number().positive().optional(),
|
singlePhaseVoltageV: z.number().positive().optional(),
|
||||||
threePhaseVoltageV: z.number().positive().optional(),
|
threePhaseVoltageV: z.number().positive().optional(),
|
||||||
});
|
});
|
||||||
@@ -20,6 +21,7 @@ export const updateProjectSettingsSchema = z
|
|||||||
externalProjectNumber: z.string().trim().max(100).nullable(),
|
externalProjectNumber: z.string().trim().max(100).nullable(),
|
||||||
buildingOwner: z.string().trim().max(200).nullable(),
|
buildingOwner: z.string().trim().max(200).nullable(),
|
||||||
description: z.string().trim().max(2000).nullable(),
|
description: z.string().trim().max(2000).nullable(),
|
||||||
|
isPublicBuilding: z.boolean(),
|
||||||
singlePhaseVoltageV: z.number().positive(),
|
singlePhaseVoltageV: z.number().positive(),
|
||||||
threePhaseVoltageV: z.number().positive(),
|
threePhaseVoltageV: z.number().positive(),
|
||||||
enabledDistributionBoardSupplyTypes: z
|
enabledDistributionBoardSupplyTypes: z
|
||||||
|
|||||||
@@ -1057,6 +1057,7 @@ describe("project command service", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -1073,6 +1074,7 @@ describe("project command service", () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
context.db
|
context.db
|
||||||
.select({
|
.select({
|
||||||
|
isPublicBuilding: projects.isPublicBuilding,
|
||||||
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: projects.threePhaseVoltageV,
|
threePhaseVoltageV: projects.threePhaseVoltageV,
|
||||||
})
|
})
|
||||||
@@ -1080,6 +1082,7 @@ describe("project command service", () => {
|
|||||||
.where(eq(projects.id, "project-1"))
|
.where(eq(projects.id, "project-1"))
|
||||||
.get(),
|
.get(),
|
||||||
{
|
{
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
}
|
}
|
||||||
@@ -1093,6 +1096,7 @@ describe("project command service", () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
context.db
|
context.db
|
||||||
.select({
|
.select({
|
||||||
|
isPublicBuilding: projects.isPublicBuilding,
|
||||||
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: projects.threePhaseVoltageV,
|
threePhaseVoltageV: projects.threePhaseVoltageV,
|
||||||
})
|
})
|
||||||
@@ -1100,6 +1104,7 @@ describe("project command service", () => {
|
|||||||
.where(eq(projects.id, "project-1"))
|
.where(eq(projects.id, "project-1"))
|
||||||
.get(),
|
.get(),
|
||||||
{
|
{
|
||||||
|
isPublicBuilding: false,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ function getSettings(context: DatabaseContext) {
|
|||||||
externalProjectNumber: projects.externalProjectNumber,
|
externalProjectNumber: projects.externalProjectNumber,
|
||||||
buildingOwner: projects.buildingOwner,
|
buildingOwner: projects.buildingOwner,
|
||||||
description: projects.description,
|
description: projects.description,
|
||||||
|
isPublicBuilding: projects.isPublicBuilding,
|
||||||
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
singlePhaseVoltageV: projects.singlePhaseVoltageV,
|
||||||
threePhaseVoltageV: projects.threePhaseVoltageV,
|
threePhaseVoltageV: projects.threePhaseVoltageV,
|
||||||
enabledDistributionBoardSupplyTypes:
|
enabledDistributionBoardSupplyTypes:
|
||||||
@@ -69,6 +70,7 @@ function settings(
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: false,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -204,6 +206,7 @@ describe("project settings project-command repository", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: false,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -231,6 +234,7 @@ describe("project settings project-command repository", () => {
|
|||||||
...settings(),
|
...settings(),
|
||||||
name: "Neuer Projektname",
|
name: "Neuer Projektname",
|
||||||
buildingOwner: "Beispiel Bau GmbH",
|
buildingOwner: "Beispiel Bau GmbH",
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -252,6 +256,7 @@ describe("project settings project-command repository", () => {
|
|||||||
...settings({
|
...settings({
|
||||||
name: "Neuer Projektname",
|
name: "Neuer Projektname",
|
||||||
buildingOwner: "Beispiel Bau GmbH",
|
buildingOwner: "Beispiel Bau GmbH",
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
}),
|
}),
|
||||||
@@ -273,6 +278,7 @@ describe("project settings project-command repository", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: false,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -300,6 +306,7 @@ describe("project settings project-command repository", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: false,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -338,6 +345,7 @@ describe("project settings project-command repository", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: "Beispiel Bau GmbH",
|
buildingOwner: "Beispiel Bau GmbH",
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 240,
|
singlePhaseVoltageV: 240,
|
||||||
threePhaseVoltageV: 415,
|
threePhaseVoltageV: 415,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -365,6 +373,66 @@ describe("project settings project-command repository", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves the building classification when applying a baseline command", () => {
|
||||||
|
const context = createTestDatabase();
|
||||||
|
try {
|
||||||
|
context.db
|
||||||
|
.update(projects)
|
||||||
|
.set({ isPublicBuilding: true })
|
||||||
|
.where(eq(projects.id, "project-1"))
|
||||||
|
.run();
|
||||||
|
const repository = new ProjectSettingsProjectCommandRepository(
|
||||||
|
context.db
|
||||||
|
);
|
||||||
|
|
||||||
|
const forward = repository.executeUpdate({
|
||||||
|
projectId: "project-1",
|
||||||
|
expectedRevision: 0,
|
||||||
|
source: "user",
|
||||||
|
command: {
|
||||||
|
schemaVersion: 1,
|
||||||
|
type: "project.update-settings",
|
||||||
|
payload: {
|
||||||
|
name: "Stand aus Baseline-Command",
|
||||||
|
internalProjectNumber: "INT-1",
|
||||||
|
externalProjectNumber: null,
|
||||||
|
buildingOwner: null,
|
||||||
|
description: null,
|
||||||
|
singlePhaseVoltageV: 230,
|
||||||
|
threePhaseVoltageV: 400,
|
||||||
|
enabledDistributionBoardSupplyTypes: [
|
||||||
|
"AV",
|
||||||
|
"SV",
|
||||||
|
"EV",
|
||||||
|
"USV",
|
||||||
|
"MSR",
|
||||||
|
"SiBe",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(getSettings(context)?.name, "Stand aus Baseline-Command");
|
||||||
|
assert.equal(getSettings(context)?.isPublicBuilding, true);
|
||||||
|
assert.equal(forward.inverse.schemaVersion, 1);
|
||||||
|
|
||||||
|
const history = new ProjectHistoryRepository(context.db);
|
||||||
|
const undoStep = history.getNextCommand("project-1", "undo");
|
||||||
|
assert.ok(undoStep);
|
||||||
|
repository.executeUpdate({
|
||||||
|
projectId: "project-1",
|
||||||
|
expectedRevision: 1,
|
||||||
|
source: "undo",
|
||||||
|
historyTargetChangeSetId: undoStep.changeSetId,
|
||||||
|
command: forward.inverse,
|
||||||
|
});
|
||||||
|
assert.equal(getSettings(context)?.name, "Testprojekt");
|
||||||
|
assert.equal(getSettings(context)?.isPublicBuilding, true);
|
||||||
|
} finally {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("persists the project supply-type selection and rejects disabling an in-use type", () => {
|
it("persists the project supply-type selection and rejects disabling an in-use type", () => {
|
||||||
const context = createTestDatabase();
|
const context = createTestDatabase();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ function minimalSnapshot() {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -142,7 +143,18 @@ describe("project state snapshot model", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects pre-baseline snapshot shapes", () => {
|
it("upgrades the supported baseline snapshot with a safe building default", () => {
|
||||||
|
const baseline = structuredClone(minimalSnapshot());
|
||||||
|
baseline.schemaVersion = 1 as typeof baseline.schemaVersion;
|
||||||
|
delete (baseline.project as Record<string, unknown>).isPublicBuilding;
|
||||||
|
|
||||||
|
const upgraded = parseProjectStateSnapshot(baseline);
|
||||||
|
|
||||||
|
assert.equal(upgraded.schemaVersion, projectStateSnapshotSchemaVersion);
|
||||||
|
assert.equal(upgraded.project.isPublicBuilding, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects malformed baseline and unknown snapshot shapes", () => {
|
||||||
const outdated = structuredClone(minimalSnapshot());
|
const outdated = structuredClone(minimalSnapshot());
|
||||||
delete (outdated.project as Record<string, unknown>).description;
|
delete (outdated.project as Record<string, unknown>).description;
|
||||||
assert.throws(() => parseProjectStateSnapshot(outdated));
|
assert.throws(() => parseProjectStateSnapshot(outdated));
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ describe("project settings presentation", () => {
|
|||||||
externalProjectNumber: null,
|
externalProjectNumber: null,
|
||||||
buildingOwner: null,
|
buildingOwner: null,
|
||||||
description: null,
|
description: null,
|
||||||
|
isPublicBuilding: true,
|
||||||
singlePhaseVoltageV: 230,
|
singlePhaseVoltageV: 230,
|
||||||
threePhaseVoltageV: 400,
|
threePhaseVoltageV: 400,
|
||||||
enabledDistributionBoardSupplyTypes: [
|
enabledDistributionBoardSupplyTypes: [
|
||||||
@@ -262,6 +263,7 @@ describe("project settings presentation", () => {
|
|||||||
assert.match(markup, /MSR/);
|
assert.match(markup, /MSR/);
|
||||||
assert.match(markup, /SiBe/);
|
assert.match(markup, /SiBe/);
|
||||||
assert.match(markup, /in Verwendung/);
|
assert.match(markup, /in Verwendung/);
|
||||||
|
assert.match(markup, /Öffentliches Gebäude/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user