fix(ui): preserve timeline duration labels
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
import type { TrajectoryTurnModel } from './layout.ts'
|
import type { TrajectoryTurnModel } from './layout.ts'
|
||||||
import {
|
import {
|
||||||
deriveTrajectoryTimeline,
|
deriveTrajectoryTimeline,
|
||||||
|
formatTimelineOffset,
|
||||||
type TrajectoryTimelineMode,
|
type TrajectoryTimelineMode,
|
||||||
type TrajectoryTimeRange,
|
type TrajectoryTimeRange,
|
||||||
} from './timeline.ts'
|
} from './timeline.ts'
|
||||||
@@ -81,6 +82,18 @@ export const TrajectoryTimeline = memo(function TrajectoryTimeline({
|
|||||||
onRecordFocus,
|
onRecordFocus,
|
||||||
}: TrajectoryTimelineProps) {
|
}: TrajectoryTimelineProps) {
|
||||||
const model = useMemo(() => deriveTrajectoryTimeline(turns, mode), [mode, turns])
|
const model = useMemo(() => deriveTrajectoryTimeline(turns, mode), [mode, turns])
|
||||||
|
const durationByIndex = useMemo(
|
||||||
|
() => new Map(turns.flatMap(turn =>
|
||||||
|
turn.groups.flatMap(group =>
|
||||||
|
group.cells.flatMap(cell =>
|
||||||
|
cell.timeSeconds === null || !Number.isFinite(cell.timeSeconds)
|
||||||
|
? []
|
||||||
|
: [[cell.index, Math.max(0, cell.timeSeconds * 1_000)] as const],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
[turns],
|
||||||
|
)
|
||||||
const dragRef = useRef<{ pointerId: number; anchor: number; width: number } | null>(null)
|
const dragRef = useRef<{ pointerId: number; anchor: number; width: number } | null>(null)
|
||||||
const [draft, setDraft] = useState<FractionRange | null>(null)
|
const [draft, setDraft] = useState<FractionRange | null>(null)
|
||||||
const [hover, setHover] = useState<number | null>(null)
|
const [hover, setHover] = useState<number | null>(null)
|
||||||
@@ -324,6 +337,7 @@ export const TrajectoryTimeline = memo(function TrajectoryTimeline({
|
|||||||
.map((span) => {
|
.map((span) => {
|
||||||
const left = (span.start - domainStart) / domainDuration
|
const left = (span.start - domainStart) / domainDuration
|
||||||
const width = (span.end - span.start) / domainDuration
|
const width = (span.end - span.start) / domainDuration
|
||||||
|
const durationMs = durationByIndex.get(span.index)
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
className={css.span}
|
className={css.span}
|
||||||
@@ -339,7 +353,9 @@ export const TrajectoryTimeline = memo(function TrajectoryTimeline({
|
|||||||
? 'true'
|
? 'true'
|
||||||
: 'false'}
|
: 'false'}
|
||||||
key={span.index}
|
key={span.index}
|
||||||
title={span.label}
|
title={durationMs === undefined
|
||||||
|
? span.label
|
||||||
|
: `${span.label} · ${formatTimelineOffset(durationMs)}`}
|
||||||
style={{
|
style={{
|
||||||
'--trajectory-span-left': `${left * 100}%`,
|
'--trajectory-span-left': `${left * 100}%`,
|
||||||
'--trajectory-span-width': `${Math.max(width * 100, 0.35)}%`,
|
'--trajectory-span-width': `${Math.max(width * 100, 0.35)}%`,
|
||||||
|
|||||||
@@ -32,6 +32,17 @@ export interface TrajectoryTimelineModel extends TrajectoryTimeRange {
|
|||||||
turnBoundaries: readonly TrajectoryTimelineTurnBoundary[]
|
turnBoundaries: readonly TrajectoryTimelineTurnBoundary[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a timeline duration with a compact unit.
|
||||||
|
* @param milliseconds - Non-negative duration in milliseconds.
|
||||||
|
* @returns Millisecond or second label.
|
||||||
|
*/
|
||||||
|
export function formatTimelineOffset(milliseconds: number): string {
|
||||||
|
if (milliseconds < 1_000) return `${Math.round(milliseconds)} ms`
|
||||||
|
const seconds = milliseconds / 1_000
|
||||||
|
return seconds >= 10 ? `${Math.round(seconds)} s` : `${seconds.toFixed(1)} s`
|
||||||
|
}
|
||||||
|
|
||||||
function laneFor(kind: TrajectoryCellKind): number {
|
function laneFor(kind: TrajectoryCellKind): number {
|
||||||
if (kind === 'tool' || kind === 'subtool') return 2
|
if (kind === 'tool' || kind === 'subtool') return 2
|
||||||
if (kind === 'message' || kind === 'compacted') return 1
|
if (kind === 'message' || kind === 'compacted') return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user