feat(ui): add live duration clock for running agent runs
When an agent run is in "running" status, the Duration field now counts up every second from startedAt, matching the same format shown when a run completes (e.g. "Duration: 5m 32s"). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7ac4d0b04
commit
9458767942
1 changed files with 19 additions and 2 deletions
|
|
@ -1553,12 +1553,29 @@ function RunDetail({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isRunning = run.status === "running" && !!run.startedAt && !run.finishedAt;
|
||||||
|
const [elapsedSec, setElapsedSec] = useState<number>(() => {
|
||||||
|
if (!run.startedAt) return 0;
|
||||||
|
return Math.max(0, Math.round((Date.now() - new Date(run.startedAt).getTime()) / 1000));
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isRunning || !run.startedAt) return;
|
||||||
|
const startMs = new Date(run.startedAt).getTime();
|
||||||
|
setElapsedSec(Math.max(0, Math.round((Date.now() - startMs) / 1000)));
|
||||||
|
const id = setInterval(() => {
|
||||||
|
setElapsedSec(Math.max(0, Math.round((Date.now() - startMs) / 1000)));
|
||||||
|
}, 1000);
|
||||||
|
return () => clearInterval(id);
|
||||||
|
}, [isRunning, run.startedAt]);
|
||||||
|
|
||||||
const timeFormat: Intl.DateTimeFormatOptions = { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false };
|
const timeFormat: Intl.DateTimeFormatOptions = { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false };
|
||||||
const startTime = run.startedAt ? new Date(run.startedAt).toLocaleTimeString("en-US", timeFormat) : null;
|
const startTime = run.startedAt ? new Date(run.startedAt).toLocaleTimeString("en-US", timeFormat) : null;
|
||||||
const endTime = run.finishedAt ? new Date(run.finishedAt).toLocaleTimeString("en-US", timeFormat) : null;
|
const endTime = run.finishedAt ? new Date(run.finishedAt).toLocaleTimeString("en-US", timeFormat) : null;
|
||||||
const durationSec = run.startedAt && run.finishedAt
|
const durationSec = run.startedAt && run.finishedAt
|
||||||
? Math.round((new Date(run.finishedAt).getTime() - new Date(run.startedAt).getTime()) / 1000)
|
? Math.round((new Date(run.finishedAt).getTime() - new Date(run.startedAt).getTime()) / 1000)
|
||||||
: null;
|
: null;
|
||||||
|
const displayDurationSec = durationSec ?? (isRunning ? elapsedSec : null);
|
||||||
const hasMetrics = metrics.input > 0 || metrics.output > 0 || metrics.cached > 0 || metrics.cost > 0;
|
const hasMetrics = metrics.input > 0 || metrics.output > 0 || metrics.cached > 0 || metrics.cost > 0;
|
||||||
const hasSession = !!(run.sessionIdBefore || run.sessionIdAfter);
|
const hasSession = !!(run.sessionIdBefore || run.sessionIdAfter);
|
||||||
const sessionChanged = run.sessionIdBefore && run.sessionIdAfter && run.sessionIdBefore !== run.sessionIdAfter;
|
const sessionChanged = run.sessionIdBefore && run.sessionIdAfter && run.sessionIdBefore !== run.sessionIdAfter;
|
||||||
|
|
@ -1597,9 +1614,9 @@ function RunDetail({ run, adapterType }: { run: HeartbeatRun; adapterType: strin
|
||||||
{relativeTime(run.startedAt!)}
|
{relativeTime(run.startedAt!)}
|
||||||
{run.finishedAt && <> → {relativeTime(run.finishedAt)}</>}
|
{run.finishedAt && <> → {relativeTime(run.finishedAt)}</>}
|
||||||
</div>
|
</div>
|
||||||
{durationSec !== null && (
|
{displayDurationSec !== null && (
|
||||||
<div className="text-xs text-muted-foreground">
|
<div className="text-xs text-muted-foreground">
|
||||||
Duration: {durationSec >= 60 ? `${Math.floor(durationSec / 60)}m ${durationSec % 60}s` : `${durationSec}s`}
|
Duration: {displayDurationSec >= 60 ? `${Math.floor(displayDurationSec / 60)}m ${displayDurationSec % 60}s` : `${displayDurationSec}s`}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue