From e4302a0bb5b2dd2ce29dc4ee3f33aafe10c05933 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Fri, 14 Apr 2023 20:38:34 +0200 Subject: [PATCH] Fix onboarding add integration (#16163) --- src/auth/ha-auth-flow.ts | 6 +- src/auth/ha-authorize.ts | 3 +- src/auth/ha-pick-auth-provider.ts | 6 +- src/onboarding/onboarding-integrations.ts | 103 ++++++++++++---------- 4 files changed, 67 insertions(+), 51 deletions(-) diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts index 0577a0af7c..b5070dee73 100644 --- a/src/auth/ha-auth-flow.ts +++ b/src/auth/ha-auth-flow.ts @@ -9,6 +9,7 @@ import { PropertyValues, } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { LocalizeFunc } from "../common/translations/localize"; import "../components/ha-alert"; import "../components/ha-checkbox"; import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data"; @@ -20,13 +21,12 @@ import { DataEntryFlowStep, DataEntryFlowStepForm, } from "../data/data_entry_flow"; -import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; import "./ha-password-manager-polyfill"; type State = "loading" | "error" | "step"; @customElement("ha-auth-flow") -export class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { +export class HaAuthFlow extends LitElement { @property({ attribute: false }) public authProvider?: AuthProvider; @property() public clientId?: string; @@ -35,6 +35,8 @@ export class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { @property() public oauth2State?: string; + @property() public localize!: LocalizeFunc; + @state() private _state: State = "loading"; @state() private _stepData?: Record; diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts index 9f780facc2..deadcf765e 100644 --- a/src/auth/ha-authorize.ts +++ b/src/auth/ha-authorize.ts @@ -82,12 +82,13 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) { .redirectUri=${this.redirectUri} .oauth2State=${this.oauth2State} .authProvider=${this._authProvider} + .localize=${this.localize} > ${inactiveProviders.length > 0 ? html` ${this.localize("ui.panel.page-authorize.pick_auth_provider")}:

diff --git a/src/onboarding/onboarding-integrations.ts b/src/onboarding/onboarding-integrations.ts index 519499721c..f972609dfb 100644 --- a/src/onboarding/onboarding-integrations.ts +++ b/src/onboarding/onboarding-integrations.ts @@ -1,20 +1,21 @@ import "@material/mwc-button/mwc-button"; import { mdiCheck, mdiDotsHorizontal } from "@mdi/js"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResultGroup, html, LitElement, + nothing, PropertyValues, TemplateResult, - nothing, } from "lit"; import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../common/config/is_component_loaded"; import { fireEvent } from "../common/dom/fire_event"; import { stringCompare } from "../common/string/compare"; import { LocalizeFunc } from "../common/translations/localize"; -import { ConfigEntry, getConfigEntries } from "../data/config_entries"; +import { ConfigEntry, subscribeConfigEntries } from "../data/config_entries"; import { getConfigFlowInProgressCollection, localizeConfigFlowTitle, @@ -27,6 +28,8 @@ import { loadConfigFlowDialog, showConfigFlowDialog, } from "../dialogs/config-flow/show-dialog-config-flow"; +import { SubscribeMixin } from "../mixins/subscribe-mixin"; +import { showAddIntegrationDialog } from "../panels/config/integrations/show-add-integration-dialog"; import { HomeAssistant } from "../types"; import "./action-badge"; import "./integration-badge"; @@ -40,7 +43,7 @@ const HIDDEN_DOMAINS = new Set([ ]); @customElement("onboarding-integrations") -class OnboardingIntegrations extends LitElement { +class OnboardingIntegrations extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @property() public onboardingLocalize!: LocalizeFunc; @@ -49,30 +52,56 @@ class OnboardingIntegrations extends LitElement { @state() private _discovered?: DataEntryFlowProgress[]; - private _unsubEvents?: () => void; - - public connectedCallback() { - super.connectedCallback(); - this.hass.loadBackendTranslation("title", undefined, true); - this._unsubEvents = subscribeConfigFlowInProgress(this.hass, (flows) => { - this._discovered = flows; - const integrations: Set = new Set(); - for (const flow of flows) { - // To render title placeholders - if (flow.context.title_placeholders) { - integrations.add(flow.handler); + public hassSubscribe(): Array> { + return [ + subscribeConfigFlowInProgress(this.hass, (flows) => { + this._discovered = flows; + const integrations: Set = new Set(); + for (const flow of flows) { + // To render title placeholders + if (flow.context.title_placeholders) { + integrations.add(flow.handler); + } } - } - this.hass.loadBackendTranslation("config", Array.from(integrations)); - }); - } - - public disconnectedCallback() { - super.disconnectedCallback(); - if (this._unsubEvents) { - this._unsubEvents(); - this._unsubEvents = undefined; - } + this.hass.loadBackendTranslation("config", Array.from(integrations)); + }), + subscribeConfigEntries( + this.hass, + (messages) => { + let fullUpdate = false; + const newEntries: ConfigEntry[] = []; + messages.forEach((message) => { + if (message.type === null || message.type === "added") { + if (HIDDEN_DOMAINS.has(message.entry.domain)) { + return; + } + newEntries.push(message.entry); + if (message.type === null) { + fullUpdate = true; + } + } else if (message.type === "removed") { + this._entries = this._entries!.filter( + (entry) => entry.entry_id !== message.entry.entry_id + ); + } else if (message.type === "updated") { + if (HIDDEN_DOMAINS.has(message.entry.domain)) { + return; + } + const newEntry = message.entry; + this._entries = this._entries!.map((entry) => + entry.entry_id === newEntry.entry_id ? newEntry : entry + ); + } + }); + if (!newEntries.length && !fullUpdate) { + return; + } + const existingEntries = fullUpdate ? [] : this._entries; + this._entries = [...existingEntries!, ...newEntries]; + }, + { type: ["device", "hub", "service"] } + ), + ]; } protected render() { @@ -149,25 +178,19 @@ class OnboardingIntegrations extends LitElement { protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); + this.hass.loadBackendTranslation("title", undefined, true); this._scanUSBDevices(); loadConfigFlowDialog(); - this._loadConfigEntries(); } private _createFlow() { - showConfigFlowDialog(this, { - dialogClosedCallback: () => { - this._loadConfigEntries(); - getConfigFlowInProgressCollection(this.hass!.connection).refresh(); - }, - }); + showAddIntegrationDialog(this); } private _continueFlow(ev) { showConfigFlowDialog(this, { continueFlowId: ev.currentTarget.flowId, dialogClosedCallback: () => { - this._loadConfigEntries(); getConfigFlowInProgressCollection(this.hass!.connection).refresh(); }, }); @@ -180,18 +203,6 @@ class OnboardingIntegrations extends LitElement { await scanUSBDevices(this.hass); } - private async _loadConfigEntries() { - const entries = await getConfigEntries(this.hass!, { - type: ["device", "hub", "service"], - }); - // We filter out the config entries that are automatically created during onboarding. - // It is one that we create automatically and it will confuse the user - // if it starts showing up during onboarding. - this._entries = entries.filter( - (entry) => !HIDDEN_DOMAINS.has(entry.domain) - ); - } - private async _finish() { fireEvent(this, "onboarding-step", { type: "integration",