Skip to content

UN-3380 [FIX] Dashboard UI/UX improvements#1897

Merged
athul-rs merged 9 commits intomainfrom
UN-3380
Apr 6, 2026
Merged

UN-3380 [FIX] Dashboard UI/UX improvements#1897
athul-rs merged 9 commits intomainfrom
UN-3380

Conversation

@athul-rs
Copy link
Copy Markdown
Contributor

@athul-rs athul-rs commented Apr 5, 2026

What

  • Dashboard UI/UX tweaks for consistency and improved subscription tab experience

Why

  • Header text was repeating ("Unstract Unstract cloud growth plan annual Plan")
  • Side spacing was inconsistent (24px vs 14px used elsewhere)
  • Tab content area lacked white background
  • Duplicate refresh buttons on Usage by Deployment tab
  • Subscription tab was a plain table with zero-value rows
  • Last Run column in deployment table was missing sort

How

  • MetricsDashboard.css: Side padding to 14px, white background on .ant-tabs-content
  • MetricsDashboard.jsx: Added useRef + deploymentRefetchRef to wire global refresh to deployment table
  • LLMUsageTable.jsx: Removed card-level refresh button, accepts refetchRef prop, added sort on Last Run column

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. Changes are CSS-only and minor component prop additions. No backend changes. No API contract changes.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • N/A

Related Issues or PRs

  • Zipstack/unstract-cloud PR (companion): UN-3380 — PlanBanner fix + Subscription tab redesign

Dependencies Versions

  • None

Notes on Testing

  • Navigate to Dashboard → verify 14px side spacing
  • Check tab content has white background
  • Usage by Deployment tab: verify single refresh button, Last Run column sortable
  • Global refresh button should refresh deployment data too

Screenshots

image image

Checklist

I have read and understood the Contribution Guidelines.

- Fix side padding to 14px for consistency with rest of product
- Add white background to tab content area
- Remove duplicate refresh button from Usage by Deployment table
- Wire global refresh to also trigger deployment data refetch
- Add sort on Last Run column in deployment usage table
- Upgrade Subscription tab with area chart, summary stats, and last 30 active days window

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 5, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a parent-controlled ref-based refetch hook for the deployment usage table (child registers its internal refetch on a passed ref), removes the table's manual refresh UI, updates "Last Run" sorting, and introduces layout wrapping and extensive "V2" subscription usage styling and spacing adjustments.

Changes

Cohort / File(s) Summary
Deployment usage refresh & table changes
frontend/src/components/metrics-dashboard/LLMUsageTable.jsx
Adds refetchRef prop (PropTypes + defaultProp). Child registers its internal refetch to refetchRef.current via useEffect with cleanup. Removes manual header refresh UI and related imports. Formats Tokens/Executions with compact suffixes and tooltips. Changes "Last Run" sorter to use localeCompare on last_execution_at (defaults to "").
Dashboard integration & layout
frontend/src/components/metrics-dashboard/MetricsDashboard.jsx
Introduces deploymentRefetchRef (useRef) and passes it to DeploymentUsageTable. Extends centralized handleRefresh to call deploymentRefetchRef.current?.() alongside other refetches. Wraps topbar, PlanBanner, Tabs, and related sections in new .metrics-dashboard-container.
Styling / V2 subscription UI
frontend/src/components/metrics-dashboard/MetricsDashboard.css
Reduces .metrics-dashboard padding and adjusts .metrics-topbar spacing/border. Adds .metrics-dashboard-container and .metrics-dashboard .ant-tabs > .ant-tabs-nav / .ant-tabs-content rules. Adds numerous .subscription-usage-tab-v2 and related selectors, responsive sizing, and compact execution/status utility classes. Minor responsive padding tweaks and legacy comment relabeling.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Dashboard as "MetricsDashboard\n(container)"
    participant Table as "DeploymentUsageTable\n(LLMUsageTable)"
    participant Hook as "useDeploymentUsage\n(hooks/API)"
    participant Backend as "Backend/API"

    Dashboard->>Dashboard: handleRefresh()
    Dashboard->>Hook: refetchOverview()
    Dashboard->>Hook: refetchChart()
    Dashboard->>Hook: refetchActivity()
    Dashboard->>Hook: refetchSubscription()
    Dashboard->>Table: deploymentRefetchRef.current?()
    Table->>Hook: refetch()
    Hook->>Backend: fetch data
    Backend-->>Hook: data
    Hook-->>Table: data
    Hook-->>Dashboard: data (overview/chart/activity/subscription)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'UN-3380 [FIX] Dashboard UI/UX improvements' accurately summarizes the main changes: CSS tweaks for spacing consistency, white background on tabs, removal of duplicate refresh buttons, and addition of sort functionality to the Last Run column.
Description check ✅ Passed The description comprehensively covers all required sections: What (UI/UX tweaks), Why (lists specific issues), How (explains changes per file), breaking changes assessment, database/env config, testing notes, and includes screenshots with the contribution checklist.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch UN-3380

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
frontend/src/components/metrics-dashboard/MetricsDashboard.css (1)

4-17: Consider centralizing the new 14px spacing as a CSS variable.

14px is now repeated across dashboard/topbar/responsive rules. A shared token would reduce drift in future tweaks.

♻️ Optional refactor
+.metrics-dashboard {
+  --metrics-page-gutter: 14px;
+}
 .metrics-dashboard {
-  padding: 14px;
+  padding: var(--metrics-page-gutter);
 }
 .metrics-topbar {
-  margin: -14px -14px 20px -14px;
-  padding: 12px 14px;
+  margin: calc(-1 * var(--metrics-page-gutter)) calc(-1 * var(--metrics-page-gutter)) 20px calc(-1 * var(--metrics-page-gutter));
+  padding: 12px var(--metrics-page-gutter);
 }
 `@media` (max-width: 768px) {
   .metrics-topbar {
-    margin: -14px -14px 16px -14px;
-    padding: 12px 14px;
+    margin: calc(-1 * var(--metrics-page-gutter)) calc(-1 * var(--metrics-page-gutter)) 16px calc(-1 * var(--metrics-page-gutter));
+    padding: 12px var(--metrics-page-gutter);
   }
   .metrics-dashboard {
-    padding: 14px;
+    padding: var(--metrics-page-gutter);
   }
 }

Also applies to: 238-253

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/metrics-dashboard/MetricsDashboard.css` around lines
4 - 17, Introduce a shared CSS variable for the repeated 14px spacing and
replace the literal values with that token: add something like --spacing-sm:
14px at a root or container scope (e.g., :root or .metrics-dashboard) and update
occurrences in .metrics-dashboard, .metrics-topbar and the related responsive
rules to use var(--spacing-sm) for padding/margin calculations (including the
margin: -14px ... and padding: 12px 14px and the height calc that uses 64px if
applicable); ensure the variable name is descriptive (e.g., --spacing-sm) and
update all other instances mentioned (lines ~238-253) so spacing is centralized.
frontend/src/components/metrics-dashboard/LLMUsageTable.jsx (1)

127-132: Add cleanup to ref assignments for defensive consistency, though not currently necessary.

The refetchRef.current assignment at line 130 should include a cleanup function, even though DeploymentUsageTable is not destroyed during tab switches (Tabs lacks destroyInactiveTabPane config). If the Tabs configuration changes to destroy inactive tabs in the future, this cleanup becomes essential to prevent stale function references. For consistency with React patterns, cleanup should be added:

🩹 Suggested fix
   useEffect(() => {
     if (refetchRef) {
       refetchRef.current = refetch;
     }
+    return () => {
+      if (refetchRef) {
+        refetchRef.current = null;
+      }
+    };
   }, [refetch, refetchRef]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/metrics-dashboard/LLMUsageTable.jsx` around lines 127
- 132, The useEffect that exposes refetch via refetchRef should add a cleanup to
avoid leaving a stale reference: inside the useEffect that assigns
refetchRef.current = refetch (in LLMUsageTable.jsx), return a cleanup function
that clears refetchRef.current (e.g., set to undefined or null) when the
component unmounts or deps change; keep the existing dependency array [refetch,
refetchRef] and only modify the effect to set the ref on mount/update and clear
it in the returned cleanup function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/components/metrics-dashboard/LLMUsageTable.jsx`:
- Around line 127-132: The useEffect that exposes refetch via refetchRef should
add a cleanup to avoid leaving a stale reference: inside the useEffect that
assigns refetchRef.current = refetch (in LLMUsageTable.jsx), return a cleanup
function that clears refetchRef.current (e.g., set to undefined or null) when
the component unmounts or deps change; keep the existing dependency array
[refetch, refetchRef] and only modify the effect to set the ref on mount/update
and clear it in the returned cleanup function.

In `@frontend/src/components/metrics-dashboard/MetricsDashboard.css`:
- Around line 4-17: Introduce a shared CSS variable for the repeated 14px
spacing and replace the literal values with that token: add something like
--spacing-sm: 14px at a root or container scope (e.g., :root or
.metrics-dashboard) and update occurrences in .metrics-dashboard,
.metrics-topbar and the related responsive rules to use var(--spacing-sm) for
padding/margin calculations (including the margin: -14px ... and padding: 12px
14px and the height calc that uses 64px if applicable); ensure the variable name
is descriptive (e.g., --spacing-sm) and update all other instances mentioned
(lines ~238-253) so spacing is centralized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c51500bf-40b0-4a7e-b830-51a0da4fcb46

📥 Commits

Reviewing files that changed from the base of the PR and between 7983c98 and 1d911c4.

📒 Files selected for processing (3)
  • frontend/src/components/metrics-dashboard/LLMUsageTable.jsx
  • frontend/src/components/metrics-dashboard/MetricsDashboard.css
  • frontend/src/components/metrics-dashboard/MetricsDashboard.jsx

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 5, 2026

Greptile Summary

This PR makes targeted UI/UX improvements to the metrics dashboard — fixing side padding (24px → 14px), adding a white background to tab content, wiring a global refresh button to the DeploymentUsageTable via a refetchRef, removing the duplicate card-level refresh button, and adding sort support to the Last Run column.

  • MetricsDashboard.jsx: Added useRef + deploymentRefetchRef to connect the global refresh to DeploymentUsageTable; reorganised the topbar/layout. handleRefresh correctly omits deploymentRefetchRef from its useCallback deps (refs don't need to be listed).
  • LLMUsageTable.jsx: refetchRef prop wired via useEffect with proper cleanup on unmount (sets current to null). PropTypes.shape({ current: PropTypes.func }) is correctly typed. Tag is imported but no longer used after the Executions column was changed to <span> elements — minor dead import.
  • MetricsDashboard.css: Padding, white background, and new compact execution styles all look correct. .llm-usage-tag-compact is now also unused (dead CSS rule) but harmless.
  • Header.jsx: Pure formatting change (brace style) with no logic impact.

Confidence Score: 5/5

Safe to merge — all changes are frontend-only with no backend, API, or database impact.

The only finding is a dead Tag import (P2 style), which won't affect runtime behaviour. Previously raised concerns about useEffect cleanup and PropTypes typing have both been addressed in this revision. No logic, security, or data-integrity issues found.

No files require special attention.

Important Files Changed

Filename Overview
frontend/src/components/metrics-dashboard/LLMUsageTable.jsx Adds refetchRef wiring, compact number formatting, Last Run sort, and Executions column redesign; one unused Tag import remains
frontend/src/components/metrics-dashboard/MetricsDashboard.jsx Adds deploymentRefetchRef + global refresh wiring; layout reorganisation looks correct
frontend/src/components/metrics-dashboard/MetricsDashboard.css Side padding fixed to 14px, white tab-content background added, new compact execution span styles
frontend/src/components/custom-tools/header/Header.jsx Formatting-only change: single-line return expanded to braced block

Sequence Diagram

sequenceDiagram
    participant User
    participant MetricsDashboard
    participant DeploymentUsageTable
    participant useDeploymentUsage

    MetricsDashboard->>DeploymentUsageTable: render(refetchRef=deploymentRefetchRef)
    DeploymentUsageTable->>useDeploymentUsage: invoke hook
    useDeploymentUsage-->>DeploymentUsageTable: { data, loading, error, refetch }
    DeploymentUsageTable->>DeploymentUsageTable: useEffect — deploymentRefetchRef.current = refetch
    Note over DeploymentUsageTable: cleanup sets current = null on unmount

    User->>MetricsDashboard: click global Refresh button
    MetricsDashboard->>MetricsDashboard: handleRefresh()
    MetricsDashboard->>MetricsDashboard: refetchOverview / refetchChart / refetchActivity / refetchSubscription
    MetricsDashboard->>DeploymentUsageTable: deploymentRefetchRef.current?.()
    DeploymentUsageTable->>useDeploymentUsage: refetch()
    useDeploymentUsage-->>DeploymentUsageTable: fresh data
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: frontend/src/components/metrics-dashboard/LLMUsageTable.jsx
Line: 13

Comment:
**Unused `Tag` import**

The `Tag` component is imported but is no longer used anywhere in this file. The Executions column was refactored from `<Tag color="success">` / `<Tag color="error">` to plain `<span>` elements with CSS classes (`.execution-success`, `.execution-error`), leaving this import as dead code.

```suggestion
  Table,
  Tabs,
  Tooltip,
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (8): Last reviewed commit: "UN-3380 [FIX] Fix biome: CSS selector fo..." | Re-trigger Greptile

athul-rs and others added 2 commits April 5, 2026 23:04
- Add cleanup function to refetchRef useEffect to prevent stale closures
- Narrow refetchRef PropTypes from object to shape({ current: func })

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@vishnuszipstack vishnuszipstack left a comment

Choose a reason for hiding this comment

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

@athul-rs why using - ve values in margin?

athul-rs and others added 2 commits April 6, 2026 12:41
…nd-layout

Follows the same pattern as API Deployments and other pages where
the entire content area (topbar, tabs, tab content) sits inside a
white container box.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/metrics-dashboard/MetricsDashboard.css`:
- Line 4: Update the dashboard wrapper paddings from 12px to 14px to match the
new horizontal gutter used by the topbar/tabs: find the two occurrences
currently using "padding: 12px" (the top wrapper near the file start and the
other occurrence around the end of the file) and change them to "padding: 14px"
so left/right alignment across dashboard wrappers is consistent.
- Around line 55-57: The current CSS uses descendant selectors that match any
.ant-tabs inside .metrics-dashboard (including nested DeploymentUsageTable
tabs); update the selectors so they only target the top-level dashboard tabs by
using direct child combinators: change rules that reference .metrics-dashboard
.ant-tabs and .ant-tabs-nav to use .metrics-dashboard > .ant-tabs >
.ant-tabs-nav (and the analogous selector for the other rule at lines 60–62),
keeping the same declarations but narrowing the selector to the top-level
.ant-tabs only.
🪄 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: CHILL

Plan: Pro

Run ID: 9e8f54b3-f6ad-4a51-b3c3-52ac62b6ea00

📥 Commits

Reviewing files that changed from the base of the PR and between b428a46 and 26868cd.

📒 Files selected for processing (1)
  • frontend/src/components/metrics-dashboard/MetricsDashboard.css

- Tokens: show as 12.6M/4.6K with full value on hover
- Executions: inline compact display instead of spilling Tag components
- Tabs nav alignment with dashboard header padding

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
frontend/src/components/metrics-dashboard/LLMUsageTable.jsx (2)

31-32: Consider nullish coalescing for clearer intent.

SonarCloud flags value || 0 as non-idiomatic. Since the goal is to handle null/undefined from API responses while preserving actual 0 values correctly, ?? is more precise than || (which would also coerce NaN or false, though unlikely here).

♻️ Suggested fix
 function formatCompactNumber(value) {
-  const num = value || 0;
+  const num = value ?? 0;
   if (num >= 1_000_000_000) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/metrics-dashboard/LLMUsageTable.jsx` around lines 31
- 32, The helper function formatCompactNumber uses `value || 0`, which
incorrectly treats falsy but valid zeros; change the fallback to the nullish
coalescing operator so it only replaces null/undefined: update the assignment in
formatCompactNumber (const num = value || 0) to use `??` (const num = value ??
0) so real 0 values are preserved while still defaulting when the API returns
null/undefined.

149-159: Ref-based refetch pattern is functional but consider useImperativeHandle for stricter typing.

The implementation correctly exposes the refetch function to the parent via ref assignment. The cleanup on unmount prevents stale calls. This works well.

For a more idiomatic React approach, useImperativeHandle with forwardRef is the canonical pattern for exposing imperative methods to parents, but the current approach is simpler and avoids the forwardRef complexity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/metrics-dashboard/LLMUsageTable.jsx` around lines 149
- 159, The current pattern assigns refetch onto refetchRef inside useEffect
(useEffect, refetchRef, refetch) which works but is not the idiomatic React way;
refactor LLMUsageTable to use forwardRef and useImperativeHandle to expose a
typed imperative API (e.g., expose a ref object with a refetch() method) instead
of direct ref assignment, implement forwardRef around the component, call
useImperativeHandle(ref, () => ({ refetch }), [refetch]) and remove the manual
cleanup logic in the existing useEffect so the parent receives a stricter,
well-typed handle.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/components/metrics-dashboard/LLMUsageTable.jsx`:
- Around line 31-32: The helper function formatCompactNumber uses `value || 0`,
which incorrectly treats falsy but valid zeros; change the fallback to the
nullish coalescing operator so it only replaces null/undefined: update the
assignment in formatCompactNumber (const num = value || 0) to use `??` (const
num = value ?? 0) so real 0 values are preserved while still defaulting when the
API returns null/undefined.
- Around line 149-159: The current pattern assigns refetch onto refetchRef
inside useEffect (useEffect, refetchRef, refetch) which works but is not the
idiomatic React way; refactor LLMUsageTable to use forwardRef and
useImperativeHandle to expose a typed imperative API (e.g., expose a ref object
with a refetch() method) instead of direct ref assignment, implement forwardRef
around the component, call useImperativeHandle(ref, () => ({ refetch }),
[refetch]) and remove the manual cleanup logic in the existing useEffect so the
parent receives a stricter, well-typed handle.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9166b772-d995-4dcc-a61a-ace2a63a445d

📥 Commits

Reviewing files that changed from the base of the PR and between 26868cd and 6b7d9ea.

📒 Files selected for processing (2)
  • frontend/src/components/metrics-dashboard/LLMUsageTable.jsx
  • frontend/src/components/metrics-dashboard/MetricsDashboard.css
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/metrics-dashboard/MetricsDashboard.css

athul-rs and others added 3 commits April 6, 2026 14:01
Use direct child selectors on .metrics-dashboard-container to prevent
padding from leaking into the nested deployment-type-tabs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 6, 2026

@athul-rs athul-rs merged commit 28a206b into main Apr 6, 2026
8 checks passed
@athul-rs athul-rs deleted the UN-3380 branch April 6, 2026 09:20
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.

3 participants