Migrate dialogs to Web Awesome wa-dialog#53
Open
bramkragten wants to merge 9 commits into
Open
Conversation
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>
Codecov Report❌ Patch coverage is
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
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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-buttonand 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. |
| </div> | ||
| </div> | ||
| </div> | ||
| <wa-dialog .open=${this.open} light-dismiss @wa-hide=${this._onWaHide}> |
| </div> | ||
| </div> | ||
| </div> | ||
| <wa-dialog .open=${this.open} light-dismiss @wa-hide=${this._onWaHide}> |
| id="button" | ||
| variant="brand" | ||
| appearance="accent" | ||
| aria-label=${ifDefined(this.label)} |
- 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>
| // 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>
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>
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 }) | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migrates the two hand-rolled dialogs (
confirm-dialog,info-dialog) to Web Awesome's<wa-dialog>, continuing the Web Awesome adoption from #5 / #16.Why
<wa-dialog>brings a focus trap, Escape-to-close, backdrop dismiss, a header close button, androle="dialog"/aria-modalfor 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-dialogandinfo-dialognow wrap<wa-dialog>. Their public APIs are unchanged, soapp-shellandminipc-setup-method-viewneed no changes:open,driveName, eventsdialog-confirm/dialog-cancelopen,title,message,primaryLabel,secondaryLabel, eventsdialog-primary/dialog-secondarydialog-cancel/dialog-secondary), with a guard so an action button doesn't also fire a dismiss event..wa-darkclass 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-modalto our--ha-*vars (and defined--ha-card-background) so dialogs followprefers-color-scheme.wa-dialog+wa-hidedismiss) and one mini-PC E2E locator (Go backnow targetsappearance="outlined"so it doesn't also match wa-dialog's built-in close button).Testing
tsc,eslint,prettier --check,vite buildall pass.🤖 Generated with Claude Code