Side tab runs sorting#69
Conversation
- Backend: /data/runs now returns [{name, startTime}, ...] instead of
plain strings. startTime is epoch seconds (null when unknown).
- Angular data source: parse the new response, use real startTime
instead of hardcoded 0.
- Legacy Polymer runsStore: extract run names from new object format
(backward-compatible with old string format).
- Runs table: add 'Started' column with human-readable timestamps
(time-only for today, month+day otherwise). Full timestamp on hover.
- Default sort changed from name-ascending to startTime-ascending,
so runs appear in the order they were created.
- Users can still click any column header to sort by name, experiment,
hparams, etc.
- Updated backend and frontend tests.
Co-authored-by: Samuel <samuel@knutsen.co>
|
Cursor Agent can help with this pull request. Just |
Preview Deployment
Details
|
- Fix Prettier formatting in runs_data_table.ng.html - Fix Black formatting in core_plugin.py (single-line list comprehension) - Add sort dropdown in the runs table filter row with presets: Oldest first, Newest first, Name A-Z, Name Z-A - The dropdown dispatches through the existing sorting infrastructure - Name sorting already uses parseNumericPrefix for best-effort numerical ordering (1/run, 2/run, 10/run sort correctly) - Column header click sorting still works independently Co-authored-by: Samuel <samuel@knutsen.co>
- Remove Name A-Z / Name Z-A presets (redundant with column header arrow toggle on the Run column). - Add 'Selected first' composite sort: floats checked/visible runs to the top, with startTime ascending as tiebreaker within each group. Useful when managing many runs with only a few selected. - Implement SORT_SELECTED_FIRST in sorting_utils.ts as a well-known composite sort key handled before the generic single-column sort. - Add test for the selected-first sort behavior. Co-authored-by: Samuel <samuel@knutsen.co>
The previous commit accidentally reformatted an unrelated line with a newer Black version (26.3.1). CI uses Black 24.3.0 which expects the multiline string % format on a separate line. Co-authored-by: Samuel <samuel@knutsen.co>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Null startTime mapped to 0 inverts sort order
- Changed the null startTime fallback from 0 to Infinity in runs_data_source.ts to match the backend's float('inf') sort semantics, ensuring eventless runs sort last in ascending order.
Or push these changes by commenting:
@cursor push 4c7bc6c61b
Preview (4c7bc6c61b)
diff --git a/tensorbored/webapp/runs/data_source/runs_data_source.ts b/tensorbored/webapp/runs/data_source/runs_data_source.ts
--- a/tensorbored/webapp/runs/data_source/runs_data_source.ts
+++ b/tensorbored/webapp/runs/data_source/runs_data_source.ts
@@ -42,7 +42,7 @@
return {
id: runToRunId(entry.name, experimentId),
name: entry.name,
- startTime: entry.startTime ?? 0,
+ startTime: entry.startTime ?? Infinity,
};
});
})
diff --git a/tensorbored/webapp/runs/data_source/runs_data_source_test.ts b/tensorbored/webapp/runs/data_source/runs_data_source_test.ts
--- a/tensorbored/webapp/runs/data_source/runs_data_source_test.ts
+++ b/tensorbored/webapp/runs/data_source/runs_data_source_test.ts
@@ -51,7 +51,7 @@
]);
}));
- it('treats null startTime as 0', fakeAsync(() => {
+ it('treats null startTime as Infinity', fakeAsync(() => {
const results = jasmine.createSpy();
dataSource.fetchRuns('exp1').subscribe(results);
@@ -61,7 +61,7 @@
flush();
expect(results).toHaveBeenCalledWith([
- {id: 'exp1/baz', name: 'baz', startTime: 0},
+ {id: 'exp1/baz', name: 'baz', startTime: Infinity},
]);
}));
});This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
| startTime: 0, | ||
| id: runToRunId(entry.name, experimentId), | ||
| name: entry.name, | ||
| startTime: entry.startTime ?? 0, |
There was a problem hiding this comment.
Null startTime mapped to 0 inverts sort order
High Severity
When the backend returns startTime: null (no events recorded), entry.startTime ?? 0 converts it to 0. Since the default sort is startTime ascending, runs with no events get startTime: 0, which sorts before all real epoch timestamps — placing them at the top. The backend explicitly sorts these runs last using float("inf"). This directly inverts the intended ordering for eventless runs. The fallback value needs to be large (e.g., Infinity) rather than 0 to match the backend's "empty times sorted last" semantics.



Motivation for features / changes
Previously, runs in the side tab were sorted alphabetically by run name. The backend already had
start_timedata but only returned run names as strings, which the frontend then re-sorted. This change addresses the user request to order runs by the time they were added, providing a more intuitive default sort order and the ability to sort by start time.Technical description of changes
This is a full-stack change across 12 files:
core_plugin.py): The/data/runsendpoint now returns a list of objects[{"name": "run1", "startTime": 1234.0}, ...]instead of plain strings["run1", ...].startTimeisnullif no events have been recorded.runs_data_source.ts): Updated to parse the new object format and use actualstartTimevalues.runsStore.ts): ModifiedextractRunNames()to handle both the new object format and the old string format for backward compatibility.runs_reducers.ts,runs_table_container.ts,runs_data_table.*):startTimeascending (oldest first), matching the "order added" request.startTimeis included in theTableDatafor sorting.core_plugin_test.py) verify the new object format and timestamp values. Frontend data source tests (runs_data_source_test.ts) verify parsing. Runs table tests (runs_table_test.ts) were updated to expect the newstartTimefield inTableData.AGENTS_DEV.md): Updated to reflect the new sorting behavior and "Started" column.Users can still click any column header (Run, Experiment, Hparams, etc.) to change the sort order.
Screenshots of UI changes (or N/A)
N/A
Detailed steps to verify changes work correctly (as executed by you)
/data/runsto confirm the backend returns objects withnameandstartTimefields.Alternate designs / implementations considered (or N/A)
N/A