Skip to content

feat(admin): refine dashboard model and overview UI#426

Merged
SantiagoDePolonia merged 4 commits into
mainfrom
feat/aliases-to-virtual-models
Jun 24, 2026
Merged

feat(admin): refine dashboard model and overview UI#426
SantiagoDePolonia merged 4 commits into
mainfrom
feat/aliases-to-virtual-models

Conversation

@SantiagoDePolonia

@SantiagoDePolonia SantiagoDePolonia commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • combine overview token and local cache metrics into wider summary cards with clearer input/output indicators
  • refine virtual model rows, redirect pills, removal actions, pricing columns, and modal labels on the models page
  • add provider overview auto-refresh for starting providers, default-collapsed details, corrected toggle labels, and shared no-data/trash icons

Tests

  • node --test internal/admin/dashboard/static/js/modules/usage.test.cjs internal/admin/dashboard/static/js/modules/dashboard-display.test.cjs internal/admin/dashboard/static/js/modules/budgets.test.cjs internal/admin/dashboard/static/js/modules/dashboard-layout.test.cjs internal/admin/dashboard/static/js/modules/virtual-models.test.cjs internal/admin/dashboard/static/js/modules/providers.test.cjs

Summary by CodeRabbit

  • New Features

    • Consolidated overview and Local Cache token metrics into wider Input/Output/Total cards.
    • Added shared “No data” empty-state illustration for charts, usage, and audit logs, including a centered chart overlay.
    • Improved virtual model management UI with alias/redirect-specific delete controls and updated labels.
  • Bug Fixes

    • Standardized missing/invalid cost and budget displays to show ---.
    • Refined dashboard table pricing alignment and empty/error presentation; updated token rendering styling.
    • Improved provider status auto-refresh and made the details panel default to collapsed with updated toggle text.
  • Tests

    • Added/updated unit and UI tests for formatting, token totals, provider polling, and virtual model overwrite/redirect/delete flows.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 89b3cb37-6902-4d8d-9e20-4d883be4380c

📥 Commits

Reviewing files that changed from the base of the PR and between ef04409 and eb6fd39.

📒 Files selected for processing (2)
  • internal/admin/dashboard/static/js/modules/virtual-models.js
  • internal/admin/dashboard/static/js/modules/virtual-models.test.cjs

📝 Walkthrough

Walkthrough

This PR updates dashboard value placeholders, combined token displays, shared empty states, provider status polling, and virtual model redirect/removal behavior, while also adjusting models table labels, pricing columns, and row actions.

Changes

Admin Dashboard

Layer / File(s) Summary
Placeholder and token totals
internal/admin/dashboard/static/js/dashboard.js, internal/admin/dashboard/static/js/modules/budgets.js, internal/admin/dashboard/static/js/modules/budgets.test.cjs, internal/admin/dashboard/static/js/modules/dashboard-display.test.cjs, internal/admin/dashboard/static/js/modules/usage.js, internal/admin/dashboard/static/js/modules/usage.test.cjs, internal/admin/dashboard/templates/page-overview.html, internal/admin/dashboard/static/css/dashboard.css, internal/admin/dashboard/static/js/modules/dashboard-layout.test.cjs
formatCost and budgetAmountLabel() return '---' for invalid values, usage helpers compute total tokens, and the overview page renders combined token cards with matching layout and tests.
Shared empty-state icon
internal/admin/dashboard/templates/no-data-icon.html, internal/admin/dashboard/static/css/dashboard.css, internal/admin/dashboard/templates/page-overview.html, internal/admin/dashboard/templates/page-audit-logs.html, internal/admin/dashboard/templates/page-usage.html
Adds a shared empty-state icon template and uses it for the overview chart, audit logs, and usage logs.
Provider status polling
internal/admin/dashboard/static/js/modules/providers.js, internal/admin/dashboard/static/js/modules/providers.test.cjs
Adds polling timer state and refresh scheduling, changes details preference initialization and toggle labels, and updates tests for persistence and polling flow.
Virtual model redirect data model
internal/admin/dashboard/static/js/modules/virtual-models.js, internal/admin/dashboard/static/js/modules/virtual-models.test.cjs
Tracks redirect-backed rows, skips alias rows with concrete sources, updates redirect badges, and adds removal-gating helpers and coverage.
Virtual model removal actions
internal/admin/dashboard/static/js/modules/virtual-models.js, internal/admin/dashboard/static/js/modules/virtual-models.test.cjs, internal/admin/dashboard/templates/trash-icon.html, internal/admin/dashboard/templates/model-table-body.html
Adds shared delete handling for alias and redirect rows, introduces the trash icon template, and wires row-level delete buttons and tests.
Models table and virtual model UI
internal/admin/dashboard/templates/model-table-body.html, internal/admin/dashboard/templates/page-models.html, internal/admin/dashboard/static/css/dashboard.css, internal/admin/dashboard/static/js/modules/dashboard-layout.test.cjs
Updates header spans, pricing columns, redirect text, toolbar and modal copy, price alignment, and masked-row styling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • ENTERPILOT/GoModel#221: Introduces the providers dashboard module flow that this PR extends with polling and refresh-state behavior.

Poem

🐇 I hop past tokens, bright and neat,
With --- for blanks and charts that greet.
Empty states bloom with icons fair,
And virtual models now know their fare.
The dashboard hums, concise and light,
A carrot-tuned, well-wired sight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main admin dashboard and models UI refinements in this changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/aliases-to-virtual-models

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread internal/admin/dashboard/static/js/dashboard.js Fixed
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown

Confidence Score: 4/5

This is close, but the provider details toggle should be fixed before merging.

  • The saved provider details preference is now preserved across reloads.
  • The visible toggle label still describes the opposite action.
  • Other inspected dashboard changes appear consistent with their callers and templates.

internal/admin/dashboard/static/js/modules/providers.js

Reviews (2): Last reviewed commit: "fix(admin): serialize virtual model row ..." | Re-trigger Greptile

Comment thread internal/admin/dashboard/static/js/modules/providers.js
Comment thread internal/admin/dashboard/static/js/modules/providers.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/admin/dashboard/static/js/dashboard.js`:
- Around line 946-949: Update formatCost in dashboard.js to treat non-finite
inputs the same as missing values, since NaN and Infinity currently fall through
to the currency formatting and produce invalid output. Add a guard at the start
of formatCost that returns the placeholder for null, undefined, NaN, and
infinite values, while keeping the existing small-value and toFixed formatting
behavior unchanged.

In `@internal/admin/dashboard/static/js/modules/budgets.js`:
- Around line 375-379: Treat null as a missing value in budgetAmountLabel before
numeric coercion. Update the budgetAmountLabel helper in budgets.js so it
returns '---' when the input value is null or otherwise absent, and only then
proceeds to Number(value) and the Number.isFinite check for valid numeric
formatting.

In `@internal/admin/dashboard/static/js/modules/providers.js`:
- Around line 60-62: The toggle label logic in providerStatusDetailsToggleLabel
is reversed relative to providerStatusDetailsExpanded. Update the label returned
from this method in providers.js so collapsed state shows “Show Details” and
expanded state shows “Hide Details”, matching the intended toggle behavior.
- Around line 31-39: The initProviderStatusPreferences method is overwriting the
saved provider details preference on every load by always writing a collapsed
value, which destroys the user’s stored choice. Update
initProviderStatusPreferences in providers.js to only initialize
this.providerStatusDetailsExpanded and read any existing value from
browserStorage()/PROVIDER_STATUS_DETAILS_STORAGE_KEY, leaving storage unchanged
unless the user explicitly toggles the details state elsewhere. Make sure the
saved preference is preserved across reloads instead of being reset during
initialization.

In `@internal/admin/dashboard/static/js/modules/providers.test.cjs`:
- Around line 94-101: The provider status details tests need a reload-style
persistence check in providers.test.cjs: current assertions around
toggleProviderStatusDetails only confirm storage writes, not that a previously
saved value is restored on module init. Update the test to seed storage with
'true', create a fresh module instance using the existing initialization path,
and assert providerStatusDetailsExpanded starts true (and the label matches) so
the persisted preference readback is covered.

In `@internal/admin/dashboard/static/js/modules/virtual-models.js`:
- Around line 59-78: buildDisplayModels() and hasConcreteSourceModel() are only
checking alias.name against qualifiedModelName()/selector, but source-backed
redirect detection should use the same identity set as the rest of the module.
Update the redirect lookup in buildDisplayModels and the concrete-model check in
hasConcreteSourceModel to reuse modelKeys() (and the existing
findConcreteModelByName path if needed) so any valid concrete key resolves
correctly. Keep the logic around aliases, rows, and
masking_alias/has_virtual_model unchanged aside from expanding the match
criteria.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8e570d79-5e7f-4d98-8314-7715b8807b27

📥 Commits

Reviewing files that changed from the base of the PR and between 787f878 and 1f062ae.

📒 Files selected for processing (19)
  • internal/admin/dashboard/static/css/dashboard.css
  • internal/admin/dashboard/static/js/dashboard.js
  • internal/admin/dashboard/static/js/modules/budgets.js
  • internal/admin/dashboard/static/js/modules/budgets.test.cjs
  • internal/admin/dashboard/static/js/modules/dashboard-display.test.cjs
  • internal/admin/dashboard/static/js/modules/dashboard-layout.test.cjs
  • internal/admin/dashboard/static/js/modules/providers.js
  • internal/admin/dashboard/static/js/modules/providers.test.cjs
  • internal/admin/dashboard/static/js/modules/usage.js
  • internal/admin/dashboard/static/js/modules/usage.test.cjs
  • internal/admin/dashboard/static/js/modules/virtual-models.js
  • internal/admin/dashboard/static/js/modules/virtual-models.test.cjs
  • internal/admin/dashboard/templates/model-table-body.html
  • internal/admin/dashboard/templates/no-data-icon.html
  • internal/admin/dashboard/templates/page-audit-logs.html
  • internal/admin/dashboard/templates/page-models.html
  • internal/admin/dashboard/templates/page-overview.html
  • internal/admin/dashboard/templates/page-usage.html
  • internal/admin/dashboard/templates/trash-icon.html

Comment thread internal/admin/dashboard/static/js/dashboard.js Outdated
Comment thread internal/admin/dashboard/static/js/modules/budgets.js
Comment thread internal/admin/dashboard/static/js/modules/providers.js
Comment on lines 60 to +62
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
return this.providerStatusDetailsExpanded ? 'Show Details' : 'Hide Details';
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Flip the toggle action labels.

When details are collapsed, the toggle should offer “Show Details”; when expanded, it should offer “Hide Details”.

Proposed fix
 providerStatusDetailsToggleLabel() {
-    return this.providerStatusDetailsExpanded ? 'Show Details' : 'Hide Details';
+    return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
return this.providerStatusDetailsExpanded ? 'Show Details' : 'Hide Details';
},
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/admin/dashboard/static/js/modules/providers.js` around lines 60 -
62, The toggle label logic in providerStatusDetailsToggleLabel is reversed
relative to providerStatusDetailsExpanded. Update the label returned from this
method in providers.js so collapsed state shows “Show Details” and expanded
state shows “Hide Details”, matching the intended toggle behavior.

Comment thread internal/admin/dashboard/static/js/modules/providers.test.cjs
Comment thread internal/admin/dashboard/static/js/modules/virtual-models.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/admin/dashboard/static/js/modules/virtual-models.js (2)

520-526: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Allow displayed alias rows to be removed even when their source matches a concrete model.

Line 84 only folds enabled valid source-backed redirects into concrete model rows; disabled/invalid source-backed redirects still render as alias rows. But Line 521 blocks removeAliasRow() for those rows, and rowRedirectCanRemove() does not apply because they are alias rows, so the row-level delete action is unavailable for that displayed virtual model.

Proposed fix
 aliasRowCanRemove(row) {
-    return Boolean(row && row.is_alias && row.alias && row.alias.name && !row.source_model_exists);
+    return Boolean(row && row.is_alias && row.alias && row.alias.name);
 },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/admin/dashboard/static/js/modules/virtual-models.js` around lines
520 - 526, Displayed alias rows that still represent source-backed redirects are
being blocked from removal because aliasRowCanRemove only allows deletion when
source_model_exists is false, even though these rows are rendered as alias rows.
Update aliasRowCanRemove and the related removeAliasRow flow in
virtual-models.js so displayed alias rows can be deleted regardless of whether
their source matches a concrete model, while keeping rowRedirectCanRemove
limited to redirect rows.

970-990: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Serialize row deletes or track multiple in-flight rows.

rowDeletingKey is a single value, but the guards only block the same row key. Deleting two different rows concurrently can overwrite rowDeletingKey, race the fetchModels() / fetchVirtualModels() refreshes, and leave displayModels with stale data from the slower request.

Proposed fix
 async removeAliasRow(row) {
-    if (!this.aliasRowCanRemove(row) || this.rowDeletingKey === row.key) {
+    if (!this.aliasRowCanRemove(row) || this.rowDeletingKey) {
         return;
     }
@@
 async removeRedirectRow(row) {
-    if (!this.rowRedirectCanRemove(row) || this.rowDeletingKey === row.key) {
+    if (!this.rowRedirectCanRemove(row) || this.rowDeletingKey) {
         return;
     }

Also applies to: 992-1035

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/admin/dashboard/static/js/modules/virtual-models.js` around lines
970 - 990, Serialize deletes in the virtual models row handlers because
rowDeletingKey only tracks one row and concurrent removes can race the
refreshes; update removeAliasRow, removeRedirectRow, and the shared
removeVirtualModelSource flow to prevent overlapping deletes or to track
multiple in-flight row keys. Make sure the guards around rowDeletingKey,
fetchModels, fetchVirtualModels, and displayModels refreshes cannot interleave
stale results from an earlier request overwriting newer data.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@internal/admin/dashboard/static/js/modules/virtual-models.js`:
- Around line 520-526: Displayed alias rows that still represent source-backed
redirects are being blocked from removal because aliasRowCanRemove only allows
deletion when source_model_exists is false, even though these rows are rendered
as alias rows. Update aliasRowCanRemove and the related removeAliasRow flow in
virtual-models.js so displayed alias rows can be deleted regardless of whether
their source matches a concrete model, while keeping rowRedirectCanRemove
limited to redirect rows.
- Around line 970-990: Serialize deletes in the virtual models row handlers
because rowDeletingKey only tracks one row and concurrent removes can race the
refreshes; update removeAliasRow, removeRedirectRow, and the shared
removeVirtualModelSource flow to prevent overlapping deletes or to track
multiple in-flight row keys. Make sure the guards around rowDeletingKey,
fetchModels, fetchVirtualModels, and displayModels refreshes cannot interleave
stale results from an earlier request overwriting newer data.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f49c21cf-f0a1-4ea6-9fa2-2e4904e0e651

📥 Commits

Reviewing files that changed from the base of the PR and between 1f062ae and b99b8b9.

📒 Files selected for processing (8)
  • internal/admin/dashboard/static/js/dashboard.js
  • internal/admin/dashboard/static/js/modules/budgets.js
  • internal/admin/dashboard/static/js/modules/budgets.test.cjs
  • internal/admin/dashboard/static/js/modules/dashboard-display.test.cjs
  • internal/admin/dashboard/static/js/modules/providers.js
  • internal/admin/dashboard/static/js/modules/providers.test.cjs
  • internal/admin/dashboard/static/js/modules/virtual-models.js
  • internal/admin/dashboard/static/js/modules/virtual-models.test.cjs

Comment on lines 65 to +67
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
return this.providerStatusDetailsExpanded ? 'Show Details' : 'Hide Details';
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Fix toggle wording The overview template uses this helper for the provider details button text and title, while providerStatusDetailsExpanded controls whether the details panel is visible. With the current return values, the default collapsed state shows Hide Details, even though clicking will show the panel, and the expanded state shows Show Details, even though clicking will hide it. Return the next action label so the control matches what the click does.

Suggested change
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
return this.providerStatusDetailsExpanded ? 'Show Details' : 'Hide Details';
},
providerStatusDetailsToggleLabel() {
return this.providerStatusDetailsExpanded ? 'Hide Details' : 'Show Details';
},

@SantiagoDePolonia SantiagoDePolonia merged commit b113cab into main Jun 24, 2026
20 checks passed
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