diff --git a/src/dialogs/config-flow/show-dialog-config-flow.ts b/src/dialogs/config-flow/show-dialog-config-flow.ts index d4323b15f7..9fc36f7dc2 100644 --- a/src/dialogs/config-flow/show-dialog-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-config-flow.ts @@ -1,4 +1,4 @@ -import { html } from "lit"; +import { html, nothing } from "lit"; import { createConfigFlow, deleteConfigFlow, @@ -194,13 +194,7 @@ export const showConfigFlowDialog = ( .content=${description} > ` - : ""} -

- ${hass.localize( - "ui.panel.config.integrations.config_flow.created_config", - { name: step.title } - )} -

+ : nothing} `; }, diff --git a/src/dialogs/config-flow/show-dialog-sub-config-flow.ts b/src/dialogs/config-flow/show-dialog-sub-config-flow.ts index 5c58671bea..a2cbfca060 100644 --- a/src/dialogs/config-flow/show-dialog-sub-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-sub-config-flow.ts @@ -1,4 +1,4 @@ -import { html } from "lit"; +import { html, nothing } from "lit"; import type { ConfigEntry } from "../../data/config_entries"; import { domainToName } from "../../data/integration"; import { @@ -200,13 +200,7 @@ export const showSubConfigFlowDialog = ( .content=${description} > ` - : ""} -

- ${hass.localize( - "ui.panel.config.integrations.config_flow.created_config", - { name: step.title } - )} -

+ : nothing} `; }, diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index db6b147f57..683771a567 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -1,10 +1,13 @@ import "@material/mwc-button"; import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; import { css, html, LitElement, nothing } from "lit"; -import { customElement, property } from "lit/decorators"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; -import { computeDeviceNameDisplay } from "../../common/entity/compute_device_name"; +import { + computeDeviceName, + computeDeviceNameDisplay, +} from "../../common/entity/compute_device_name"; import { computeDomain } from "../../common/entity/compute_domain"; import { navigate } from "../../common/navigate"; import "../../components/ha-area-picker"; @@ -18,6 +21,8 @@ import { showAlertDialog } from "../generic/show-dialog-box"; import { showVoiceAssistantSetupDialog } from "../voice-assistant-setup/show-voice-assistant-setup-dialog"; import type { FlowConfig } from "./show-dialog-data-entry-flow"; import { configFlowContentStyles } from "./styles"; +import { brandsUrl } from "../../util/brands-url"; +import { domainToName } from "../../data/integration"; @customElement("step-flow-create-entry") class StepFlowCreateEntry extends LitElement { @@ -27,7 +32,12 @@ class StepFlowCreateEntry extends LitElement { @property({ attribute: false }) public step!: DataEntryFlowStepCreateEntry; - navigateToResult = false; + public navigateToResult = false; + + @state() private _deviceUpdate: Record< + string, + { name?: string; area?: string } + > = {}; private _devices = memoizeOne( ( @@ -99,7 +109,13 @@ class StepFlowCreateEntry extends LitElement { this.step.result?.entry_id ); return html` -

${localize("ui.panel.config.integrations.config_flow.success")}!

+

+ ${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" @@ -110,31 +126,62 @@ class StepFlowCreateEntry extends LitElement { >` : nothing} ${devices.length === 0 - ? nothing + ? html`

+ ${localize( + "ui.panel.config.integrations.config_flow.created_config", + { name: this.step.title } + )} +

` : html` -

- ${localize( - "ui.panel.config.integrations.config_flow.found_following_devices" - )}: -

${devices.map( (device) => html`
-
- ${computeDeviceNameDisplay(device, this.hass)}
- ${!device.model && !device.manufacturer - ? html` ` - : html`${device.model} - ${device.manufacturer - ? html`(${device.manufacturer})` - : ""}`} +
+ ${this.step.result?.domain + ? html`${domainToName(` + : nothing} +
+ ${device.model || device.manufacturer} + ${device.model + ? html` + ${device.manufacturer} + ` + : nothing} +
+
@@ -146,14 +193,32 @@ class StepFlowCreateEntry extends LitElement {
${localize( - "ui.panel.config.integrations.config_flow.finish" + `ui.panel.config.integrations.config_flow.${!devices.length || Object.keys(this._deviceUpdate).length ? "finish" : "finish_skip"}` )}
`; } - private _flowDone(): void { + private async _flowDone(): Promise { + if (Object.keys(this._deviceUpdate).length) { + await Promise.all( + Object.entries(this._deviceUpdate).map(([deviceId, update]) => + updateDeviceRegistryEntry(this.hass, deviceId, { + name_by_user: update.name, + area_id: update.area, + }).catch((err: any) => { + showAlertDialog(this, { + text: this.hass.localize( + "ui.panel.config.integrations.config_flow.error_saving_device", + { error: err.message } + ), + }); + }) + ) + ); + } + fireEvent(this, "flow-update", { step: undefined }); if (this.step.result && this.navigateToResult) { navigate( @@ -165,21 +230,25 @@ class StepFlowCreateEntry extends LitElement { private async _areaPicked(ev: CustomEvent) { const picker = ev.currentTarget as any; const device = picker.device; - const area = ev.detail.value; - try { - await updateDeviceRegistryEntry(this.hass, device, { - area_id: area, - }); - } catch (err: any) { - showAlertDialog(this, { - text: this.hass.localize( - "ui.panel.config.integrations.config_flow.error_saving_area", - { error: err.message } - ), - }); - picker.value = null; + + if (!(device in this._deviceUpdate)) { + this._deviceUpdate[device] = {}; } + this._deviceUpdate[device].area = area; + this.requestUpdate("_deviceUpdate"); + } + + private _deviceNameChanged(ev): void { + const picker = ev.currentTarget as any; + const device = picker.device; + const name = picker.value; + + if (!(device in this._deviceUpdate)) { + this._deviceUpdate[device] = {}; + } + this._deviceUpdate[device].name = name; + this.requestUpdate("_deviceUpdate"); } static get styles(): CSSResultGroup { @@ -188,18 +257,41 @@ class StepFlowCreateEntry extends LitElement { css` .devices { display: flex; - flex-wrap: wrap; margin: -4px; max-height: 600px; overflow-y: auto; + flex-direction: column; } .device { border: 1px solid var(--divider-color); - padding: 5px; + padding: 6px; border-radius: 4px; margin: 4px; display: inline-block; - width: 250px; + } + .device-info { + display: flex; + align-items: center; + gap: 8px; + } + .device-info img { + width: 40px; + height: 40px; + } + .device-info-details { + display: flex; + flex-direction: column; + justify-content: center; + } + .secondary { + color: var(--secondary-text-color); + } + ha-textfield, + ha-area-picker { + display: block; + } + ha-textfield { + margin: 8px 0; } .buttons > *:last-child { margin-left: auto; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts index 0c411f8ad6..dca4ce1cd2 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts @@ -189,7 +189,7 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) { } catch (err: any) { showAlertDialog(this, { text: this.hass.localize( - "ui.panel.config.integrations.config_flow.error_saving_area", + "ui.panel.config.integrations.config_flow.error_saving_device", { error: err.message } ), }); diff --git a/src/translations/en.json b/src/translations/en.json index 990c7a5079..1624b08491 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5304,19 +5304,21 @@ }, "config_flow": { "success": "Success", + "assign_area": "Assign {number, plural,\n one {device}\n other {devices}\n} to area", + "device_name": "Device name", "aborted": "Aborted", "close": "Close", "finish": "Finish", + "finish_skip": "Skip and finish", "submit": "Submit", "next": "Next", "preview": "Preview", - "found_following_devices": "We found the following devices", "yaml_only_title": "This integration cannot be added from the UI", "yaml_only": "You can add this integration by adding it to your ''configuration.yaml''. See the documentation for more information.", "open_documentation": "Open documentation", "no_config_flow": "This integration does not support configuration via the UI. If you followed this link from the Home Assistant website, make sure you run the latest version of Home Assistant.", "not_all_required_fields": "Not all required fields are filled in.", - "error_saving_area": "Error saving area: {error}", + "error_saving_device": "Error updating device: {error}", "created_config": "Created configuration for {name}.", "external_step": { "description": "This step requires you to visit an external website to be completed.",