mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-18 06:23:18 +00:00
842ee7dd0c
* feat(fleet): export a whole-fleet Markdown dossier Add an admin-only "Export Dossier" action to the Fleet view that walks every node and stack, pairs each stack's generated Compose anatomy with its operator notes, and downloads a folder-structured homelab-dossier.zip (index, per-node and per-stack pages, plus fleet-wide port, volume, network, env, access-URL, and VLAN/firewall maps). Reuses the existing stack dossier and anatomy Markdown generators by extracting the shared Compose parsers into a frontend lib module. Unreachable nodes are recorded with a reason and never block the export; only env variable names and counts are ever emitted, never values. * fix(fleet): unique stack slugs and reproducible dossier archive Disambiguate stack names on one node that slugify to the same value (e.g. `Web` and `web` on a case-sensitive host) with a per-node slug map shared by the node-page links and the file emission, so neither overwrites the other. Pin a fixed entry timestamp on the zip so the archive bytes are a pure function of the file map rather than the wall clock.
24 lines
888 B
TypeScript
24 lines
888 B
TypeScript
/**
|
|
* Trigger a browser download of in-memory text as a file, using the standard
|
|
* object-URL + anchor-click idiom (the same pattern used elsewhere for exports,
|
|
* e.g. AuditLogView). Suited to client-side text such as a Markdown export.
|
|
*/
|
|
export function downloadTextFile(filename: string, text: string, mime = 'text/markdown'): void {
|
|
downloadBlob(filename, new Blob([text], { type: `${mime};charset=utf-8` }));
|
|
}
|
|
|
|
/**
|
|
* Trigger a browser download of an in-memory Blob (e.g. a zip archive built
|
|
* client-side). Same object-URL + anchor-click idiom as {@link downloadTextFile}.
|
|
*/
|
|
export function downloadBlob(filename: string, blob: Blob): void {
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
document.body.removeChild(a);
|
|
URL.revokeObjectURL(url);
|
|
}
|