From 68883d1a843b7f3de9f1ddaa07685b016563e1a6 Mon Sep 17 00:00:00 2001 From: oliver Date: Fri, 31 Jul 2026 11:13:22 +0800 Subject: [PATCH] Open WebCRT in its own module tab and fix UTC naive time display. Config/NE/topology links now focus the webcrt window instead of replacing network routes; formatSystemTime treats naive API timestamps as UTC. Co-authored-by: Cursor --- web/src/pages/NePage.tsx | 2 +- web/src/pages/TopologyPage.tsx | 4 ++-- web/src/pages/network/NetworkConfigsPage.tsx | 16 ++++++++++++---- web/src/utils/time.ts | 18 ++++++++++++------ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/web/src/pages/NePage.tsx b/web/src/pages/NePage.tsx index aca1461..ac779b1 100644 --- a/web/src/pages/NePage.tsx +++ b/web/src/pages/NePage.tsx @@ -780,7 +780,7 @@ export function NePage() { className="link-btn" onClick={() => openOrFocusModule({ - moduleId: "network", + moduleId: "webcrt", path: `/webcrt?ne_id=${encodeURIComponent(row.id)}`, }) } diff --git a/web/src/pages/TopologyPage.tsx b/web/src/pages/TopologyPage.tsx index 49cae7b..77e7b86 100644 --- a/web/src/pages/TopologyPage.tsx +++ b/web/src/pages/TopologyPage.tsx @@ -676,14 +676,14 @@ export function TopologyPage() { const umeId = node?.data.ume_ne_id; if (managedId) { openOrFocusModule({ - moduleId: "network", + moduleId: "webcrt", path: `/webcrt?ne_id=${encodeURIComponent(managedId)}`, }); return; } if (umeId) { openOrFocusModule({ - moduleId: "network", + moduleId: "webcrt", path: `/webcrt?ne_id=${encodeURIComponent(umeId)}&source=ume`, }); return; diff --git a/web/src/pages/network/NetworkConfigsPage.tsx b/web/src/pages/network/NetworkConfigsPage.tsx index 7bc991f..cdf2f89 100644 --- a/web/src/pages/network/NetworkConfigsPage.tsx +++ b/web/src/pages/network/NetworkConfigsPage.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import { Link } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { downloadNeConfigSnapshot, @@ -9,6 +8,7 @@ import { import { queryKeys } from "../../constants/queryKeys"; import { useI18n } from "../../i18n"; import { useToast } from "../../hooks/useToast"; +import { openOrFocusModule } from "../../utils/moduleWindows"; import { pageCount } from "../../utils/display"; import { formatSystemTime } from "../../utils/time"; @@ -161,11 +161,19 @@ export function NetworkConfigsPage() { > {t("networkConfigs.export")} - { + const path = + row.source === "ume" + ? `/webcrt?ne_id=${encodeURIComponent(row.target_id)}&source=ume` + : `/webcrt?ne_id=${encodeURIComponent(row.target_id)}`; + openOrFocusModule({ moduleId: "webcrt", path }); + }} > WebCRT - + ); diff --git a/web/src/utils/time.ts b/web/src/utils/time.ts index 1d42c7a..0464334 100644 --- a/web/src/utils/time.ts +++ b/web/src/utils/time.ts @@ -1,17 +1,24 @@ const systemTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; type FormatTimeOptions = { - /** Treat timezone-less ISO timestamp strings as UTC. */ + /** + * Treat timezone-less timestamps as UTC (DB/API default). + * Defaults to true so naive ISO strings show in the browser system timezone. + */ assumeUtcNaive?: boolean; }; function normalizeTimeInput(value: string | number | Date, options?: FormatTimeOptions): string | number | Date { - if (!options?.assumeUtcNaive || typeof value !== "string") return value; + const assumeUtc = options?.assumeUtcNaive !== false; + if (!assumeUtc || typeof value !== "string") return value; const text = value.trim(); if (!text) return value; - // Match "YYYY-MM-DDTHH:mm:ss(.sss)" without explicit timezone offset. - const isIsoLike = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(text); - return isIsoLike ? `${text}Z` : value; + // Already has explicit offset / Z. + if (/[zZ]$|[+-]\d{2}:\d{2}$/.test(text)) return value; + // "YYYY-MM-DDTHH:mm:ss(.sss)" or "YYYY-MM-DD HH:mm:ss(.sss)" + const isoLike = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(text); + if (!isoLike) return value; + return `${text.replace(" ", "T")}Z`; } export function formatSystemTime( @@ -27,4 +34,3 @@ export function formatSystemTime( timeZone: systemTimeZone, }); } -