forked from jappel/leistungsbilanz-ts
Add print view, board info card and document logo upload
- Seitenansicht (/projects/:projectId/print): tabular cover page, board overview with supply structure and power sums, one plan per board with a repeating title block; PDF via the browser print dialog with named @page rules (A4 portrait cover, A4/A3 landscape plans, page x of y). - Distribution-board info card (board number, location, fed-from, remark) in the board edit dialog, persisted through the additively extended distribution-board.update command (migration 0008, snapshot schema 6, legacy subtree commands normalized). - Global document logo upload (PNG/JPEG/SVG, max 2 MB) outside project revisions and snapshots. - fed-from stays free text; the overview hierarchy and cumulated sums are preliminary until the feed link is modeled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
2e3e85a8e5
commit
4779e4a1a7
40 changed files with 5297 additions and 33 deletions
|
|
@ -377,6 +377,67 @@ describe("project snapshot repository", () => {
|
|||
context.close();
|
||||
}
|
||||
});
|
||||
|
||||
it("restores snapshots stored with an older supported schema version", () => {
|
||||
const context = createTestDatabase();
|
||||
try {
|
||||
const repository = new ProjectSnapshotRepository(context.db);
|
||||
const snapshot = repository.createNamed({
|
||||
projectId: "project-1",
|
||||
expectedRevision: 0,
|
||||
name: "Vor dem Update",
|
||||
});
|
||||
assert.ok(snapshot);
|
||||
// Rewrite the stored payload into the previous (version 5) shape, as it
|
||||
// exists for snapshots created before the current version.
|
||||
const payload = JSON.parse(
|
||||
context.db
|
||||
.select({ payloadJson: projectSnapshots.payloadJson })
|
||||
.from(projectSnapshots)
|
||||
.where(eq(projectSnapshots.id, snapshot.id))
|
||||
.get()!.payloadJson
|
||||
) as {
|
||||
schemaVersion: number;
|
||||
project: Record<string, unknown>;
|
||||
distributionBoards: Array<Record<string, unknown>>;
|
||||
};
|
||||
payload.schemaVersion = 5;
|
||||
for (const field of ["siteAddress", "workStage", "projectLead", "projectEditor"]) {
|
||||
delete payload.project[field];
|
||||
}
|
||||
for (const board of payload.distributionBoards) {
|
||||
for (const field of ["boardNumber", "location", "fedFrom", "remark"]) {
|
||||
delete board[field];
|
||||
}
|
||||
}
|
||||
const payloadJson = JSON.stringify(payload);
|
||||
context.db
|
||||
.update(projectSnapshots)
|
||||
.set({
|
||||
schemaVersion: 5,
|
||||
payloadJson,
|
||||
payloadSha256: crypto
|
||||
.createHash("sha256")
|
||||
.update(payloadJson)
|
||||
.digest("hex"),
|
||||
})
|
||||
.where(eq(projectSnapshots.id, snapshot.id))
|
||||
.run();
|
||||
|
||||
const prepared = repository.prepareRestore("project-1", snapshot.id);
|
||||
assert.ok(prepared);
|
||||
const targetState = prepared.command.payload.targetState;
|
||||
assert.equal(targetState.schemaVersion, projectStateSnapshotSchemaVersion);
|
||||
assert.ok(targetState.distributionBoards.length > 0);
|
||||
assert.ok(
|
||||
targetState.distributionBoards.every(
|
||||
(board) => board.boardNumber === null && board.fedFrom === null
|
||||
)
|
||||
);
|
||||
} finally {
|
||||
context.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("portable project transfer", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue