mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 14:56:37 +00:00
Convert auth-flow to TypeScript/Lit (#3174)
* Change ha-pick-auth-provider to typescript * Convert auth-flow to TypeScript/Lit
This commit is contained in:
parent
32e68c1a4b
commit
8924a5f043
@ -1,270 +0,0 @@
|
|||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import "../components/ha-form";
|
|
||||||
import "../components/ha-markdown";
|
|
||||||
import { localizeLiteMixin } from "../mixins/localize-lite-mixin";
|
|
||||||
|
|
||||||
class HaAuthFlow extends localizeLiteMixin(PolymerElement) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
/* So we can set min-height to avoid jumping during loading */
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
margin: 24px 0 8px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<form>
|
|
||||||
<template is="dom-if" if='[[_equals(_state, "loading")]]'>
|
|
||||||
[[localize('ui.panel.page-authorize.form.working')]]:
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if='[[_equals(_state, "error")]]'>
|
|
||||||
<div class="error">Error: [[_errorMsg]]</div>
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if='[[_equals(_state, "step")]]'>
|
|
||||||
<template is="dom-if" if='[[_equals(_step.type, "abort")]]'>
|
|
||||||
[[localize('ui.panel.page-authorize.abort_intro')]]:
|
|
||||||
<ha-markdown
|
|
||||||
content="[[_computeStepAbortedReason(localize, _step)]]"
|
|
||||||
></ha-markdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template is="dom-if" if='[[_equals(_step.type, "form")]]'>
|
|
||||||
<template
|
|
||||||
is="dom-if"
|
|
||||||
if="[[_computeStepDescription(localize, _step)]]"
|
|
||||||
>
|
|
||||||
<ha-markdown
|
|
||||||
content="[[_computeStepDescription(localize, _step)]]"
|
|
||||||
allow-svg
|
|
||||||
></ha-markdown>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<ha-form
|
|
||||||
data="{{_stepData}}"
|
|
||||||
schema="[[_step.data_schema]]"
|
|
||||||
error="[[_step.errors]]"
|
|
||||||
compute-label="[[_computeLabelCallback(localize, _step)]]"
|
|
||||||
compute-error="[[_computeErrorCallback(localize, _step)]]"
|
|
||||||
></ha-form>
|
|
||||||
</template>
|
|
||||||
<div class="action">
|
|
||||||
<mwc-button raised on-click="_handleSubmit"
|
|
||||||
>[[_computeSubmitCaption(_step.type)]]</mwc-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</form>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
authProvider: {
|
|
||||||
type: Object,
|
|
||||||
observer: "_providerChanged",
|
|
||||||
},
|
|
||||||
clientId: String,
|
|
||||||
redirectUri: String,
|
|
||||||
oauth2State: String,
|
|
||||||
_state: {
|
|
||||||
type: String,
|
|
||||||
value: "loading",
|
|
||||||
},
|
|
||||||
_stepData: {
|
|
||||||
type: Object,
|
|
||||||
value: () => ({}),
|
|
||||||
},
|
|
||||||
_step: {
|
|
||||||
type: Object,
|
|
||||||
notify: true,
|
|
||||||
},
|
|
||||||
_errorMsg: String,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
super.ready();
|
|
||||||
|
|
||||||
this.addEventListener("keypress", (ev) => {
|
|
||||||
if (ev.keyCode === 13) {
|
|
||||||
this._handleSubmit(ev);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async _providerChanged(newProvider, oldProvider) {
|
|
||||||
if (oldProvider && this._step && this._step.type === "form") {
|
|
||||||
fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
|
||||||
method: "DELETE",
|
|
||||||
credentials: "same-origin",
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch("/auth/login_flow", {
|
|
||||||
method: "POST",
|
|
||||||
credentials: "same-origin",
|
|
||||||
body: JSON.stringify({
|
|
||||||
client_id: this.clientId,
|
|
||||||
handler: [newProvider.type, newProvider.id],
|
|
||||||
redirect_uri: this.redirectUri,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
// allow auth provider bypass the login form
|
|
||||||
if (data.type === "create_entry") {
|
|
||||||
this._redirect(data.result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateStep(data);
|
|
||||||
} else {
|
|
||||||
this.setProperties({
|
|
||||||
_state: "error",
|
|
||||||
_errorMsg: data.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.error("Error starting auth flow", err);
|
|
||||||
this.setProperties({
|
|
||||||
_state: "error",
|
|
||||||
_errorMsg: this.localize("ui.panel.page-authorize.form.unknown_error"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_redirect(authCode) {
|
|
||||||
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
|
|
||||||
let url = this.redirectUri;
|
|
||||||
if (!url.includes("?")) {
|
|
||||||
url += "?";
|
|
||||||
} else if (!url.endsWith("&")) {
|
|
||||||
url += "&";
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `code=${encodeURIComponent(authCode)}`;
|
|
||||||
|
|
||||||
if (this.oauth2State) {
|
|
||||||
url += `&state=${encodeURIComponent(this.oauth2State)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.location = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateStep(step) {
|
|
||||||
const props = {
|
|
||||||
_step: step,
|
|
||||||
_state: "step",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (
|
|
||||||
this._step &&
|
|
||||||
(step.flow_id !== this._step.flow_id ||
|
|
||||||
step.step_id !== this._step.step_id)
|
|
||||||
) {
|
|
||||||
props._stepData = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setProperties(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
_equals(a, b) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeSubmitCaption(stepType) {
|
|
||||||
return stepType === "form" ? "Next" : "Start over";
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeStepAbortedReason(localize, step) {
|
|
||||||
return localize(
|
|
||||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${
|
|
||||||
step.reason
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeStepDescription(localize, step) {
|
|
||||||
const args = [
|
|
||||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
|
|
||||||
step.step_id
|
|
||||||
}.description`,
|
|
||||||
];
|
|
||||||
const placeholders = step.description_placeholders || {};
|
|
||||||
Object.keys(placeholders).forEach((key) => {
|
|
||||||
args.push(key);
|
|
||||||
args.push(placeholders[key]);
|
|
||||||
});
|
|
||||||
return localize(...args);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeLabelCallback(localize, step) {
|
|
||||||
// Returns a callback for ha-form to calculate labels per schema object
|
|
||||||
return (schema) =>
|
|
||||||
localize(
|
|
||||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
|
|
||||||
step.step_id
|
|
||||||
}.data.${schema.name}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeErrorCallback(localize, step) {
|
|
||||||
// Returns a callback for ha-form to calculate error messages
|
|
||||||
return (error) =>
|
|
||||||
localize(
|
|
||||||
`ui.panel.page-authorize.form.providers.${
|
|
||||||
step.handler[0]
|
|
||||||
}.error.${error}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _handleSubmit(ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
if (this._step.type !== "form") {
|
|
||||||
this._providerChanged(this.authProvider, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._state = "loading";
|
|
||||||
// To avoid a jumping UI.
|
|
||||||
this.style.setProperty("min-height", `${this.offsetHeight}px`);
|
|
||||||
|
|
||||||
const postData = Object.assign({}, this._stepData, {
|
|
||||||
client_id: this.clientId,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
|
||||||
method: "POST",
|
|
||||||
credentials: "same-origin",
|
|
||||||
body: JSON.stringify(postData),
|
|
||||||
});
|
|
||||||
|
|
||||||
const newStep = await response.json();
|
|
||||||
|
|
||||||
if (newStep.type === "create_entry") {
|
|
||||||
this._redirect(newStep.result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._updateStep(newStep);
|
|
||||||
} catch (err) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.error("Error submitting step", err);
|
|
||||||
this._state = "error-loading";
|
|
||||||
} finally {
|
|
||||||
this.style.setProperty("min-height", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customElements.define("ha-auth-flow", HaAuthFlow);
|
|
296
src/auth/ha-auth-flow.ts
Normal file
296
src/auth/ha-auth-flow.ts
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
import { LitElement, html, property, PropertyValues } from "lit-element";
|
||||||
|
import "@material/mwc-button";
|
||||||
|
import "../components/ha-form";
|
||||||
|
import "../components/ha-markdown";
|
||||||
|
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||||
|
import { AuthProvider } from "../data/auth";
|
||||||
|
import { ConfigFlowStep, ConfigFlowStepForm } from "../data/config_entries";
|
||||||
|
|
||||||
|
type State = "loading" | "error" | "step";
|
||||||
|
|
||||||
|
class HaAuthFlow extends litLocalizeLiteMixin(LitElement) {
|
||||||
|
@property() public authProvider?: AuthProvider;
|
||||||
|
@property() public clientId?: string;
|
||||||
|
@property() public redirectUri?: string;
|
||||||
|
@property() public oauth2State?: string;
|
||||||
|
@property() private _state: State = "loading";
|
||||||
|
@property() private _stepData: any = {};
|
||||||
|
@property() private _step?: ConfigFlowStep;
|
||||||
|
@property() private _errorMessage?: string;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
:host {
|
||||||
|
/* So we can set min-height to avoid jumping during loading */
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
margin: 24px 0 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<form>
|
||||||
|
${this._renderForm()}
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
|
||||||
|
if (this.clientId == null || this.redirectUri == null) {
|
||||||
|
// tslint:disable-next-line: no-console
|
||||||
|
console.error(
|
||||||
|
"clientId and redirectUri must not be null",
|
||||||
|
this.clientId,
|
||||||
|
this.redirectUri
|
||||||
|
);
|
||||||
|
this._state = "error";
|
||||||
|
this._errorMessage = this._unknownError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addEventListener("keypress", (ev) => {
|
||||||
|
if (ev.keyCode === 13) {
|
||||||
|
this._handleSubmit(ev);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (changedProps.has("authProvider")) {
|
||||||
|
this._providerChanged(this.authProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderForm() {
|
||||||
|
switch (this._state) {
|
||||||
|
case "step":
|
||||||
|
if (this._step == null) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
${this._renderStep(this._step)}
|
||||||
|
<div class="action">
|
||||||
|
<mwc-button raised @click=${this._handleSubmit}
|
||||||
|
>${this._step.type === "form" ? "Next" : "Start over"}</mwc-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
case "error":
|
||||||
|
return html`
|
||||||
|
<div class="error">Error: ${this._errorMessage}</div>
|
||||||
|
`;
|
||||||
|
case "loading":
|
||||||
|
return html`
|
||||||
|
${this.localize("ui.panel.page-authorize.form.working")}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderStep(step: ConfigFlowStep) {
|
||||||
|
switch (step.type) {
|
||||||
|
case "abort":
|
||||||
|
return html`
|
||||||
|
${this.localize("ui.panel.page-authorize.abort_intro")}:
|
||||||
|
<ha-markdown
|
||||||
|
.content=${this.localize(
|
||||||
|
`ui.panel.page-authorize.form.providers.${
|
||||||
|
step.handler[0]
|
||||||
|
}.abort.${step.reason}`
|
||||||
|
)}
|
||||||
|
></ha-markdown>
|
||||||
|
`;
|
||||||
|
case "form":
|
||||||
|
return html`
|
||||||
|
${this._computeStepDescription(step)
|
||||||
|
? html`
|
||||||
|
<ha-markdown
|
||||||
|
.content=${this._computeStepDescription(step)}
|
||||||
|
allow-svg
|
||||||
|
></ha-markdown>
|
||||||
|
`
|
||||||
|
: html``}
|
||||||
|
<ha-form
|
||||||
|
.data=${this._stepData}
|
||||||
|
.schema=${step.data_schema}
|
||||||
|
.error=${step.errors}
|
||||||
|
.computeLabel=${this._computeLabelCallback(step)}
|
||||||
|
.computeError=${this._computeErrorCallback(step)}
|
||||||
|
></ha-form>
|
||||||
|
`;
|
||||||
|
default:
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _providerChanged(newProvider?: AuthProvider) {
|
||||||
|
if (this._step && this._step.type === "form") {
|
||||||
|
fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
credentials: "same-origin",
|
||||||
|
}).catch((err) => {
|
||||||
|
// tslint:disable-next-line: no-console
|
||||||
|
console.error("Error delete obsoleted auth flow", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newProvider == null) {
|
||||||
|
// tslint:disable-next-line: no-console
|
||||||
|
console.error("No auth provider");
|
||||||
|
this._state = "error";
|
||||||
|
this._errorMessage = this._unknownError();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/auth/login_flow", {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "same-origin",
|
||||||
|
body: JSON.stringify({
|
||||||
|
client_id: this.clientId,
|
||||||
|
handler: [newProvider.type, newProvider.id],
|
||||||
|
redirect_uri: this.redirectUri,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
// allow auth provider bypass the login form
|
||||||
|
if (data.type === "create_entry") {
|
||||||
|
this._redirect(data.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateStep(data);
|
||||||
|
} else {
|
||||||
|
this._state = "error";
|
||||||
|
this._errorMessage = data.message;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// tslint:disable-next-line: no-console
|
||||||
|
console.error("Error starting auth flow", err);
|
||||||
|
this._state = "error";
|
||||||
|
this._errorMessage = this._unknownError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _redirect(authCode: string) {
|
||||||
|
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
|
||||||
|
let url = this.redirectUri!!;
|
||||||
|
if (!url.includes("?")) {
|
||||||
|
url += "?";
|
||||||
|
} else if (!url.endsWith("&")) {
|
||||||
|
url += "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
url += `code=${encodeURIComponent(authCode)}`;
|
||||||
|
|
||||||
|
if (this.oauth2State) {
|
||||||
|
url += `&state=${encodeURIComponent(this.oauth2State)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.location.assign(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateStep(step: ConfigFlowStep) {
|
||||||
|
let stepData: any = null;
|
||||||
|
if (
|
||||||
|
this._step &&
|
||||||
|
(step.flow_id !== this._step.flow_id ||
|
||||||
|
(step.type === "form" &&
|
||||||
|
this._step.type === "form" &&
|
||||||
|
step.step_id !== this._step.step_id))
|
||||||
|
) {
|
||||||
|
stepData = {};
|
||||||
|
}
|
||||||
|
this._step = step;
|
||||||
|
this._state = "step";
|
||||||
|
if (stepData != null) {
|
||||||
|
this._stepData = stepData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeStepDescription(step: ConfigFlowStepForm) {
|
||||||
|
const resourceKey = `ui.panel.page-authorize.form.providers.${
|
||||||
|
step.handler[0]
|
||||||
|
}.step.${step.step_id}.description`;
|
||||||
|
const args: string[] = [];
|
||||||
|
const placeholders = step.description_placeholders || {};
|
||||||
|
Object.keys(placeholders).forEach((key) => {
|
||||||
|
args.push(key);
|
||||||
|
args.push(placeholders[key]);
|
||||||
|
});
|
||||||
|
return this.localize(resourceKey, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeLabelCallback(step: ConfigFlowStepForm) {
|
||||||
|
// Returns a callback for ha-form to calculate labels per schema object
|
||||||
|
return (schema) =>
|
||||||
|
this.localize(
|
||||||
|
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${
|
||||||
|
step.step_id
|
||||||
|
}.data.${schema.name}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeErrorCallback(step: ConfigFlowStepForm) {
|
||||||
|
// Returns a callback for ha-form to calculate error messages
|
||||||
|
return (error) =>
|
||||||
|
this.localize(
|
||||||
|
`ui.panel.page-authorize.form.providers.${
|
||||||
|
step.handler[0]
|
||||||
|
}.error.${error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _unknownError() {
|
||||||
|
return this.localize("ui.panel.page-authorize.form.unknown_error");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleSubmit(ev: Event) {
|
||||||
|
ev.preventDefault();
|
||||||
|
if (this._step == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._step.type !== "form") {
|
||||||
|
this._providerChanged(this.authProvider);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._state = "loading";
|
||||||
|
// To avoid a jumping UI.
|
||||||
|
this.style.setProperty("min-height", `${this.offsetHeight}px`);
|
||||||
|
|
||||||
|
const postData = { ...this._stepData, client_id: this.clientId };
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "same-origin",
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
const newStep = await response.json();
|
||||||
|
|
||||||
|
if (newStep.type === "create_entry") {
|
||||||
|
this._redirect(newStep.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._updateStep(newStep);
|
||||||
|
} catch (err) {
|
||||||
|
// tslint:disable-next-line: no-console
|
||||||
|
console.error("Error submitting step", err);
|
||||||
|
this._state = "error";
|
||||||
|
this._errorMessage = this._unknownError();
|
||||||
|
} finally {
|
||||||
|
this.style.setProperty("min-height", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("ha-auth-flow", HaAuthFlow);
|
@ -108,7 +108,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
.resources="${this.resources}"
|
.resources="${this.resources}"
|
||||||
.clientId="${this.clientId}"
|
.clientId="${this.clientId}"
|
||||||
.authProviders="${inactiveProviders}"
|
.authProviders="${inactiveProviders}"
|
||||||
@pick="${this._handleAuthProviderPick}"
|
@pick-auth-provider="${this._handleAuthProviderPick}"
|
||||||
></ha-pick-auth-provider>
|
></ha-pick-auth-provider>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-item/paper-item-body";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
|
|
||||||
import { EventsMixin } from "../mixins/events-mixin";
|
|
||||||
import { localizeLiteMixin } from "../mixins/localize-lite-mixin";
|
|
||||||
import "../components/ha-icon-next";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @appliesMixin EventsMixin
|
|
||||||
*/
|
|
||||||
class HaPickAuthProvider extends EventsMixin(
|
|
||||||
localizeLiteMixin(PolymerElement)
|
|
||||||
) {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
paper-item {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<p>[[localize('ui.panel.page-authorize.pick_auth_provider')]]:</p>
|
|
||||||
<template is="dom-repeat" items="[[authProviders]]">
|
|
||||||
<paper-item on-click="_handlePick">
|
|
||||||
<paper-item-body>[[item.name]]</paper-item-body>
|
|
||||||
<ha-icon-next></ha-icon-next>
|
|
||||||
</paper-item>
|
|
||||||
</template>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
_state: {
|
|
||||||
type: String,
|
|
||||||
value: "loading",
|
|
||||||
},
|
|
||||||
authProviders: Array,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_handlePick(ev) {
|
|
||||||
this.fire("pick", ev.model.item);
|
|
||||||
}
|
|
||||||
|
|
||||||
_equal(a, b) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);
|
|
44
src/auth/ha-pick-auth-provider.ts
Normal file
44
src/auth/ha-pick-auth-provider.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { LitElement, html, property } from "lit-element";
|
||||||
|
import "@polymer/paper-item/paper-item";
|
||||||
|
import "@polymer/paper-item/paper-item-body";
|
||||||
|
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import "../components/ha-icon-next";
|
||||||
|
import { AuthProvider } from "../data/auth";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"pick-auth-provider": AuthProvider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HaPickAuthProvider extends litLocalizeLiteMixin(LitElement) {
|
||||||
|
@property() public authProviders: AuthProvider[] = [];
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<style>
|
||||||
|
paper-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p>
|
||||||
|
${this.authProviders.map(
|
||||||
|
(provider) => html`
|
||||||
|
<paper-item .auth_provider=${provider} @click=${this._handlePick}>
|
||||||
|
<paper-item-body>${provider.name}</paper-item-body>
|
||||||
|
<ha-icon-next></ha-icon-next>
|
||||||
|
</paper-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handlePick(ev) {
|
||||||
|
fireEvent(this, "pick-auth-provider", ev.currentTarget.auth_provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define("ha-pick-auth-provider", HaPickAuthProvider);
|
Loading…
x
Reference in New Issue
Block a user