fix: render workbench time from yaml config

This commit is contained in:
lyon
2026-06-20 13:29:55 +08:00
parent 0346295ac4
commit 01f72df333
6 changed files with 97 additions and 5 deletions
+3 -1
View File
@@ -346,7 +346,9 @@ lanes:
- internal/dev-entrypoint/cloud-web-routes.mjs
- tools/src/hwlab-cli/trace-renderer.ts
env:
TZ: Asia/Shanghai
HWLAB_CLOUD_WEB_DISPLAY_TIME_ZONE: Asia/Shanghai
HWLAB_CLOUD_WEB_DISPLAY_TIME_LOCALE: zh-CN
HWLAB_CLOUD_WEB_DISPLAY_TIME_LABEL: 北京时间
observable: true
hwlab-gateway:
runtimeKind: bun-command
+34 -1
View File
@@ -125,12 +125,45 @@ function injectCloudWebRuntimeConfig(body) {
}
function runtimeConfigFromEnv() {
const config = {};
const config = { displayTime: displayTimeConfigFromEnv() };
const workbench = workbenchRuntimeConfigFromEnv();
if (workbench) config.workbench = workbench;
return config;
}
function displayTimeConfigFromEnv() {
const timeZone = requiredRuntimeConfigEnv("HWLAB_CLOUD_WEB_DISPLAY_TIME_ZONE");
const locale = requiredRuntimeConfigEnv("HWLAB_CLOUD_WEB_DISPLAY_TIME_LOCALE");
const label = requiredRuntimeConfigEnv("HWLAB_CLOUD_WEB_DISPLAY_TIME_LABEL");
validateDisplayTimeZone(timeZone);
validateDisplayLocale(locale);
return { timeZone, locale, label };
}
function requiredRuntimeConfigEnv(name) {
const value = process.env[name];
if (typeof value !== "string" || value.trim().length === 0) {
throw new Error(`missing required Cloud Web runtime config env: ${name}`);
}
return value.trim();
}
function validateDisplayTimeZone(timeZone) {
try {
new Intl.DateTimeFormat("en-US", { timeZone }).format(new Date(0));
} catch {
throw new Error(`invalid HWLAB_CLOUD_WEB_DISPLAY_TIME_ZONE: ${timeZone}`);
}
}
function validateDisplayLocale(locale) {
try {
new Intl.DateTimeFormat(locale).format(new Date(0));
} catch {
throw new Error(`invalid HWLAB_CLOUD_WEB_DISPLAY_TIME_LOCALE: ${locale}`);
}
}
function workbenchRuntimeConfigFromEnv() {
const traceTimeline = {};
const autoExpandRunning = parseEnvBoolean(process.env.HWLAB_WORKBENCH_TRACE_AUTO_EXPAND_RUNNING);
@@ -6,6 +6,7 @@ import { computed, ref } from "vue";
import { useWorkbenchStore } from "@/stores/workbench";
import { useClipboard } from "@/composables/useClipboard";
import LoadingState from "@/components/common/LoadingState.vue";
import { formatDisplayDateTime } from "@/config/runtime";
import { workbenchSessionPath } from "@/utils";
const workbench = useWorkbenchStore();
@@ -91,7 +92,7 @@ function formatSessionUpdatedTime(value: string | null | undefined): string {
if (delta < 3_600_000) return `${Math.max(1, Math.round(delta / 60_000))}`;
if (delta < 86_400_000) return `${Math.max(1, Math.round(delta / 3_600_000))}`;
if (delta < 604_800_000) return `${Math.max(1, Math.round(delta / 86_400_000))}`;
return date.toLocaleString(undefined, { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" });
return formatDisplayDateTime(date, { month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" });
}
</script>
+50
View File
@@ -1,5 +1,55 @@
import type { WorkbenchTraceTimelinePolicy } from "@/components/workbench/trace-lifecycle";
export interface DisplayTimeConfig {
timeZone: string;
locale: string;
label: string;
}
export function displayTimeConfig(): DisplayTimeConfig {
const config = window.HWLAB_CLOUD_WEB_CONFIG?.displayTime;
const timeZone = requiredDisplayTimeField(config?.timeZone, "timeZone");
const locale = requiredDisplayTimeField(config?.locale, "locale");
const label = requiredDisplayTimeField(config?.label, "label");
validateDisplayTimeZone(timeZone);
validateDisplayLocale(locale);
return { timeZone, locale, label };
}
export function displayTimeLabel(): string {
return displayTimeConfig().label;
}
export function formatDisplayDateTime(value: string | Date, options: Intl.DateTimeFormatOptions = {}): string {
const date = value instanceof Date ? value : new Date(value);
if (!Number.isFinite(date.getTime())) return String(value);
const config = displayTimeConfig();
return new Intl.DateTimeFormat(config.locale, { hour12: false, ...options, timeZone: config.timeZone }).format(date);
}
function requiredDisplayTimeField(value: unknown, field: string): string {
if (typeof value !== "string" || value.trim().length === 0) {
throw new Error(`HWLAB Cloud Web displayTime.${field} is required`);
}
return value.trim();
}
function validateDisplayTimeZone(timeZone: string): void {
try {
new Intl.DateTimeFormat("en-US", { timeZone }).format(new Date(0));
} catch {
throw new Error(`HWLAB Cloud Web displayTime.timeZone is invalid: ${timeZone}`);
}
}
function validateDisplayLocale(locale: string): void {
try {
new Intl.DateTimeFormat(locale).format(new Date(0));
} catch {
throw new Error(`HWLAB Cloud Web displayTime.locale is invalid: ${locale}`);
}
}
export function workbenchTraceTimelinePolicy(): WorkbenchTraceTimelinePolicy {
const config = window.HWLAB_CLOUD_WEB_CONFIG?.workbench?.traceTimeline;
return {
@@ -1,3 +1,4 @@
import { displayTimeLabel, formatDisplayDateTime } from "@/config/runtime";
import type { ApiResult, HwpodNodeOpsResponse, HwpodSpecsResponse, LiveProbePayload, LiveSurface, Tone } from "@/types";
import { asRecord, firstNonEmptyString, statusTone } from "@/utils";
@@ -148,7 +149,7 @@ export function formatTimestamp(value: unknown): string {
if (!text) return "未观测";
const date = new Date(text);
if (!Number.isFinite(date.getTime())) return text;
return date.toLocaleString("zh-CN", { hour12: false, timeZone: "Asia/Shanghai" });
return formatDisplayDateTime(date, { hour12: false });
}
export function shortToken(value: unknown, size = 12): string | null {
@@ -224,7 +225,7 @@ function rowFromLiveHealth(payload: LiveProbePayload | null): BuildRow {
}
function latestBuildText(row: BuildRow): string {
const time = row.builtAt ? `${formatTimestamp(row.builtAt)} 北京时间` : "构建时间不可用";
const time = row.builtAt ? `${formatTimestamp(row.builtAt)} ${displayTimeLabel()}` : "构建时间不可用";
return `最新镜像构建时间:${time} · ${row.label} · tag ${row.tag ?? "unknown"} · commit ${row.commitShort ?? "unknown"} · env ${row.envImageTag ?? row.envCommitShort ?? "unknown"} · revision ${row.revisionShort ?? "unknown"}`;
}
+5
View File
@@ -2,6 +2,11 @@ declare global {
interface Window {
HWLAB_CLOUD_WEB_CONFIG?: {
auth?: { mode?: "auto" | "manual"; username?: string; password?: string };
displayTime?: {
timeZone?: string;
locale?: string;
label?: string;
};
workbench?: {
traceTimeline?: {
autoExpandRunning?: boolean;