generated from Dicken/dickendock
round60: Delta-Vergleich zum vorherigen Scan (FritzBox + Sammel-Scan) statt statischer Zahlen
This commit is contained in:
@@ -334,6 +334,10 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
const allStale: DeviceScanResult["staleServices"] = [];
|
||||
const allNameChanges: DeviceScanResult["nameChanges"] = [];
|
||||
const allNew: DeviceScanResult["newServices"] = [];
|
||||
// Sammelt die IDs ALLER gefundenen Dienste über den kompletten
|
||||
// Sammel-Scan hinweg - für den Vergleich mit dem vorherigen Lauf (siehe
|
||||
// weiter unten bei finishJob).
|
||||
const allServiceIds: string[] = [];
|
||||
let cancelled = false;
|
||||
|
||||
try {
|
||||
@@ -536,6 +540,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
allStale.push(...result.staleServices);
|
||||
allNameChanges.push(...result.nameChanges);
|
||||
allNew.push(...result.newServices);
|
||||
allServiceIds.push(...result.services.map((s) => s.id));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -566,6 +571,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
allStale.push(...result.staleServices);
|
||||
allNameChanges.push(...result.nameChanges);
|
||||
allNew.push(...result.newServices);
|
||||
allServiceIds.push(...result.services.map((s) => s.id));
|
||||
} catch (err) {
|
||||
// Einzelnes fehlgeschlagenes Gerät soll den Rest nicht
|
||||
// abbrechen - ABER trotzdem persistent loggen, statt
|
||||
@@ -598,6 +604,38 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
updateJobProgress("devices", scannedCount, null);
|
||||
}
|
||||
|
||||
// NEU (round60): Vergleich mit dem VORHERIGEN Sammel-Scan (siehe
|
||||
// gleiches Prinzip beim FritzBox-Scan oben) - Mengenvergleich der
|
||||
// gefundenen Dienst-IDs statt reiner Zahlenvergleich.
|
||||
const previousServiceIdsRaw = settingsRepo.getSetting("deviceScanLastServiceIds");
|
||||
const previousServiceIds: string[] | null = previousServiceIdsRaw ? JSON.parse(previousServiceIdsRaw) : null;
|
||||
const currentServiceIdSet = new Set(allServiceIds);
|
||||
|
||||
let changesSinceLastScan: string;
|
||||
if (cancelled) {
|
||||
changesSinceLastScan = "Abgebrochen - kein vollständiger Vergleich möglich.";
|
||||
} else if (previousServiceIds === null) {
|
||||
changesSinceLastScan = "Erster Scan - kein Vergleich zu einem vorherigen Lauf möglich.";
|
||||
} else {
|
||||
const previousSet = new Set(previousServiceIds);
|
||||
const newlyAppeared = allServiceIds.filter((id) => !previousSet.has(id));
|
||||
const noLongerSeen = previousServiceIds.filter((id) => !currentServiceIdSet.has(id));
|
||||
if (newlyAppeared.length === 0 && noLongerSeen.length === 0) {
|
||||
changesSinceLastScan = "Keine Änderungen seit dem letzten Sammel-Scan.";
|
||||
} else {
|
||||
const parts: string[] = [];
|
||||
if (newlyAppeared.length > 0) parts.push(`${newlyAppeared.length} neue(r) Dienst(e)`);
|
||||
if (noLongerSeen.length > 0) parts.push(`${noLongerSeen.length} Dienst(e) fehlen jetzt`);
|
||||
changesSinceLastScan = `Änderungen seit dem letzten Sammel-Scan: ${parts.join(", ")}.`;
|
||||
}
|
||||
}
|
||||
// Bei einem abgebrochenen Lauf NICHT als Vergleichsbasis speichern -
|
||||
// sonst würde ein unvollständiger Durchlauf fälschlich "Dienste
|
||||
// fehlen jetzt" für alle noch gar nicht gescannten Geräte anzeigen.
|
||||
if (!cancelled) {
|
||||
settingsRepo.setSetting("deviceScanLastServiceIds", JSON.stringify(allServiceIds));
|
||||
}
|
||||
|
||||
finishJob("devices", {
|
||||
totalDevices: devices.length,
|
||||
scannedCount,
|
||||
@@ -607,6 +645,7 @@ export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
staleServices: allStale,
|
||||
nameChanges: allNameChanges,
|
||||
newServices: allNew,
|
||||
changesSinceLastScan,
|
||||
});
|
||||
} catch (err) {
|
||||
// WICHTIG: Vorher wurde ein Abbruch des GESAMTEN Sammel-Scans nur im
|
||||
@@ -794,10 +833,43 @@ function mergeFritzboxHosts(hosts: FritzBoxHost[]): FritzBoxHost[] {
|
||||
return now - lastSeen >= staleThresholdMs;
|
||||
});
|
||||
|
||||
// NEU (round60): Vergleich mit dem VORHERIGEN Scan-Lauf - vorher
|
||||
// stand hier bei jedem Scan nur eine absolute Zahl ("45 Einträge"),
|
||||
// egal ob sich seit dem letzten Mal etwas geändert hatte oder nicht
|
||||
// (siehe Bugreport: "wird immer nur angezeigt wieviel Einträge beim
|
||||
// letzten Scan waren, das die ganze Zeit"). Die Geräte-IDs des
|
||||
// letzten erfolgreichen Laufs werden dafür in den Einstellungen
|
||||
// (app_settings) gemerkt und mit den JETZT gefundenen verglichen -
|
||||
// ein einfacher Mengenvergleich (nicht nur ein Zahlenvergleich),
|
||||
// damit "3 raus, 3 rein" nicht fälschlich als "keine Änderung"
|
||||
// durchgeht.
|
||||
const previousDeviceIdsRaw = settingsRepo.getSetting("fritzboxScanLastDeviceIds");
|
||||
const previousDeviceIds: string[] = previousDeviceIdsRaw ? JSON.parse(previousDeviceIdsRaw) : null;
|
||||
const currentDeviceIds = devices.map((d) => d.id);
|
||||
const currentDeviceIdSet = new Set(currentDeviceIds);
|
||||
|
||||
let changesSinceLastScan: string;
|
||||
if (previousDeviceIds === null) {
|
||||
changesSinceLastScan = "Erster Scan - kein Vergleich zu einem vorherigen Lauf möglich.";
|
||||
} else {
|
||||
const previousSet = new Set(previousDeviceIds);
|
||||
const newlyAppeared = currentDeviceIds.filter((id) => !previousSet.has(id));
|
||||
const noLongerSeen = previousDeviceIds.filter((id) => !currentDeviceIdSet.has(id));
|
||||
if (newlyAppeared.length === 0 && noLongerSeen.length === 0) {
|
||||
changesSinceLastScan = "Keine Änderungen seit dem letzten Scan.";
|
||||
} else {
|
||||
const parts: string[] = [];
|
||||
if (newlyAppeared.length > 0) parts.push(`${newlyAppeared.length} neue(s) Gerät(e)`);
|
||||
if (noLongerSeen.length > 0) parts.push(`${noLongerSeen.length} Gerät(e) fehlen jetzt`);
|
||||
changesSinceLastScan = `Änderungen seit dem letzten Scan: ${parts.join(", ")}.`;
|
||||
}
|
||||
}
|
||||
settingsRepo.setSetting("fritzboxScanLastDeviceIds", JSON.stringify(currentDeviceIds));
|
||||
|
||||
logRepo.logScan({
|
||||
type: "fritzbox",
|
||||
level: "info",
|
||||
message: `FritzBox-Scan: ${hosts.length} Eintrag/Einträge (${devices.length} eindeutige Geräte)${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""}`,
|
||||
message: `FritzBox-Scan: ${hosts.length} Eintrag/Einträge (${devices.length} eindeutige Geräte)${staleDevices.length > 0 ? `, ${staleDevices.length} nicht mehr gemeldet` : ""}${deviceChanges.length > 0 ? `, ${deviceChanges.length} Änderung(en) vorgeschlagen` : ""} - ${changesSinceLastScan}`,
|
||||
});
|
||||
|
||||
finishJob("fritzbox", {
|
||||
@@ -805,6 +877,7 @@ function mergeFritzboxHosts(hosts: FritzBoxHost[]): FritzBoxHost[] {
|
||||
uniqueDevices: devices.length,
|
||||
staleDevices,
|
||||
deviceChanges,
|
||||
changesSinceLastScan,
|
||||
});
|
||||
} catch (err) {
|
||||
const detail = err instanceof Error ? err.message : String(err);
|
||||
|
||||
@@ -551,7 +551,7 @@ export function ScannerPage() {
|
||||
[]
|
||||
);
|
||||
const [fritzboxSummary, setFritzboxSummary] = usePersistedState<
|
||||
{ found: number; uniqueDevices: number } | null
|
||||
{ found: number; uniqueDevices: number; changesSinceLastScan?: string } | null
|
||||
>("scanner:fritzboxSummary", null);
|
||||
const [fritzboxError, setFritzboxError] = usePersistedState<string | null>(
|
||||
"scanner:fritzboxError",
|
||||
@@ -573,7 +573,11 @@ export function ScannerPage() {
|
||||
|
||||
if (!s.running && s.lastResult && s.startedAt !== getHandledResultId("scanner:fritzboxLastHandledAt")) {
|
||||
setHandledResultId("scanner:fritzboxLastHandledAt", s.startedAt);
|
||||
setFritzboxSummary({ found: s.lastResult.found, uniqueDevices: s.lastResult.uniqueDevices });
|
||||
setFritzboxSummary({
|
||||
found: s.lastResult.found,
|
||||
uniqueDevices: s.lastResult.uniqueDevices,
|
||||
changesSinceLastScan: s.lastResult.changesSinceLastScan,
|
||||
});
|
||||
setFritzboxError(null);
|
||||
setStaleDevices(s.lastResult.staleDevices);
|
||||
setDeviceChanges(s.lastResult.deviceChanges);
|
||||
@@ -650,7 +654,8 @@ export function ScannerPage() {
|
||||
`${r.created} neue(r) Dienst(e) gefunden.` +
|
||||
(pending > 0
|
||||
? ` ${pending} Änderung(en) warten unten auf deine Bestätigung.`
|
||||
: " Keine Änderungen an bestehenden Diensten vorgeschlagen.")
|
||||
: " Keine Änderungen an bestehenden Diensten vorgeschlagen.") +
|
||||
(r.changesSinceLastScan ? ` ${r.changesSinceLastScan}` : "")
|
||||
);
|
||||
setBulkStaleServices(r.staleServices);
|
||||
setBulkNameChanges(r.nameChanges);
|
||||
@@ -730,7 +735,19 @@ export function ScannerPage() {
|
||||
{fritzboxRunning ? "Scanne …" : "FritzBox jetzt scannen"}
|
||||
</Button>
|
||||
{fritzboxSummary ? (
|
||||
<p className="mt-2 text-sm text-emerald-600 dark:text-emerald-400">
|
||||
<div className="mt-2 text-sm">
|
||||
{fritzboxSummary.changesSinceLastScan ? (
|
||||
<p
|
||||
className={
|
||||
fritzboxSummary.changesSinceLastScan.startsWith("Keine Änderungen")
|
||||
? "text-black/50 dark:text-white/50"
|
||||
: "font-medium text-emerald-600 dark:text-emerald-400"
|
||||
}
|
||||
>
|
||||
{fritzboxSummary.changesSinceLastScan}
|
||||
</p>
|
||||
) : null}
|
||||
<p className="text-black/50 dark:text-white/50">
|
||||
{fritzboxSummary.found} Eintrag/Einträge von der FritzBox,{" "}
|
||||
{fritzboxSummary.uniqueDevices} eindeutige Geräte
|
||||
{fritzboxSummary.found !== fritzboxSummary.uniqueDevices
|
||||
@@ -738,6 +755,7 @@ export function ScannerPage() {
|
||||
: ""}
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
{fritzboxError ? <p className="mt-2 text-sm text-red-500">{fritzboxError}</p> : null}
|
||||
<DeviceChangesReview
|
||||
|
||||
Reference in New Issue
Block a user