Skip to content

Home dashboard UI polish#7902

Merged
eastandwestwind merged 5 commits intoENG-3353from
karolis-ui-polish
Apr 13, 2026
Merged

Home dashboard UI polish#7902
eastandwestwind merged 5 commits intoENG-3353from
karolis-ui-polish

Conversation

@kruulik
Copy link
Copy Markdown
Contributor

@kruulik kruulik commented Apr 13, 2026

Ticket ENG-3353

Description Of Changes

Polish pass on the new home dashboard: PostureCard, TrendCard, PriorityActionsCard, and shared chart primitives.

image image Screenshot 2026-04-13 at 2 34 45 AM

Code Changes

  • PostureCard: mono-font score, band tag, clickable alert opening posture drawer
  • PostureBreakdownContent: GPS explanation, per-dimension progress bars, clickable rows
  • TrendCard: x-axis date labels, per-point tooltips; DSR volume switched to bar chart; help tooltip on title
  • PriorityActionsCard: flat list (no tabs), Status/Severity filter dropdowns, clickable rows
  • RadarChart: label z-order fix, cursor tooltip anchored to mouse, score/band tag in labels, text stroke outline
  • Sparkline/BarChart: x-axis labels with interior tick spacing, hover tooltips
  • SystemCoverageCard / DSRStatusCard: help tooltips on card titles
  • HomeDashboard: dashed "Last 30 days" divider, ThemeModeToggle, activity/astralis/agent feature flags
  • Removed CommandBar

Steps to Confirm

  1. Open the home dashboard
  2. Hover over radar chart labels — tooltip should appear anchored to cursor and dismiss cleanly on leave
  3. Hover over trend chart points — tooltips should show values with labels
  4. Use Status/Severity filters on Priority Actions list
  5. Click PostureCard alert — drawer should open to breakdown view

Pre-Merge Checklist

  • Issue requirements met
  • All CI pipelines succeeded
  • CHANGELOG.md updated
  • UX feedback:
    • All UX related changes have been reviewed by a designer
  • Followup issues:
    • No followup issues
  • Database migrations:
    • No migrations
  • Documentation:
    • No documentation updates required

kruulik and others added 3 commits April 13, 2026 01:45
…chart improvements

- PostureCard: mono-font score, band tag, clickable alert wrapper opening posture drawer
- PostureBreakdownContent: GPS explanation, per-dimension progress bars, clickable rows with Launch icon
- DashboardDrawer: dark theme fix via explicit token.colorBgContainer on styles prop
- TrendCard: x-axis date labels, per-point tooltips; DSR volume switched to bar chart; Help icon tooltip on titles
- PriorityActionsCard: flat list (removed tabs), Status/Severity filter dropdowns, clickable rows
- RadarChart: label z-order fix (zIndex=2100), animated cursor tooltip anchored to mouse, score/band tag in labels, text outline (stroke + opacity)
- Sparkline/BarChart: x-axis labels with even interior tick spacing, hover tooltips
- HomeDashboard: dashed "Last 30 days" divider, ThemeModeToggle icon button, activity/astralis/agent feature flags
- SystemCoverageCard/DSRStatusCard: Help icon tooltips on card titles
- Remove CommandBar (deleted files + flag)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
fides-plus-nightly Ready Ready Preview, Comment Apr 13, 2026 3:15pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
fides-privacy-center Ignored Ignored Apr 13, 2026 3:15pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 13, 2026

Dependency Review

The following issues were found:
  • ✅ 0 vulnerable package(s)
See the Details below.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA dc3459e.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

  • .github/workflows/cli_checks.yml
  • .github/workflows/frontend_checks.yml
  • .github/workflows/static_checks.yml
  • .github/workflows/trigger_fidesplus_slack_notifier.yml
  • clients/admin-ui/package.json
  • clients/package-lock.json
  • pyproject.toml
  • uv.lock

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 13, 2026

Title Lines Statements Branches Functions
admin-ui Coverage: 7%
5.86% (2547/43393) 4.88% (1203/24617) 3.94% (508/12861)
fides-js Coverage: 78%
78.98% (1962/2484) 65.55% (1214/1852) 72.57% (336/463)
privacy-center Coverage: 88%
85.93% (330/384) 81.1% (176/217) 78.87% (56/71)

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (ENG-3353@5a376bf). Learn more about missing BASE report.

Additional details and impacted files
@@             Coverage Diff             @@
##             ENG-3353    #7902   +/-   ##
===========================================
  Coverage            ?   85.07%           
===========================================
  Files               ?      627           
  Lines               ?    40794           
  Branches            ?     4742           
===========================================
  Hits                ?    34707           
  Misses              ?     5018           
  Partials            ?     1069           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@kruulik kruulik changed the base branch from ENG-3353 to main April 13, 2026 06:22
@kruulik kruulik changed the base branch from main to ENG-3353 April 13, 2026 06:23
@kruulik kruulik requested a review from eastandwestwind April 13, 2026 06:32
@kruulik kruulik marked this pull request as ready for review April 13, 2026 06:32
@kruulik kruulik requested a review from a team as a code owner April 13, 2026 06:32
@kruulik kruulik requested review from gilluminate and removed request for a team and gilluminate April 13, 2026 06:32
@kruulik kruulik marked this pull request as draft April 13, 2026 06:32
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Code Review: Home Dashboard UI Polish

This is a solid UI polish pass — the shift from tabs to inline filters in PriorityActionsCard, the new score card layout, radar chart tag overlays, sparkline/bar chart tooltips with x-axis labels, and the card-level help tooltips all represent clear improvements. The CSS specificity doubles (.quickActionButton.quickActionButton) to replace !important is a clean technique. The overdue-date normalization in constants.ts is a good correctness fix.

Issues found

Medium — Non-null assertions on tooltipContent prop (BarChart.tsx, Sparkline.tsx)
Both chart components use tooltipContent!(value, label) inside a useCallback. The call site is safe today, but the ! hides the invariant from the type system and will throw at runtime if the callback ever fires unexpectedly. See inline comments for suggested alternatives.

Minor — Internal fidesui/src/ path import (PostureCard.tsx)
Importing directly from fidesui/src/palette/palette.module.scss bypasses the package's public API surface and is fragile against internal refactors or build changes. See inline comment.

Minor — bandColorMap/getBandColor not memoized (PostureBreakdownContent.tsx)
Both are recreated on every render. Wrapping with useMemo/useCallback is straightforward here. See inline comment.

Minor — zIndex={2100} on PolarAngleAxis is a no-op (RadarChart.tsx)
Recharts doesn't honour a zIndex prop on SVG elements — DOM paint order is the correct lever. See inline comment.

Observation — Mixed-timezone arithmetic in due-date normalization (constants.ts)
The fix is correct for its purpose; a short comment explaining the UTC-parse / local-mutate behaviour would help future readers. See inline comment.


🔬 Codegraph: connected (46300 nodes)


💡 Write /code-review in a comment to re-run this review.

fontSize: token.fontSizeSM,
}}
>
{tooltipContent!(entry.value, entry.label)}
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.

clients/fidesui/src/components/charts/BarChart.tsx:129

Non-null assertion tooltipContent! is used here, but the outer condition (showTooltip || tooltipContent) doesn't guarantee tooltipContent is defined when renderTooltipContent is called via content={tooltipContent ? renderTooltipContent : undefined}. The logic is actually safe in practice (the content prop is only set when tooltipContent is truthy), but the assertion is fragile and hides the intent.

Consider a guard instead:

{tooltipContent(entry.value, entry.label)}

Since renderTooltipContent is only ever set as the content prop when tooltipContent is defined, you can simply call it directly (no !) and TypeScript will be happy after narrowing the closure capture — or restructure the useCallback so tooltipContent is required in its type signature.

top: strokeWidth,
right: 20,
right: 0,
bottom: bottomMargin,
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.

clients/fidesui/src/components/charts/Sparkline.tsx:133

Same non-null assertion pattern as in BarChart.tsxtooltipContent!(entry.value, label). The callback is only registered when tooltipContent is defined (!empty && tooltipContent && <Tooltip ...>), so it's safe, but the ! makes the type contract invisible to readers and linters.

Consider either:

  1. Narrowing the type: move the tooltipContent check into a helper that returns NonNullable<typeof tooltipContent>.
  2. Simply using tooltipContent?.(entry.value, label) (optional call) so the worst case is undefined rendered as nothing rather than a runtime throw.

Tooltip,
useThemeMode,
} from "fidesui";
import palette from "fidesui/src/palette/palette.module.scss";
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.

clients/admin-ui/src/home/PostureCard.tsx:14

import palette from "fidesui/src/palette/palette.module.scss";

This reaches into fidesui's internal src/ tree rather than going through the package's public API. It will break if fidesui's internal directory structure changes, if the package starts bundling differently, or when used in an environment that resolves fidesui from a compiled artifact rather than source.

If the palette tokens need to be consumed externally, the cleaner path is to export them from fidesui's index (e.g., import { palette } from "fidesui") or convert the values to CSS custom properties that can be read at runtime from the token instead.

Comment thread clients/admin-ui/src/home/PostureBreakdownContent.tsx
{!empty && (
<PolarAngleAxis
dataKey="subject"
zIndex={2100}
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.

clients/fidesui/src/components/charts/RadarChart.tsx:350

zIndex={2100} is not a valid prop for Recharts' PolarAngleAxis. Recharts SVG elements don't honour a zIndex prop — SVG layering is determined by DOM order, not CSS z-index. This prop will be silently ignored (or generate an "unknown DOM attribute" React warning in dev mode).

If the goal is to ensure tick labels render above the radar fill/grid, the correct approach is to move the PolarAngleAxis element later in the JSX tree so it's painted last by SVG's painter's algorithm.

Copy link
Copy Markdown
Contributor

@eastandwestwind eastandwestwind left a comment

Choose a reason for hiding this comment

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

This is overall looking very polished! Much better than what I had.

I like the new priority actions status + severity filter, and how you've styled the timeline charts.

3 small things I'd like to see, but let me know what is feasible so we can merge by EOD today:

  1. Governance posture score card - I'd like to see a CTA like "View Details ->" as it's not obvious that section is clickable. Instead of the entire "Up 3.8 points this week, driven by Casey completing 34 classification reviews across Snowflake and BigQuery.", I think we can truncate to "Up 3.8 points this week." with a small green up or red down arrow in front of it to indicate the trend.
Image
  1. The date text on the DSR volume graph are overlapping, so let's check this.
Image
  1. Dark mode causes the highlighted dropdown filter text to be illegible:
Screenshot 2026-04-13 at 2 47 54 PM

@eastandwestwind eastandwestwind merged commit 959b336 into ENG-3353 Apr 13, 2026
48 of 51 checks passed
@eastandwestwind eastandwestwind deleted the karolis-ui-polish branch April 13, 2026 16:04
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Code Review — Home Dashboard UI Polish

Overall this is a well-structured polish pass. The feature-flag gating of alpha cards, the migration from tabs to inline filter dropdowns, the radar chart label z-ordering fix, and the tooltip-on-chart-title pattern are all solid. A few items worth addressing before merge:

Issues found

Medium

  • PostureCard.tsx:14 — Direct import from fidesui/src/palette/palette.module.scss bypasses the package's public API. This is fragile; prefer re-exporting the tokens from fidesui's public index or using Ant Design CSS variables already on the token object.

Low / Nit

  • PostureCard.tsx clickable divaria-label="View posture breakdown" was removed from the role="button" div. Screen-reader users now land on an unlabeled interactive control. Should be restored.
  • BarChart.tsx / Sparkline.tsx — Both renderTooltipContent callbacks use the non-null assertion tooltipContent!. The invariant is upheld by the surrounding conditional, but optional chaining (tooltipContent?.(...)) is safer and signals intent more clearly.
  • constants.ts getUrgencyGroupsetHours(23,59,59,999) normalises to the local browser timezone, while new Date("YYYY-MM-DD") is parsed as UTC midnight. The fix improves things for timezones east of UTC but may still be off for users west of UTC. A pure string comparison (dueDate < new Date().toISOString().slice(0,10)) is unambiguous if sub-day precision isn't needed.
  • PostureBreakdownContent.tsxbandColorMap is an object literal created unconditionally on every render; a useMemo depending on token would be more consistent.
  • RadarChart.tsx tooltip width: 140 — Fixed width can clip longer dimension descriptions. maxWidth: 200 would be more flexible.

Informational

  • AgentBriefingBanner.tsxfixPluralGrammar was a client-side workaround for server-generated text ("1 privacy requests are overdue"). Confirm the server now handles this correctly before merging, so the regression isn't invisible.

Positive highlights

  • The .quickActionButton.quickActionButton CSS specificity bump to avoid !important is the right approach.
  • Moving x-axis tick rendering to a custom renderXAxisTick callback (Sparkline) and renderSimpleTick (BarChart) with proper idx-based addressing is a clean fix for the earlier label-offset bug.
  • aspect-ratio: 1 on .radarChartWrapper is a good constraint to prevent the radar from distorting at extreme card heights.
  • Feature-flag gating of ActivityFeedCard, AstralisPanel, and AgentBriefingBanner with proper column-width fallback when only one panel is enabled is well-handled.

🔬 Codegraph: connected (46300 nodes)


💡 Write /code-review in a comment to re-run this review.

Tooltip,
useThemeMode,
} from "fidesui";
import palette from "fidesui/src/palette/palette.module.scss";
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.

clients/admin-ui/src/home/PostureCard.tsx:14

Direct import from fidesui/src/... reaches into the package's internal source tree, bypassing its public API:

import palette from "fidesui/src/palette/palette.module.scss";

If fidesui ever restructures its internals (path rename, file split, build output change) this will break silently. Consider re-exporting the specific palette tokens you need from fidesui's public index, or using the CSS custom properties (var(--...)) already exposed on palette.FIDESUI_BG_MINOS / palette.FIDESUI_MINOS via the theme tokens instead.

borderRadius: token.borderRadius,
padding: `${token.paddingXXS}px ${token.paddingXS}px`,
boxShadow: token.boxShadow,
fontSize: token.fontSizeSM,
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.

clients/fidesui/src/components/charts/BarChart.tsx:126

The non-null assertion tooltipContent! here is safe in practice (the outer (showTooltip || tooltipContent) && guard prevents this callback from being registered without a value), but the assertion is invisible to readers and will panic if the invariant is ever broken. Prefer an explicit guard or optional call:

{tooltipContent?.(entry.value, entry.label)}

Same pattern in Sparkline.tsx (the renderTooltipContent callback there also uses tooltipContent!).

<Icons.Help size={14} className="opacity-30" />
</Flex>
</Tooltip>
}
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.

clients/admin-ui/src/home/PostureCard.tsx:116

The aria-label that was previously on this role="button" div (aria-label="View posture breakdown") was removed in this PR. Screen-reader users navigating by button now land on an unnamed control. Add it back:

<div
  role="button"
  tabIndex={0}
  aria-label="View posture breakdown"
  className={styles.clickableAlert}
  ...
>

// Past due date → Overdue, regardless of severity
if (dueDate && new Date(dueDate) < new Date()) {
return "overdue";
// Normalize to end-of-day to avoid timezone boundary issues with date-only strings
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.

clients/admin-ui/src/features/dashboard/constants.ts:156

setHours(23, 59, 59, 999) normalises to local browser timezone end-of-day, while new Date("2026-04-13") (a date-only ISO string) is parsed as UTC midnight. This fixes the most common off-by-one in timezones east of UTC, but a user in UTC+2 whose local midnight is 22:00 UTC would still see "overdue" an hour early.

If dueDate is always a date-only string (YYYY-MM-DD) with no intent for sub-day precision, a purely string-based comparison (dueDate < today) avoids all timezone ambiguity and is simpler:

if (dueDate) {
  const today = new Date().toISOString().slice(0, 10); // "YYYY-MM-DD" in UTC
  if (dueDate < today) return "overdue";
}

If local-timezone semantics are intentional, the current approach is acceptable — just worth a comment clarifying why setHours is used vs. a UTC comparison.


const { briefing: rawText, quick_actions: quickActions } = briefing;
const text = fixPluralGrammar(rawText);
const text = rawText;
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.

clients/admin-ui/src/home/AgentBriefingBanner.tsx:53

fixPluralGrammar was a client-side workaround for server-generated text that said "1 privacy requests are overdue". Removing it is fine if the server now generates grammatically correct text, but if it doesn't this will regress visible grammar errors. Worth a quick sanity-check with a real briefing payload containing a count of 1 before merging.

const bandColorMap: Record<string, string> = {
success: token.colorSuccess,
caution: token.colorWarning,
error: token.colorError,
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.

clients/admin-ui/src/home/PostureBreakdownContent.tsx:37

bandColorMap is a plain object literal created inside the component body — it re-allocates on every render. It only depends on token values (which are stable between renders unless the theme changes), so either:

  • Wrap it in useMemo(() => ({ ... }), [token]), or
  • Move getBandColor outside the component and accept token as a parameter.

Low impact for a drawer-level component, but worth keeping consistent with the memoization pattern used elsewhere in this file.

@@ -331,6 +375,7 @@ export const RadarChart = ({
transform: "translate(-50%, -100%) translateY(-8px)",
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.

clients/fidesui/src/components/charts/RadarChart.tsx:375

The tooltip container is given a fixed width: 140. Descriptions like "Percentage of systems with at least one data classification applied" (from DIMENSION_DESCRIPTIONS) can easily overflow or wrap awkwardly at 140 px. Consider using maxWidth instead (e.g., maxWidth: 200) so short tooltips stay compact while longer ones can expand.

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