Skip to content

Migrate dialogs to Web Awesome wa-dialog#53

Open
bramkragten wants to merge 9 commits into
home-assistant:mainfrom
bramkragten:webawesome-dialogs
Open

Migrate dialogs to Web Awesome wa-dialog#53
bramkragten wants to merge 9 commits into
home-assistant:mainfrom
bramkragten:webawesome-dialogs

Conversation

@bramkragten

Copy link
Copy Markdown
Member

Migrates the two hand-rolled dialogs (confirm-dialog, info-dialog) to Web Awesome's <wa-dialog>, continuing the Web Awesome adoption from #5 / #16.

Stacked on #51 (buttons migration). Until that merges, this PR's diff also shows the button changes; it reduces to dialogs-only once #51 lands.

Why

<wa-dialog> brings a focus trap, Escape-to-close, backdrop dismiss, a header close button, and role="dialog"/aria-modal for free — resolving the dialog accessibility gaps called out in the review (no focus management, no Escape, no ARIA on the old custom overlays).

What changed

  • confirm-dialog and info-dialog now wrap <wa-dialog>. Their public APIs are unchanged, so app-shell and minipc-setup-method-view need no changes:
    • confirm-dialog: open, driveName, events dialog-confirm / dialog-cancel
    • info-dialog: open, title, message, primaryLabel, secondaryLabel, events dialog-primary / dialog-secondary
  • Escape, backdrop click, and the header close button all map to the dismiss event (dialog-cancel / dialog-secondary), with a guard so an action button doesn't also fire a dismiss event.
  • Dark mode: Web Awesome's dark tokens are gated on a .wa-dark class this app doesn't set, so the dialog surface would otherwise stay light. Mapped --wa-color-surface-raised / --wa-color-text-normal / --wa-color-overlay-modal to our --ha-* vars (and defined --ha-card-background) so dialogs follow prefers-color-scheme.
  • Updated unit tests for the new structure (wa-dialog + wa-hide dismiss) and one mini-PC E2E locator (Go back now targets appearance="outlined" so it doesn't also match wa-dialog's built-in close button).

Testing

  • Unit: 178/178. tsc, eslint, prettier --check, vite build all pass.
  • E2E (chromium): confirm-dialog SBC flow (open / cancel / confirm) and mini-PC info-dialog flow (open / primary / go-back) all pass.
  • Verified both dialogs in the browser in light and dark mode, and confirmed Escape/backdrop dismiss fires the dismiss event exactly once (no double-fire).

🤖 Generated with Claude Code

bramkragten and others added 5 commits July 13, 2026 11:32
Replace every custom <button> element and its per-component CSS with
<wa-button> from the @home-assistant/webawesome fork, fulfilling the
existing repo convention (contributing.md: prefer <wa-*> components).

- Map variants/states: brand/danger + accent/outlined/plain, disabled,
  and loading (drive refresh uses the native loading prop)
- Add ha-svg-icon (ported from the frontend) for inline MDI paths in
  button slots; icons live in start/end slots instead of custom markup
- Extract the toolbox FAB into a fab-button component using wa-tooltip
- Map Web Awesome color tokens onto our --ha-* theme colors in styles.css
  so buttons keep the Home Assistant palette in light and dark
- Add vite-env.d.ts for ambient *.css / vite client types

Removes ~450 lines of duplicated per-component button styles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Retarget unit-test selectors from removed CSS classes (.back-button,
  .dialog-button.*, .lets-go-button, .footer-button.primary) to wa-button
  via stable container/attribute selectors; fixes 29 failing tests
- Remove dead ?loading binding on the drive refresh buttons (they're never
  rendered while _loading is true — the view swaps to the spinner)
- fab-button: make label optional so ifDefined() actually omits aria-label
  for icon-only use (empty-string default would have kept aria-label="")
- Add unit tests for ha-svg-icon and fab-button
- web-test-runner: prefer the "browser" export condition so nanoid (pulled
  in transitively via wa-tooltip) resolves its browser build instead of the
  node:crypto one, which failed to import under the test runner

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Migrate all Playwright E2E locators off the removed CSS classes
  (.lets-go-button, .back-button, .cancel-button, .footer-button.primary,
  .dialog-button.*, .download-button, .refresh-button) to wa-button selectors
- Replace toBeDisabled()/toBeEnabled() with toHaveJSProperty("disabled", …);
  Playwright can't read a custom element's disabled state
- Wait for the proxmox configure Next button to enable before clicking (its
  node/storage defaults load async; Playwright no longer auto-waits on
  wa-button), fixing the proxmox flow specs
- drive-selection: show the full-page spinner only on the initial scan; a
  refresh now keeps the list visible and drives the header button's native
  loading prop, matching the PR description
- welcome CTA: size="large" -> size="l" (long form deprecated in the fork)

Full chromium E2E suite passes serially (174/174); unit 178/178.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Playwright's isEnabled()/isDisabled() only recognize native/ARIA disabled
state, so on a wa-button host they always report enabled. The UTM flow used
them to branch (skip/throw) and in one tautological assertion, so the checks
were bypassed. Read wa-button's `disabled` JS property directly instead, via
a small buttonDisabled() helper.

UTM e2e spec passes (42/42 chromium).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the hand-rolled overlay/panel dialogs with Web Awesome's <wa-dialog>,
which brings a focus trap, Escape-to-close, backdrop dismiss, a header close
button, and role="dialog"/aria-modal for free — resolving the dialog
accessibility gaps from the frontend review (home-assistant#5).

- Public APIs are unchanged: confirm-dialog keeps open/driveName +
  dialog-confirm/dialog-cancel; info-dialog keeps open/title/message/
  primaryLabel/secondaryLabel + dialog-primary/dialog-secondary. Escape,
  backdrop, and the close button map to cancel/secondary (dismiss), with a
  guard so an action button doesn't double-fire a dismiss event.
- Map --wa-color-surface-raised/--wa-color-text-normal/--wa-color-overlay-modal
  (and define --ha-card-background) so dialogs follow prefers-color-scheme;
  Web Awesome's own dark tokens are gated on a .wa-dark class we don't set.
- Update unit tests for the wa-dialog structure and wa-hide dismiss; update
  the mini-PC E2E "Go back" locator to target appearance="outlined" so it
  doesn't also match wa-dialog's built-in close button.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 13:04
@codecov-commenter

codecov-commenter commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.31903% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.30%. Comparing base (016a565) to head (89ed7d9).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/views/sbc/device-selection-view.ts 14.28% 6 Missing ⚠️
src/components/confirm-dialog.ts 95.06% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #53      +/-   ##
==========================================
- Coverage   89.54%   89.30%   -0.24%     
==========================================
  Files          29       31       +2     
  Lines       10910    10731     -179     
  Branches       84       99      +15     
==========================================
- Hits         9769     9583     -186     
- Misses       1141     1148       +7     
Flag Coverage Δ
backend 92.01% <ø> (ø)
frontend 83.91% <97.31%> (-0.95%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Migrates custom dialogs to Web Awesome while incorporating the stacked button migration and associated accessibility, theming, and test updates.

Changes:

  • Replaces confirmation and information overlays with wa-dialog.
  • Migrates buttons to wa-button and adds reusable icon/FAB components.
  • Updates dependencies, theme tokens, unit tests, and E2E selectors.

Reviewed changes

Copilot reviewed 31 out of 33 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
web-test-runner.config.mjs Enables browser dependency exports.
test/unit/views/welcome-view.test.ts Updates button selectors.
test/unit/views/path-selection-view.test.ts Updates back-button selectors.
test/unit/components/wizard-shell.test.ts Updates wizard button tests.
test/unit/components/info-dialog.test.ts Tests migrated information dialog.
test/unit/components/ha-svg-icon.test.ts Adds SVG icon tests.
test/unit/components/fab-button.test.ts Adds FAB component tests.
test/unit/components/confirm-dialog.test.ts Tests migrated confirmation dialog.
test/e2e/utm-flow.spec.ts Updates UTM flow selectors and state checks.
test/e2e/proxmox-flow.spec.ts Updates Proxmox flow selectors and waits.
test/e2e/other-options-flow.spec.ts Updates navigation selectors.
test/e2e/navigation.spec.ts Updates general wizard selectors.
test/e2e/minipc-flow.spec.ts Updates mini-PC dialog and button selectors.
test/e2e/ha-hardware-flow.spec.ts Updates hardware-flow selectors.
src/vite-env.d.ts Adds Vite client types.
src/views/welcome-view.ts Migrates the primary CTA.
src/views/utm/utm-check-view.ts Migrates UTM actions and icons.
src/views/sbc/drive-selection-view.ts Migrates refresh/retry controls.
src/views/sbc/device-selection-view.ts Migrates retry control.
src/views/path-selection-view.ts Migrates back control.
src/views/other-options-view.ts Migrates back control.
src/views/minipc/architecture-selection-view.ts Migrates retry control.
src/views/ha-hardware/device-selection-view.ts Migrates retry control.
src/styles.css Maps application theme tokens to Web Awesome.
src/main.ts Loads the Web Awesome theme.
src/components/wizard-shell.ts Migrates wizard navigation controls.
src/components/info-dialog.ts Reimplements information dialog with wa-dialog.
src/components/ha-svg-icon.ts Adds reusable SVG icon component.
src/components/fab-button.ts Adds Web Awesome-based floating action button.
src/components/confirm-dialog.ts Reimplements confirmation dialog with wa-dialog.
src/components/app-shell.ts Uses the new FAB component.
package.json Switches to the Home Assistant Web Awesome fork.
package-lock.json Locks the updated dependency graph.

Comment thread src/components/confirm-dialog.ts Outdated
</div>
</div>
</div>
<wa-dialog .open=${this.open} light-dismiss @wa-hide=${this._onWaHide}>
Comment thread src/components/info-dialog.ts Outdated
</div>
</div>
</div>
<wa-dialog .open=${this.open} light-dismiss @wa-hide=${this._onWaHide}>
Comment thread src/components/fab-button.ts Outdated
id="button"
variant="brand"
appearance="accent"
aria-label=${ifDefined(this.label)}
bramkragten and others added 2 commits July 13, 2026 15:35
- Dialogs: sync state and dispatch the dismiss event on wa-after-hide instead
  of wa-hide. wa-hide is the cancelable *request* (before the 200ms close
  animation); feeding open=false back into wa-dialog there made its watcher
  start a second requestClose mid-animation. Use an explicit
  _closingViaAction flag (instead of reading `open`) so action-button closes
  don't also emit a dismiss event — the previous open-based guard was racy.
- fab-button: a host aria-label isn't forwarded to wa-button's shadow-root
  <button>, so the icon-only control had no accessible name. Put the label in
  the button as visually-hidden text (keeping the tooltip); assert the name
  in the unit test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Web Awesome's dark tokens are gated on a `wa-dark` class, not
prefers-color-scheme, so unmapped tokens (neutral hover fill, tooltip colors)
stayed light in dark mode. Toggle `wa-dark` on <html> from matchMedia so every
Web Awesome component flips correctly, instead of mapping tokens one by one.
Our --ha-* overrides still pin brand/danger/surface to Home Assistant colors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 13:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 3 comments.

Comment thread src/components/info-dialog.ts Outdated
// Fires after the dialog has fully closed (Escape / backdrop / header close
// button). Syncing here rather than on wa-hide avoids feeding open=false back
// into wa-dialog mid-animation, which would trigger a second close request.
private _onAfterHide() {
Comment on lines +189 to +191
el.shadowRoot!.querySelector("wa-dialog")!.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
);
Comment on lines +168 to +170
el.shadowRoot!.querySelector("wa-dialog")!.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
);
wa-after-hide bubbles and is composed, so a nested Web Awesome overlay slotted
into a dialog body would reach the wrapper's handler and wrongly dismiss the
outer dialog. Guard on eventPhase === AT_TARGET (the same idiom the frontend's
ha-dialog uses) so only the dialog's own close is handled. Add a bubbling test,
and dispatch the AT_TARGET wa-after-hide the real close emits in the
no-double-dismiss guard tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 14:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 2 comments.

Comment on lines +135 to +146
it("dispatches dialog-cancel when dismissed (escape/backdrop/close)", async () => {
const el = await fixture<ConfirmDialog>(html`
<confirm-dialog open></confirm-dialog>
`);

const overlay = el.shadowRoot!.querySelector(".overlay") as HTMLElement;
const dialog = el.shadowRoot!.querySelector("wa-dialog")!;

setTimeout(() => overlay.click());
setTimeout(() =>
dialog.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
)
);
Comment on lines +156 to +167
it("dispatches dialog-secondary when dismissed (escape/backdrop/close)", async () => {
const el = await fixture<InfoDialog>(html`
<info-dialog open></info-dialog>
`);

const overlay = el.shadowRoot!.querySelector(".overlay") as HTMLElement;
const dialog = el.shadowRoot!.querySelector("wa-dialog")!;

setTimeout(() => overlay.click());
setTimeout(() =>
dialog.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
)
);
The unit "dismissed" tests only exercise the local wa-after-hide handler, so a
regression in the wa-dialog dismissal integration (Escape / backdrop / close
button) would go unnoticed. Add Playwright tests that press Escape on the open
confirm-dialog (SBC flow) and info-dialog (mini-PC flow) and assert the dialog
closes and the underlying view remains.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 33 changed files in this pull request and generated 4 comments.

Comment on lines +121 to +126
if (this._closingViaAction) {
this._closingViaAction = false;
return;
}
this.open = false;
this._dispatch("dialog-cancel");
Comment on lines +134 to +139
if (this._closingViaAction) {
this._closingViaAction = false;
return;
}
this.open = false;
this._dispatch("dialog-secondary");
Comment on lines +168 to +170
el.shadowRoot!.querySelector("wa-dialog")!.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
);
Comment on lines +187 to +191
primaryButton.click();
await el.updateComplete;
el.shadowRoot!.querySelector("wa-dialog")!.dispatchEvent(
new CustomEvent("wa-after-hide", { bubbles: true, composed: true })
);
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.

3 participants