diff --git a/apps/dashboard/src/components/RunList.mobile.spec.tsx b/apps/dashboard/src/components/RunList.mobile.spec.tsx
index a918411f..4f355763 100644
--- a/apps/dashboard/src/components/RunList.mobile.spec.tsx
+++ b/apps/dashboard/src/components/RunList.mobile.spec.tsx
@@ -45,4 +45,22 @@ describe('buildRunListItemView', () => {
expect(view.isActive).toBe(true);
expect(view.passing).toBe(false);
});
+
+ it('uses compact run display without duplicating the pass-rate column', () => {
+ const view = buildRunListItemView(
+ runMeta({
+ display_name: '2026-03-27T05-00-00-000Z',
+ filename: 'remote::2026-03-27T05-00-00-000Z',
+ target: 'remote-target',
+ timestamp: '2026-03-27T05:00:00.000Z',
+ pass_rate: 1,
+ source: 'remote',
+ }),
+ 0.8,
+ );
+
+ expect(view.display.primary).toBe('27/03 05:00');
+ expect(view.display.secondary).toBe('remote-target');
+ expect(view.label).toBe('27/03 05:00 · remote-target');
+ });
});
diff --git a/apps/dashboard/src/components/RunList.tsx b/apps/dashboard/src/components/RunList.tsx
index 9da2dfc6..d21599ce 100644
--- a/apps/dashboard/src/components/RunList.tsx
+++ b/apps/dashboard/src/components/RunList.tsx
@@ -30,7 +30,7 @@ import {
useStudioConfig,
} from '~/lib/api';
import { executionErrorCount } from '~/lib/result-summary';
-import { formatRunLabel } from '~/lib/run-label';
+import { type RunDisplay, formatRunDisplay } from '~/lib/run-label';
import {
buildCombineSuccessMessage,
buildDeleteSuccessMessage,
@@ -63,6 +63,7 @@ interface RunListItemView {
ts: { date: string; full: string };
isActive: boolean;
label: string;
+ display: RunDisplay;
errors: number;
qualityCount: number;
passing: boolean;
@@ -94,7 +95,8 @@ function formatDate(ts: string | undefined | null): { date: string; full: string
export function buildRunListItemView(run: RunMeta, passThreshold: number): RunListItemView {
const ts = formatDate(run.timestamp);
const isActive = run.status === 'starting' || run.status === 'running';
- const label = formatRunLabel(run);
+ const display = formatRunDisplay(run, { includePassRate: false });
+ const label = display.label;
const errors = executionErrorCount(run);
const qualityCount = Math.max(0, run.test_count - errors);
const passing = qualityCount > 0 ? run.pass_rate >= passThreshold : errors === 0;
@@ -107,6 +109,7 @@ export function buildRunListItemView(run: RunMeta, passThreshold: number): RunLi
ts,
isActive,
label,
+ display,
errors,
qualityCount,
passing,
@@ -380,8 +383,17 @@ export function RunList({
)}
{runViews.map((view) => {
- const { run, ts, label, errors, qualityCount, passedCount, failedCount, metadataDirty } =
- view;
+ const {
+ run,
+ ts,
+ label,
+ display,
+ errors,
+ qualityCount,
+ passedCount,
+ failedCount,
+ metadataDirty,
+ } = view;
const selectionDisabledReason = runSelectionDisabledReason(run);
const selectable = !selectionDisabledReason && selectableRunIds.includes(run.filename);
@@ -411,9 +423,15 @@ export function RunList({
+ {display.secondary ? (
+
+ {display.secondary}
+
+ ) : null}
{metadataDirty ?
: null}
@@ -479,6 +497,7 @@ export function RunList({
run,
ts,
label,
+ display,
errors,
qualityCount,
passedCount,
@@ -514,14 +533,25 @@ export function RunList({
{/* Run name */}
-
-
- {metadataDirty ? : null}
+
+
+
+ {metadataDirty ? : null}
+
+ {display.secondary ? (
+
+ {display.secondary}
+
+ ) : null}
|
@@ -581,11 +611,13 @@ function RunNameLink({
projectId,
runId,
label,
+ title,
className,
}: {
projectId?: string;
runId: string;
label: string;
+ title: string;
className: string;
}) {
return projectId ? (
@@ -593,12 +625,12 @@ function RunNameLink({
to="/projects/$projectId/runs/$runId"
params={{ projectId, runId }}
className={className}
- title={label}
+ title={title}
>
{label}
) : (
-
+
{label}
);
diff --git a/apps/dashboard/src/components/Sidebar.tsx b/apps/dashboard/src/components/Sidebar.tsx
index a35bf735..f93df921 100644
--- a/apps/dashboard/src/components/Sidebar.tsx
+++ b/apps/dashboard/src/components/Sidebar.tsx
@@ -34,7 +34,7 @@ import {
useStudioConfig,
} from '~/lib/api';
import { resolveProjectDisplayName } from '~/lib/project-display-name';
-import { formatRunLabel, timeAgo } from '~/lib/run-label';
+import { formatRunDisplay } from '~/lib/run-label';
import { useSidebarContext } from '~/lib/sidebar-context';
import { BrandName } from './BrandName';
@@ -88,6 +88,17 @@ function BrandHeader({ projectId }: { projectId?: string }) {
);
}
+function SidebarRunText({ display }: { display: ReturnType
}) {
+ return (
+ <>
+ {display.primary}
+ {display.secondary ? (
+ {display.secondary}
+ ) : null}
+ >
+ );
+}
+
function useProjectDisplayName(projectId: string): string {
const { data } = useProjectList();
return resolveProjectDisplayName(projectId, data?.projects);
@@ -274,6 +285,7 @@ function RunSidebar() {
{data?.runs.map((run) => {
+ const display = formatRunDisplay(run);
const isActive =
isHome === false &&
runMatch &&
@@ -289,10 +301,9 @@ function RunSidebar() {
to="/projects/$projectId/runs/$runId"
params={{ projectId: run.project_id, runId: run.filename }}
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.project_name}
+ title={`${display.title}\nProject: ${run.project_name}`}
>
-
{formatRunLabel(run)}
-
{timeAgo(run.timestamp)}
+
);
}
@@ -307,9 +318,9 @@ function RunSidebar() {
? 'bg-gray-800 text-cyan-400'
: 'text-gray-400 hover:bg-gray-800/50 hover:text-gray-200'
}`}
+ title={display.title}
>
-
{formatRunLabel(run)}
-
{timeAgo(run.timestamp)}
+
);
})}
@@ -507,6 +518,7 @@ function ProjectRunDetailSidebar({
Runs
{data?.runs.map((run) => {
+ const display = formatRunDisplay(run);
const isActive = currentRunId === run.filename;
return (