From e64060fe0dc707f6307ba06dcdb78e034cd3f5d3 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sat, 25 Apr 2026 19:14:42 -0400 Subject: [PATCH] fix(ui): address PR-Agent round 2 on health redesign PR-Agent flagged two more real regressions vs the original health page: 1. Stale timestamp (HealthStatusRibbon): formatRelativeTime reads Date.now() during render, but nothing forces a re-render after mount so the 'last scan' label froze and never advanced to '1 minute ago', '2 hours ago', etc. Restore the per-second tick (matching the original health.tsx behavior) so the label behaves like a real relative timestamp. 2. Hidden copy action (HealthPriorityCard): the fix-copy button was gated by group-hover, making it invisible to keyboard users and unreachable on mobile (no hover state). Make it always visible with an aria-label so screen-reader and touch users can copy the fix command. --- ui/src/components/health/health-priority-card.tsx | 10 ++++++++-- ui/src/components/health/health-status-ribbon.tsx | 13 +++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ui/src/components/health/health-priority-card.tsx b/ui/src/components/health/health-priority-card.tsx index 9c817807..b74df697 100644 --- a/ui/src/components/health/health-priority-card.tsx +++ b/ui/src/components/health/health-priority-card.tsx @@ -127,14 +127,20 @@ export function HealthPriorityCard({ check }: HealthPriorityCardProps) { {(check.fix || check.fixable) && (
{check.fix && ( -
+
{check.fix} + {/* + * Always-visible copy button. The previous design hid it behind + * group-hover, which excluded keyboard users and touch-only + * devices (no hover state on mobile = effectively unreachable). + */} diff --git a/ui/src/components/health/health-status-ribbon.tsx b/ui/src/components/health/health-status-ribbon.tsx index 320ece6d..5e6c9867 100644 --- a/ui/src/components/health/health-status-ribbon.tsx +++ b/ui/src/components/health/health-status-ribbon.tsx @@ -1,3 +1,4 @@ +import { useEffect, useState } from 'react'; import { Cpu, RefreshCw, Terminal, Copy } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; @@ -41,6 +42,18 @@ export function HealthStatusRibbon({ }: HealthStatusRibbonProps) { const { t } = useTranslation(); + // formatRelativeTime reads Date.now() during render. Without a ticking + // re-render, the "last scan" label freezes at whatever it showed on mount + // and never advances to "1 minute ago", "2 hours ago", etc. — even though + // the underlying lastScan timestamp is stale. Force a re-render every + // second; the cost is negligible (one tiny component) and the UX win is + // a label that actually behaves like a relative timestamp. + const [, setTick] = useState(0); + useEffect(() => { + const interval = setInterval(() => setTick((n) => n + 1), 1000); + return () => clearInterval(interval); + }, []); + const copyDoctorCommand = () => { navigator.clipboard.writeText('ccs doctor'); toast.success(t('health.copied'));