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`
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",