fix(system): preserve MQTT interval draft editing

This commit is contained in:
DCCONSTRUCTIONS
2026-07-28 01:56:36 +03:00
parent d2964a0ddc
commit 65a72d40a8
4 changed files with 185 additions and 19 deletions
@@ -0,0 +1,70 @@
export const DEFAULT_TELEMETRY_POLL_INTERVAL_SECONDS = 3;
export const MIN_TELEMETRY_POLL_INTERVAL_SECONDS = 1;
export const MAX_TELEMETRY_POLL_INTERVAL_SECONDS = 60;
export interface TelemetryPollIntervalDraftResolution {
accepted: boolean;
draft: string;
seconds: number;
}
function normalizeCommittedSeconds(seconds: number): number {
if (
!Number.isSafeInteger(seconds)
|| seconds < MIN_TELEMETRY_POLL_INTERVAL_SECONDS
|| seconds > MAX_TELEMETRY_POLL_INTERVAL_SECONDS
) {
return DEFAULT_TELEMETRY_POLL_INTERVAL_SECONDS;
}
return seconds;
}
export function parseTelemetryPollIntervalDraft(draft: string): number | null {
const candidate = draft.trim();
if (!/^[0-9]+$/.test(candidate)) return null;
const seconds = Number(candidate);
if (
!Number.isSafeInteger(seconds)
|| seconds < MIN_TELEMETRY_POLL_INTERVAL_SECONDS
|| seconds > MAX_TELEMETRY_POLL_INTERVAL_SECONDS
) {
return null;
}
return seconds;
}
export function resolveTelemetryPollIntervalDraft(
draft: string,
committedSeconds: number,
): TelemetryPollIntervalDraftResolution {
const seconds = parseTelemetryPollIntervalDraft(draft);
if (seconds === null) {
const fallbackSeconds = normalizeCommittedSeconds(committedSeconds);
return {
accepted: false,
draft: String(fallbackSeconds),
seconds: fallbackSeconds,
};
}
return {
accepted: true,
draft: String(seconds),
seconds,
};
}
export function normalizeWorkerTelemetryPollMilliseconds(
pollMilliseconds: number,
): number {
if (!Number.isFinite(pollMilliseconds)) {
return DEFAULT_TELEMETRY_POLL_INTERVAL_SECONDS * 1_000;
}
return Math.min(
MAX_TELEMETRY_POLL_INTERVAL_SECONDS * 1_000,
Math.max(
MIN_TELEMETRY_POLL_INTERVAL_SECONDS * 1_000,
Math.round(pollMilliseconds),
),
);
}
@@ -4,6 +4,7 @@ import {
fetchWorkerTelemetry,
type WorkerTelemetry,
} from "./workerTelemetry";
import { normalizeWorkerTelemetryPollMilliseconds } from "./telemetryPollInterval";
export const DEFAULT_WORKER_TELEMETRY_POLL_MILLISECONDS = 3_000;
@@ -18,6 +19,9 @@ export function useWorkerTelemetry(
pollMilliseconds = DEFAULT_WORKER_TELEMETRY_POLL_MILLISECONDS,
enabled = true,
): WorkerTelemetryState {
const normalizedPollMilliseconds = normalizeWorkerTelemetryPollMilliseconds(
pollMilliseconds,
);
const [telemetry, setTelemetry] = useState<WorkerTelemetry | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
@@ -51,9 +55,9 @@ export function useWorkerTelemetry(
useEffect(() => {
if (!enabled || loading) return;
const timer = window.setTimeout(refresh, pollMilliseconds);
const timer = window.setTimeout(refresh, normalizedPollMilliseconds);
return () => window.clearTimeout(timer);
}, [enabled, loading, pollMilliseconds, refresh]);
}, [enabled, loading, normalizedPollMilliseconds, refresh]);
return { telemetry, loading, error, refresh };
}