Decouple cutover HF from portrait and tighten ops UI.

Portrait stays on biz-monitor; cutover create/ensure owns purpose=cutover_hf slots with project collect override, multi-interval bindings, window pause, and industrial detail UX. Also expand ZTE collect/config parsers and TextFSM for route/BGP/L2VPN/VRRP coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-19 21:11:31 +08:00
parent a65c9fc420
commit 285c19e5a3
67 changed files with 9510 additions and 723 deletions

View file

@ -44,3 +44,31 @@ export function formatSystemTime(
timeZone: systemTimeZone,
});
}
/**
* `<input type="datetime-local">` (browser system wall clock) → UTC ISO with `Z` for API/DB.
* Global deployments store UTC; each operator edits in their local timezone.
*/
export function localDatetimeInputToUtcIso(localValue: string): string | null {
const v = String(localValue || "").trim();
if (!v) return null;
const m = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?/.exec(v);
if (!m) return null;
const y = Number(m[1]);
const mo = Number(m[2]) - 1;
const day = Number(m[3]);
const h = Number(m[4]);
const mi = Number(m[5]);
const sec = Number(m[6] || 0);
const local = new Date(y, mo, day, h, mi, sec);
if (Number.isNaN(local.getTime())) return null;
return local.toISOString();
}
/** API/DB UTC (naive or `Z`) → `datetime-local` value in the browser system timezone. */
export function utcIsoToLocalDatetimeInput(iso: string | null | undefined): string {
const d = parseApiTime(iso);
if (!d) return "";
const pad = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}