From 8d2f7d99afa88a6aae0e4d812f0bb7509bf4b480 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 29 Sep 2022 14:32:24 +0200 Subject: [PATCH] Fixes for add integration (#13914) --- .../integrations/protocolIntegrationPicked.ts | 2 +- src/data/integrations.ts | 2 +- .../integrations/dialog-add-integration.ts | 59 ++++++++++++++++--- .../integrations/ha-domain-integrations.ts | 20 +++++-- .../integrations/ha-integration-list-item.ts | 27 ++++----- src/translations/en.json | 2 +- 6 files changed, 84 insertions(+), 28 deletions(-) diff --git a/src/common/integrations/protocolIntegrationPicked.ts b/src/common/integrations/protocolIntegrationPicked.ts index 4af63a34b1..0cebbea25b 100644 --- a/src/common/integrations/protocolIntegrationPicked.ts +++ b/src/common/integrations/protocolIntegrationPicked.ts @@ -18,7 +18,7 @@ export const protocolIntegrationPicked = async ( domain: "zwave_js", }); - if (!entries.length) { + if (!isComponentLoaded(hass, "zwave_js") || !entries.length) { // If the component isn't loaded, ask them to load the integration first showConfirmationDialog(element, { text: hass.localize( diff --git a/src/data/integrations.ts b/src/data/integrations.ts index 70c799b154..fb09c44fcf 100644 --- a/src/data/integrations.ts +++ b/src/data/integrations.ts @@ -1,6 +1,6 @@ import { HomeAssistant } from "../types"; -export type IotStandards = "z-wave" | "zigbee" | "homekit" | "matter"; +export type IotStandards = "zwave" | "zigbee" | "homekit" | "matter"; export interface Integration { name?: string; diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index 1ea5fa8f7a..0d142feb9b 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -22,6 +22,7 @@ import { } from "../../../data/integration"; import { getIntegrationDescriptions, + Integration, Integrations, } from "../../../data/integrations"; import { @@ -173,11 +174,12 @@ class AddIntegrationDialog extends LitElement { })); for (const [domain, domainBrands] of Object.entries(sb)) { - const integration = i[domain]; + const integration = this._findIntegration(domain); if ( - !integration.config_flow && - !integration.iot_standards && - !integration.integrations + !integration || + (!integration.config_flow && + !integration.iot_standards && + !integration.integrations) ) { continue; } @@ -221,10 +223,33 @@ class AddIntegrationDialog extends LitElement { is_built_in: integration.is_built_in !== false, cloud: integration.iot_class?.startsWith("cloud_"), })); + const yaml: IntegrationListItem[] = Object.entries(i) + .filter( + ([_domain, integration]) => + !integration.config_flow && + !integration.iot_standards && + !integration.integrations + ) + .map(([domain, integration]) => ({ + domain, + name: integration.name || domainToName(localize, domain), + config_flow: integration.config_flow, + iot_standards: integration.iot_standards, + integrations: integration.integrations + ? Object.entries(integration.integrations).map( + ([dom, val]) => val.name || domainToName(localize, dom) + ) + : undefined, + is_built_in: integration.is_built_in !== false, + cloud: integration.iot_class?.startsWith("cloud_"), + })); return [ ...new Fuse(integrations, options) .search(filter) .map((result) => result.item), + ...new Fuse(yaml, options) + .search(filter) + .map((result) => result.item), ...new Fuse(helpers, options) .search(filter) .map((result) => result.item), @@ -239,6 +264,21 @@ class AddIntegrationDialog extends LitElement { } ); + private _findIntegration(domain: string): Integration | undefined { + if (!this._integrations) { + return undefined; + } + if (domain in this._integrations) { + return this._integrations[domain]; + } + for (const integration of Object.values(this._integrations)) { + if (integration.integrations && domain in integration.integrations) { + return integration.integrations[domain]; + } + } + return undefined; + } + private _getIntegrations() { return this._filterIntegrations( this._integrations!, @@ -424,7 +464,7 @@ class AddIntegrationDialog extends LitElement { } ), confirm: () => { - const supportIntegration = this._integrations?.[domain]; + const supportIntegration = this._findIntegration(domain); this.closeDialog(); if (["zha", "zwave_js"].includes(domain)) { protocolIntegrationPicked(this, this.hass, domain); @@ -518,8 +558,8 @@ class AddIntegrationDialog extends LitElement { > ${this.hass.localize( "ui.panel.config.integrations.config_flow.documentation" - )} - ` + )}` : this.hass.localize( "ui.panel.config.integrations.config_flow.documentation" ), @@ -584,6 +624,11 @@ class AddIntegrationDialog extends LitElement { haStyleScrollbar, haStyleDialog, css` + @media all and (min-width: 550px) { + ha-dialog { + --mdc-dialog-min-width: 500px; + } + } ha-dialog { --dialog-content-padding: 0; } diff --git a/src/panels/config/integrations/ha-domain-integrations.ts b/src/panels/config/integrations/ha-domain-integrations.ts index bdba6a3653..80c1b85729 100644 --- a/src/panels/config/integrations/ha-domain-integrations.ts +++ b/src/panels/config/integrations/ha-domain-integrations.ts @@ -2,6 +2,7 @@ import { css, html, LitElement } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { protocolIntegrationPicked } from "../../../common/integrations/protocolIntegrationPicked"; +import { caseInsensitiveStringCompare } from "../../../common/string/compare"; import { localizeConfigFlowTitle } from "../../../data/config_flow"; import { DataEntryFlowProgress } from "../../../data/data_entry_flow"; import { @@ -17,7 +18,7 @@ import { brandsUrl } from "../../../util/brands-url"; import { documentationUrl } from "../../../util/documentation-url"; import "./ha-integration-list-item"; -const standardToDomain = { zigbee: "zha", "z-wave": "zwave_js" } as const; +const standardToDomain = { zigbee: "zha", zwave: "zwave_js" } as const; @customElement("ha-domain-integrations") class HaDomainIntegrations extends LitElement { @@ -90,7 +91,18 @@ class HaDomainIntegrations extends LitElement { : ""} ${this.integration?.integrations ? Object.entries(this.integration.integrations) - .filter(([_dom, val]) => val.config_flow) + .sort((a, b) => { + if (a[1].config_flow && !b[1].config_flow) { + return -1; + } + if (b[1].config_flow && !a[1].config_flow) { + return 0; + } + return caseInsensitiveStringCompare( + a[1].name || domainToName(this.hass.localize, a[0]), + b[1].name || domainToName(this.hass.localize, b[0]) + ); + }) .map( ([dom, val]) => html` ${this.hass.localize( "ui.panel.config.integrations.config_flow.documentation" - )} - ` + )}` : this.hass.localize( "ui.panel.config.integrations.config_flow.documentation" ), diff --git a/src/panels/config/integrations/ha-integration-list-item.ts b/src/panels/config/integrations/ha-integration-list-item.ts index 26f28b5051..714f15d667 100644 --- a/src/panels/config/integrations/ha-integration-list-item.ts +++ b/src/panels/config/integrations/ha-integration-list-item.ts @@ -3,7 +3,7 @@ import { ListItemBase, } from "@material/mwc-list/mwc-list-item-base"; import { styles } from "@material/mwc-list/mwc-list-item.css"; -import { mdiCloudOutline, mdiCodeBraces, mdiPackageVariant } from "@mdi/js"; +import { mdiCloudOutline, mdiOpenInNew, mdiPackageVariant } from "@mdi/js"; import { css, CSSResultGroup, html } from "lit"; import { classMap } from "lit/directives/class-map"; import { customElement, property } from "lit/decorators"; @@ -62,18 +62,6 @@ export class HaIntegrationListItem extends ListItemBase { return html``; } return html` - ${!this.integration.config_flow && - !this.integration.integrations && - !this.integration.iot_standards - ? html`${this.hass.localize( - "ui.panel.config.integrations.config_entry.yaml_only" - )}` - : ""} ${this.integration.cloud ? html`` : ""} - + ${!this.integration.config_flow && + !this.integration.integrations && + !this.integration.iot_standards + ? html`${this.hass.localize( + "ui.panel.config.integrations.config_entry.yaml_only" + )}` + : html``} `; } @@ -129,6 +127,7 @@ export class HaIntegrationListItem extends ListItemBase { } .mdc-deprecated-list-item__meta { width: auto; + white-space: nowrap; } .mdc-deprecated-list-item__meta > * { margin-right: 8px; diff --git a/src/translations/en.json b/src/translations/en.json index 17f8b9e441..6def4400c0 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2935,7 +2935,7 @@ }, "provided_by_custom_integration": "Provided by a custom integration", "depends_on_cloud": "Depends on the cloud", - "yaml_only": "Can not be setup from the UI", + "yaml_only": "Needs manual configuration", "disabled_polling": "Automatic polling for updated data disabled", "state": { "loaded": "Loaded",