Skip to content

Dashboard: design-token system, typography refresh, UX polish & axe accessibility tests - #18943

Merged
David Pine (IEvangelist) merged 5 commits into
mainfrom
dapine/dashboard-css-tokens
Aug 4, 2026
Merged

Dashboard: design-token system, typography refresh, UX polish & axe accessibility tests#18943
David Pine (IEvangelist) merged 5 commits into
mainfrom
dapine/dashboard-css-tokens

Conversation

@IEvangelist

Copy link
Copy Markdown
Member

Description

The Aspire Dashboard's visual styling had grown ad-hoc — colors, spacing, radii, and font sizes were hardcoded and scattered throughout app.css, which made even small design tweaks slow, risky, and inconsistent across light/dark themes. This PR introduces a design-token layer so the dashboard's look-and-feel can be tuned from one place, refreshes typography, applies a broad UX / information-architecture polish pass, and adds an automated accessibility (axe-core) test suite that guards the result.

This is a Dashboard-only change (Blazor components, CSS, JS, localized strings, and tests). There are no public API changes.

Fixes # (issue)

What changed for users

  • Design tokens & theming — a new wwwroot/css/tokens.css defines the spacing, color, radius, and typography primitives; app.css now consumes them. Incremental design changes become fast and consistent across both themes.
  • Typography refresh — self-hosted Geist (UI text), Poppins (headings / dialog titles), and Geist Mono (code) fonts, with their upstream LICENSE.txt files included.
  • Header & navigation — a full-width brand lockup, a collapsible left nav rail (collapsed/expanded state persisted) with left-aligned logo and titles when collapsed, and a left-aligned page title that lines up with the left edge of the content panel below it. The nav item for structured logs now reads "Structured logs" (reusing the existing page-title string).
  • Toolbars — consistent spacing/padding between controls, icon-only buttons with proper borders and a uniform 32px control height, and responsive toolbars that stack and left-align on tablet/mobile widths instead of wrapping while right-aligned.
  • Contrast & readability — removed text-input underlines, darkened the light-theme code-block background (previously read as lavender / too close to the dialog background) for clearer contrast, and dark-theme primary buttons now use a light-purple background with dark text (light theme unchanged).

Accessibility

A new tests/Aspire.Dashboard.Tests/Integration/Playwright/AccessibilityTests.cs runs axe-core (via Deque.AxeCore.Playwright) against the dashboard and fails on any serious/critical WCAG 2.x A/AA violation:

  • 5 core pages × light/dark
  • Home page across mobile / tablet / desktop viewports
  • Code-block syntax-color contrast (WCAG AA)
  • Dialogs & flyouts — Settings flyout + structured-logs Add-filter dialog × light/dark (these live behind a click, so resting-page scans never reached them)

The suite surfaced, and this PR fixes, real issues it found: message-bar contrast, light-theme code-block contrast, and a missing accessible name on the Settings language selector (aria-input-field-name, WCAG 4.1.2) — Fluent's Label renders a standalone <label> it never associates with the combobox, so an explicit aria-label (reusing the existing localized string) was added. Full suite: 19/19 passing locally. These are [OuterloopTest] Playwright tests that run off the regular CI loop.

Implementation notes

  • wwwroot/js/app.js / app-theme.js handle the nav-collapse toggle and persistence (BrowserStorageKeys) plus theme wiring; the collapsed state is stored in localStorage (UI preference only — no server or network behavior changes).
  • New localized strings in the ControlsStrings and Layout resources, with .xlf synced across all 13 locales via UpdateXlf.
  • Directory.Packages.props adds the Deque.AxeCore.Playwright package version consumed by the test project.

Screenshots / Recordings

This PR includes UI changes. Please add screenshots or screen recordings so reviewers can evaluate the visual changes without running locally.

  • For before/after comparisons, place them side-by-side or label them clearly.
  • For interactive changes (animations, transitions, new flows), prefer a short screen recording (GIF or video).
  • If you cannot capture visuals now, note what scenario to test and mark this section as TODO.

Validation

  • Dashboard + Aspire.Dashboard.Tests build clean (0 warnings / 0 errors).
  • AccessibilityTests full class: 19/19 pass.
  • Manually verified live against the Stress playground dashboard in light and dark themes across desktop/tablet/mobile widths.

Follow-ups (tracked, not blocking)

A few incremental polish items remain and may land as follow-up changes: additional spacing on the top-right header icons, final chrome padding/boxing, and micro-alignment of the page-title left edge.

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

Copilot AI balanced review requested due to automatic review settings July 30, 2026 20:03
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18943

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18943"

@github-actions

This comment has been minimized.

Copilot AI 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.

🟡 Not ready to approve

Accessibility regressions, existing test failures, and premature axe scans must be addressed.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

Introduces a centralized Dashboard design system, refreshes navigation and typography, polishes interactions, and adds automated accessibility coverage.

Changes:

  • Adds design tokens, self-hosted fonts, theme updates, and responsive UI styling.
  • Adds collapsible navigation, grid/scroll enhancements, and accessibility fixes.
  • Adds axe-core Playwright tests and localized accessibility labels.
File summaries
File Description
Directory.Packages.props Adds axe-core package version.
tests/Aspire.Dashboard.Tests/Aspire.Dashboard.Tests.csproj References axe-core Playwright.
tests/Aspire.Dashboard.Tests/Integration/Playwright/AccessibilityTests.cs Adds accessibility scans.
src/Aspire.Dashboard/wwwroot/css/tokens.css Defines design tokens and fonts.
src/Aspire.Dashboard/wwwroot/css/app.css Applies broad visual and UX changes.
src/Aspire.Dashboard/wwwroot/css/markdown.css Uses the mono font token.
src/Aspire.Dashboard/wwwroot/js/app.js Adds grid, scroll, and hover interactions.
src/Aspire.Dashboard/wwwroot/js/app-theme.js Connects tokens to Fluent theming.
src/Aspire.Dashboard/wwwroot/fonts/geist/LICENSE.txt Adds Geist license.
src/Aspire.Dashboard/wwwroot/fonts/geist/Geist-Variable.woff2 Adds Geist variable font.
src/Aspire.Dashboard/wwwroot/fonts/geist/GeistMono-Variable.woff2 Adds Geist Mono font.
src/Aspire.Dashboard/wwwroot/fonts/poppins/LICENSE.txt Adds Poppins license.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-500-normal.woff2 Adds Poppins Latin 500.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-600-normal.woff2 Adds Poppins Latin 600.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-700-normal.woff2 Adds Poppins Latin 700.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-ext-500-normal.woff2 Adds extended Latin 500.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-ext-600-normal.woff2 Adds extended Latin 600.
src/Aspire.Dashboard/wwwroot/fonts/poppins/latin-ext-700-normal.woff2 Adds extended Latin 700.
src/Aspire.Dashboard/Utils/DashboardUIHelpers.cs Defines the page-title section key.
src/Aspire.Dashboard/Utils/BrowserStorageKeys.cs Adds persisted navigation state key.
src/Aspire.Dashboard/Components/App.razor Loads tokens and preloads fonts.
src/Aspire.Dashboard/Components/_Imports.razor Imports Blazor sections.
src/Aspire.Dashboard/Components/Layout/MainLayout.razor Adds full-width header and nav toggle.
src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs Persists navigation expansion state.
src/Aspire.Dashboard/Components/Layout/MainLayout.razor.css Restyles desktop layout and rail.
src/Aspire.Dashboard/Components/Layout/DesktopNavMenu.razor Renames structured-logs navigation.
src/Aspire.Dashboard/Components/Layout/MobileNavMenu.razor.cs Updates the mobile navigation label.
src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor Moves page titles into the header.
src/Aspire.Dashboard/Components/Layout/AspirePageContentLayout.razor.cs Adds toolbar hiding support.
src/Aspire.Dashboard/Components/Pages/Resources.razor Combines tabs and desktop filters.
src/Aspire.Dashboard/Components/Pages/Resources.razor.css Styles the combined toolbar row.
src/Aspire.Dashboard/Components/ResourcesGridColumns/ResourceNameDisplay.razor Enlarges resource icons.
src/Aspire.Dashboard/Components/Controls/ResourceActions.razor Aligns action-button slots.
src/Aspire.Dashboard/Components/Controls/ResourceActions.razor.css Styles fixed-width action slots.
src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor Changes menu ARIA metadata.
src/Aspire.Dashboard/Components/Controls/TextVisualizer.razor Names and focuses its scroll region.
src/Aspire.Dashboard/Components/Controls/TextVisualizer.razor.cs Injects localized control strings.
src/Aspire.Dashboard/Components/Controls/SummaryDetailsView.razor.css Retints detail headers.
src/Aspire.Dashboard/Components/Dialogs/SettingsDialog.razor Names the language selector.
src/Aspire.Dashboard/Components/Dialogs/TextVisualizerDialog.razor Promotes the copy action.
src/Aspire.Dashboard/Components/Dialogs/FilterDialog.razor Uses accent styling for Apply.
src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor Changes secret-toggle focus behavior.
src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor.cs Suppresses native reveal controls.
src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor.js Injects password-control styling.
src/Aspire.Dashboard/Resources/Layout.resx Adds navigation-toggle strings.
src/Aspire.Dashboard/Resources/Layout.Designer.cs Exposes generated layout strings.
src/Aspire.Dashboard/Resources/ControlsStrings.resx Adds the text-region label.
src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs Exposes the generated label.
src/Aspire.Dashboard/Resources/xlf/Layout.cs.xlf Syncs Czech layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.de.xlf Syncs German layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.es.xlf Syncs Spanish layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.fr.xlf Syncs French layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.it.xlf Syncs Italian layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.ja.xlf Syncs Japanese layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.ko.xlf Syncs Korean layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.pl.xlf Syncs Polish layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.pt-BR.xlf Syncs Portuguese layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.ru.xlf Syncs Russian layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.tr.xlf Syncs Turkish layout resources.
src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hans.xlf Syncs simplified Chinese resources.
src/Aspire.Dashboard/Resources/xlf/Layout.zh-Hant.xlf Syncs traditional Chinese resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.cs.xlf Syncs Czech control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.de.xlf Syncs German control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.es.xlf Syncs Spanish control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.fr.xlf Syncs French control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.it.xlf Syncs Italian control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ja.xlf Syncs Japanese control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ko.xlf Syncs Korean control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pl.xlf Syncs Polish control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.pt-BR.xlf Syncs Portuguese control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.ru.xlf Syncs Russian control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.tr.xlf Syncs Turkish control resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hans.xlf Syncs simplified Chinese resources.
src/Aspire.Dashboard/Resources/xlf/ControlsStrings.zh-Hant.xlf Syncs traditional Chinese resources.
Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file
  • Files reviewed: 64/74 changed files
  • Comments generated: 7
  • Review effort level: Medium

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

Comment thread src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor Outdated
Comment thread src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs
Comment thread src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor Outdated
Comment thread src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor.cs Outdated
Comment thread src/Aspire.Dashboard/wwwroot/js/app.js Outdated
Comment thread src/Aspire.Dashboard/wwwroot/css/app.css Outdated
@IEvangelist

Copy link
Copy Markdown
Member Author

PR Testing Report — #18943

PR Information

Artifact / Version Verification

  • Approach: source-based. The PR's headline deliverable — the new axe-core Playwright AccessibilityTests — ships only in the test project, not in the CLI, and the "Dogfood this PR" CLI artifacts weren't built yet (CI still pending). So testing was done from an isolated git worktree checked out at the exact PR head rather than via the dogfood CLI.
  • Installed version: N/A — source checkout at head commit 4a5a134.
  • Status: ✅ Verified (worktree HEAD == 4a5a134).

Changes Analyzed

Dashboard-only change (74 files, +3292/-176). No public API changes.

  • CLI changes
  • Hosting integration changes
  • Dashboard changestokens.css (new), app.css refresh (+1142/-51), self-hosted Geist/Poppins/Geist Mono fonts, collapsible nav rail + persistence (app.js +415, app-theme.js +103, MainLayout), responsive toolbars, Resources/ResourceActions polish, Settings language-selector aria-label fix, new Layout/ControlsStrings strings + 13-locale .xlf.
  • CI infrastructure changes
  • VS Code extension changes
  • Test changes — new AccessibilityTests.cs (+422); Directory.Packages.props adds Deque.AxeCore.Playwright.

Test Scenarios Executed

Scenario 1 — Build validation

Objective: Confirm the PR's "Dashboard + Aspire.Dashboard.Tests build clean (0 warnings / 0 errors)" claim.
Coverage: Happy path • Status: ✅ Passed

  • restore.cmd → Build succeeded, 0 warnings / 0 errors.
  • dotnet build tests/Aspire.Dashboard.TestsBuild succeeded, 0 Warning(s), 0 Error(s). Chromium auto-installed to artifacts/bin/playwright-deps (Windows-local default).

Scenario 2 — Accessibility suite (headline)

Objective: Verify the PR's "19/19 passing" claim for the new AccessibilityTests.
Coverage: Happy path + regression guard • Status: ⚠️ Flaky — issue found

The suite is 19 cases: 10 (5 pages × light/dark) + 3 (home @ mobile/tablet/desktop) + 4 (Settings/Filter dialogs × light/dark) + 2 (codeblock contrast). All are [OuterloopTest] + [RequiresFeature(Playwright)], run with outerloop included.

Run (fresh process) Result
1 18/19DashboardPage_HasNoSeriousOrCriticalWcagViolations("/", "Light") failed
2 ✅ 19/19
3 ✅ 19/19
4 ✅ 19/19

The one failure (2 serious/critical violations on / Light, 1280×900):

[serious] aria-progressbar-name: ARIA progressbar nodes must have an accessible name
  target: #f5125575
  html:   <fluent-progress-ring ... role="progressbar">  (loading spinner, no aria-label/labelledby/title)

[critical] button-name: Buttons must have discernible text
  target: [["#f7eb1cd5e", ".clear-button"]]
  html:   <button part="clear-button" tabindex="-1" class="clear-button clear-button__hidden">

Why this is flaky, not a real page regression: the separate DashboardHomePage_IsAccessibleAcrossViewports("Desktop", 1280, 900) case scans the identical URL/theme/viewport and passed in the same run, and 3 subsequent full-class reruns were all 19/19. Both flagged nodes are transient: a fluent-progress-ring shown while the resource grid is still loading, and a search field's .clear-button in its clear-button__hidden state.

Root cause: AssertNoBlockingWcagViolationsAsync gates the scan on h1.page-header / main visibility only — it does not wait for the resource grid's async load to finish (loading spinner detached, rows present) before freezing animations and running axe. On the first/cold scan of /, axe samples the still-loading page and catches the spinner + transient clear-button.

Impact: intermittent red in the Outerloop workflow. This is the well-known "readiness check / race condition on startup" flaky pattern.

Suggested fix: before running axe, also wait for grid content to be present and loading spinners (fluent-progress-ring) to detach (e.g., wait for a known resource row / fluent-data-grid rows). A temporary capture test in this run that waited for the seeded frontend row before snapshotting never hit the transient state.

Scenario 3 — Visual evidence capture

Objective: Confirm the design-token / typography / nav / toolbar changes render correctly.
Coverage: Happy path • Status: ✅ Passed

Captured via a temporary Playwright test against the same mock-data dashboard fixture (8 screenshots, light+dark, desktop→mobile). Observations:

  • Header lockup — full-width top header: Aspire logo → app name → left-aligned page title, with a fixed left edge that doesn't shift when the rail collapses/expands. ✅
  • Collapsible nav rail — collapsed = icons only; expanded = icon+label for Resources/Console/Structured logs/Traces/Metrics with a "Collapse sidebar" label on the bottom toggle. The "Structured logs" nav rename is present. ✅
  • Dark theme — header/rail/grid all render with readable contrast. ✅
  • Responsive — at 768/375 the app switches to mobile chrome (hamburger nav, page title below header, stacked left-aligned toolbar, full-width primary "View filters" button). ✅
  • Settings flyout — right-aligned panel; the Language combobox (the control that received the aria-label WCAG 4.1.2 fix) renders; suite's scan of this surface passed light+dark. ✅
  • Structured logs toolbar — consistent spacing, icon-only bordered controls, uniform control height. ✅

Unhappy-Path / Boundary Coverage

Case Result Notes
Nav-collapse persistence ✅ Passed Functional test: default collapsed → expand sets localStorage['Aspire_NavMenu_Expanded']='true' → reload restores expanded → collapse sets 'false' → reload restores collapsed.
Responsive boundaries (tablet 768 / mobile 375) ✅ Passed Mobile chrome engages at ≤768; toolbars stack and left-align; a11y viewport matrix passes.
Settings-flyout a11y guard (aria-input-field-name / WCAG 4.1.2) ✅ Passed Both Settings dialog cases (light+dark) pass — the language-selector fix holds.

Summary

Scenario Status Notes
1 — Build validation ✅ Passed 0 warnings / 0 errors
2 — Accessibility suite ⚠️ Flaky 18/19 on cold run, 19/19 on 3 reruns; readiness race on / first scan
3 — Visual evidence ✅ Passed All design-token/typography/nav/toolbar changes render correctly
Nav-collapse persistence ✅ Passed localStorage round-trips across reload
Responsive boundaries ✅ Passed Mobile/tablet chrome correct
Settings-flyout a11y guard ✅ Passed aria-label fix verified

Overall Result

✅ Verified, with one issue found. The build is clean, the visual/UX changes render correctly across themes and viewports, and nav-collapse persistence works. The one issue is test robustness, not product behavior: the new AccessibilityTests suite is flakyDashboardPage_HasNoSeriousOrCriticalWcagViolations("/", "Light") intermittently scans before the resource grid finishes loading and trips on a transient loading spinner + search clear-button.

Recommendation

Strengthen the readiness gate in AssertNoBlockingWcagViolationsAsync (wait for grid rows present / loading spinner detached) before running axe so the suite is deterministic in the Outerloop workflow. The dashboard's shipped code itself is fine; no product change is required for this finding.

Tested from an isolated worktree at the PR head; screenshots captured locally via a throwaway Playwright test that was not added to the PR.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings July 30, 2026 20:52
@IEvangelist

Copy link
Copy Markdown
Member Author

Thanks for the review — all four findings are addressed in aa4e323, plus a reliability pass on the new a11y tests:

1. (Medium) Functional tests for the 3 net-new JS behaviors — Added DashboardInteractionsTests (tests/Aspire.Dashboard.Tests/Integration/Playwright) with three Playwright/outerloop tests that drive the real interactions and assert their DOM effects, so a markup rename (.resources-name-container, .resize-handle, the depth indent) fails loudly:

  • GridColumn_DoubleClickResizeHandle_AutoFitsColumnWidth — dispatches dblclick on a resize handle and asserts the grid's inline grid-template-columns resolves to an explicit px template.
  • ParentRow_Hover_HighlightsDescendantRows — hovers a parent row (nested fixture resource) and asserts the child row gains/loses parent-hover-descendant.
  • ScrollButtons_ActivateForOverflowingRegion_AndScrollIt — exercises the MutationObserver discovery, 240px activation / 120px edge-visibility thresholds, and click-to-scroll.

2. (Medium) Hardcoded English scroll-button labels — The labels are now localized in .NET (new ControlsStrings.ScrollToTop / ScrollToBottom, xlf synced across all 13 locales) and surfaced to the JS via data-scroll-to-top-label / data-scroll-to-bottom-label on <body> (App.razor). The English literals remain only as a defensive fallback if the attributes are ever absent.

3. (Low) setNeutralBaseColor() tints both themes — Intended. The both-theme tint was tuned and verified live; gating it to dark would regress the light theme. Updated the doc comment to state the both-theme intent (richer in dark, faint brand warmth in light; ~8% saturation still reads as neutral).

4. (Low) Body-wide subtree MutationObserver — Kept subtree: true (targets are deep in Blazor's tree, dialogs append at body level) but the callback now schedules a rescan only when an added/removed node is or contains a scroll target or fluent-dialog. Pure content churn inside an already-registered container (streaming logs) no longer triggers the three document-wide querySelectorAll scans.

Plus — a11y test flakiness: app.js clears before-upgrade as soon as the first web component upgrades, so axe could scan a still-hydrating fluent-select (non-deterministic aria-name results). AccessibilityTests now waits for every custom element in the DOM to finish upgrading and for document.fonts.ready, and settles two animation frames after the animation-freeze, before scanning. Full suite is green (19/19) and the three new interaction tests pass across repeated runs.

@github-actions

This comment has been minimized.

Copilot AI 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.

🟡 Not ready to approve

Accessibility regressions, stale menu-state tests, and dynamic scroll-region update handling must be corrected.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file

Comments suppressed due to low confidence (5)

src/Aspire.Dashboard/Components/Controls/AspireMenuButton.razor:14

  • Removing aria-expanded means the menu button no longer exposes whether its popup is open, so screen-reader users lose the state required by the menu-button pattern. It also guarantees failures in the existing ResourcesTests.ViewOptionsMenu_ReportsExpandedState and AspireMenuButtonFocusTests Playwright tests, which assert the false/true/false transitions. Please forward the state to the actual shadow-DOM button (or otherwise expose it on an element with the button role) and update the tests to target that valid element.
        // opens a menu. We intentionally do NOT set aria-expanded here: aria-expanded is only permitted on
        // a specific set of roles (button, combobox, etc.), and the <fluent-button> host is generic, so
        // axe/Accessibility Insights flag it as WCAG 4.1.2 aria-allowed-attr. Moving role="button" onto the
        // host would make aria-expanded legal but introduces a nested-interactive violation because Fluent's
        // shadow DOM already renders a real <button>. Relying on aria-haspopup alone is the accessible,

src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor:76

  • This removes the only keyboard-reachable control for showing or hiding the secret. The native reveal control is now suppressed, while this replacement button is excluded from sequential focus, so keyboard-only users cannot invoke the action. Keep the custom button in the tab order.
                                                  tabindex="-1"

src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor.cs:151

  • Setting _pendingHideNativeReveal does not schedule another render. If hideNativeReveal returns false in the not-yet-upgraded case described above, OnAfterRenderAsync will not retry until some unrelated UI event happens, leaving the duplicate native reveal control visible. Wait for the custom element/shadow root in JS or schedule a bounded retry explicitly.
            _pendingHideNativeReveal = !allApplied;

src/Aspire.Dashboard/wwwroot/js/app.js:762

  • Ignoring content-only mutations prevents these controls from activating when a registered region grows after registration. For example, a console log region can start below the 240px threshold and then accumulate rows; its box size stays fixed, so ResizeObserver does not fire, and no update occurs until the user scrolls or resizes the window. Schedule an rAF-throttled visibility update for mutations inside registered containers while keeping full rescans limited to structural triggers.
    src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs:438
  • The new collapse/expand behavior and its local-storage restoration have no focused browser test. A regression in the dynamic label/icon, rail class, or persisted state would not be caught by the axe scans. Add Playwright coverage that toggles the rail, verifies the collapsed/expanded UI, reloads, and confirms the saved state is restored.
    private async Task ToggleNavMenuExpandedAsync()
    {
        _isNavMenuExpanded = !_isNavMenuExpanded;
        await LocalStorage.SetUnprotectedAsync(BrowserStorageKeys.NavMenuExpanded, _isNavMenuExpanded);
    }
  • Files reviewed: 65/75 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings July 31, 2026 14:12
@github-actions

This comment has been minimized.

@JamesNK

Copy link
Copy Markdown
Member

Gap to the right of tables on pages. I believe this is common to all content displayed and isn't specific to grids:
image

I don't like highlighting child with the parent. Also the child button background color is wrong. Return to the old behavior for now:
image

Content has too many different positions in details view. Note there were two positions before:
image
image

Scrollbars are too light. Need to be more subtle:
image

nit: See whether these can line up. It wasn't good before:
image

Remove Collapse sidebar text:
image

The no data message on grids should have padding above/below the message:
image

Trace detail page needs a lot of work. This grid had a lot of customization in its CSS. There shouldn't be horizontal lines between rows, and the vertical time markers should be continious lines:
image

Header needs to gracefully handle a long title (i.e. cut off content with ellipsis):
image

Colors used for code blocks need work. Doesn't look good in light or dark:
image
image

I'm not sure I like the scroll to top/bottom buttons always being visible when not at the top or bottom. They're a little over bearing. Maybe only appear when the mouse is near the area? What do other websites do?
image

Copilot AI 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.

🟡 Not ready to approve

Keyboard-accessibility gaps and scroll/readiness bugs can leave features unavailable or tests false-passing.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file

Suppressed comments (6)

src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor:76

  • Removing this show/hide button from the tab order makes the secret-value visibility action mouse-only. The same change also suppresses the browser's native reveal control, so keyboard users have no remaining way to perform this action. Leave the custom button keyboard-focusable.
                                                  tabindex="-1"

tests/Aspire.Dashboard.Tests/Integration/Playwright/AccessibilityTests.cs:239

  • The page title is rendered before the Resources page finishes its async resource subscription, so this readiness check can let axe scan the loading shell before the fixture's frontend row and its controls exist. Waiting for component upgrades/fonts does not wait for that Blazor data update, which makes the new gate capable of false-passing. For the root route, wait for the fixture resource to be visible before scanning.
    src/Aspire.Dashboard/wwwroot/js/app.js:773
  • Content growth inside an already-registered scroll region never refreshes the controls. ResizeObserver only observes the container box, not scrollHeight, and this observer explicitly ignores the log/grid mutations that make an initially short region overflow. As a result, streaming console/structured logs can remain without buttons until some unrelated scroll or resize occurs; the test only covers a region that is already overflowing when inserted. Schedule the inexpensive rAF update for mutations inside registered targets while still reserving full rescans for target/dialog additions.
    src/Aspire.Dashboard/wwwroot/js/app.js:600
  • These visible buttons are removed from sequential keyboard navigation, but not every target has another keyboard path: TextVisualizerDialog.razor makes .markdown-content an overflow-y:auto scroll container without a tabindex. Keyboard users therefore cannot focus that region or invoke either jump action. Keep the buttons tabbable (or make every target focusable with an equivalent accessible control).
    src/Aspire.Dashboard/Components/Dialogs/InteractionsInputDialog.razor.js:36
  • Returning false here does not actually guarantee a retry: OnAfterRenderAsync only updates _pendingHideNativeReveal and does not request another render, and Blazor does not rerender when OnAfterRenderAsync completes. If the Fluent element is not upgraded on the first call, the native reveal control can remain indefinitely. Wait for the custom element definition within this JS call instead of relying on an unrelated future render.
export function hideNativeReveal(hostId) {
    const host = document.getElementById(hostId);
    if (!host || !host.shadowRoot) {
        return false;

src/Aspire.Dashboard/Components/Layout/MainLayout.razor:66

  • The new navigation interaction and persistence path has no focused coverage: the Playwright interaction tests exercise grid auto-fit, row hover, and scroll controls, while the axe matrix only scans the default collapsed state. Add a browser test that toggles this button, verifies the expanded class/labels, reloads, and confirms the local-storage state is restored; otherwise the central new interaction can break without any test failing.
            <FluentButton Class="nav-toggle-button nav-toggle-bottom"
                          Appearance="Appearance.Stealth" OnClick="@ToggleNavMenuExpandedAsync"
                          Title="@(_isNavMenuExpanded ? Loc[nameof(Layout.NavMenuToggleCollapse)] : Loc[nameof(Layout.NavMenuToggleExpand)])"
                          aria-label="@(_isNavMenuExpanded ? Loc[nameof(Layout.NavMenuToggleCollapse)] : Loc[nameof(Layout.NavMenuToggleExpand)])">
  • Files reviewed: 66/76 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@JamesNK

James Newton-King (JamesNK) commented Jul 31, 2026

Copy link
Copy Markdown
Member

Line these up:
image

I think the color of information bar could be more subtle. Just a bit lighter than the dark background (like how in light mode the color is slightly darker than the light background):
image

The GenAI dialog needs a lot of work in dark mode. It is fine in light mode. You can generate a genai trace in the stress playground app using stress-apiservice command:
image

Is it intentional that there is different spacing from the horizontal delimiter? I think more spacing before the page title would be good.
image

@JamesNK

Copy link
Copy Markdown
Member

Mouseover on the manage logs and telemetry page (via settings) is grey. Also the header is a dark color, which is different than before but I'm not sure is intentional or not.
image

The dropdown button for instrument filters increases in size when it becomes selected:
image

@JamesNK

James Newton-King (JamesNK) commented Jul 31, 2026

Copy link
Copy Markdown
Member

On the colors, the light mode feels ok. There is a tiny hint of purple.

Dark mode feels very purple. Especially dialogs. What do you think of toning dark mode purple down? Maybe get some before and after screenshots for people to compare.

I wouldn't mind seeing what the design looks like with completely neutral backgrounds. I think the purple theme would still come through in icons, highlights, scrollbars, etc.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

David Pine (IEvangelist) pushed a commit that referenced this pull request Jul 31, 2026
… theming)

Root-caused and fixed all 11 items from the PR #18943 screenshot review:

- Resources Actions column -> auto so the action icons hug the content right
  edge instead of leaving a large dead gap; freed width goes to the URLs column.
- Remove the parent-row hover ownership highlight (the app.js feature + CSS rule
  and its now-stale interaction test + child fixture resource).
- Align the property-grid Name/Value headers with their values: the unsortable
  <th> rendered flush while Fluent inset the <td> 16px, so zero the cell
  inline-start padding to kill the stair-step.
- Quiet, tint-free neutral scrollbars in both themes (was brand violet).
- Drop the visible "Collapse sidebar" label; the icon + aria-label carry it.
- Keep the empty-state ("No X found") cell padding by excluding it from the
  compact row-padding rule so the message isn't cramped.
- Trace waterfall: re-zero cell padding/border (row-scoped, !important) so the
  vertical time markers are continuous full-height lines and there are no
  horizontal row separators.
- Ellipsize long page/trace titles in the header (display:block) instead of
  bleeding into the top-right nav icons.
- New --codeblock-header-background-color token so the code block header strip
  is a subtle step off the body in both light and dark.
- Scroll-to-top/bottom buttons reveal on pointer proximity (200ms anti-flicker
  hide) instead of being always-on; keyboard focus still force-reveals them.
- Line up the span/log detail flyout's trailing controls: the header
  (panel-resize + Close) shipped a 12px inline padding and the filter toolbar
  fell back to Fluent's default 8px, so the Close and options buttons
  stair-stepped ~4-6px short of the page toolbar's trailing control. Pin both to
  the shared page gutter (--layout-right-padding) so they land on one clean
  vertical edge with the toolbar. Desktop split view only; below 768px the
  flyout stacks full-width and keeps its own header inset.

Validation: dashboard build 0/0; DashboardInteractionsTests 2/2; Accessibility
Tests 19/19; test project 0/0. Verified live in light + dark, including the
flyout right-edge alignment (Close, filter options, and page-toolbar options
all resolve to the same right x).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b530660c-2232-498c-b083-c1d1d6f7227a
@github-actions

This comment has been minimized.

Copilot AI 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.

🟡 Not ready to approve

Scroll-button activation can become stale, the contrast probe measures the wrong backgrounds, and the auto-fit interaction remains unresolved.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file

Suppressed comments (4)

src/Aspire.Dashboard/wwwroot/js/app.js:621

  • This observer only watches the scroll viewport's border box. Live log/trace updates change the child size and scrollHeight without resizing that fixed viewport, while onBodyMutations explicitly ignores content churn, so is-active can remain stale when overflow crosses 240px until another scroll/window resize occurs. Observe the scrolling content or schedule an update for mutations inside registered targets, and make the interaction test grow content after registration.
    tests/Aspire.Dashboard.Tests/Integration/Playwright/AccessibilityTests.cs:443
  • The probe measures against a synthetic --neutral-layer-1 background, not either production surface it claims to protect. Markdown code blocks use --codeblock-background-color (--neutral-layer-2), while the text visualizer is transparent over the dialog background. A palette can therefore pass here while failing on the rendered background. Render probes in the actual code-block/dialog contexts and measure each effective background.
    src/Aspire.Dashboard/Components/App.razor:16
  • Preloading Geist Mono forces every dashboard visit to download it, even though the initial Resources page has no code and the monospace stack prefers installed Cascadia Mono. Let the @font-face load it lazily when code is rendered; only the body font benefits from an unconditional preload.
    <link rel="preload" href="fonts/geist/GeistMono-Variable.woff2" as="font" type="font/woff2" crossorigin />

tests/Aspire.Dashboard.Tests/Integration/Playwright/DashboardInteractionsTests.cs:114

  • This describes and purports to test behavior that no longer exists: neither app.js nor app.css toggles is-hovered, and .scroll-button.is-visible is visible without pointer proximity. The hover therefore proves nothing and the comment misleadingly narrates earlier review evolution. Assert the current always-visible behavior directly.
  • Files reviewed: 79/89 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Copilot AI review requested due to automatic review settings August 4, 2026 19:00
@github-actions

This comment has been minimized.

Copilot AI 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.

🟡 Not ready to approve

Live-content overflow is not re-evaluated, and the contrast probe measures non-production backgrounds.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file

Suppressed comments (3)

src/Aspire.Dashboard/wwwroot/js/app.js:725

  • Pure content churn is exactly what increases scrollHeight, but it is ignored here. A ResizeObserver does not fire when an overflow container keeps the same box size while log rows are appended, and no scroll event occurs until the user interacts, so a region registered below 240px can remain permanently inactive after live data grows past the threshold. Schedule an update for child-list mutations inside a registered target, and cover the incremental-growth case rather than injecting a region that already overflows.
    tests/Aspire.Dashboard.Tests/Integration/Playwright/AccessibilityTests.cs:443
  • This probe does not use either production background it claims to guard: markdown code blocks use --codeblock-background-color (--neutral-layer-2), while the text visualizer is transparent over --dialog-background-color; the probe forces --neutral-layer-1. A palette can therefore pass this calculation while failing on the actual rendered surface, particularly the newly darkened light-theme code block. Render and measure the real markdown and dialog/text-visualizer DOM (or test both computed production backgrounds).
    tests/Aspire.Dashboard.Tests/Integration/Playwright/DashboardInteractionsTests.cs:114
  • This block describes and tests an .is-hovered proximity gate that no longer exists: app.js never toggles that class, and the current CSS makes .is-visible immediately visible. The hover is therefore a no-op and the comments contradict the behavior under test. Assert visibility directly so the test documents the current always-visible affordance.
  • Files reviewed: 79/89 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@github-actions

This comment has been minimized.

AspireMenuButton put aria-haspopup/aria-expanded on the role-less <fluent-button> host, which axe-core flags as a critical aria-allowed-attr violation (neither is a global ARIA attribute). Replace the per-button OnAfterRender interop and declarative host attributes with a single document-level MutationObserver keyed by a neutral data-aspire-menu-trigger marker.

The observer moves both attributes onto the inner native button[part~=control] (which has an implicit role=button): aria-haspopup=menu is set directly, and the aria-expanded that FluentMenu re-stamps on the host is captured, stripped from the host (keeping it axe-clean), and re-pinned onto the inner control. FAST asynchronously mirrors/clears the host's aria-expanded onto the inner button, so the observer watches both targets and re-applies the authoritative value; equality guards prevent observer recursion. The trigger therefore still reports its expanded state to assistive technology while the host carries no disallowed attributes.

Also point the Resources context-menu FluentMenu anchor at a hidden, non-focusable <button> so the aria-expanded FluentMenu stamps on its anchor no longer lands on the visible role-less summary <div>.

Accessibility axe class passes 19/19 (was 2/19); the menu-button aria-expanded outerloop tests (ViewOptionsMenu_ReportsExpandedState, MenuButton_ItemSelected_RestoresFocusToMenuButton) pass, and the bUnit host-contract test is updated to the marker-based contract.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b530660c-2232-498c-b083-c1d1d6f7227a
Copilot AI review requested due to automatic review settings August 4, 2026 19:38
@IEvangelist
David Pine (IEvangelist) enabled auto-merge (squash) August 4, 2026 19:44

Copilot AI 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.

🟡 Not ready to approve

Scroll-button activation misses content-only growth, and the grid auto-fit interaction remains unverified with real pointer input.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Review details

Files not reviewed (2)

  • src/Aspire.Dashboard/Resources/ControlsStrings.Designer.cs: Generated file
  • src/Aspire.Dashboard/Resources/Layout.Designer.cs: Generated file

Suppressed comments (5)

src/Aspire.Dashboard/Components/Controls/ResourceActions.razor.css:31

  • --aspire-space-3xs is undefined, so this margin bypasses the design-token system and always uses its fallback. Use the existing --aspire-space-2xs token defined as 2px.
    margin-inline: var(--aspire-space-3xs, 2px);

src/Aspire.Dashboard/wwwroot/js/app.js:622

  • ResizeObserver only reports changes to the observed element's box, not its scrollHeight. These scroll containers keep a fixed viewport while their child grid/log content grows, and the body observer below explicitly ignores content churn, so Structured Logs or Traces can cross the 240px threshold without ever activating the button until an unrelated scroll/resize occurs. Observe the rendered content as well (as initializeContinuousScroll already does), and cover growth after registration in the Playwright test.
    tests/Aspire.Dashboard.Tests/Integration/Playwright/DashboardInteractionsTests.cs:114
  • This comment describes proximity gating, .is-hovered, and a hide delay that do not exist in the current implementation. app.css makes .scroll-button.is-visible visible without pointer proximity, so the hover is redundant and the test does not assert the behavior described here. Remove the stale within-branch narrative and keep the actual visibility assertion.
    src/Aspire.Dashboard/Components/Controls/ResourceActions.razor.css:6
  • --aspire-space-3xs is not defined by the new token scale (tokens.css starts at --aspire-space-2xs), so this always falls back to a hardcoded value and cannot be tuned through the design-token layer. Use the existing 2px token.

This issue also appears on line 31 of the same file.

    gap: var(--aspire-space-3xs, 2px);

src/Aspire.Dashboard/Components/Layout/MainLayout.razor:72

  • This committed comment references review feedback rather than explaining the current design in isolation. Keep the rationale, but remove the within-branch history so the comment remains meaningful after merge.
                       No visible text label: the icon plus the dynamic Title/aria-label carry the meaning, and a
                       written "Collapse sidebar" beside it read as redundant chrome (review feedback). *@
  • Files reviewed: 79/89 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Tests selector (audit mode)

The full test matrix and all jobs still run in audit mode. The tests and jobs below are what selective CI would run under enforcement.

Runs the full test matrix + all jobs (ALL) — a rule matching 'Directory.Packages.props' selects ALL


Selection computed for commit ffd67f9.

@adamint

Copy link
Copy Markdown
Member
image

catalogservice (application) seemingly has less contrast now - it's disabled and needs higher contrast on the text or a different background to show that

@adamint

Adam Ratzman (adamint) commented Aug 4, 2026

Copy link
Copy Markdown
Member

I know that's the behavior in the dashboard today, but it's even more strange to me now that the page titles are not clickable. With this redesign, they act more as breadcrumbs (note that I do prefer the updated design), which I would expect to be clickable

image

@adamint Adam Ratzman (adamint) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think this is ready yet. The amendment fixes the menu state, component test, and current axe matrix, but a few blockers remain:

  • register() can retry forever through already-resolved customElements.whenDefined() promises if a marked trigger is detached before it upgrades. A staged current-head repro blocked the page main thread for more than 45 seconds. Could we bail when !host.isConnected and bound any retry?
  • Newly inserted triggers still wait behind the 100 ms document scan before registration. A Fluent harness observed the roleless host retaining invalid aria-expanded through the immediate and 25 ms snapshots. Could we register matching added nodes directly in the mutation callback?
  • Dark accent buttons measure 4.27:1 on hover and 3.84:1 while active, both below WCAG AA. The code-block contrast test also probes --neutral-layer-1 rather than the production surfaces and misses --hljs-section at 4.25:1.

The visible keyboard-focus, Resources toolbar semantics, and off-screen scroll-overlay findings also remain unchanged. Could we fix the retry and WCAG blockers before merging?

@IEvangelist
David Pine (IEvangelist) merged commit c3f9713 into main Aug 4, 2026
342 checks passed
@IEvangelist
David Pine (IEvangelist) deleted the dapine/dashboard-css-tokens branch August 4, 2026 20:12
@github-actions github-actions Bot added this to the 13.5 milestone Aug 4, 2026
@aspire-repo-bot

Copy link
Copy Markdown
Contributor

⚠️ Documentation was required for this change, but a docs PR could not be drafted automatically.

Documentation was required for the collapsible navigation rail and responsive toolbar changes (signal: dashboard_user_facing_page_changedResources.razor, StructuredLogs.razor, TraceDetail.razor modified). A docs update was written to src/frontend/src/content/docs/dashboard/explore.mdx (new "Dashboard navigation" section), committed to branch docs/dashboard-ux-redesign-18943, but the create_pull_request tool failed twice with "Pinned SHA failed to generate patch" — a shallow-clone infrastructure error. The docs change needs to be manually pushed and a PR opened targeting release/13.5.

See the workflow run for details: https://github.com/microsoft/aspire/actions/runs/30946832615

@IEvangelist

Copy link
Copy Markdown
Member Author

I know that's the behavior in the dashboard today, but it's even more strange to me now that the page titles are not clickable. With this redesign, they act more as breadcrumbs (note that I do prefer the updated design), which I would expect to be clickable

image

If you're on "Structured logs", and that was link/button...where would you expect to go? You're already on that page, and the logo to the left navs home. The only place that would potentially warrant a bread crumb UX, is traversing the trace details.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🔍 CI Failure Analysis: Transient Infrastructure Failure

The CI build failed due to transient infrastructure issues.

Failed jobs:

  • Tests / Hosting-4 / Hosting-4 (windows-latest) — Windows runner infrastructure failure: 'A device which does not exist was specified' when writing to D:\a_temp_runner_file_commands\add_path_* paths during NuGet restore/build. This is a GitHub Actions runner environment issue unrelated to PR changes. (transient-infra)

If a rerun was not already requested automatically, visit the workflow run page to rerun the failed jobs manually.

Adam Ratzman (adamint) pushed a commit that referenced this pull request Aug 5, 2026
Resolves conflicts with #18943 (design-token system / UX polish), which
replaced AspireMenuButton's `Items` parameter with a lazy `ItemsProvider`.

- AspireMenuButton: keep main's ItemsProvider + JS init sequencing, re-add
  this branch's Disabled and IconStart* parameters. Disabled is now combined
  with main's "no actionable items" auto-disable via UpdateDisabled().
- Drop this branch's OnOpening parameter: ItemsProvider supersedes it, since
  both existed to solve lazy menu item loading.
- DashboardRunSelect: migrate from Items/OnOpening to ItemsProvider.
- Tests: menus now render into MainLayout's FluentMenuProvider rather than
  inline, so DOM queries move from the run select to the page. Add
  FluentUISetupHelpers.SetupMenuService for suites that configure FluentUI
  piecemeal, and register the IMenuService instance instead of resolving it
  so bUnit's service collection isn't sealed during setup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 15a04c2e-0866-4704-9c64-71c66cb1d50b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants