Add buildings above floors and a building structure page
Projects with several buildings could not be structured: floors and rooms hung directly off the project. Floors can now belong to a building (migration 0009: table buildings, nullable floors.building_id). Rooms and distribution boards keep their floor; their building follows from it. Existing floors stay without a building. Buildings use the location-structure command store with project-building.insert/.update/.delete, inverses and persistent Undo/Redo; deleting a building with assigned floors is rejected. Floor commands carry buildingId since command version 2. Version 1 floor commands from existing history predate buildings and are upgraded with buildingId = null before they are executed and persisted, so forward and inverse keep one version. Project snapshot schema 7 stores buildings and floor.buildingId; versions 1-6 are upgraded without buildings. Restore and portable transfer include buildings, and the transfer remaps building ids. Buildings, floors and rooms move from the project overview to their own page /projects/:id/struktur with three columns (Gebäude -> Etagen -> Räume) that filter each other, and a sidebar entry. Floor selects in the board and room dialogs are grouped by building. Unchanged dialogs close without a command. Details in docs/building-structure.md; see issue #6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7692699ee2
commit
cd89c4a499
42 changed files with 5883 additions and 373 deletions
|
|
@ -1,5 +1,7 @@
|
|||
import type {
|
||||
BuildingDto,
|
||||
CircuitListDto,
|
||||
CreateBuildingInput,
|
||||
CreateFloorInput,
|
||||
CreateProjectDeviceInput,
|
||||
CreateRoomInput,
|
||||
|
|
@ -17,6 +19,7 @@ import type {
|
|||
ProjectCommandResultDto,
|
||||
ProjectDeviceCommandResultDto,
|
||||
ProjectDeviceDto,
|
||||
ProjectBuildingCommandResultDto,
|
||||
ProjectFloorCommandResultDto,
|
||||
ProjectHistoryStateDto,
|
||||
ProjectRevisionPageDto,
|
||||
|
|
@ -881,6 +884,61 @@ export function renumberCircuitSectionCommand(
|
|||
);
|
||||
}
|
||||
|
||||
export function listBuildings(projectId: string) {
|
||||
return request<BuildingDto[]>(`/api/projects/${projectId}/buildings`);
|
||||
}
|
||||
|
||||
export function createBuilding(
|
||||
projectId: string,
|
||||
input: CreateBuildingInput,
|
||||
expectedRevision: number
|
||||
) {
|
||||
return request<ProjectBuildingCommandResultDto>(
|
||||
`/api/projects/${projectId}/buildings`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name: input.name, expectedRevision }),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function updateBuilding(
|
||||
projectId: string,
|
||||
buildingId: string,
|
||||
input: CreateBuildingInput,
|
||||
expectedRevision: number
|
||||
) {
|
||||
return request<ProjectBuildingCommandResultDto>(
|
||||
`/api/projects/${projectId}/buildings/${buildingId}`,
|
||||
{
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ name: input.name, expectedRevision }),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function deleteBuilding(
|
||||
projectId: string,
|
||||
buildingId: string,
|
||||
expectedRevision: number
|
||||
) {
|
||||
return request<ProjectCommandResultDto>(
|
||||
`/api/projects/${projectId}/buildings/${buildingId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({ expectedRevision }),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// buildingId is only sent when the caller passes it (string or null);
|
||||
// an omitted buildingId keeps the current assignment on update.
|
||||
function toFloorRequestBody(input: CreateFloorInput, expectedRevision: number) {
|
||||
return input.buildingId === undefined
|
||||
? { name: input.name, expectedRevision }
|
||||
: { name: input.name, buildingId: input.buildingId, expectedRevision };
|
||||
}
|
||||
|
||||
export function listFloors(projectId: string) {
|
||||
return request<FloorDto[]>(`/api/projects/${projectId}/floors`);
|
||||
}
|
||||
|
|
@ -894,7 +952,7 @@ export function createFloor(
|
|||
`/api/projects/${projectId}/floors`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ ...input, expectedRevision }),
|
||||
body: JSON.stringify(toFloorRequestBody(input, expectedRevision)),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -907,7 +965,7 @@ export function updateFloor(
|
|||
) {
|
||||
return request<ProjectFloorCommandResultDto>(`/api/projects/${projectId}/floors/${floorId}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ ...input, expectedRevision }),
|
||||
body: JSON.stringify(toFloorRequestBody(input, expectedRevision)),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue