refactor(settings): extract shared parseGoDuration to drop the duplicated parser (F10)
The auto-heal floor fix copied durationPattern/unitSeconds/parseGoDurationSeconds verbatim from AutoUpdatePanel into AutoHealPanel. Move them to a shared SettingsView/parseGoDuration module imported by both panels — single source of truth (mirrors the STALE_TIME dedup), so the two clients' floors can't drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,48 +1,16 @@
|
||||
import { SchemaOf, boolean, mixed, object, string } from 'yup';
|
||||
|
||||
import { AutoHealScope } from '../../types';
|
||||
import { durationPattern, parseGoDurationSeconds } from '../parseGoDuration';
|
||||
|
||||
import { Values } from './types';
|
||||
|
||||
// Matches Go's time.ParseDuration units (e.g. "30s", "1m30s", "2h").
|
||||
const durationPattern = /^(\d+(\.\d+)?(ns|us|µs|ms|s|m|h))+$/;
|
||||
|
||||
// Lower bound for the check interval, kept in sync with the backend
|
||||
// (minAutoHealCheckInterval). A near-zero interval would hammer Docker with
|
||||
// list/inspect calls for no benefit, and the backend rejects it (400), so the
|
||||
// front-end must reject it too rather than letting a sub-second value through.
|
||||
const minCheckIntervalSeconds = 1;
|
||||
|
||||
// Seconds per Go duration unit, used to evaluate the configured interval against
|
||||
// the floor. Mirrors the units accepted by durationPattern.
|
||||
const unitSeconds: Record<string, number> = {
|
||||
ns: 1e-9,
|
||||
us: 1e-6,
|
||||
µs: 1e-6,
|
||||
ms: 1e-3,
|
||||
s: 1,
|
||||
m: 60,
|
||||
h: 3600,
|
||||
};
|
||||
|
||||
// parseGoDurationSeconds converts a Go-style duration (e.g. "1h30m") to seconds,
|
||||
// or returns null when the string is not a well-formed duration.
|
||||
function parseGoDurationSeconds(value: string): number | null {
|
||||
if (!durationPattern.test(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
const componentPattern = /(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)/g;
|
||||
let match = componentPattern.exec(value);
|
||||
while (match !== null) {
|
||||
total += parseFloat(match[1]) * unitSeconds[match[2]];
|
||||
match = componentPattern.exec(value);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
export function validation(): SchemaOf<Values> {
|
||||
return object({
|
||||
enabled: boolean().default(false),
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { SchemaOf, boolean, mixed, object, string } from 'yup';
|
||||
|
||||
import { AutoUpdateScope } from '../../types';
|
||||
import { durationPattern, parseGoDurationSeconds } from '../parseGoDuration';
|
||||
|
||||
import { Values } from './types';
|
||||
|
||||
// Matches Go's time.ParseDuration units (e.g. "6h", "30m", "1h30m").
|
||||
const durationPattern = /^(\d+(\.\d+)?(ns|us|µs|ms|s|m|h))+$/;
|
||||
|
||||
// Lower bound for the poll interval, kept in sync with the backend
|
||||
// (minAutoUpdatePollInterval). Polling more often than this only adds registry
|
||||
// load: the image-status cache (~5m) bounds detection latency, so a sub-minute
|
||||
@@ -18,36 +16,6 @@ const minPollIntervalSeconds = 60;
|
||||
// container can pass its healthcheck, defeating the gate.
|
||||
const minRollbackTimeoutSeconds = 10;
|
||||
|
||||
// Seconds per Go duration unit, used to evaluate the configured interval against
|
||||
// the floor. Mirrors the units accepted by durationPattern.
|
||||
const unitSeconds: Record<string, number> = {
|
||||
ns: 1e-9,
|
||||
us: 1e-6,
|
||||
µs: 1e-6,
|
||||
ms: 1e-3,
|
||||
s: 1,
|
||||
m: 60,
|
||||
h: 3600,
|
||||
};
|
||||
|
||||
// parseGoDurationSeconds converts a Go-style duration (e.g. "1h30m") to seconds,
|
||||
// or returns null when the string is not a well-formed duration.
|
||||
function parseGoDurationSeconds(value: string): number | null {
|
||||
if (!durationPattern.test(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
const componentPattern = /(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)/g;
|
||||
let match = componentPattern.exec(value);
|
||||
while (match !== null) {
|
||||
total += parseFloat(match[1]) * unitSeconds[match[2]];
|
||||
match = componentPattern.exec(value);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
export function validation(): SchemaOf<Values> {
|
||||
return object({
|
||||
enabled: boolean().default(false),
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Matches Go's time.ParseDuration units (e.g. "6h", "30m", "1h30m").
|
||||
export const durationPattern = /^(\d+(\.\d+)?(ns|us|µs|ms|s|m|h))+$/;
|
||||
|
||||
// Seconds per Go duration unit, used to evaluate a configured interval against a
|
||||
// floor. Mirrors the units accepted by durationPattern.
|
||||
const unitSeconds: Record<string, number> = {
|
||||
ns: 1e-9,
|
||||
us: 1e-6,
|
||||
µs: 1e-6,
|
||||
ms: 1e-3,
|
||||
s: 1,
|
||||
m: 60,
|
||||
h: 3600,
|
||||
};
|
||||
|
||||
// parseGoDurationSeconds converts a Go-style duration (e.g. "1h30m") to seconds,
|
||||
// or returns null when the string is not a well-formed duration.
|
||||
export function parseGoDurationSeconds(value: string): number | null {
|
||||
if (!durationPattern.test(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let total = 0;
|
||||
const componentPattern = /(\d+(?:\.\d+)?)(ns|us|µs|ms|s|m|h)/g;
|
||||
let match = componentPattern.exec(value);
|
||||
while (match !== null) {
|
||||
total += parseFloat(match[1]) * unitSeconds[match[2]];
|
||||
match = componentPattern.exec(value);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
Reference in New Issue
Block a user