From 910e7e10a72aebc3233911f31feab78d063b68d6 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Tue, 13 May 2025 13:17:54 +0200 Subject: [PATCH] Use ha-dialog-header for data-entry-flow (#25403) * Use ha-dialog-header for data-entry-flow header * Fix header wrap --- .../config-flow/dialog-data-entry-flow.ts | 191 ++++++++++++++---- .../show-dialog-data-entry-flow.ts | 20 +- src/dialogs/config-flow/step-flow-abort.ts | 8 - .../config-flow/step-flow-create-entry.ts | 48 +---- src/dialogs/config-flow/step-flow-external.ts | 9 - src/dialogs/config-flow/step-flow-form.ts | 15 +- src/dialogs/config-flow/step-flow-menu.ts | 6 - src/dialogs/config-flow/step-flow-progress.ts | 8 +- src/dialogs/config-flow/styles.ts | 3 - .../config/repairs/show-dialog-repair-flow.ts | 40 +++- src/translations/en.json | 2 +- 11 files changed, 208 insertions(+), 142 deletions(-) diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts index 726143bdb1..5f141c3572 100644 --- a/src/dialogs/config-flow/dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -1,17 +1,20 @@ import { mdiClose, mdiHelpCircle } from "@mdi/js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; -import type { CSSResultGroup, PropertyValues } from "lit"; +import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import type { HASSDomEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-dialog"; +import "../../components/ha-dialog-header"; import "../../components/ha-icon-button"; import type { DataEntryFlowStep } from "../../data/data_entry_flow"; import { subscribeDataEntryFlowProgress, subscribeDataEntryFlowProgressed, } from "../../data/data_entry_flow"; +import type { DeviceRegistryEntry } from "../../data/device_registry"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; @@ -171,6 +174,92 @@ class DataEntryFlowDialog extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } + private _devices = memoizeOne( + ( + showDevices: boolean, + devices: DeviceRegistryEntry[], + entry_id?: string + ) => + showDevices && entry_id + ? devices.filter((device) => device.config_entries.includes(entry_id)) + : [] + ); + + private _getDialogTitle(): string { + if (this._loading || !this._step || !this._params) { + return ""; + } + + switch (this._step.type) { + case "form": + return this._params.flowConfig.renderShowFormStepHeader( + this.hass, + this._step + ); + case "abort": + return this._params.flowConfig.renderAbortHeader + ? this._params.flowConfig.renderAbortHeader(this.hass, this._step) + : this.hass.localize( + `component.${this._params.domain ?? this._step.handler}.title` + ); + case "progress": + return this._params.flowConfig.renderShowFormProgressHeader( + this.hass, + this._step + ); + case "menu": + return this._params.flowConfig.renderMenuHeader(this.hass, this._step); + case "create_entry": { + const devicesLength = this._devices( + this._params.flowConfig.showDevices, + Object.values(this.hass.devices), + this._step.result?.entry_id + ).length; + return this.hass.localize( + `ui.panel.config.integrations.config_flow.${ + devicesLength ? "device_created" : "success" + }`, + { + number: devicesLength, + } + ); + } + default: + return ""; + } + } + + private _getDialogSubtitle(): string | TemplateResult | undefined { + if (this._loading || !this._step || !this._params) { + return ""; + } + + switch (this._step.type) { + case "form": + return this._params.flowConfig.renderShowFormStepSubheader?.( + this.hass, + this._step + ); + case "abort": + return this._params.flowConfig.renderAbortSubheader?.( + this.hass, + this._step + ); + case "progress": + return this._params.flowConfig.renderShowFormProgressSubheader?.( + this.hass, + this._step + ); + case "menu": + return this._params.flowConfig.renderMenuSubheader?.( + this.hass, + this._step + ); + default: + return ""; + } + } + protected render() { if (!this._params) { return nothing; @@ -187,6 +276,9 @@ class DataEntryFlowDialog extends LitElement { this._params.manifest?.is_built_in) || !!this._params.manifest?.documentation; + const dialogTitle = this._getDialogTitle(); + const dialogSubtitle = this._getDialogSubtitle(); + return html` + + + +
+ ${dialogTitle} +
+ + ${dialogSubtitle + ? html`
${dialogSubtitle}
` + : nothing} + ${showDocumentationLink && !this._loading && this._step + ? html` + + + + ` + : nothing} +
${this._loading || this._step === null ? html` @@ -211,40 +346,12 @@ class DataEntryFlowDialog extends LitElement { // to reset the element. nothing : html` -
- ${showDocumentationLink - ? html` - - - - ` - : nothing} - -
${this._step.type === "form" ? html` ` : this._step.type === "external" @@ -253,7 +360,6 @@ class DataEntryFlowDialog extends LitElement { .flowConfig=${this._params.flowConfig} .step=${this._step} .hass=${this.hass} - .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "abort" @@ -265,7 +371,6 @@ class DataEntryFlowDialog extends LitElement { .handler=${this._step.handler} .domain=${this._params.domain ?? this._step.handler} - .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "progress" @@ -275,7 +380,6 @@ class DataEntryFlowDialog extends LitElement { .step=${this._step} .hass=${this.hass} .progress=${this._progress} - .increasePaddingEnd=${showDocumentationLink} > ` : this._step.type === "menu" @@ -284,7 +388,6 @@ class DataEntryFlowDialog extends LitElement { .flowConfig=${this._params.flowConfig} .step=${this._step} .hass=${this.hass} - .increasePaddingEnd=${showDocumentationLink} > ` : html` @@ -294,7 +397,11 @@ class DataEntryFlowDialog extends LitElement { .hass=${this.hass} .navigateToResult=${this._params .navigateToResult ?? false} - .increasePaddingEnd=${showDocumentationLink} + .devices=${this._devices( + this._params.flowConfig.showDevices, + Object.values(this.hass.devices), + this._step.result?.entry_id + )} > `} `} @@ -384,16 +491,14 @@ class DataEntryFlowDialog extends LitElement { ha-dialog { --dialog-content-padding: 0; } - .dialog-actions { - padding: 16px; - position: absolute; - top: 0; - right: 0; - inset-inline-start: initial; - inset-inline-end: 0px; - direction: var(--direction); + .dialog-title { + overflow: hidden; + text-overflow: ellipsis; } - .dialog-actions > * { + .dialog-title.form { + white-space: normal; + } + .help { color: var(--secondary-text-color); } `, diff --git a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts index add3a2573c..4bdf0c522f 100644 --- a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts @@ -31,10 +31,12 @@ export interface FlowConfig { deleteFlow(hass: HomeAssistant, flowId: string): Promise; - renderAbortHeader?( + renderAbortHeader?(hass: HomeAssistant, step: DataEntryFlowStepAbort): string; + + renderAbortSubheader?( hass: HomeAssistant, step: DataEntryFlowStepAbort - ): TemplateResult | string; + ): string | TemplateResult; renderAbortDescription( hass: HomeAssistant, @@ -44,6 +46,11 @@ export interface FlowConfig { renderShowFormStepHeader( hass: HomeAssistant, step: DataEntryFlowStepForm + ): string; + + renderShowFormStepSubheader?( + hass: HomeAssistant, + step: DataEntryFlowStepForm ): string | TemplateResult; renderShowFormStepDescription( @@ -100,6 +107,11 @@ export interface FlowConfig { renderShowFormProgressHeader( hass: HomeAssistant, step: DataEntryFlowStepProgress + ): string; + + renderShowFormProgressSubheader?( + hass: HomeAssistant, + step: DataEntryFlowStepProgress ): string | TemplateResult; renderShowFormProgressDescription( @@ -107,7 +119,9 @@ export interface FlowConfig { step: DataEntryFlowStepProgress ): TemplateResult | ""; - renderMenuHeader( + renderMenuHeader(hass: HomeAssistant, step: DataEntryFlowStepMenu): string; + + renderMenuSubheader?( hass: HomeAssistant, step: DataEntryFlowStepMenu ): string | TemplateResult; diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index 9f0ad9abb0..7277e0b0f8 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -22,9 +22,6 @@ class StepFlowAbort extends LitElement { @property({ attribute: false }) public handler!: string; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; - protected firstUpdated(changed: PropertyValues) { super.firstUpdated(changed); if (this.step.reason === "missing_credentials") { @@ -37,11 +34,6 @@ class StepFlowAbort extends LitElement { return nothing; } return html` -

- ${this.params.flowConfig.renderAbortHeader - ? this.params.flowConfig.renderAbortHeader(this.hass, this.step) - : this.hass.localize(`component.${this.domain}.title`)} -

${this.params.flowConfig.renderAbortDescription(this.hass, this.step)}
diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index eac44ccff9..5a609fac8f 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -36,8 +36,7 @@ class StepFlowCreateEntry extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepCreateEntry; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; + @property({ attribute: false }) public devices!: DeviceRegistryEntry[]; public navigateToResult = false; @@ -46,17 +45,6 @@ class StepFlowCreateEntry extends LitElement { { name?: string; area?: string } > = {}; - private _devices = memoizeOne( - ( - showDevices: boolean, - devices: DeviceRegistryEntry[], - entry_id?: string - ) => - showDevices && entry_id - ? devices.filter((device) => device.config_entries.includes(entry_id)) - : [] - ); - private _deviceEntities = memoizeOne( ( deviceId: string, @@ -75,22 +63,16 @@ class StepFlowCreateEntry extends LitElement { return; } - const devices = this._devices( - this.flowConfig.showDevices, - Object.values(this.hass.devices), - this.step.result?.entry_id - ); - if ( - devices.length !== 1 || - devices[0].primary_config_entry !== this.step.result?.entry_id || + this.devices.length !== 1 || + this.devices[0].primary_config_entry !== this.step.result?.entry_id || this.step.result.domain === "voip" ) { return; } const assistSatellites = this._deviceEntities( - devices[0].id, + this.devices[0].id, Object.values(this.hass.entities), "assist_satellite" ); @@ -103,26 +85,14 @@ class StepFlowCreateEntry extends LitElement { this.navigateToResult = false; this._flowDone(); showVoiceAssistantSetupDialog(this, { - deviceId: devices[0].id, + deviceId: this.devices[0].id, }); } } protected render(): TemplateResult { const localize = this.hass.localize; - const devices = this._devices( - this.flowConfig.showDevices, - Object.values(this.hass.devices), - this.step.result?.entry_id - ); return html` -

- ${devices.length - ? localize("ui.panel.config.integrations.config_flow.assign_area", { - number: devices.length, - }) - : `${localize("ui.panel.config.integrations.config_flow.success")}!`} -

${this.flowConfig.renderCreateEntryDescription(this.hass, this.step)} ${this.step.result?.state === "not_loaded" @@ -132,10 +102,10 @@ class StepFlowCreateEntry extends LitElement { )}` : nothing} - ${devices.length === 0 && + ${this.devices.length === 0 && ["options_flow", "repair_flow"].includes(this.flowConfig.flowType) ? nothing - : devices.length === 0 + : this.devices.length === 0 ? html`

${localize( "ui.panel.config.integrations.config_flow.created_config", @@ -144,7 +114,7 @@ class StepFlowCreateEntry extends LitElement {

` : html`
- ${devices.map( + ${this.devices.map( (device) => html`
@@ -203,7 +173,7 @@ class StepFlowCreateEntry extends LitElement {
${localize( - `ui.panel.config.integrations.config_flow.${!devices.length || Object.keys(this._deviceUpdate).length ? "finish" : "finish_skip"}` + `ui.panel.config.integrations.config_flow.${!this.devices.length || Object.keys(this._deviceUpdate).length ? "finish" : "finish_skip"}` )}
diff --git a/src/dialogs/config-flow/step-flow-external.ts b/src/dialogs/config-flow/step-flow-external.ts index 98d98c61ef..7907dd2901 100644 --- a/src/dialogs/config-flow/step-flow-external.ts +++ b/src/dialogs/config-flow/step-flow-external.ts @@ -15,16 +15,10 @@ class StepFlowExternal extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepExternal; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; - protected render(): TemplateResult { const localize = this.hass.localize; return html` -

- ${this.flowConfig.renderExternalStepHeader(this.hass, this.step)} -

${this.flowConfig.renderExternalStepDescription(this.hass, this.step)}
@@ -56,9 +50,6 @@ class StepFlowExternal extends LitElement { .open-button a { text-decoration: none; } - h2.end-space { - padding-inline-end: 72px; - } `, ]; } diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts index 06ec17dc0d..aa012c2163 100644 --- a/src/dialogs/config-flow/step-flow-form.ts +++ b/src/dialogs/config-flow/step-flow-form.ts @@ -6,18 +6,18 @@ import { dynamicElement } from "../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../common/dom/fire_event"; import { isNavigationClick } from "../../common/dom/is-navigation-click"; import "../../components/ha-alert"; -import "../../components/ha-spinner"; import { computeInitialHaFormData } from "../../components/ha-form/compute-initial-ha-form-data"; import "../../components/ha-form/ha-form"; import type { HaFormSchema } from "../../components/ha-form/types"; import "../../components/ha-markdown"; +import "../../components/ha-spinner"; import { autocompleteLoginFields } from "../../data/auth"; import type { DataEntryFlowStepForm } from "../../data/data_entry_flow"; +import { previewModule } from "../../data/preview"; +import { haStyle } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import type { FlowConfig } from "./show-dialog-data-entry-flow"; import { configFlowContentStyles } from "./styles"; -import { haStyle } from "../../resources/styles"; -import { previewModule } from "../../data/preview"; @customElement("step-flow-form") class StepFlowForm extends LitElement { @@ -27,9 +27,6 @@ class StepFlowForm extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; - @state() private _loading = false; @state() private _stepData?: Record; @@ -46,9 +43,6 @@ class StepFlowForm extends LitElement { const stepData = this._stepDataProcessed; return html` -

- ${this.flowConfig.renderShowFormStepHeader(this.hass, this.step)} -

${this.flowConfig.renderShowFormStepDescription(this.hass, this.step)} ${this._errorMsg @@ -281,9 +275,6 @@ class StepFlowForm extends LitElement { margin-top: 24px; display: block; } - h2 { - word-break: break-word; - } `, ]; } diff --git a/src/dialogs/config-flow/step-flow-menu.ts b/src/dialogs/config-flow/step-flow-menu.ts index b0fcd3ba64..ede8a2998e 100644 --- a/src/dialogs/config-flow/step-flow-menu.ts +++ b/src/dialogs/config-flow/step-flow-menu.ts @@ -17,9 +17,6 @@ class StepFlowMenu extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepMenu; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; - protected render(): TemplateResult { let options: string[]; let translations: Record; @@ -45,9 +42,6 @@ class StepFlowMenu extends LitElement { ); return html` -

- ${this.flowConfig.renderMenuHeader(this.hass, this.step)} -

${description ? html`
${description}
` : ""}
${options.map( diff --git a/src/dialogs/config-flow/step-flow-progress.ts b/src/dialogs/config-flow/step-flow-progress.ts index c71efcb98c..f92d355920 100644 --- a/src/dialogs/config-flow/step-flow-progress.ts +++ b/src/dialogs/config-flow/step-flow-progress.ts @@ -2,13 +2,13 @@ import "@material/mwc-button"; import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; +import { blankBeforePercent } from "../../common/translations/blank_before_percent"; import "../../components/ha-progress-ring"; import "../../components/ha-spinner"; import type { DataEntryFlowStepProgress } from "../../data/data_entry_flow"; import type { HomeAssistant } from "../../types"; import type { FlowConfig } from "./show-dialog-data-entry-flow"; import { configFlowContentStyles } from "./styles"; -import { blankBeforePercent } from "../../common/translations/blank_before_percent"; @customElement("step-flow-progress") class StepFlowProgress extends LitElement { @@ -24,14 +24,8 @@ class StepFlowProgress extends LitElement { @property({ type: Number }) public progress?: number; - @property({ type: Boolean, attribute: "increase-padding-end" }) - public increasePaddingEnd = false; - protected render(): TemplateResult { return html` -

- ${this.flowConfig.renderShowFormProgressHeader(this.hass, this.step)} -

${this.progress ? html` diff --git a/src/dialogs/config-flow/styles.ts b/src/dialogs/config-flow/styles.ts index b82dc29bf1..dce0b9c326 100644 --- a/src/dialogs/config-flow/styles.ts +++ b/src/dialogs/config-flow/styles.ts @@ -25,9 +25,6 @@ export const configFlowContentStyles = css` text-transform: var(--mdc-typography-headline6-text-transform, inherit); box-sizing: border-box; } - h2.end-space { - padding-inline-end: 72px; - } .content, .preview { diff --git a/src/panels/config/repairs/show-dialog-repair-flow.ts b/src/panels/config/repairs/show-dialog-repair-flow.ts index 3ea9e79353..6f006b2e39 100644 --- a/src/panels/config/repairs/show-dialog-repair-flow.ts +++ b/src/panels/config/repairs/show-dialog-repair-flow.ts @@ -1,7 +1,6 @@ import { html, nothing } from "lit"; import type { DataEntryFlowStep } from "../../../data/data_entry_flow"; import { domainToName } from "../../../data/integration"; -import "./dialog-repairs-issue-subtitle"; import type { RepairsIssue } from "../../../data/repairs"; import { createRepairsFlow, @@ -14,6 +13,7 @@ import { showFlowDialog, } from "../../../dialogs/config-flow/show-dialog-data-entry-flow"; import type { HomeAssistant } from "../../../types"; +import "./dialog-repairs-issue-subtitle"; const mergePlaceholders = (issue: RepairsIssue, step: DataEntryFlowStep) => step.description_placeholders && issue.translation_placeholders @@ -68,8 +68,11 @@ export const showRepairsFlowDialog = ( deleteFlow: deleteRepairsFlow, renderAbortHeader(hass) { + return hass.localize("ui.dialogs.repair_flow.form.header"); + }, + + renderAbortSubheader(hass) { return html` - ${hass.localize("ui.dialogs.repair_flow.form.header")}