Files
yaak-mountain-loop/apps/yaak-proxy/components/FlowTimeline.tsx
T
Gregory SchierandClaude Opus 5.5 c78732ecaf Polish Yaak Proxy's flow list, sidebar and header
Columns keep fixed widths, Path included, and the list scrolls sideways
with the header in step instead of dropping columns or capping Host.
Resize handles sit on every column boundary, a double-click resets one,
and a third click on a sorted header goes back to start time, with empty
values sorting lowest. The search box takes up to 44rem and wraps over
the list while focused, its completions as wide as it. The list/detail
handle fills the gutter. Native title tooltips become Yaak's tooltip,
shared buttons gain an opt-in for it, and folder and program rows in the
sidebar get Reveal in Finder and Copy path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:45:46 -07:00

73 lines
2.3 KiB
TypeScript

import type { Flow } from "@yaakapp-internal/proxy-lib";
import {
CONTROL_TOOLTIP_DELAY,
EventViewer,
EventViewerRow,
formatMillis,
Icon,
type IconProps,
Tooltip,
} from "@yaakapp-internal/ui";
import { useMemo } from "react";
import { type FlowPhase, flowPhases, type PhaseKind } from "../lib/phases";
const ICONS: Record<PhaseKind, { icon: IconProps["icon"]; color: IconProps["color"] }> = {
start: { icon: "send_horizontal", color: "secondary" },
step: { icon: "arrow_right", color: "secondary" },
end: { icon: "check", color: "success" },
error: { icon: "alert_triangle", color: "danger" },
cancelled: { icon: "circle_off", color: "secondary" },
};
/** Yaak's event list with the flow's phases as rows, each saying how long it took */
export function FlowTimeline({ flow }: { flow: Flow }) {
const phases = useMemo(() => flowPhases(flow), [flow]);
return (
<EventViewer<FlowPhase>
events={phases}
getEventKey={(p) => p.key}
splitLayoutStorageKey="proxy_flow_timeline"
enableKeyboardNav={false}
emptyMessage="No timings recorded"
renderRow={({ event, isActive, onClick }) => {
const { icon, color } = ICONS[event.kind];
return (
<EventViewerRow
isActive={isActive}
onClick={onClick}
icon={<Icon icon={icon} color={color} size="sm" />}
content={
event.detail == null ? (
<span>{event.label}</span>
) : (
<Tooltip
wrap
onlyWhenTruncated
content={event.detail}
delay={CONTROL_TOOLTIP_DELAY}
>
<span>
{event.label}
<span className="text-text-subtlest">{` ${event.detail}`}</span>
</span>
</Tooltip>
)
}
columns="auto minmax(0,1fr) 6rem 6rem"
cells={{
trailing: [
<span key="took" className="tabular-nums">
{event.kind === "start" ? "" : `+${formatMillis(event.tookMs)}`}
</span>,
<span key="at" className="tabular-nums opacity-50">
{formatMillis(event.atMs)}
</span>,
],
}}
/>
);
}}
/>
);
}