From ef834ef536ef29f63ce26e2e5978c5ccb94caf73 Mon Sep 17 00:00:00 2001 From: Zack Date: Mon, 1 Aug 2022 15:39:41 -0500 Subject: [PATCH] First pass --- .../more-info/controls/more-info-update.ts | 12 +- .../config/dashboard/ha-config-dashboard.ts | 2 +- src/panels/config/ha-panel-config.ts | 2 +- src/panels/config/updates/dialog-update.ts | 263 ++++++++++++++++++ .../ha-config-section-updates.ts | 2 +- .../ha-config-updates.ts | 15 +- .../config/updates/show-update-dialog.ts | 19 ++ src/translations/en.json | 11 +- 8 files changed, 310 insertions(+), 16 deletions(-) create mode 100644 src/panels/config/updates/dialog-update.ts rename src/panels/config/{core => updates}/ha-config-section-updates.ts (99%) rename src/panels/config/{dashboard => updates}/ha-config-updates.ts (94%) create mode 100644 src/panels/config/updates/show-update-dialog.ts diff --git a/src/dialogs/more-info/controls/more-info-update.ts b/src/dialogs/more-info/controls/more-info-update.ts index ee855ddb13..8c2ea6e5d7 100644 --- a/src/dialogs/more-info/controls/more-info-update.ts +++ b/src/dialogs/more-info/controls/more-info-update.ts @@ -1,12 +1,13 @@ -import "../../../components/ha-alert"; -import "../../../components/ha-faded"; import "@material/mwc-button/mwc-button"; import "@material/mwc-linear-progress/mwc-linear-progress"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { BINARY_STATE_OFF } from "../../../common/const"; import { supportsFeature } from "../../../common/entity/supports-feature"; +import "../../../components/ha-alert"; import "../../../components/ha-checkbox"; import "../../../components/ha-circular-progress"; +import "../../../components/ha-faded"; import "../../../components/ha-formfield"; import "../../../components/ha-markdown"; import { UNAVAILABLE_STATES } from "../../../data/entity"; @@ -21,7 +22,6 @@ import { UPDATE_SUPPORT_SPECIFIC_VERSION, } from "../../../data/update"; import type { HomeAssistant } from "../../../types"; -import { BINARY_STATE_OFF } from "../../../common/const"; @customElement("more-info-update") class MoreInfoUpdate extends LitElement { @@ -114,7 +114,8 @@ class MoreInfoUpdate extends LitElement { >` : ""} ${supportsFeature(this.stateObj, UPDATE_SUPPORT_BACKUP) - ? html`
+ ? html` +
- ` + + ` : ""}
diff --git a/src/panels/config/dashboard/ha-config-dashboard.ts b/src/panels/config/dashboard/ha-config-dashboard.ts index 9c0ea74e89..a857e6d4f1 100644 --- a/src/panels/config/dashboard/ha-config-dashboard.ts +++ b/src/panels/config/dashboard/ha-config-dashboard.ts @@ -43,8 +43,8 @@ import { documentationUrl } from "../../../util/documentation-url"; import "../ha-config-section"; import { configSections } from "../ha-panel-config"; import "../repairs/ha-config-repairs"; +import "../updates/ha-config-updates"; import "./ha-config-navigation"; -import "./ha-config-updates"; const randomTip = (hass: HomeAssistant, narrow: boolean) => { const weighted: string[] = []; diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index c910dfdbeb..e71df5dd57 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -441,7 +441,7 @@ class HaPanelConfig extends HassRouterPage { }, updates: { tag: "ha-config-section-updates", - load: () => import("./core/ha-config-section-updates"), + load: () => import("./updates/ha-config-section-updates"), }, repairs: { tag: "ha-config-repairs-dashboard", diff --git a/src/panels/config/updates/dialog-update.ts b/src/panels/config/updates/dialog-update.ts new file mode 100644 index 0000000000..9d5615d049 --- /dev/null +++ b/src/panels/config/updates/dialog-update.ts @@ -0,0 +1,263 @@ +import "@material/mwc-button/mwc-button"; +import "@material/mwc-linear-progress/mwc-linear-progress"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { BINARY_STATE_OFF } from "../../../common/const"; +import { fireEvent } from "../../../common/dom/fire_event"; +import { supportsFeature } from "../../../common/entity/supports-feature"; +import "../../../components/ha-checkbox"; +import "../../../components/ha-circular-progress"; +import { createCloseHeading } from "../../../components/ha-dialog"; +import "../../../components/ha-faded"; +import "../../../components/ha-formfield"; +import "../../../components/ha-markdown"; +import { + UpdateEntity, + updateIsInstalling, + updateReleaseNotes, + UPDATE_SUPPORT_BACKUP, + UPDATE_SUPPORT_PROGRESS, + UPDATE_SUPPORT_RELEASE_NOTES, + UPDATE_SUPPORT_SPECIFIC_VERSION, +} from "../../../data/update"; +import { haStyle, haStyleDialog } from "../../../resources/styles"; +import type { HomeAssistant } from "../../../types"; +import type { UpdateDialogParams } from "./show-update-dialog"; + +@customElement("dialog-update") +class DialogUpdate extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _entity?: UpdateEntity; + + @state() private _releaseNotes?: string | null; + + @state() private _error?: string; + + @state() private _params?: UpdateDialogParams; + + public showDialog(params: UpdateDialogParams): void { + this._params = params; + this._entity = this._params.entity; + + if (supportsFeature(this._entity, UPDATE_SUPPORT_RELEASE_NOTES)) { + updateReleaseNotes(this.hass, this._entity!.entity_id) + .then((result) => { + this._releaseNotes = result; + }) + .catch((err) => { + this._error = err.message; + }); + } + } + + public closeDialog() { + this._params = undefined; + this._entity = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render(): TemplateResult { + if (!this._entity) { + return html``; + } + + const entity = this._entity; + const skippedVersion = + this._entity.attributes.latest_version && + this._entity.attributes.skipped_version === + this._entity.attributes.latest_version; + + return html` + + ${this._error + ? html`${this._error}` + : ""} +
+ ${this.hass.localize( + "ui.panel.config.updates.dialog.latest_version", + { + latest_version: + entity.attributes.latest_version ?? + this.hass.localize("state.default.unavailable"), + } + )} +
+ ${this._entity.attributes.in_progress + ? supportsFeature(this._entity, UPDATE_SUPPORT_PROGRESS) && + typeof this._entity.attributes.in_progress === "number" + ? html`` + : html`` + : ""} + ${supportsFeature(this._entity, UPDATE_SUPPORT_RELEASE_NOTES) && + !this._error + ? this._releaseNotes === undefined + ? html`` + : html` + + + + ` + : this._entity.attributes.release_summary + ? html` + + ` + : ""} + ${this._entity.attributes.release_url + ? html` + + ` + : ""} + ${supportsFeature(this._entity, UPDATE_SUPPORT_BACKUP) + ? html` +
+
+ + + +
+ ` + : ""} + ${this._entity.attributes.auto_update + ? "" + : html` + + ${this._entity.state === BINARY_STATE_OFF && + this._entity.attributes.skipped_version + ? this.hass.localize( + "ui.panel.config.updates.dialog.clear_skipped" + ) + : this.hass.localize("ui.panel.config.updates.dialog.skip")} + + `} + + ${this.hass.localize("ui.panel.config.updates.dialog.update_now")} + +
+ `; + } + + get _shouldCreateBackup(): boolean | null { + if (!supportsFeature(this._entity!, UPDATE_SUPPORT_BACKUP)) { + return null; + } + const checkbox = this.shadowRoot?.querySelector("ha-checkbox"); + if (checkbox) { + return checkbox.checked; + } + return true; + } + + private _handleInstall(): void { + const installData: Record = { + entity_id: this._entity!.entity_id, + }; + + if (this._shouldCreateBackup) { + installData.backup = true; + } + + if ( + supportsFeature(this._entity!, UPDATE_SUPPORT_SPECIFIC_VERSION) && + this._entity!.attributes.latest_version + ) { + installData.version = this._entity!.attributes.latest_version; + } + + this.hass.callService("update", "install", installData); + } + + private _handleSkip(): void { + this.hass.callService("update", "skip", { + entity_id: this._entity!.entity_id, + }); + } + + static styles: CSSResultGroup = [ + haStyleDialog, + haStyle, + css` + ha-expansion-panel, + ha-markdown { + margin: 16px 0; + } + .latest_version { + font-weight: 500; + } + .backup { + margin-top: 16px; + } + ha-circular-progress { + width: 100%; + justify-content: center; + } + mwc-linear-progress { + margin-bottom: -10px; + margin-top: -10px; + } + .release_url { + text-align: center; + margin: 16px 0; + } + a.button { + display: inline-block; + text-decoration: none; + color: var(--primary-text-color); + padding: 6px 16px; + border-radius: 32px; + border: 1px solid var(--divider-color); + } + `, + ]; +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-update": DialogUpdate; + } +} diff --git a/src/panels/config/core/ha-config-section-updates.ts b/src/panels/config/updates/ha-config-section-updates.ts similarity index 99% rename from src/panels/config/core/ha-config-section-updates.ts rename to src/panels/config/updates/ha-config-section-updates.ts index 4b2da37924..30e2161c5e 100644 --- a/src/panels/config/core/ha-config-section-updates.ts +++ b/src/panels/config/updates/ha-config-section-updates.ts @@ -30,7 +30,7 @@ import { } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/hass-subpage"; import type { HomeAssistant } from "../../../types"; -import "../dashboard/ha-config-updates"; +import "./ha-config-updates"; @customElement("ha-config-section-updates") class HaConfigSectionUpdates extends LitElement { diff --git a/src/panels/config/dashboard/ha-config-updates.ts b/src/panels/config/updates/ha-config-updates.ts similarity index 94% rename from src/panels/config/dashboard/ha-config-updates.ts rename to src/panels/config/updates/ha-config-updates.ts index a24bce31e2..c558a8f8ef 100644 --- a/src/panels/config/dashboard/ha-config-updates.ts +++ b/src/panels/config/updates/ha-config-updates.ts @@ -2,14 +2,14 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-list/mwc-list"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; -import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/entity/state-badge"; import "../../../components/ha-alert"; +import "../../../components/ha-circular-progress"; import "../../../components/ha-icon-next"; +import "../../../components/ha-list-item"; import type { UpdateEntity } from "../../../data/update"; import type { HomeAssistant } from "../../../types"; -import "../../../components/ha-circular-progress"; -import "../../../components/ha-list-item"; +import { showUpdateDialog } from "./show-update-dialog"; @customElement("ha-config-updates") class HaConfigUpdates extends LitElement { @@ -43,7 +43,7 @@ class HaConfigUpdates extends LitElement { twoline graphic="avatar" class=${entity.attributes.skipped_version ? "skipped" : ""} - .entity_id=${entity.entity_id} + .entity=${entity} .hasMeta=${!this.narrow} @click=${this._openMoreInfo} > @@ -95,9 +95,10 @@ class HaConfigUpdates extends LitElement { } private _openMoreInfo(ev: MouseEvent): void { - fireEvent(this, "hass-more-info", { - entityId: (ev.currentTarget as any).entity_id, - }); + showUpdateDialog(this, { entity: (ev.currentTarget as any).entity }); + // fireEvent(this, "hass-more-info", { + // entityId: (ev.currentTarget as any).entity.entity_id, + // }); } static get styles(): CSSResultGroup[] { diff --git a/src/panels/config/updates/show-update-dialog.ts b/src/panels/config/updates/show-update-dialog.ts new file mode 100644 index 0000000000..3a6ece1c6a --- /dev/null +++ b/src/panels/config/updates/show-update-dialog.ts @@ -0,0 +1,19 @@ +import { fireEvent } from "../../../common/dom/fire_event"; +import type { UpdateEntity } from "../../../data/update"; + +export interface UpdateDialogParams { + entity: UpdateEntity; +} + +export const loadUpdateDialog = () => import("./dialog-update"); + +export const showUpdateDialog = ( + element: HTMLElement, + updateParams: UpdateDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-update", + dialogImport: loadUpdateDialog, + dialogParams: updateParams, + }); +}; diff --git a/src/translations/en.json b/src/translations/en.json index 13084e5d84..285a069bee 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1223,7 +1223,16 @@ "show_skipped": "Show skipped updates", "join_beta": "[%key:supervisor::system::supervisor::join_beta_action%]", "leave_beta": "[%key:supervisor::system::supervisor::leave_beta_action%]", - "skipped": "Skipped" + "skipped": "Skipped", + "dialog": { + "title": "{entity_name} Update Available", + "create_backup": "[%key:ui::dialogs::more_info_control::update::create_backup%]", + "release_notes": "Read release notes", + "update_now": "Update now", + "skip": "[%key:ui::dialogs::more_info_control::update::skip%]", + "clear_skip": "[%key:ui::dialogs::more_info_control::update::clear_skipped%]", + "latest_version": "New version available: {latest_version}" + } }, "repairs": { "caption": "Repairs",