Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add update actions card feature #19110

Merged
merged 7 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions gallery/src/pages/more-info/update.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import {
UPDATE_SUPPORT_BACKUP,
UPDATE_SUPPORT_PROGRESS,
UPDATE_SUPPORT_INSTALL,
UPDATE_SUPPORT_RELEASE_NOTES,
} from "../../../../src/data/update";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
Expand All @@ -15,13 +9,14 @@ import {
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
import { LONG_TEXT } from "../../data/text";
import { UpdateEntityFeature } from "../../../../src/data/update";

const base_attributes = {
title: "Awesome",
installed_version: "1.2.2",
latest_version: "1.2.3",
release_url: "https://home-assistant.io",
supported_features: UPDATE_SUPPORT_INSTALL,
supported_features: UpdateEntityFeature.INSTALL,
skipped_version: null,
in_progress: false,
release_summary:
Expand Down Expand Up @@ -61,7 +56,7 @@ const ENTITIES = [
getEntity("update", "update7", "on", {
...base_attributes,
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_BACKUP,
base_attributes.supported_features + UpdateEntityFeature.BACKUP,
friendly_name: "With backup support",
}),
getEntity("update", "update8", "on", {
Expand All @@ -73,21 +68,21 @@ const ENTITIES = [
...base_attributes,
in_progress: 25,
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_PROGRESS,
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
friendly_name: "With 25 in_progress",
}),
getEntity("update", "update10", "on", {
...base_attributes,
in_progress: 50,
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_PROGRESS,
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
friendly_name: "With 50 in_progress",
}),
getEntity("update", "update11", "on", {
...base_attributes,
in_progress: 75,
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_PROGRESS,
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
friendly_name: "With 75 in_progress",
}),
getEntity("update", "update12", "unavailable", {
Expand All @@ -114,19 +109,19 @@ const ENTITIES = [
...base_attributes,
friendly_name: "Update with release notes",
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_RELEASE_NOTES,
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
}),
getEntity("update", "update17", "off", {
...base_attributes,
friendly_name: "Update with release notes error",
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_RELEASE_NOTES,
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
}),
getEntity("update", "update18", "off", {
...base_attributes,
friendly_name: "Update with release notes loading",
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_RELEASE_NOTES,
base_attributes.supported_features + UpdateEntityFeature.RELEASE_NOTES,
}),
getEntity("update", "update19", "on", {
...base_attributes,
Expand All @@ -142,9 +137,10 @@ const ENTITIES = [
getEntity("update", "update21", "on", {
...base_attributes,
in_progress: true,
friendly_name: "Update with in_progress true and UPDATE_SUPPORT_PROGRESS",
friendly_name:
"Update with in_progress true and UpdateEntityFeature.PROGRESS",
supported_features:
base_attributes.supported_features + UPDATE_SUPPORT_PROGRESS,
base_attributes.supported_features + UpdateEntityFeature.PROGRESS,
}),
];

Expand Down
18 changes: 10 additions & 8 deletions src/data/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import { showAlertDialog } from "../dialogs/generic/show-dialog-box";
import { HomeAssistant } from "../types";
import { showToast } from "../util/toast";

export const UPDATE_SUPPORT_INSTALL = 1;
export const UPDATE_SUPPORT_SPECIFIC_VERSION = 2;
export const UPDATE_SUPPORT_PROGRESS = 4;
export const UPDATE_SUPPORT_BACKUP = 8;
export const UPDATE_SUPPORT_RELEASE_NOTES = 16;
export enum UpdateEntityFeature {
INSTALL = 1,
SPECIFIC_VERSION = 2,
PROGRESS = 4,
BACKUP = 8,
RELEASE_NOTES = 16,
}

interface UpdateEntityAttributes extends HassEntityAttributeBase {
auto_update: boolean | null;
Expand All @@ -35,7 +37,7 @@ export interface UpdateEntity extends HassEntityBase {
}

export const updateUsesProgress = (entity: UpdateEntity): boolean =>
supportsFeature(entity, UPDATE_SUPPORT_PROGRESS) &&
supportsFeature(entity, UpdateEntityFeature.PROGRESS) &&
typeof entity.attributes.in_progress === "number";

export const updateCanInstall = (
Expand All @@ -44,7 +46,7 @@ export const updateCanInstall = (
): boolean =>
(entity.state === BINARY_STATE_ON ||
(showSkipped && Boolean(entity.attributes.skipped_version))) &&
supportsFeature(entity, UPDATE_SUPPORT_INSTALL);
supportsFeature(entity, UpdateEntityFeature.INSTALL);

export const updateIsInstalling = (entity: UpdateEntity): boolean =>
updateUsesProgress(entity) || !!entity.attributes.in_progress;
Expand Down Expand Up @@ -176,7 +178,7 @@ export const computeUpdateStateDisplay = (
if (state === "on") {
if (updateIsInstalling(stateObj)) {
const supportsProgress =
supportsFeature(stateObj, UPDATE_SUPPORT_PROGRESS) &&
supportsFeature(stateObj, UpdateEntityFeature.PROGRESS) &&
typeof attributes.in_progress === "number";
if (supportsProgress) {
return hass.localize("ui.card.update.installing_with_progress", {
Expand Down
20 changes: 8 additions & 12 deletions src/dialogs/more-info/controls/more-info-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ import "../../../components/ha-markdown";
import { isUnavailableState } from "../../../data/entity";
import {
UpdateEntity,
UpdateEntityFeature,
updateIsInstalling,
updateReleaseNotes,
UPDATE_SUPPORT_BACKUP,
UPDATE_SUPPORT_INSTALL,
UPDATE_SUPPORT_PROGRESS,
UPDATE_SUPPORT_RELEASE_NOTES,
UPDATE_SUPPORT_SPECIFIC_VERSION,
} from "../../../data/update";
import type { HomeAssistant } from "../../../types";

Expand Down Expand Up @@ -49,7 +45,7 @@ class MoreInfoUpdate extends LitElement {

return html`
${this.stateObj.attributes.in_progress
? supportsFeature(this.stateObj, UPDATE_SUPPORT_PROGRESS) &&
? supportsFeature(this.stateObj, UpdateEntityFeature.PROGRESS) &&
typeof this.stateObj.attributes.in_progress === "number"
? html`<mwc-linear-progress
.progress=${this.stateObj.attributes.in_progress / 100}
Expand Down Expand Up @@ -101,7 +97,7 @@ class MoreInfoUpdate extends LitElement {
</div>
</div>`
: ""}
${supportsFeature(this.stateObj!, UPDATE_SUPPORT_RELEASE_NOTES) &&
${supportsFeature(this.stateObj!, UpdateEntityFeature.RELEASE_NOTES) &&
!this._error
? !this._releaseNotes
? html`<div class="flex center">
Expand All @@ -117,7 +113,7 @@ class MoreInfoUpdate extends LitElement {
.content=${this.stateObj.attributes.release_summary}
></ha-markdown>`
: ""}
${supportsFeature(this.stateObj, UPDATE_SUPPORT_BACKUP)
${supportsFeature(this.stateObj, UpdateEntityFeature.BACKUP)
? html`<hr />
<ha-formfield
.label=${this.hass.localize(
Expand Down Expand Up @@ -155,7 +151,7 @@ class MoreInfoUpdate extends LitElement {
)}
</mwc-button>
`}
${supportsFeature(this.stateObj, UPDATE_SUPPORT_INSTALL)
${supportsFeature(this.stateObj, UpdateEntityFeature.INSTALL)
? html`
<mwc-button
@click=${this._handleInstall}
Expand All @@ -174,7 +170,7 @@ class MoreInfoUpdate extends LitElement {
}

protected firstUpdated(): void {
if (supportsFeature(this.stateObj!, UPDATE_SUPPORT_RELEASE_NOTES)) {
if (supportsFeature(this.stateObj!, UpdateEntityFeature.RELEASE_NOTES)) {
updateReleaseNotes(this.hass, this.stateObj!.entity_id)
.then((result) => {
this._releaseNotes = result;
Expand All @@ -186,7 +182,7 @@ class MoreInfoUpdate extends LitElement {
}

get _shouldCreateBackup(): boolean | null {
if (!supportsFeature(this.stateObj!, UPDATE_SUPPORT_BACKUP)) {
if (!supportsFeature(this.stateObj!, UpdateEntityFeature.BACKUP)) {
return null;
}
const checkbox = this.shadowRoot?.querySelector("ha-checkbox");
Expand All @@ -206,7 +202,7 @@ class MoreInfoUpdate extends LitElement {
}

if (
supportsFeature(this.stateObj!, UPDATE_SUPPORT_SPECIFIC_VERSION) &&
supportsFeature(this.stateObj!, UpdateEntityFeature.SPECIFIC_VERSION) &&
this.stateObj!.attributes.latest_version
) {
installData.version = this.stateObj!.attributes.latest_version;
Expand Down
92 changes: 92 additions & 0 deletions src/dialogs/update_backup/dialog-update-backup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import "../../components/ha-button";
import { createCloseHeading } from "../../components/ha-dialog";
import { HomeAssistant } from "../../types";
import { UpdateBackupDialogParams } from "./show-update-backup-dialog";

@customElement("dialog-update-backup")
class DialogBox extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@state() private _params?: UpdateBackupDialogParams;

public async showDialog(params: UpdateBackupDialogParams): Promise<void> {
this._params = params;
}

protected render() {
if (!this._params) {
return nothing;
}

return html`
<ha-dialog
open
@closed=${this._cancel}
defaultAction="ignore"
.heading=${createCloseHeading(
this.hass,
this.hass.localize("ui.dialogs.update_backup.title")
)}
>
<p>${this.hass.localize("ui.dialogs.update_backup.text")}</p>
<ha-button @click=${this._no} slot="secondaryAction">
${this.hass!.localize("ui.common.no")}
</ha-button>
<ha-button @click=${this._yes} slot="primaryAction">
${this.hass.localize("ui.dialogs.update_backup.create")}
</ha-button>
</ha-dialog>
`;
}

private _no(): void {
if (this._params!.submit) {
this._params!.submit(false);
}
this.closeDialog();
}

private _yes(): void {
if (this._params!.submit) {
this._params!.submit(true);
}
this.closeDialog();
}

private _cancel(): void {
this._params?.cancel?.();
this.closeDialog();
}

public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}

static get styles(): CSSResultGroup {
return css`
p {
margin: 0;
color: var(--primary-text-color);
}
ha-dialog {
/* Place above other dialogs */
--dialog-z-index: 104;
}
@media all and (min-width: 600px) {
ha-dialog {
--mdc-dialog-min-width: 400px;
}
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"dialog-update-backup": DialogBox;
}
}
35 changes: 35 additions & 0 deletions src/dialogs/update_backup/show-update-backup-dialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { fireEvent } from "../../common/dom/fire_event";

export interface UpdateBackupDialogParams {
submit?: (response: boolean) => void;
cancel?: () => void;
}

export const showUpdateBackupDialogParams = (
element: HTMLElement,
dialogParams: UpdateBackupDialogParams
) =>
new Promise<boolean | null>((resolve) => {
const origCancel = dialogParams.cancel;
const origSubmit = dialogParams.submit;

fireEvent(element, "show-dialog", {
dialogTag: "dialog-update-backup",
dialogImport: () => import("./dialog-update-backup"),
dialogParams: {
...dialogParams,
cancel: () => {
resolve(null);
if (origCancel) {
origCancel();
}
},
submit: (response: boolean) => {
resolve(response);
if (origSubmit) {
origSubmit(response);
}
},
},
});
});
Loading
Loading