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",