mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add connection check and dialog with results for cloud login (#24301)
This commit is contained in:
parent
783132ae46
commit
a438fc5e41
@ -73,6 +73,7 @@ export interface CloudWebhook {
|
|||||||
interface CloudLoginBase {
|
interface CloudLoginBase {
|
||||||
hass: HomeAssistant;
|
hass: HomeAssistant;
|
||||||
email: string;
|
email: string;
|
||||||
|
check_connection?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CloudLoginPassword extends CloudLoginBase {
|
export interface CloudLoginPassword extends CloudLoginBase {
|
||||||
|
@ -10,6 +10,7 @@ import "../../../components/ha-svg-icon";
|
|||||||
import "../../../components/ha-textfield";
|
import "../../../components/ha-textfield";
|
||||||
import type { HaTextField } from "../../../components/ha-textfield";
|
import type { HaTextField } from "../../../components/ha-textfield";
|
||||||
import { cloudLogin } from "../../../data/cloud";
|
import { cloudLogin } from "../../../data/cloud";
|
||||||
|
import { showCloudAlreadyConnectedDialog } from "../../../panels/config/cloud/dialog-cloud-already-connected/show-dialog-cloud-already-connected";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -25,6 +26,8 @@ export class CloudStepSignin extends LitElement {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
@state() private _checkConnection = true;
|
||||||
|
|
||||||
@query("#email", true) private _emailField!: HaTextField;
|
@query("#email", true) private _emailField!: HaTextField;
|
||||||
|
|
||||||
@query("#password", true) private _passwordField!: HaPasswordField;
|
@query("#password", true) private _passwordField!: HaPasswordField;
|
||||||
@ -115,6 +118,7 @@ export class CloudStepSignin extends LitElement {
|
|||||||
hass: this.hass,
|
hass: this.hass,
|
||||||
email: username,
|
email: username,
|
||||||
...(code ? { code } : { password }),
|
...(code ? { code } : { password }),
|
||||||
|
check_connection: this._checkConnection,
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const errCode = err && err.body && err.body.code;
|
const errCode = err && err.body && err.body.code;
|
||||||
@ -139,6 +143,20 @@ export class CloudStepSignin extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (errCode === "alreadyconnectederror") {
|
||||||
|
showCloudAlreadyConnectedDialog(this, {
|
||||||
|
details: JSON.parse(err.body.message),
|
||||||
|
logInHereAction: () => {
|
||||||
|
this._checkConnection = false;
|
||||||
|
doLogin(username);
|
||||||
|
},
|
||||||
|
closeDialog: () => {
|
||||||
|
this._requestInProgress = false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (errCode === "usernotfound" && username !== username.toLowerCase()) {
|
if (errCode === "usernotfound" && username !== username.toLowerCase()) {
|
||||||
await doLogin(username.toLowerCase());
|
await doLogin(username.toLowerCase());
|
||||||
return;
|
return;
|
||||||
|
@ -0,0 +1,171 @@
|
|||||||
|
import type { CSSResultGroup } from "lit";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, state } from "lit/decorators";
|
||||||
|
import { mdiEye, mdiEyeOff } from "@mdi/js";
|
||||||
|
import { formatDateTime } from "../../../../common/datetime/format_date_time";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-alert";
|
||||||
|
import "../../../../components/ha-button";
|
||||||
|
import "../../../../components/ha-icon-button";
|
||||||
|
import { createCloseHeading } from "../../../../components/ha-dialog";
|
||||||
|
import { haStyleDialog } from "../../../../resources/styles";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import type { CloudAlreadyConnectedParams as CloudAlreadyConnectedDialogParams } from "./show-dialog-cloud-already-connected";
|
||||||
|
import { obfuscateUrl } from "../../../../util/url";
|
||||||
|
|
||||||
|
@customElement("dialog-cloud-already-connected")
|
||||||
|
class DialogCloudAlreadyConnected extends LitElement {
|
||||||
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _params?: CloudAlreadyConnectedDialogParams;
|
||||||
|
|
||||||
|
@state() private _obfuscateIp = true;
|
||||||
|
|
||||||
|
public showDialog(params: CloudAlreadyConnectedDialogParams) {
|
||||||
|
this._params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._params?.closeDialog();
|
||||||
|
this._params = undefined;
|
||||||
|
this._obfuscateIp = true;
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._params) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
const { details } = this._params;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
@closed=${this.closeDialog}
|
||||||
|
.heading=${createCloseHeading(
|
||||||
|
this.hass,
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.heading"
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div class="intro">
|
||||||
|
<span>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.description"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<b>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.other_home_assistant"
|
||||||
|
)}
|
||||||
|
</b>
|
||||||
|
</div>
|
||||||
|
<div class="instance-details">
|
||||||
|
<div class="instance-detail">
|
||||||
|
<span>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.ip_address"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<div class="obfuscated">
|
||||||
|
<span>
|
||||||
|
${this._obfuscateIp
|
||||||
|
? obfuscateUrl(details.remote_ip_address)
|
||||||
|
: details.remote_ip_address}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<ha-icon-button
|
||||||
|
class="toggle-unmasked-url"
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.panel.config.cloud.dialog_already_connected.obfuscated_ip.${this._obfuscateIp ? "hide" : "show"}`
|
||||||
|
)}
|
||||||
|
@click=${this._toggleObfuscateIp}
|
||||||
|
.path=${this._obfuscateIp ? mdiEye : mdiEyeOff}
|
||||||
|
></ha-icon-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="instance-detail">
|
||||||
|
<span>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.connected_at"
|
||||||
|
)}:
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
${formatDateTime(
|
||||||
|
new Date(details.connected_at),
|
||||||
|
this.hass.locale,
|
||||||
|
this.hass.config
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ha-alert
|
||||||
|
alert-type="info"
|
||||||
|
.title=${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.info_backups.title"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.info_backups.description"
|
||||||
|
)}
|
||||||
|
</ha-alert>
|
||||||
|
|
||||||
|
<ha-button @click=${this.closeDialog} slot="secondaryAction">
|
||||||
|
${this.hass!.localize("ui.common.cancel")}
|
||||||
|
</ha-button>
|
||||||
|
<ha-button @click=${this._logInHere} slot="primaryAction">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.config.cloud.dialog_already_connected.login_here"
|
||||||
|
)}
|
||||||
|
</ha-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleObfuscateIp() {
|
||||||
|
this._obfuscateIp = !this._obfuscateIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _logInHere() {
|
||||||
|
this._params?.logInHereAction();
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
css`
|
||||||
|
ha-dialog {
|
||||||
|
--mdc-dialog-max-width: 535px;
|
||||||
|
}
|
||||||
|
.intro b {
|
||||||
|
display: block;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
.instance-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.instance-detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.obfuscated {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-cloud-already-connected": DialogCloudAlreadyConnected;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
|
||||||
|
export interface CloudAlreadyConnectedParams {
|
||||||
|
details: {
|
||||||
|
remote_ip_address: string;
|
||||||
|
connected_at: string;
|
||||||
|
};
|
||||||
|
logInHereAction: () => void;
|
||||||
|
closeDialog: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showCloudAlreadyConnectedDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
webhookDialogParams: CloudAlreadyConnectedParams
|
||||||
|
): void => {
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-cloud-already-connected",
|
||||||
|
dialogImport: () => import("./dialog-cloud-already-connected"),
|
||||||
|
dialogParams: webhookDialogParams,
|
||||||
|
});
|
||||||
|
};
|
@ -28,6 +28,7 @@ import { haStyle } from "../../../../resources/styles";
|
|||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import "../../ha-config-section";
|
import "../../ha-config-section";
|
||||||
import { showSupportPackageDialog } from "../account/show-dialog-cloud-support-package";
|
import { showSupportPackageDialog } from "../account/show-dialog-cloud-support-package";
|
||||||
|
import { showCloudAlreadyConnectedDialog } from "../dialog-cloud-already-connected/show-dialog-cloud-already-connected";
|
||||||
|
|
||||||
@customElement("cloud-login")
|
@customElement("cloud-login")
|
||||||
export class CloudLogin extends LitElement {
|
export class CloudLogin extends LitElement {
|
||||||
@ -47,6 +48,8 @@ export class CloudLogin extends LitElement {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
@state() private _checkConnection = true;
|
||||||
|
|
||||||
@query("#email", true) private _emailField!: HaTextField;
|
@query("#email", true) private _emailField!: HaTextField;
|
||||||
|
|
||||||
@query("#password", true) private _passwordField!: HaPasswordField;
|
@query("#password", true) private _passwordField!: HaPasswordField;
|
||||||
@ -244,6 +247,7 @@ export class CloudLogin extends LitElement {
|
|||||||
hass: this.hass,
|
hass: this.hass,
|
||||||
email: username,
|
email: username,
|
||||||
...(code ? { code } : { password }),
|
...(code ? { code } : { password }),
|
||||||
|
check_connection: this._checkConnection,
|
||||||
});
|
});
|
||||||
this.email = "";
|
this.email = "";
|
||||||
this._password = "";
|
this._password = "";
|
||||||
@ -283,6 +287,21 @@ export class CloudLogin extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (errCode === "alreadyconnectederror") {
|
||||||
|
showCloudAlreadyConnectedDialog(this, {
|
||||||
|
details: JSON.parse(err.body.message),
|
||||||
|
logInHereAction: () => {
|
||||||
|
this._checkConnection = false;
|
||||||
|
doLogin(username);
|
||||||
|
},
|
||||||
|
closeDialog: () => {
|
||||||
|
this._requestInProgress = false;
|
||||||
|
this.email = "";
|
||||||
|
this._password = "";
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (errCode === "PasswordChangeRequired") {
|
if (errCode === "PasswordChangeRequired") {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
|
@ -4730,6 +4730,23 @@
|
|||||||
"fingerprint": "Certificate fingerprint:",
|
"fingerprint": "Certificate fingerprint:",
|
||||||
"close": "Close"
|
"close": "Close"
|
||||||
},
|
},
|
||||||
|
"dialog_already_connected": {
|
||||||
|
"heading": "Account linked to other Home Assistant",
|
||||||
|
"description": "We noticed that another instance is currently connected to your Home Assistant Cloud account. Your Home Assistant Cloud account can only be signed into one Home Assistant instance at a time. If you log in here, the other instance will be disconnected along with its Cloud services.",
|
||||||
|
"other_home_assistant": "Other Home Assistant",
|
||||||
|
"ip_address": "IP Address",
|
||||||
|
"connected_at": "Connected at",
|
||||||
|
"obfuscated_ip": {
|
||||||
|
"show": "Show IP address",
|
||||||
|
"hide": "Hide IP address"
|
||||||
|
},
|
||||||
|
"info_backups": {
|
||||||
|
"title": "Home Assistant Cloud backups",
|
||||||
|
"description": "Your Cloud backup may be overwritten if you proceed. We strongly recommend downloading your current backup from your Nabu Casa account page before continuing."
|
||||||
|
},
|
||||||
|
"close": "Close",
|
||||||
|
"login_here": "Log in here"
|
||||||
|
},
|
||||||
"dialog_cloudhook": {
|
"dialog_cloudhook": {
|
||||||
"webhook_for": "Webhook for {name}",
|
"webhook_for": "Webhook for {name}",
|
||||||
"managed_by_integration": "This webhook is managed by an integration and cannot be disabled.",
|
"managed_by_integration": "This webhook is managed by an integration and cannot be disabled.",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user