Add support for Supported Brands (#13184)

This commit is contained in:
Zack Barett 2022-07-13 10:51:17 -05:00 committed by GitHub
parent 24e54554ad
commit b611a58fce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 120 additions and 31 deletions

View File

@ -0,0 +1,8 @@
import type { HomeAssistant } from "../types";
export type SupportedBrandHandler = Record<string, string>;
export const getSupportedBrands = (hass: HomeAssistant) =>
hass.callWS<Record<string, SupportedBrandHandler>>({
type: "supported_brands",
});

View File

@ -7,6 +7,7 @@ import {
handleConfigFlowStep, handleConfigFlowStep,
} from "../../data/config_flow"; } from "../../data/config_flow";
import { domainToName } from "../../data/integration"; import { domainToName } from "../../data/integration";
import { getSupportedBrands } from "../../data/supported_brands";
import { import {
DataEntryFlowDialogParams, DataEntryFlowDialogParams,
loadDataEntryFlowDialog, loadDataEntryFlowDialog,
@ -22,12 +23,14 @@ export const showConfigFlowDialog = (
showFlowDialog(element, dialogParams, { showFlowDialog(element, dialogParams, {
loadDevicesAndAreas: true, loadDevicesAndAreas: true,
getFlowHandlers: async (hass) => { getFlowHandlers: async (hass) => {
const [integrations, helpers] = await Promise.all([ const [integrations, helpers, supportedBrands] = await Promise.all([
getConfigFlowHandlers(hass, "integration"), getConfigFlowHandlers(hass, "integration"),
getConfigFlowHandlers(hass, "helper"), getConfigFlowHandlers(hass, "helper"),
getSupportedBrands(hass),
hass.loadBackendTranslation("title", undefined, true), hass.loadBackendTranslation("title", undefined, true),
]); ]);
return { integrations, helpers };
return { integrations, helpers, supportedBrands };
}, },
createFlow: async (hass, handler) => { createFlow: async (hass, handler) => {
const [step] = await Promise.all([ const [step] = await Promise.all([

View File

@ -10,12 +10,14 @@ import {
DataEntryFlowStepMenu, DataEntryFlowStepMenu,
DataEntryFlowStepProgress, DataEntryFlowStepProgress,
} from "../../data/data_entry_flow"; } from "../../data/data_entry_flow";
import { IntegrationManifest } from "../../data/integration"; import type { IntegrationManifest } from "../../data/integration";
import { HomeAssistant } from "../../types"; import type { SupportedBrandHandler } from "../../data/supported_brands";
import type { HomeAssistant } from "../../types";
export interface FlowHandlers { export interface FlowHandlers {
integrations: string[]; integrations: string[];
helpers: string[]; helpers: string[];
supportedBrands: Record<string, SupportedBrandHandler>;
} }
export interface FlowConfig { export interface FlowConfig {
loadDevicesAndAreas: boolean; loadDevicesAndAreas: boolean;

View File

@ -1,5 +1,6 @@
import "@polymer/paper-item"; import "@polymer/paper-item";
import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item-body";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";

View File

@ -15,18 +15,19 @@ import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import "../../components/search-input";
import { caseInsensitiveStringCompare } from "../../common/string/compare"; import { caseInsensitiveStringCompare } from "../../common/string/compare";
import { LocalizeFunc } from "../../common/translations/localize"; import { LocalizeFunc } from "../../common/translations/localize";
import "../../components/ha-icon-next"; import "../../components/ha-icon-next";
import "../../components/search-input";
import { getConfigEntries } from "../../data/config_entries"; import { getConfigEntries } from "../../data/config_entries";
import { domainToName } from "../../data/integration"; import { domainToName } from "../../data/integration";
import { showZWaveJSAddNodeDialog } from "../../panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node"; import { showZWaveJSAddNodeDialog } from "../../panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-add-node";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { brandsUrl } from "../../util/brands-url"; import { brandsUrl } from "../../util/brands-url";
import { documentationUrl } from "../../util/documentation-url"; import { documentationUrl } from "../../util/documentation-url";
import { configFlowContentStyles } from "./styles"; import { showConfirmationDialog } from "../generic/show-dialog-box";
import { FlowHandlers } from "./show-dialog-data-entry-flow"; import { FlowHandlers } from "./show-dialog-data-entry-flow";
import { configFlowContentStyles } from "./styles";
interface HandlerObj { interface HandlerObj {
name: string; name: string;
@ -35,6 +36,10 @@ interface HandlerObj {
is_helper?: boolean; is_helper?: boolean;
} }
interface SupportedBrandObj extends HandlerObj {
supported_flows: string[];
}
declare global { declare global {
// for fire event // for fire event
interface HASSDomEvents { interface HASSDomEvents {
@ -63,11 +68,22 @@ class StepFlowPickHandler extends LitElement {
h: FlowHandlers, h: FlowHandlers,
filter?: string, filter?: string,
_localize?: LocalizeFunc _localize?: LocalizeFunc
): [HandlerObj[], HandlerObj[]] => { ): [(HandlerObj | SupportedBrandObj)[], HandlerObj[]] => {
const integrations: HandlerObj[] = h.integrations.map((handler) => ({ const integrations: (HandlerObj | SupportedBrandObj)[] =
name: domainToName(this.hass.localize, handler), h.integrations.map((handler) => ({
slug: handler, name: domainToName(this.hass.localize, handler),
})); slug: handler,
}));
for (const [domain, domainBrands] of Object.entries(h.supportedBrands)) {
for (const [slug, name] of Object.entries(domainBrands)) {
integrations.push({
slug,
name,
supported_flows: [domain],
});
}
}
if (filter) { if (filter) {
const options: Fuse.IFuseOptions<HandlerObj> = { const options: Fuse.IFuseOptions<HandlerObj> = {
@ -238,27 +254,10 @@ class StepFlowPickHandler extends LitElement {
} }
private async _handlerPicked(ev) { private async _handlerPicked(ev) {
const handler: HandlerObj = ev.currentTarget.handler; const handler: HandlerObj | SupportedBrandObj = ev.currentTarget.handler;
if (handler.is_add) { if (handler.is_add) {
if (handler.slug === "zwave_js") { this._handleAddPicked(handler.slug);
const entries = await getConfigEntries(this.hass, {
domain: "zwave_js",
});
if (!entries.length) {
return;
}
showZWaveJSAddNodeDialog(this, {
entry_id: entries[0].entry_id,
});
} else if (handler.slug === "zha") {
navigate("/config/zha/add");
}
// This closes dialog.
fireEvent(this, "flow-update");
return; return;
} }
@ -269,11 +268,84 @@ class StepFlowPickHandler extends LitElement {
return; return;
} }
if ("supported_flows" in handler) {
const slug = handler.supported_flows[0];
showConfirmationDialog(this, {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.supported_brand_flow",
{
supported_brand: handler.name,
flow_domain_name: domainToName(this.hass.localize, slug),
}
),
confirm: () => {
if (["zha", "zwave_js"].includes(slug)) {
this._handleAddPicked(slug);
return;
}
fireEvent(this, "handler-picked", {
handler: slug,
});
},
});
return;
}
fireEvent(this, "handler-picked", { fireEvent(this, "handler-picked", {
handler: handler.slug, handler: handler.slug,
}); });
} }
private async _handleAddPicked(slug: string): Promise<void> {
if (slug === "zwave_js") {
const entries = await getConfigEntries(this.hass, {
domain: "zwave_js",
});
if (!entries.length) {
// If the component isn't loaded, ask them to load the integration first
showConfirmationDialog(this, {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.missing_zwave_js"
),
confirm: () => {
fireEvent(this, "handler-picked", {
handler: "zwave_js",
});
},
});
return;
}
showZWaveJSAddNodeDialog(this, {
entry_id: entries[0].entry_id,
});
} else if (slug === "zha") {
// If the component isn't loaded, ask them to load the integration first
if (!isComponentLoaded(this.hass, "zha")) {
showConfirmationDialog(this, {
text: this.hass.localize(
"ui.panel.config.integrations.config_flow.missing_zha"
),
confirm: () => {
fireEvent(this, "handler-picked", {
handler: "zha",
});
},
});
return;
}
navigate("/config/zha/add");
}
// This closes dialog.
fireEvent(this, "flow-update");
}
private _maybeSubmit(ev: KeyboardEvent) { private _maybeSubmit(ev: KeyboardEvent) {
if (ev.key !== "Enter") { if (ev.key !== "Enter") {
return; return;

View File

@ -2850,7 +2850,10 @@
"error": "Error", "error": "Error",
"could_not_load": "Config flow could not be loaded", "could_not_load": "Config flow could not be loaded",
"not_loaded": "The integration could not be loaded, try to restart Home Assistant.", "not_loaded": "The integration could not be loaded, try to restart Home Assistant.",
"missing_credentials": "Setting up {integration} requires configuring application credentials. Do you want to do that now?" "missing_credentials": "Setting up {integration} requires configuring application credentials. Do you want to do that now?",
"supported_brand_flow": "Support for {supported_brand} devices is provided by {flow_domain_name}. Do you want to continue?",
"missing_zwave_js": "To add a Z-Wave device, you first need to set up the Z-Wave integration. Do you want to do that now?",
"missing_zha": "To add a Zigbee device, you first need to set up the Zigbee Home Automation integration. Do you want to do that now?"
} }
}, },
"users": { "users": {