generated from Dicken/dickendock
round36: Bestaetigte Scan-Ergebnisse erscheinen nach Neuladen der Seite nicht mehr erneut (betraf alle drei Scanner)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
@@ -71,6 +71,35 @@ function nameChangeKey(c: ScanNameChange): string {
|
||||
return `${c.serviceId}:${c.field}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merkt sich (dauerhaft über sessionStorage, NICHT über React-State), welches
|
||||
* Backend-Scan-Ergebnis (identifiziert über seinen startedAt-Zeitstempel)
|
||||
* bereits in die lokale Anzeige übernommen wurde. Bewusst kein
|
||||
* usePersistedState/useState hier: der Poll-Callback läuft in einem
|
||||
* setInterval, das nur einmal erzeugt wird (leeres deps-Array) - ein
|
||||
* React-State-Wert wäre in diesem Callback für immer auf seinem Anfangswert
|
||||
* eingefroren (stale closure). Gleichzeitig darf der Wert NICHT nur im
|
||||
* Speicher (useRef) leben, sonst würde ein Neuladen der Seite ihn auf null
|
||||
* zurücksetzen und dieselbe Meldung (inkl. bereits bestätigter Einträge)
|
||||
* einfach erneut aus dem immer noch unveränderten Backend-Ergebnis
|
||||
* importieren - genau das gemeldete Problem.
|
||||
*/
|
||||
function getHandledResultId(key: string): string | null {
|
||||
try {
|
||||
return sessionStorage.getItem(`launchpad:${key}`);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function setHandledResultId(key: string, value: string): void {
|
||||
try {
|
||||
sessionStorage.setItem(`launchpad:${key}`, value);
|
||||
} catch {
|
||||
// Speicher evtl. nicht verfügbar (Privatmodus o. ä.) - dann greift die
|
||||
// Deduplizierung für die aktuelle Sitzung eben nicht, kein Absturz nötig.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Übernimmt einen Namens-/Kategorie-Vorschlag des Scanners. Setzt dabei
|
||||
* explizit die *EditedManually-Flag auf false zurück, damit der Dienst
|
||||
@@ -311,8 +340,6 @@ function ApiScannerCard() {
|
||||
const [lastNewFindings, setLastNewFindings] = usePersistedState<
|
||||
{ serviceId: string; serviceName: string; apis: DetectedApiEntry[] }[]
|
||||
>("scanner:apiNewFindings", []);
|
||||
const lastHandledStartedAt = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
@@ -328,8 +355,8 @@ function ApiScannerCard() {
|
||||
setStatus(
|
||||
`Prüfe ${s.progress.currentLabel ?? "…"} (${s.progress.current + 1} von ${s.progress.total})`
|
||||
);
|
||||
} else if (s.lastResult && s.startedAt !== lastHandledStartedAt.current) {
|
||||
lastHandledStartedAt.current = s.startedAt;
|
||||
} else if (s.lastResult && s.startedAt !== getHandledResultId("scanner:apiLastHandledAt")) {
|
||||
setHandledResultId("scanner:apiLastHandledAt", s.startedAt);
|
||||
const r = s.lastResult;
|
||||
const newCount = r.newFindings.reduce(
|
||||
(sum: number, f: { apis: unknown[] }) => sum + f.apis.length,
|
||||
@@ -456,7 +483,6 @@ export function ScannerPage() {
|
||||
);
|
||||
|
||||
const [fritzboxRunning, setFritzboxRunning] = useState(false);
|
||||
const lastFritzboxHandledAt = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -469,16 +495,16 @@ export function ScannerPage() {
|
||||
|
||||
setFritzboxRunning(s.running);
|
||||
|
||||
if (!s.running && s.lastResult && s.startedAt !== lastFritzboxHandledAt.current) {
|
||||
lastFritzboxHandledAt.current = s.startedAt;
|
||||
if (!s.running && s.lastResult && s.startedAt !== getHandledResultId("scanner:fritzboxLastHandledAt")) {
|
||||
setHandledResultId("scanner:fritzboxLastHandledAt", s.startedAt);
|
||||
setFritzboxSummary({ found: s.lastResult.found, uniqueDevices: s.lastResult.uniqueDevices });
|
||||
setFritzboxError(null);
|
||||
setStaleDevices(s.lastResult.staleDevices);
|
||||
setDeviceChanges(s.lastResult.deviceChanges);
|
||||
queryClient.invalidateQueries({ queryKey: ["devices"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["logs"] });
|
||||
} else if (!s.running && s.lastError && s.startedAt !== lastFritzboxHandledAt.current) {
|
||||
lastFritzboxHandledAt.current = s.startedAt;
|
||||
} else if (!s.running && s.lastError && s.startedAt !== getHandledResultId("scanner:fritzboxLastHandledAt")) {
|
||||
setHandledResultId("scanner:fritzboxLastHandledAt", s.startedAt);
|
||||
setFritzboxError(s.lastError);
|
||||
}
|
||||
} catch {
|
||||
@@ -512,7 +538,6 @@ export function ScannerPage() {
|
||||
// die Seite offen ist - egal ob DIESER Browser den Scan gestartet hat oder
|
||||
// ein anderes Gerät: der Fortschritt/das letzte Ergebnis kommt direkt vom
|
||||
// Backend, ist also für jeden sichtbar, der die Seite gerade offen hat.
|
||||
const lastHandledResultAt = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
@@ -529,8 +554,8 @@ export function ScannerPage() {
|
||||
setBulkStatus(
|
||||
`Scanne ${status.progress.currentLabel ?? "…"} (${status.progress.current + 1} von ${status.progress.total})`
|
||||
);
|
||||
} else if (status.lastResult && status.startedAt !== lastHandledResultAt.current) {
|
||||
lastHandledResultAt.current = status.startedAt;
|
||||
} else if (status.lastResult && status.startedAt !== getHandledResultId("scanner:bulkLastHandledAt")) {
|
||||
setHandledResultId("scanner:bulkLastHandledAt", status.startedAt);
|
||||
const r = status.lastResult;
|
||||
const pending = r.nameChanges.length + r.staleServices.length;
|
||||
setBulkStatus(
|
||||
|
||||
Reference in New Issue
Block a user