Add device traffic reset with outbound baselines
Build and Deploy Gateway / build-and-push (push) Successful in 21s
Build and Deploy Gateway / deploy (push) Successful in 14s

This commit is contained in:
2026-08-12 23:55:34 +03:00
parent 08cc013def
commit b86812d02b
18 changed files with 369 additions and 33 deletions
+34 -1
View File
@@ -19,6 +19,7 @@ interface DevicesFeatureOptions {
isGateway: boolean;
listDevices: () => Promise<unknown>;
refreshDevices: () => Promise<unknown>;
resetDeviceTraffic: (expectedRevision: number) => Promise<unknown>;
updateDevice: (id: string, patch: Record<string, unknown>, expectedRevision: number) => Promise<unknown>;
setDevicePolicy: (id: string, mode: DevicePolicy, expectedRevision: number) => Promise<unknown>;
}
@@ -40,6 +41,7 @@ export function useDevicesFeature({
isGateway,
listDevices,
refreshDevices,
resetDeviceTraffic,
updateDevice: requestDeviceUpdate,
setDevicePolicy,
}: DevicesFeatureOptions) {
@@ -50,6 +52,8 @@ export function useDevicesFeature({
const [refreshing, setRefreshing] = useState(false);
const [refreshCycle, setRefreshCycle] = useState(0);
const [savingId, setSavingId] = useState('');
const [resetOpen, setResetOpen] = useState(false);
const [resetting, setResetting] = useState(false);
const panelRef = useRef<HTMLElement>(null);
const toggleRef = useRef<HTMLButtonElement>(null);
const closeRef = useRef<HTMLButtonElement>(null);
@@ -136,6 +140,29 @@ export function useDevicesFeature({
}
}
async function confirmResetTraffic() {
if (!snapshot) return;
setResetting(true);
try {
let next: DeviceSnapshot;
try {
next = parseDeviceSnapshot(await resetDeviceTraffic(snapshot.revision));
} catch (caught) {
if (requestError(caught).code !== 'STATE_CONFLICT') throw caught;
const latest = parseDeviceSnapshot(await listDevices());
publish(latest);
next = parseDeviceSnapshot(await resetDeviceTraffic(latest.revision));
}
publish(next);
setError(null);
setResetOpen(false);
} catch (caught) {
setError(caught);
} finally {
setResetting(false);
}
}
useEffect(() => {
if (!isGateway) return undefined;
load();
@@ -152,6 +179,7 @@ export function useDevicesFeature({
if (!isOpen) return undefined;
const frame = requestAnimationFrame(() => closeRef.current?.focus());
const closeDevices = (event: PointerEvent | KeyboardEvent) => {
if (resetOpen) return;
if (event.type === 'keydown' && (event as KeyboardEvent).key !== 'Escape') return;
if (event.type !== 'keydown' && (
panelRef.current?.contains(event.target as Node) || toggleRef.current?.contains(event.target as Node)
@@ -168,7 +196,7 @@ export function useDevicesFeature({
if (panelRef.current?.contains(document.activeElement)) toggleRef.current?.focus();
});
};
}, [isOpen]);
}, [isOpen, resetOpen]);
return {
isOpen,
@@ -178,12 +206,17 @@ export function useDevicesFeature({
refreshing,
refreshCycle,
savingId,
resetOpen,
resetting,
panelRef,
toggleRef,
closeRef,
load,
updateDevice,
updatePolicy,
requestTrafficReset: () => setResetOpen(true),
cancelTrafficReset: () => setResetOpen(false),
confirmResetTraffic,
close: () => setIsOpen(false),
toggle: () => setIsOpen((open) => !open),
};