diff --git a/apps/desktop/src/components/nacos/NacosConfigHistoryDialog.vue b/apps/desktop/src/components/nacos/NacosConfigHistoryDialog.vue index ac23cce5d7..999f6a8dc9 100644 --- a/apps/desktop/src/components/nacos/NacosConfigHistoryDialog.vue +++ b/apps/desktop/src/components/nacos/NacosConfigHistoryDialog.vue @@ -5,6 +5,7 @@ import { useI18n } from "vue-i18n"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { formatNacosHistoryTime } from "@/lib/nacos/nacosAdmin"; import type { NacosConfigHistoryItem, NacosConfigItem } from "@/types/nacos"; const open = defineModel("open", { default: false }); @@ -69,6 +70,10 @@ function display(value?: string | null) { return trimmed || "-"; } +function displayHistoryTime(value?: string | null) { + return formatNacosHistoryTime(value); +} + function operationLabel(value?: string) { const normalized = value?.trim().toLowerCase(); if (!normalized) return "-"; @@ -128,7 +133,7 @@ function loadPage(pageNo: number) { {{ item.dataId }} {{ item.group || "DEFAULT_GROUP" }} - {{ display(item.lastModifiedTime) }} + {{ displayHistoryTime(item.lastModifiedTime) }} {{ display(item.appName) }} {{ operationLabel(item.operation) }} @@ -189,7 +194,7 @@ function loadPage(pageNo: number) {
namespace={{ viewingItem.namespace || "public" }}
dataId={{ viewingItem.dataId }}
group={{ viewingItem.group || "DEFAULT_GROUP" }}
-
{{ t("nacos.updatedAt") }}={{ display(viewingItem.lastModifiedTime) }}
+
{{ t("nacos.updatedAt") }}={{ displayHistoryTime(viewingItem.lastModifiedTime) }}
diff --git a/apps/desktop/src/lib/__tests__/nacos/nacosAdmin.spec.ts b/apps/desktop/src/lib/__tests__/nacos/nacosAdmin.spec.ts index 5485ad5ea7..d6e7c4f3ca 100644 --- a/apps/desktop/src/lib/__tests__/nacos/nacosAdmin.spec.ts +++ b/apps/desktop/src/lib/__tests__/nacos/nacosAdmin.spec.ts @@ -13,6 +13,7 @@ import { createNacosConfigDeleteSnapshot, createNacosConfigSaveSnapshot, createNacosLatestRequestGuard, + formatNacosHistoryTime, isNacosRawMutation, isNacosErrorCode, isNacosConfigSaveSnapshotCurrent, @@ -98,6 +99,23 @@ describe("nacosAdmin helpers", () => { expect(isNacosErrorCode(new Error("stalePreview"), "stalePreview")).toBe(false); }); + it("formats Nacos history timestamps for display", () => { + const epochDate = new Date(1_710_000_000_000); + const epochDatePart = [epochDate.getFullYear(), epochDate.getMonth() + 1, epochDate.getDate()].map((part) => String(part).padStart(2, "0")).join("-"); + const epochTimePart = [epochDate.getHours(), epochDate.getMinutes(), epochDate.getSeconds()].map((part) => String(part).padStart(2, "0")).join(":"); + const epochDisplay = `${epochDatePart} ${epochTimePart}`; + + expect(formatNacosHistoryTime("2026-07-27T18:16:36.000+08:00")).toBe("2026-07-27 18:16:36"); + expect(formatNacosHistoryTime("2026-07-27T18:16:36Z")).toBe("2026-07-27 18:16:36"); + expect(formatNacosHistoryTime("2026-07-27 18:16:36")).toBe("2026-07-27 18:16:36"); + expect(formatNacosHistoryTime("1710000000000")).toBe(epochDisplay); + expect(formatNacosHistoryTime("1710000000")).toBe(epochDisplay); + expect(formatNacosHistoryTime("0")).toBe("-"); + expect(formatNacosHistoryTime("")).toBe("-"); + expect(formatNacosHistoryTime(null)).toBe("-"); + expect(formatNacosHistoryTime("not-a-time")).toBe("not-a-time"); + }); + it("redirects r-nacos console settings to the compatible OpenAPI endpoint", () => { expect(resolveRNacosOpenApiFallback("http://rnacos.example:10848", "/rnacos")).toEqual({ serverAddr: "http://rnacos.example:8848", diff --git a/apps/desktop/src/lib/nacos/nacosAdmin.ts b/apps/desktop/src/lib/nacos/nacosAdmin.ts index 07724156ce..4799a6223e 100644 --- a/apps/desktop/src/lib/nacos/nacosAdmin.ts +++ b/apps/desktop/src/lib/nacos/nacosAdmin.ts @@ -672,6 +672,24 @@ export function buildNacosConfigDeleteConfirm(item: NacosConfigItem, fallbackNam return formatNacosConfigIdentity(item, fallbackNamespace); } +export function formatNacosHistoryTime(value?: string | null): string { + const trimmed = value?.trim(); + if (!trimmed) return "-"; + if (/^0+$/.test(trimmed)) return "-"; + if (/^\d{10}(?:\d{3})?$/.test(trimmed)) { + const timestamp = Number(trimmed); + const date = new Date(trimmed.length === 10 ? timestamp * 1_000 : timestamp); + if (!Number.isNaN(date.getTime())) { + const datePart = [date.getFullYear(), date.getMonth() + 1, date.getDate()].map((part) => String(part).padStart(2, "0")).join("-"); + const timePart = [date.getHours(), date.getMinutes(), date.getSeconds()].map((part) => String(part).padStart(2, "0")).join(":"); + return `${datePart} ${timePart}`; + } + } + const match = trimmed.match(/^(\d{4}-\d{2}-\d{2})[T ](\d{2}:\d{2}:\d{2})(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/); + if (!match) return trimmed; + return `${match[1]} ${match[2]}`; +} + export function buildNacosConfigHistoryRollbackConfirm(item: NacosConfigHistoryItem, fallbackNamespace = ""): string { return [`namespace=${item.namespace || fallbackNamespace || "public"}`, `dataId=${item.dataId}`, `group=${item.group || "DEFAULT_GROUP"}`, item.lastModifiedTime ? `historyTime=${item.lastModifiedTime}` : "", item.operator ? `operator=${item.operator}` : ""].filter(Boolean).join("\n"); }