Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions apps/studio/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
useRunList,
useStudioConfig,
} from '~/lib/api';
import { formatRunLabel } from '~/lib/run-label';
import { formatRunLabel, timeAgo } from '~/lib/run-label';
import { useSidebarContext } from '~/lib/sidebar-context';

/** Responsive <aside> wrapper. Handles mobile overlay and desktop static placement. */
Expand Down Expand Up @@ -211,10 +211,11 @@ function RunSidebar() {
key={`${run.benchmark_id}/${run.filename}`}
to="/benchmarks/$benchmarkId/runs/$runId"
params={{ benchmarkId: run.benchmark_id, runId: run.filename }}
className="mb-0.5 block truncate rounded-md px-2 py-1.5 text-sm text-gray-400 transition-colors hover:bg-gray-800/50 hover:text-gray-200"
className="mb-0.5 block rounded-md px-2 py-1.5 text-sm text-gray-400 transition-colors hover:bg-gray-800/50 hover:text-gray-200"
title={run.benchmark_name}
>
{formatRunLabel(run)}
<span className="block truncate">{formatRunLabel(run)}</span>
<span className="block text-xs text-gray-600">{timeAgo(run.timestamp)}</span>
</Link>
);
}
Expand All @@ -224,13 +225,14 @@ function RunSidebar() {
key={run.filename}
to="/runs/$runId"
params={{ runId: run.filename }}
className={`mb-0.5 block truncate rounded-md px-2 py-1.5 text-sm transition-colors ${
className={`mb-0.5 block rounded-md px-2 py-1.5 text-sm transition-colors ${
isActive
? 'bg-gray-800 text-cyan-400'
: 'text-gray-400 hover:bg-gray-800/50 hover:text-gray-200'
}`}
>
{formatRunLabel(run)}
<span className="block truncate">{formatRunLabel(run)}</span>
<span className="block text-xs text-gray-600">{timeAgo(run.timestamp)}</span>
</Link>
);
})}
Expand Down Expand Up @@ -446,13 +448,14 @@ function BenchmarkRunDetailSidebar({
key={run.filename}
to="/benchmarks/$benchmarkId/runs/$runId"
params={{ benchmarkId, runId: run.filename }}
className={`mb-0.5 block truncate rounded-md px-2 py-1.5 text-sm transition-colors ${
className={`mb-0.5 block rounded-md px-2 py-1.5 text-sm transition-colors ${
isActive
? 'bg-gray-800 text-cyan-400'
: 'text-gray-400 hover:bg-gray-800/50 hover:text-gray-200'
}`}
>
{formatRunLabel(run)}
<span className="block truncate">{formatRunLabel(run)}</span>
<span className="block text-xs text-gray-600">{timeAgo(run.timestamp)}</span>
</Link>
);
})}
Expand Down
27 changes: 19 additions & 8 deletions apps/studio/src/lib/run-label.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,34 @@ import { describe, expect, it } from 'bun:test';
import { formatRunLabel } from './run-label';

describe('formatRunLabel', () => {
it('prefers target and experiment over the timestamp display name', () => {
it('shows DD/MM HH:mm · target · experiment · score', () => {
expect(
formatRunLabel({
filename: 'issue-1198::2026-04-29T09-17-30-111Z',
display_name: '2026-04-29T09-17-30-111Z',
target: 'llm-dry-run',
experiment: 'issue-1198',
timestamp: '2026-04-29T09:17:30.111Z',
pass_rate: 0.8,
}),
).toBe('llm-dry-run · issue-1198');
).toBe('29/04 09:17 · llm-dry-run · issue-1198 · 80%');
});

it('falls back to the display name when no richer metadata is available', () => {
it('omits experiment when it is the default', () => {
expect(
formatRunLabel({
filename: '2026-04-29T09-17-30-111Z',
display_name: '2026-04-29T09-17-30-111Z',
target: 'azure',
experiment: 'default',
timestamp: '2026-04-29T09:17:30.111Z',
pass_rate: 1,
}),
).toBe('2026-04-29T09-17-30-111Z');
).toBe('29/04 09:17 · azure · 100%');
});

it('shows just timestamp and score when no target is present', () => {
expect(
formatRunLabel({
timestamp: '2026-04-29T09:17:30.111Z',
pass_rate: 0,
}),
).toBe('29/04 09:17 · 0%');
});
});
48 changes: 41 additions & 7 deletions apps/studio/src/lib/run-label.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,48 @@
import type { RunMeta } from './types';

type RunLabelInput = Pick<RunMeta, 'display_name' | 'experiment' | 'filename' | 'target'>;
type RunLabelInput = Pick<RunMeta, 'experiment' | 'target' | 'timestamp' | 'pass_rate'>;

/** DD/MM HH:mm — short human-readable slice of the run's timestamp. */
function shortTimestamp(ts: string): string {
try {
const d = new Date(ts);
if (Number.isNaN(d.getTime())) return ts.slice(0, 10);
const dd = String(d.getDate()).padStart(2, '0');
const mm = String(d.getMonth() + 1).padStart(2, '0');
const hh = String(d.getHours()).padStart(2, '0');
const min = String(d.getMinutes()).padStart(2, '0');
return `${dd}/${mm} ${hh}:${min}`;
} catch {
return ts.slice(0, 10);
}
}

/** Human-readable relative time string, e.g. "4 hr ago". */
export function timeAgo(ts: string): string {
try {
const diffMs = Date.now() - new Date(ts).getTime();
const diffMin = Math.floor(diffMs / 60_000);
if (diffMin < 1) return 'just now';
if (diffMin < 60) return `${diffMin} min ago`;
const diffHour = Math.floor(diffMs / 3_600_000);
if (diffHour < 24) return `${diffHour} hr ago`;
const diffDay = Math.floor(diffMs / 86_400_000);
return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`;
} catch {
return '';
}
}

/** Format a run label consistently across tables and nav surfaces. */
export function formatRunLabel(run: RunLabelInput): string {
const parts = [run.target, run.experiment].filter(
(part): part is string => !!part && part !== 'default' && part !== '-',
);
if (parts.length > 0) {
return parts.join(' · ');
const parts: string[] = [shortTimestamp(run.timestamp)];

if (run.target) parts.push(run.target);
if (run.experiment && run.experiment !== 'default' && run.experiment !== '-') {
parts.push(run.experiment);
}
return run.display_name ?? run.filename;

parts.push(`${Math.round(run.pass_rate * 100)}%`);

return parts.join(' · ');
}
Loading