Skip to content

Commit ce85069

Browse files
authored
fix(dashboard): sort runs by timestamp (#1359)
1 parent 34b15e1 commit ce85069

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

apps/cli/src/commands/results/serve.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,22 @@ function hasUsableTimestamp(timestamp: string | undefined): boolean {
411411
return !!timestamp && timestamp !== 'unknown' && !Number.isNaN(new Date(timestamp).getTime());
412412
}
413413

414+
function compareRunsByTimestampDesc<T extends { timestamp: string; filename: string }>(
415+
a: T,
416+
b: T,
417+
): number {
418+
const aTime = hasUsableTimestamp(a.timestamp) ? new Date(a.timestamp).getTime() : null;
419+
const bTime = hasUsableTimestamp(b.timestamp) ? new Date(b.timestamp).getTime() : null;
420+
421+
if (aTime !== null && bTime !== null && aTime !== bTime) {
422+
return bTime - aTime;
423+
}
424+
if (aTime !== null && bTime === null) return -1;
425+
if (aTime === null && bTime !== null) return 1;
426+
427+
return b.filename.localeCompare(a.filename);
428+
}
429+
414430
interface QualitySummaryInput {
415431
readonly score: number;
416432
readonly executionStatus?: string;
@@ -561,6 +577,7 @@ async function handleRuns(c: C, { searchDir, agentvDir, projectId }: DataContext
561577
};
562578
}),
563579
);
580+
runs.sort(compareRunsByTimestampDesc);
564581
const page = paginateRuns(runs, cursor, limit);
565582
return c.json({
566583
runs: page.runs,
@@ -1646,7 +1663,7 @@ export function createApp(
16461663
}
16471664
}
16481665

1649-
allRuns.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
1666+
allRuns.sort(compareRunsByTimestampDesc);
16501667
return c.json({ runs: allRuns });
16511668
});
16521669

apps/cli/test/commands/results/serve.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,33 @@ describe('serve app', () => {
628628
expect(secondPage.next_cursor).toBeUndefined();
629629
});
630630

631+
it('sorts runs by displayed timestamp descending before pagination', async () => {
632+
createLocalRun(tempDir, 'z-older-directory-name', {
633+
...RESULT_A,
634+
timestamp: '2026-03-25T10:00:00.000Z',
635+
});
636+
createLocalRun(tempDir, 'a-newer-directory-name', {
637+
...RESULT_A,
638+
timestamp: '2026-03-25T10:09:00.000Z',
639+
});
640+
641+
const app = createApp([], tempDir, tempDir, undefined, { studioDir });
642+
643+
const res = await app.request('/api/runs?limit=1');
644+
expect(res.status).toBe(200);
645+
const data = (await res.json()) as {
646+
runs: Array<{ filename: string; timestamp: string }>;
647+
next_cursor?: string;
648+
};
649+
expect(data.runs.map(({ filename, timestamp }) => ({ filename, timestamp }))).toEqual([
650+
{
651+
filename: 'a-newer-directory-name',
652+
timestamp: '2026-03-25T10:09:00.000Z',
653+
},
654+
]);
655+
expect(data.next_cursor).toBe('a-newer-directory-name');
656+
});
657+
631658
it('returns an empty page for unknown cursors', async () => {
632659
createLocalRun(tempDir, '2026-03-25T10-00-00-000Z', RESULT_A);
633660
createLocalRun(tempDir, '2026-03-25T11-00-00-000Z', RESULT_A);

0 commit comments

Comments
 (0)