diff --git a/src/lib/protocols.ts b/src/lib/protocols.ts index a5946ee..3e890fb 100644 --- a/src/lib/protocols.ts +++ b/src/lib/protocols.ts @@ -3,7 +3,7 @@ */ import { saveProtocol } from './db'; -import type { Device, Measurement, Protocol } from './types'; +import type { Device, Measurement, Protocol, SavedScan } from './types'; /** Eindeutige ID erzeugen */ export function uid(): string { @@ -73,6 +73,30 @@ export function renameDevice(protocol: Protocol, clientId: string, name: string) if (d) d.customName = name.trim() || undefined; } +/** + * Den aktuellen Geräte-Stand als benannten Scan-Snapshot einfrieren. + * Der Snapshot ist eine tiefe Kopie — spätere Re-Scans verändern ihn nicht. + */ +export function saveScan(protocol: Protocol, name: string): SavedScan { + const scan: SavedScan = { + id: uid(), + name: name.trim() || new Date().toLocaleString('de-DE'), + createdAt: Date.now(), + subnet: protocol.subnet, + // JSON-Roundtrip löst den Svelte-State-Proxy und friert die Daten ein + devices: JSON.parse(JSON.stringify(protocol.devices)) as Device[], + }; + (protocol.savedScans ??= []).push(scan); + return scan; +} + +/** Gespeicherten Scan-Snapshot löschen */ +export function deleteScan(protocol: Protocol, scanId: string): void { + if (protocol.savedScans) { + protocol.savedScans = protocol.savedScans.filter((s) => s.id !== scanId); + } +} + /** Messung zum Protokoll hinzufügen */ export function addMeasurement( protocol: Protocol, diff --git a/src/routes/protokoll/[id]/+page.svelte b/src/routes/protokoll/[id]/+page.svelte index ce3c4c6..2c7433f 100644 --- a/src/routes/protokoll/[id]/+page.svelte +++ b/src/routes/protokoll/[id]/+page.svelte @@ -11,7 +11,14 @@ import TextPromptDialog from '$lib/components/TextPromptDialog.svelte'; import ConfirmDialog from '$lib/components/ConfirmDialog.svelte'; import { getProtocol, saveProtocol, deleteProtocol } from '$lib/db'; - import { addMeasurement, upsertDevice, toggleFavorite, renameDevice } from '$lib/protocols'; + import { + addMeasurement, + upsertDevice, + toggleFavorite, + renameDevice, + saveScan, + deleteScan, + } from '$lib/protocols'; import { sync } from '$lib/sync.svelte'; import { toast } from '$lib/toast.svelte'; import { pushOverlay } from '$lib/overlay.svelte'; @@ -26,6 +33,9 @@ let saving = $state(false); let renameTarget = $state(null); let confirmDelete = $state(false); + let saveScanOpen = $state(false); + let expandedScan = $state(null); + let deleteScanId = $state(null); let appStateListener: PluginListenerHandle | null = null; @@ -162,6 +172,39 @@ goto('/auftraege/'); } + /** Datum + Uhrzeit kurz */ + function fmtDateTime(ts: number): string { + return new Date(ts).toLocaleString('de-DE', { + day: '2-digit', + month: '2-digit', + hour: '2-digit', + minute: '2-digit', + }); + } + + /** Vorschlag für den Scan-Namen */ + function defaultScanName(): string { + return 'Scan ' + fmtDateTime(Date.now()); + } + + /** Aktuellen Geräte-Stand als Snapshot speichern */ + function doSaveScan(name: string) { + if (protocol) { + saveScan(protocol, name); + void persist(); + toast.show('Scan gespeichert', 'success'); + } + saveScanOpen = false; + } + + function doDeleteScan() { + if (protocol && deleteScanId) { + deleteScan(protocol, deleteScanId); + void persist(); + } + deleteScanId = null; + } + function measurementsFor(deviceClientId: string) { return protocol?.measurements.filter((m) => m.deviceClientId === deviceClientId) ?? []; } @@ -246,9 +289,16 @@
-

- Geräte ({protocol.devices.length}) -

+
+

+ Geräte ({protocol.devices.length}) +

+ {#if protocol.devices.length > 0} + + {/if} +
{#if protocol.devices.length === 0}

Noch keine Geräte — IP-Scanner ausführen, um das Netz zu erfassen. @@ -266,6 +316,45 @@ {/each}

+ + {#if protocol.savedScans && protocol.savedScans.length > 0} +
+

Gespeicherte Scans

+ {#each protocol.savedScans as scan (scan.id)} +
+ + {#if expandedScan === scan.id} +
+ {#each scan.devices as d (d.clientId)} + + {/each} + +
+ {/if} +
+ {/each} +
+ {/if} +