From 23b179f2a73a7ed6a05c08b979ed86ce7e56a282 Mon Sep 17 00:00:00 2001 From: lorentz Date: Thu, 7 May 2026 08:31:22 -0400 Subject: [PATCH] feat(07.1-05): user-tz on admin operational pages - zabbix-wan, rmm-overshell, itglue-writes, ticket-digest, device-link-conflicts, workflow/history, workflow/pipelines/[id]: each gets useUserTimezone() at the component entry; threads tz into every inline toLocaleString call. Migrates 11 of 81 audit leak callsites. --- app/admin/device-link-conflicts/page.tsx | 4 +++- app/admin/itglue-writes/page.tsx | 4 +++- app/admin/rmm-overshell/page.tsx | 8 +++++--- app/admin/ticket-digest/page.tsx | 4 +++- app/admin/workflow/history/page.tsx | 4 +++- app/admin/workflow/pipelines/[id]/page.tsx | 4 +++- app/admin/zabbix-wan/page.tsx | 6 ++++-- 7 files changed, 24 insertions(+), 10 deletions(-) diff --git a/app/admin/device-link-conflicts/page.tsx b/app/admin/device-link-conflicts/page.tsx index 72d06fb..1f3ec8f 100644 --- a/app/admin/device-link-conflicts/page.tsx +++ b/app/admin/device-link-conflicts/page.tsx @@ -16,6 +16,7 @@ import { } from '@/components/ui/select'; import { CheckCircle2, AlertTriangle, Loader2 } from 'lucide-react'; import { PageHeader } from '@/components/navigation/page-header'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; interface Candidate { ciId: string; @@ -77,6 +78,7 @@ function dedupeCandidates(candidates: Candidate[]): Candidate[] { } export default function DeviceLinkConflictsPage() { + const tz = useUserTimezone(); const [items, setItems] = useState(null); const [total, setTotal] = useState(0); const [error, setError] = useState(null); @@ -220,7 +222,7 @@ export default function DeviceLinkConflictsPage() { {r.xref.serial && serial: {r.xref.serial}} {r.xref.mac && mac: {r.xref.mac}} {r.xref.lastSeenAt && ( - last seen: {new Date(r.xref.lastSeenAt).toLocaleString()} + last seen: {new Date(r.xref.lastSeenAt).toLocaleString(undefined, { timeZone: tz })} )} diff --git a/app/admin/itglue-writes/page.tsx b/app/admin/itglue-writes/page.tsx index f80f518..efc3a47 100644 --- a/app/admin/itglue-writes/page.tsx +++ b/app/admin/itglue-writes/page.tsx @@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button'; import { Skeleton } from '@/components/ui/skeleton'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { PageHeader } from '@/components/navigation/page-header'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; interface WriteRow { id: string; @@ -47,6 +48,7 @@ function statusVariant( } export default function ItglueWritesPage() { + const tz = useUserTimezone(); const [rows, setRows] = useState(null); const [error, setError] = useState(null); const [statusFilter, setStatusFilter] = @@ -141,7 +143,7 @@ export default function ItglueWritesPage() { {w.field_name}

- {new Date(w.performed_at).toLocaleString()} + {new Date(w.performed_at).toLocaleString(undefined, { timeZone: tz })}

Before: diff --git a/app/admin/rmm-overshell/page.tsx b/app/admin/rmm-overshell/page.tsx index 5d42d61..2b04cc9 100644 --- a/app/admin/rmm-overshell/page.tsx +++ b/app/admin/rmm-overshell/page.tsx @@ -9,6 +9,7 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Loader2, RefreshCw, Terminal } from 'lucide-react'; import { toast } from 'sonner'; import { PageHeader } from '@/components/navigation/page-header'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; interface Settings { overshellComponentUid: string | null; @@ -35,6 +36,7 @@ interface ExecRow { } export default function RmmOvershellAdminPage() { + const tz = useUserTimezone(); const [settings, setSettings] = useState(null); const [counts, setCounts] = useState<{ total: string; running: string; failed_24h: string } | null>(null); const [executions, setExecutions] = useState(null); @@ -139,7 +141,7 @@ export default function RmmOvershellAdminPage() {

{settings.discoveredAt && (

- discovered {new Date(settings.discoveredAt).toLocaleString()} + discovered {new Date(settings.discoveredAt).toLocaleString(undefined, { timeZone: tz })}

)} @@ -196,7 +198,7 @@ export default function RmmOvershellAdminPage() { {settings.logliftDiscoveredAt && (

discovered{' '} - {new Date(settings.logliftDiscoveredAt).toLocaleString()} + {new Date(settings.logliftDiscoveredAt).toLocaleString(undefined, { timeZone: tz })}

)} @@ -262,7 +264,7 @@ export default function RmmOvershellAdminPage() { - {new Date(e.queuedAt).toLocaleString()} + {new Date(e.queuedAt).toLocaleString(undefined, { timeZone: tz })} {e.errorMessage && ( diff --git a/app/admin/ticket-digest/page.tsx b/app/admin/ticket-digest/page.tsx index ab81430..2dc9991 100644 --- a/app/admin/ticket-digest/page.tsx +++ b/app/admin/ticket-digest/page.tsx @@ -8,6 +8,7 @@ import { Calendar, CalendarDays, CalendarRange, MessageSquare, Bell, Globe, ExternalLink, } from 'lucide-react'; import { PageHeader } from '@/components/navigation/page-header'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; interface DigestConfig { daily_enabled: boolean; @@ -73,6 +74,7 @@ function PeriodIcon({ period }: { period: string }) { } export default function TicketDigestPage() { + const tz = useUserTimezone(); const [config, setConfig] = useState(null); const [channels, setChannels] = useState([]); const [history, setHistory] = useState([]); @@ -407,7 +409,7 @@ export default function TicketDigestPage() {
{report.period_type} - {new Date(report.generated_at).toLocaleString()} + {new Date(report.generated_at).toLocaleString(undefined, { timeZone: tz })}
diff --git a/app/admin/workflow/history/page.tsx b/app/admin/workflow/history/page.tsx index 814931c..37df302 100644 --- a/app/admin/workflow/history/page.tsx +++ b/app/admin/workflow/history/page.tsx @@ -32,6 +32,7 @@ import { ChevronRight, } from 'lucide-react'; import { WorkflowExecutionWithSteps } from '@/lib/types/workflow'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; export default function ExecutionHistoryPage() { return ( @@ -42,6 +43,7 @@ export default function ExecutionHistoryPage() { } function ExecutionHistoryContent() { + const tz = useUserTimezone(); const searchParams = useSearchParams(); const highlightId = searchParams.get('id'); @@ -189,7 +191,7 @@ function ExecutionHistoryContent() { {exec.duration_ms ? `${exec.duration_ms}ms` : '-'} - {new Date(exec.created_at).toLocaleString()} + {new Date(exec.created_at).toLocaleString(undefined, { timeZone: tz })} ))} diff --git a/app/admin/workflow/pipelines/[id]/page.tsx b/app/admin/workflow/pipelines/[id]/page.tsx index 0b9fb38..6ca5f12 100644 --- a/app/admin/workflow/pipelines/[id]/page.tsx +++ b/app/admin/workflow/pipelines/[id]/page.tsx @@ -26,6 +26,7 @@ import { Eye, } from 'lucide-react'; import StepConfigEditor from '@/components/admin/pipeline/StepConfigEditor'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; interface Pipeline { id: number; @@ -91,6 +92,7 @@ const STATUS_ICONS: Record = { }; export default function PipelineEditorPage() { + const tz = useUserTimezone(); const params = useParams(); const router = useRouter(); const pipelineId = params.id as string; @@ -579,7 +581,7 @@ export default function PipelineEditorPage() { {exec.trigger_source} {exec.duration_ms && {exec.duration_ms}ms} - {new Date(exec.started_at).toLocaleString()} + {new Date(exec.started_at).toLocaleString(undefined, { timeZone: tz })} {exec.error_message && ( diff --git a/app/admin/zabbix-wan/page.tsx b/app/admin/zabbix-wan/page.tsx index e748a87..b1ab64d 100644 --- a/app/admin/zabbix-wan/page.tsx +++ b/app/admin/zabbix-wan/page.tsx @@ -51,6 +51,7 @@ import { import { toast } from 'sonner'; import { HostManager } from '@/components/zabbix/host-manager'; import { PageHeader } from '@/components/navigation/page-header'; +import { useUserTimezone } from '@/lib/hooks/use-user-timezone'; type SyncMode = 'all' | 'client' | 'site'; @@ -139,6 +140,7 @@ interface RmmOnlyRow { alert_uid: string; site_name: string; alert_class: string type PageTab = 'sync' | 'gaps' | 'correlation'; export default function ZabbixWanPage() { + const tz = useUserTimezone(); const [activeTab, setActiveTab] = useState('sync'); const [mode, setMode] = useState('all'); const [companyId, setCompanyId] = useState(''); @@ -209,8 +211,8 @@ export default function ZabbixWanPage() { finally { setSyncing(null); } }; - const fmtSynced = (ts: string | null) => ts ? new Date(ts).toLocaleString() : 'Never'; - const fmtTs = (ts: string | null) => ts ? new Date(ts).toLocaleString() : '—'; + const fmtSynced = (ts: string | null) => ts ? new Date(ts).toLocaleString(undefined, { timeZone: tz }) : 'Never'; + const fmtTs = (ts: string | null) => ts ? new Date(ts).toLocaleString(undefined, { timeZone: tz }) : '—'; const fmtDuration = (s: number | null, hasRecovery?: boolean) => { if (s === null || s === undefined) return hasRecovery ? '< 1m' : 'Open'; if (s === 0) return hasRecovery ? '< 1m' : 'Open';