diff --git a/src/data/cloud.ts b/src/data/cloud.ts index 1a35be028b..b7fea8fae2 100644 --- a/src/data/cloud.ts +++ b/src/data/cloud.ts @@ -181,3 +181,6 @@ export const updateCloudGoogleEntityConfig = ( export const cloudSyncGoogleAssistant = (hass: HomeAssistant) => hass.callApi("POST", "cloud/google_actions/sync"); + +export const fetchSupportPackage = (hass: HomeAssistant) => + hass.callApi("GET", "cloud/support_package"); diff --git a/src/panels/config/cloud/account/cloud-account.ts b/src/panels/config/cloud/account/cloud-account.ts index 5ccbe1ef60..82730ce21c 100644 --- a/src/panels/config/cloud/account/cloud-account.ts +++ b/src/panels/config/cloud/account/cloud-account.ts @@ -1,15 +1,15 @@ import "@material/mwc-button"; +import { mdiDeleteForever, mdiDotsVertical, mdiDownload } from "@mdi/js"; import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; -import { mdiDeleteForever, mdiDotsVertical } from "@mdi/js"; import { formatDateTime } from "../../../../common/datetime/format_date_time"; import { fireEvent } from "../../../../common/dom/fire_event"; import { debounce } from "../../../../common/util/debounce"; import "../../../../components/ha-alert"; -import "../../../../components/ha-card"; -import "../../../../components/ha-tip"; -import "../../../../components/ha-list-item"; import "../../../../components/ha-button-menu"; +import "../../../../components/ha-card"; +import "../../../../components/ha-list-item"; +import "../../../../components/ha-tip"; import type { CloudStatusLoggedIn, SubscriptionInfo, @@ -32,6 +32,7 @@ import "./cloud-ice-servers-pref"; import "./cloud-remote-pref"; import "./cloud-tts-pref"; import "./cloud-webhooks"; +import { showSupportPackageDialog } from "./show-dialog-cloud-support-package"; @customElement("cloud-account") export class CloudAccount extends SubscribeMixin(LitElement) { @@ -52,7 +53,7 @@ export class CloudAccount extends SubscribeMixin(LitElement) { .narrow=${this.narrow} header="Home Assistant Cloud" > - + + + ${this.hass.localize( + "ui.panel.config.cloud.account.download_support_package" + )} + +
@@ -286,6 +293,16 @@ export class CloudAccount extends SubscribeMixin(LitElement) { fireEvent(this, "ha-refresh-cloud-status"); } + private _handleMenuAction(ev) { + switch (ev.detail.index) { + case 0: + this._deleteCloudData(); + break; + case 1: + this._downloadSupportPackage(); + } + } + private async _deleteCloudData() { const confirm = await showConfirmationDialog(this, { title: this.hass.localize( @@ -316,6 +333,10 @@ export class CloudAccount extends SubscribeMixin(LitElement) { } } + private async _downloadSupportPackage() { + showSupportPackageDialog(this); + } + static get styles() { return [ haStyle, diff --git a/src/panels/config/cloud/account/dialog-cloud-support-package.ts b/src/panels/config/cloud/account/dialog-cloud-support-package.ts new file mode 100644 index 0000000000..920db783a4 --- /dev/null +++ b/src/panels/config/cloud/account/dialog-cloud-support-package.ts @@ -0,0 +1,206 @@ +import "@material/mwc-button"; +import "@material/mwc-list/mwc-list-item"; +import { mdiClose } from "@mdi/js"; +import { css, html, LitElement, nothing } from "lit"; +import { customElement, property, query, state } from "lit/decorators"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import "../../../../components/ha-alert"; +import "../../../../components/ha-button"; +import "../../../../components/ha-circular-progress"; +import "../../../../components/ha-dialog-header"; +import "../../../../components/ha-markdown-element"; +import "../../../../components/ha-md-dialog"; +import type { HaMdDialog } from "../../../../components/ha-md-dialog"; +import "../../../../components/ha-select"; +import "../../../../components/ha-textarea"; +import { fetchSupportPackage } from "../../../../data/cloud"; +import type { HomeAssistant } from "../../../../types"; +import { fileDownload } from "../../../../util/file_download"; + +@customElement("dialog-cloud-support-package") +export class DialogSupportPackage extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _open = false; + + @state() private _supportPackage?: string; + + @query("ha-md-dialog") private _dialog?: HaMdDialog; + + public showDialog() { + this._open = true; + this._loadSupportPackage(); + } + + private _dialogClosed(): void { + this._open = false; + this._supportPackage = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + public closeDialog() { + this._dialog?.close(); + return true; + } + + protected render() { + if (!this._open) { + return nothing; + } + return html` + + + + Download support package + + +
+ ${this._supportPackage + ? html`` + : html` +
+ + Generating preview... +
+ `} +
+ +
+ `; + } + + private async _loadSupportPackage() { + this._supportPackage = await fetchSupportPackage(this.hass); + } + + private async _download() { + fileDownload( + "data:text/plain;charset=utf-8," + + encodeURIComponent(this._supportPackage || ""), + "support-package.md" + ); + } + + static styles = css` + ha-md-dialog { + min-width: 90vw; + min-height: 90vh; + } + + .progress-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: calc(90vh - 260px); + width: 100%; + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + ha-md-dialog { + min-width: 100vw; + min-height: 100vh; + } + .progress-container { + height: calc(100vh - 260px); + } + } + + .footer { + flex-direction: column; + } + .actions { + display: flex; + gap: 8px; + justify-content: flex-end; + } + hr { + border: none; + border-top: 1px solid var(--divider-color); + width: calc(100% + 48px); + margin-right: -24px; + margin-left: -24px; + } + table, + th, + td { + border: none; + } + + table { + width: 100%; + display: table; + border-collapse: collapse; + border-spacing: 0; + } + + table tr { + border-bottom: none; + } + + table > tbody > tr:nth-child(odd) { + background-color: rgba(var(--rgb-primary-text-color), 0.04); + } + + table > tbody > tr > td { + border-radius: 0; + } + + table > tbody > tr { + -webkit-transition: background-color 0.25s ease; + transition: background-color 0.25s ease; + } + + table > tbody > tr:hover { + background-color: rgba(var(--rgb-primary-text-color), 0.08); + } + + tr { + border-bottom: 1px solid var(--divider-color); + } + + td, + th { + padding: 15px 5px; + display: table-cell; + text-align: left; + vertical-align: middle; + border-radius: 2px; + } + details { + background-color: var(--secondary-background-color); + padding: 16px 24px; + margin: 8px 0; + border: 1px solid var(--divider-color); + border-radius: 16px; + } + summary { + font-weight: bold; + cursor: pointer; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-cloud-support-package": DialogSupportPackage; + } +} diff --git a/src/panels/config/cloud/account/show-dialog-cloud-support-package.ts b/src/panels/config/cloud/account/show-dialog-cloud-support-package.ts new file mode 100644 index 0000000000..697b16d0e9 --- /dev/null +++ b/src/panels/config/cloud/account/show-dialog-cloud-support-package.ts @@ -0,0 +1,12 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; + +export const loadSupportPackageDialog = () => + import("./dialog-cloud-support-package"); + +export const showSupportPackageDialog = (element: HTMLElement): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-cloud-support-package", + dialogImport: loadSupportPackageDialog, + dialogParams: {}, + }); +}; diff --git a/src/panels/config/cloud/login/cloud-login.ts b/src/panels/config/cloud/login/cloud-login.ts index 1a05db180f..5fe14e24ba 100644 --- a/src/panels/config/cloud/login/cloud-login.ts +++ b/src/panels/config/cloud/login/cloud-login.ts @@ -1,6 +1,6 @@ import "@material/mwc-button"; import "@material/mwc-list/mwc-list"; -import { mdiDeleteForever, mdiDotsVertical } from "@mdi/js"; +import { mdiDeleteForever, mdiDotsVertical, mdiDownload } from "@mdi/js"; import type { TemplateResult } from "lit"; import { css, html, LitElement } from "lit"; import { customElement, property, query, state } from "lit/decorators"; @@ -27,6 +27,7 @@ import "../../../../layouts/hass-subpage"; import { haStyle } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import "../../ha-config-section"; +import { showSupportPackageDialog } from "../account/show-dialog-cloud-support-package"; @customElement("cloud-login") export class CloudLogin extends LitElement { @@ -57,7 +58,7 @@ export class CloudLogin extends LitElement { .narrow=${this.narrow} header="Home Assistant Cloud" > - + + + ${this.hass.localize( + "ui.panel.config.cloud.account.download_support_package" + )} + +
@@ -348,6 +355,16 @@ export class CloudLogin extends LitElement { fireEvent(this, "flash-message-changed", { value: "" }); } + private _handleMenuAction(ev) { + switch (ev.detail.index) { + case 0: + this._deleteCloudData(); + break; + case 1: + this._downloadSupportPackage(); + } + } + private async _deleteCloudData() { const confirm = await showConfirmationDialog(this, { title: this.hass.localize( @@ -377,6 +394,10 @@ export class CloudLogin extends LitElement { } } + private async _downloadSupportPackage() { + showSupportPackageDialog(this); + } + static get styles() { return [ haStyle, diff --git a/src/translations/en.json b/src/translations/en.json index 530eda935c..92313a008b 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -4592,6 +4592,7 @@ "account_created": "Account created! Check your email for instructions on how to activate your account." }, "account": { + "download_support_package": "Download support package", "reset_cloud_data": "Reset cloud data", "reset_data_confirm_title": "Reset cloud data?", "reset_data_confirm_text": "This will reset all your cloud settings. This includes your remote connection, Google Assistant and Amazon Alexa integrations. This action cannot be undone.",