Skip to content

Commit 991438e

Browse files
committed
fix: clarify dashboard timestamps and scrolling
1 parent 88d2744 commit 991438e

4 files changed

Lines changed: 31 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- Keep call details sticky while scrolling and render timestamps as local human-readable date/time values.
1313
- Prefer non-review models in mixed thread model summaries, add fit-to-width model labels, and add a scroll-aware `Top` button.
1414
- Hide single-page dashboard pagination and keep multi-page controls compact in the toolbar.
15+
- Render fetched and refreshed timestamps as local human-readable date-times and make the call details scrollbar visible.
1516
- Add a screenshot-driven dashboard guide built from synthetic aggregate fixture data.
1617
- Preserve requested virtualenv Python paths during plugin install instead of resolving through interpreter symlinks.
1718
- Keep generated dashboards, SQLite databases, CSV exports, and raw Codex logs out of git.

docs/dashboard-guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The dashboard opens in `Calls` view. This is the most direct way to inspect indi
3636
- Time values are shown in your browser's local date/time format while sorting still uses the logged timestamp.
3737
- Click a column header like `Time`, `Thread`, `Tokens`, `Cost`, or `Cache` to sort. Click the same header again to reverse the direction.
3838
- Hover or click a row to pin its aggregate fields in `Call Details`; on desktop, the details panel stays visible as you scroll.
39+
- The `Call Details` panel always reserves a visible scrollbar so long field lists are discoverable before you start scrolling.
3940
- Pagination appears only when the active Calls or Threads view has more than one page.
4041
- After you scroll down, the bottom-right `Top` button returns to the top of the dashboard.
4142

src/codex_usage_tracker/dashboard.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,10 +501,29 @@ def _html(payload: str) -> str:
501501
flex: 1 1 auto;
502502
padding: 14px 16px;
503503
min-height: 280px;
504-
overflow: auto;
504+
overflow-x: hidden;
505+
overflow-y: scroll;
506+
scrollbar-gutter: stable;
507+
scrollbar-width: thin;
508+
scrollbar-color: #94a3b8 #eef2f8;
505509
color: var(--muted);
506510
line-height: 1.45;
507511
}}
512+
.detail::-webkit-scrollbar {{
513+
width: 10px;
514+
}}
515+
.detail::-webkit-scrollbar-track {{
516+
background: #eef2f8;
517+
border-left: 1px solid var(--line);
518+
}}
519+
.detail::-webkit-scrollbar-thumb {{
520+
background: #94a3b8;
521+
border: 2px solid #eef2f8;
522+
border-radius: 999px;
523+
}}
524+
.detail::-webkit-scrollbar-thumb:hover {{
525+
background: #64748b;
526+
}}
508527
.detail dl {{ display: grid; grid-template-columns: minmax(120px, 0.6fr) minmax(0, 1fr); gap: 8px 14px; margin: 0; }}
509528
.detail dt {{ font-weight: 720; color: var(--ink); }}
510529
.detail dd {{ margin: 0; overflow-wrap: anywhere; }}
@@ -907,10 +926,12 @@ def _html(payload: str) -> str:
907926
const sourceParts = [
908927
pricingSource.name || 'Pricing source',
909928
pricingSource.tier ? `${{pricingSource.tier}} tier` : '',
910-
pricingSource.fetched_at ? `fetched ${{pricingSource.fetched_at}}` : '',
929+
pricingSource.fetched_at ? `fetched ${{formatTimestamp(pricingSource.fetched_at)}}` : '',
911930
].filter(Boolean);
912931
sourceEl.textContent = `Costs: ${{sourceParts.join(' · ')}}`;
913-
sourceEl.title = 'Internal Codex labels may use marked best-guess estimates.';
932+
sourceEl.title = pricingSource.fetched_at
933+
? `Fetched from ${{pricingSource.url}} at ${{formatTimestampTitle(pricingSource.fetched_at)}}. Internal Codex labels may use marked best-guess estimates.`
934+
: 'Internal Codex labels may use marked best-guess estimates.';
914935
}} else {{
915936
sourceEl.textContent = pricingConfigured ? '' : 'Costs unavailable';
916937
sourceEl.title = pricingConfigured ? '' : 'Run codex-usage-tracker update-pricing to configure estimated costs.';
@@ -1587,11 +1608,6 @@ def _html(payload: str) -> str:
15871608
currentPage = 1;
15881609
render();
15891610
}}
1590-
function localTime(value) {{
1591-
const date = value ? new Date(value) : new Date();
1592-
if (Number.isNaN(date.getTime())) return '';
1593-
return date.toLocaleTimeString([], {{ hour: 'numeric', minute: '2-digit', second: '2-digit' }});
1594-
}}
15951611
function updateLiveStatus(message) {{
15961612
liveStatusEl.textContent = message;
15971613
}}
@@ -1636,7 +1652,7 @@ def _html(payload: str) -> str:
16361652
const indexed = result.inserted_or_updated_events === undefined
16371653
? ''
16381654
: ` Indexed ${{number.format(result.inserted_or_updated_events)}} aggregate rows from ${{number.format(result.scanned_files || 0)}} logs.`;
1639-
updateLiveStatus(`Updated ${{localTime(nextPayload.refreshed_at)}}. ${{loadedRowsDescription()}}.${{indexed}}`);
1655+
updateLiveStatus(`Updated ${{formatTimestamp(nextPayload.refreshed_at)}}. ${{loadedRowsDescription()}}.${{indexed}}`);
16401656
}} catch (error) {{
16411657
const message = error.message || String(error);
16421658
updateLiveStatus(`Live refresh unavailable: ${{message}}${{manual ? '. Reload this page after regenerating a static dashboard, or run codex-usage-tracker serve-dashboard.' : ''}}`);

tests/test_store_dashboard_mcp.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ def test_dashboard_and_csv_are_aggregate_only(tmp_path: Path) -> None:
101101
assert "detail-section" in dashboard
102102
assert "time-cell" in dashboard
103103
assert "formatTimestamp" in dashboard
104+
assert "scrollbar-gutter: stable" in dashboard
105+
assert "overflow-y: scroll" in dashboard
106+
assert "formatTimestamp(pricingSource.fetched_at)" in dashboard
107+
assert "formatTimestamp(nextPayload.refreshed_at)" in dashboard
104108
assert "threadModelSummary" in dashboard
105109
assert "model-pill" in dashboard
106110
assert "Back to top" in dashboard

0 commit comments

Comments
 (0)