import { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item-base";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { fireEvent } from "../../../common/dom/fire_event";
import {
protocolIntegrationPicked,
PROTOCOL_INTEGRATIONS,
} from "../../../common/integrations/protocolIntegrationPicked";
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
import { navigate } from "../../../common/navigate";
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
import { localizeConfigFlowTitle } from "../../../data/config_flow";
import { DataEntryFlowProgress } from "../../../data/data_entry_flow";
import {
domainToName,
fetchIntegrationManifest,
} from "../../../data/integration";
import { Brand, Integration } from "../../../data/integrations";
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import "./ha-integration-list-item";
import { showYamlIntegrationDialog } from "./show-add-integration-dialog";
const standardToDomain = { zigbee: "zha", zwave: "zwave_js" } as const;
@customElement("ha-domain-integrations")
class HaDomainIntegrations extends LitElement {
public hass!: HomeAssistant;
@property() public domain!: string;
@property({ attribute: false }) public integration?: Brand | Integration;
@property({ attribute: false })
public flowsInProgress?: DataEntryFlowProgress[];
protected render() {
return html`
${this.flowsInProgress?.length
? html`
${this.hass.localize("ui.panel.config.integrations.discovered")}
${this.flowsInProgress.map(
(flow) =>
html`
${localizeConfigFlowTitle(this.hass.localize, flow)}
`
)}
${this.integration &&
"integrations" in this.integration &&
this.integration.integrations
? html`
${this.hass.localize(
"ui.panel.config.integrations.available_integrations"
)}
`
: ""}`
: ""}
${this.integration?.iot_standards
? this.integration.iot_standards
.filter((standard) =>
(PROTOCOL_INTEGRATIONS as ReadonlyArray).includes(
standardToDomain[standard] || standard
)
)
.map((standard) => {
const domain: (typeof PROTOCOL_INTEGRATIONS)[number] =
standardToDomain[standard] || standard;
return html`
${this.hass.localize(
`ui.panel.config.integrations.add_${domain}_device`
)}
`;
})
: ""}
${this.integration &&
"integrations" in this.integration &&
this.integration.integrations
? Object.entries(this.integration.integrations)
.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]),
this.hass.locale.language
);
})
.map(
([dom, val]) =>
html`
`
)
: ""}
${(PROTOCOL_INTEGRATIONS as ReadonlyArray).includes(this.domain)
? html`
${this.hass.localize(
`ui.panel.config.integrations.add_${
this.domain as (typeof PROTOCOL_INTEGRATIONS)[number]
}_device`
)}
`
: ""}
${this.integration &&
"config_flow" in this.integration &&
this.integration.config_flow
? html`${this.flowsInProgress?.length
? html`
${this.hass.localize("ui.panel.config.integrations.new_flow", {
integration:
this.integration.name ||
domainToName(this.hass.localize, this.domain),
})}
`
: html`
`}`
: ""}
`;
}
private async _integrationPicked(ev: CustomEvent) {
if (!shouldHandleRequestSelectedEvent(ev)) {
return;
}
const domain = (ev.currentTarget as any).domain;
if (
["cloud", "google_assistant", "alexa"].includes(domain) &&
isComponentLoaded(this.hass, "cloud")
) {
fireEvent(this, "close-dialog");
navigate("/config/cloud");
return;
}
const integration = (ev.currentTarget as any).integration;
if (integration.supported_by) {
// @ts-ignore
fireEvent(this, "supported-by", { integration });
return;
}
if (integration.iot_standards) {
// @ts-ignore
fireEvent(this, "select-brand", {
brand: integration.domain,
});
return;
}
if (
(domain === this.domain &&
(("integration_type" in this.integration! &&
!this.integration.config_flow) ||
(!("integration_type" in this.integration!) &&
(!this.integration!.integrations ||
!(domain in this.integration!.integrations))))) ||
// config_flow being undefined means its false
(!("integration_type" in this.integration!) &&
!this.integration!.integrations?.[domain]?.config_flow)
) {
const manifest = await fetchIntegrationManifest(this.hass, domain);
showYamlIntegrationDialog(this, { manifest });
return;
}
const root = this.getRootNode();
showConfigFlowDialog(
root instanceof ShadowRoot ? (root.host as HTMLElement) : this,
{
startFlowHandler: domain,
showAdvanced: this.hass.userData?.showAdvanced,
manifest: await fetchIntegrationManifest(this.hass, domain),
}
);
fireEvent(this, "close-dialog");
}
private async _flowInProgressPicked(ev: CustomEvent) {
if (!shouldHandleRequestSelectedEvent(ev)) {
return;
}
const flow: DataEntryFlowProgress = (ev.currentTarget as any).flow;
const root = this.getRootNode();
showConfigFlowDialog(
root instanceof ShadowRoot ? (root.host as HTMLElement) : this,
{
continueFlowId: flow.flow_id,
showAdvanced: this.hass.userData?.showAdvanced,
manifest: await fetchIntegrationManifest(this.hass, flow.handler),
}
);
fireEvent(this, "close-dialog");
}
private _standardPicked(ev: CustomEvent) {
if (!shouldHandleRequestSelectedEvent(ev)) {
return;
}
const domain = (ev.currentTarget as any).domain;
const root = this.getRootNode();
fireEvent(this, "close-dialog");
protocolIntegrationPicked(
root instanceof ShadowRoot ? (root.host as HTMLElement) : this,
this.hass,
domain,
{ brand: this.domain }
);
}
static styles = [
haStyle,
css`
:host {
display: block;
--mdc-list-item-graphic-size: 40px;
--mdc-list-side-padding: 24px;
}
h3 {
margin: 8px 24px 0;
color: var(--secondary-text-color);
font-size: 14px;
font-weight: 500;
}
h3:first-of-type {
margin-top: 0;
}
img {
width: 40px;
height: 40px;
}
li[divider] {
margin-top: 8px;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-domain-integrations": HaDomainIntegrations;
}
}