Skip to content

Side tab runs sorting#69

Merged
Demonstrandum merged 4 commits into
masterfrom
cursor/side-tab-runs-sorting-cedd
Mar 16, 2026
Merged

Side tab runs sorting#69
Demonstrandum merged 4 commits into
masterfrom
cursor/side-tab-runs-sorting-cedd

Conversation

@Demonstrandum

Copy link
Copy Markdown
Owner

Motivation for features / changes

Previously, runs in the side tab were sorted alphabetically by run name. The backend already had start_time data 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:

  1. Backend (core_plugin.py): The /data/runs endpoint now returns a list of objects [{"name": "run1", "startTime": 1234.0}, ...] instead of plain strings ["run1", ...]. startTime is null if no events have been recorded.
  2. Angular Frontend (runs_data_source.ts): Updated to parse the new object format and use actual startTime values.
  3. Legacy Polymer (runsStore.ts): Modified extractRunNames() to handle both the new object format and the old string format for backward compatibility.
  4. Runs Table UI (runs_reducers.ts, runs_table_container.ts, runs_data_table.*):
    • A new "Started" column has been added to the runs table, which is sortable.
    • The default sort order for runs is now startTime ascending (oldest first), matching the "order added" request.
    • startTime is included in the TableData for sorting.
    • The "Started" column displays human-readable timestamps: time-only for today's runs (e.g., "10:30 AM"), month and day for older runs (e.g., "Jan 15"). A full timestamp is shown on hover via a tooltip.
  5. Tests: Backend tests (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 new startTime field in TableData.
  6. Documentation (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)

  1. Start the TensorBoard application.
  2. Navigate to the runs side tab (usually on the left).
  3. Observe the runs list:
    • Verify a new column labeled "Started" is present, typically next to the "Run" column.
    • Confirm that runs are sorted by the "Started" time in ascending order (oldest first) by default.
  4. Click on the "Started" column header to reverse the sort order (newest first).
  5. Click on other column headers (e.g., "Run") to ensure that sorting by other criteria still functions correctly.
  6. Check the formatting of the "Started" column:
    • For runs started today, verify only the time is displayed (e.g., "10:30 AM").
    • For runs started on previous days, verify the month and day are displayed (e.g., "Jan 15").
    • Hover over a "Started" time to confirm a tooltip appears showing the full timestamp.
  7. (Optional, for developers) Inspect the network request to /data/runs to confirm the backend returns objects with name and startTime fields.

Alternate designs / implementations considered (or N/A)

N/A

Open in Web Open in Cursor 

- 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

cursor Bot commented Mar 12, 2026

Copy link
Copy Markdown

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@github-actions

github-actions Bot commented Mar 12, 2026

Copy link
Copy Markdown

Preview Deployment

Status ✅ Running
Live Preview https://Demonstrandum-tensorbored-pr-69.hf.space
Space https://huggingface.co/spaces/Demonstrandum/tensorbored-pr-69
Details
  • Wheel: tensorbored_nightly-2.21.0a20260313-py3-none-any.whl
  • Commit: 06d0b36
  • Build status: success

cursoragent and others added 3 commits March 12, 2026 23:03
- 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>
@Demonstrandum Demonstrandum marked this pull request as ready for review March 16, 2026 13:54
@Demonstrandum Demonstrandum merged commit 553f02d into master Mar 16, 2026
14 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

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.

Create PR

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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Additional Locations (1)
Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants