diff --git a/src/auth/ha-auth-external.ts b/src/auth/ha-auth-external.ts new file mode 100644 index 000000000000..fdb8c9c16286 --- /dev/null +++ b/src/auth/ha-auth-external.ts @@ -0,0 +1,82 @@ +import type { CSSResultGroup, TemplateResult } from "lit"; +import { css, html } from "lit"; +import { customElement, property } from "lit/decorators"; +import type { DataEntryFlowStepExternal } from "../data/data_entry_flow"; +import { fireEvent } from "../common/dom/fire_event"; +import type { LocalizeFunc } from "../common/translations/localize"; +import { HaForm } from "../components/ha-form/ha-form"; + +@customElement("ha-auth-external") +export class HaAuthExternal extends HaForm { + @property({ attribute: false }) public localize!: LocalizeFunc; + + @property({ attribute: false }) public stepTitle?: string; + + @property({ attribute: false }) public step!: DataEntryFlowStepExternal; + + @property({ attribute: false }) public blocked = false; + + protected render(): TemplateResult { + return html` +

${this.stepTitle}

+
+ ${this.localize("ui.panel.page-authorize.external.description")} + ${this.blocked + ? html` + ${this.localize("ui.panel.page-authorize.external.popup_blocked")} + ` + : ""} +
+ + ${this.localize("ui.panel.page-authorize.external.open_site")} + +
+
+ `; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + this._openExternalStep(); + } + + private _openExternalStep() { + const externalWindow = window.open(this.step.url); + this.blocked = externalWindow == null; + if (this.blocked) { + return; + } + window.addEventListener("message", async (message: MessageEvent) => { + if ( + message.origin === window.location.origin && + message.source === externalWindow && + message.data.type === "externalCallback" + ) { + fireEvent(this, "step-finished"); + } + }); + } + + static get styles(): CSSResultGroup { + return [ + css` + .open-button { + text-align: center; + padding: 24px 0; + } + .open-button a { + text-decoration: none; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-auth-external": HaAuthExternal; + } + interface HASSDomEvents { + "step-finished": undefined; + } +} diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts index 2adce4d34786..6fd50df55973 100644 --- a/src/auth/ha-auth-flow.ts +++ b/src/auth/ha-auth-flow.ts @@ -23,6 +23,7 @@ import type { DataEntryFlowStepForm, } from "../data/data_entry_flow"; import "./ha-auth-form"; +import "./ha-auth-external"; type State = "loading" | "error" | "step"; @@ -171,18 +172,7 @@ export class HaAuthFlow extends LitElement { } return html` - ${this._renderStep(this.step)} -
- - ${this.step.type === "form" - ? this.localize("ui.panel.page-authorize.form.next") - : this.localize("ui.panel.page-authorize.form.start_over")} - -
+ ${this._renderStep(this.step)} ${this._renderAction(this.step)} `; case "error": return html` @@ -266,11 +256,35 @@ export class HaAuthFlow extends LitElement { ` : ""} `; + case "external": + return html``; default: return nothing; } } + private _renderAction(step: DataEntryFlowStep) { + if (step.type === "external") { + return nothing; + } + return html`
+ + ${step.type === "form" + ? this.localize("ui.panel.page-authorize.form.next") + : this.localize("ui.panel.page-authorize.form.start_over")} + +
`; + } + private _storeTokenChanged(e: CustomEvent) { this._storeToken = (e.currentTarget as HTMLInputElement).checked; } @@ -359,12 +373,14 @@ export class HaAuthFlow extends LitElement { this._providerChanged(this.authProvider); } - private async _handleSubmit(ev: Event) { - ev.preventDefault(); + private async _handleSubmit(ev?: Event) { + if (ev) { + ev.preventDefault(); + } if (this.step == null) { return; } - if (this.step.type !== "form") { + if (this.step.type !== "form" && this.step.type !== "external") { this._providerChanged(this.authProvider); return; } @@ -403,6 +419,10 @@ export class HaAuthFlow extends LitElement { this._submitting = false; } } + + private _externalStepFinished(_ev: CustomEvent) { + this._handleSubmit(); + } } declare global { diff --git a/src/translations/en.json b/src/translations/en.json index e8bfe80a397a..24c2798232e3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -7144,6 +7144,11 @@ } } } + }, + "external": { + "description": "This step requires you to visit an external website to be completed.", + "open_site": "Open website", + "popup_blocked": "Could not open external website because a popup was blocked. Please allow to continue." } }, "page-demo": {