diff --git a/gallery/src/pages/more-info/update.ts b/gallery/src/pages/more-info/update.ts index ce4fa4f6f7..43951d4c5e 100644 --- a/gallery/src/pages/more-info/update.ts +++ b/gallery/src/pages/more-info/update.ts @@ -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 { @@ -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: @@ -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", { @@ -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", { @@ -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, @@ -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, }), ]; diff --git a/src/data/update.ts b/src/data/update.ts index cf13f58daf..01443b5221 100644 --- a/src/data/update.ts +++ b/src/data/update.ts @@ -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; @@ -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 = ( @@ -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; @@ -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", { diff --git a/src/dialogs/more-info/controls/more-info-update.ts b/src/dialogs/more-info/controls/more-info-update.ts index cb62294078..00367bdd37 100644 --- a/src/dialogs/more-info/controls/more-info-update.ts +++ b/src/dialogs/more-info/controls/more-info-update.ts @@ -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"; @@ -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` ` : ""} - ${supportsFeature(this.stateObj!, UPDATE_SUPPORT_RELEASE_NOTES) && + ${supportsFeature(this.stateObj!, UpdateEntityFeature.RELEASE_NOTES) && !this._error ? !this._releaseNotes ? html`
@@ -117,7 +113,7 @@ class MoreInfoUpdate extends LitElement { .content=${this.stateObj.attributes.release_summary} >` : ""} - ${supportsFeature(this.stateObj, UPDATE_SUPPORT_BACKUP) + ${supportsFeature(this.stateObj, UpdateEntityFeature.BACKUP) ? html`
`} - ${supportsFeature(this.stateObj, UPDATE_SUPPORT_INSTALL) + ${supportsFeature(this.stateObj, UpdateEntityFeature.INSTALL) ? html` { this._releaseNotes = result; @@ -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"); @@ -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; diff --git a/src/dialogs/update_backup/dialog-update-backup.ts b/src/dialogs/update_backup/dialog-update-backup.ts new file mode 100644 index 0000000000..5caa9a5841 --- /dev/null +++ b/src/dialogs/update_backup/dialog-update-backup.ts @@ -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 { + this._params = params; + } + + protected render() { + if (!this._params) { + return nothing; + } + + return html` + +

${this.hass.localize("ui.dialogs.update_backup.text")}

+ + ${this.hass!.localize("ui.common.no")} + + + ${this.hass.localize("ui.dialogs.update_backup.create")} + +
+ `; + } + + 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; + } +} diff --git a/src/dialogs/update_backup/show-update-backup-dialog.ts b/src/dialogs/update_backup/show-update-backup-dialog.ts new file mode 100644 index 0000000000..fcb0aa7a41 --- /dev/null +++ b/src/dialogs/update_backup/show-update-backup-dialog.ts @@ -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((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); + } + }, + }, + }); + }); diff --git a/src/panels/lovelace/card-features/hui-update-actions-card-feature.ts b/src/panels/lovelace/card-features/hui-update-actions-card-feature.ts new file mode 100644 index 0000000000..a2f9ddb8ad --- /dev/null +++ b/src/panels/lovelace/card-features/hui-update-actions-card-feature.ts @@ -0,0 +1,165 @@ +import { mdiCancel, mdiCellphoneArrowDown } from "@mdi/js"; +import { HassEntity } from "home-assistant-js-websocket"; +import { LitElement, css, html, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { computeDomain } from "../../../common/entity/compute_domain"; +import { stateActive } from "../../../common/entity/state_active"; +import { supportsFeature } from "../../../common/entity/supports-feature"; +import "../../../components/ha-control-button"; +import "../../../components/ha-control-button-group"; +import { UNAVAILABLE } from "../../../data/entity"; +import { + UpdateEntity, + UpdateEntityFeature, + updateIsInstalling, +} from "../../../data/update"; +import { showUpdateBackupDialogParams } from "../../../dialogs/update_backup/show-update-backup-dialog"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types"; +import { UpdateActionsCardFeatureConfig } from "./types"; + +export const DEFAULT_UPDATE_BACKUP_OPTION = "ask"; + +export const supportsUpdateActionsCardFeature = (stateObj: HassEntity) => { + const domain = computeDomain(stateObj.entity_id); + return ( + domain === "update" && + supportsFeature(stateObj, UpdateEntityFeature.INSTALL) + ); +}; + +@customElement("hui-update-actions-card-feature") +class HuiUpdateActionsCardFeature + extends LitElement + implements LovelaceCardFeature +{ + @property({ attribute: false }) public hass?: HomeAssistant; + + @property({ attribute: false }) public stateObj?: HassEntity; + + @state() private _config?: UpdateActionsCardFeatureConfig; + + public static async getConfigElement(): Promise { + await import( + "../editor/config-elements/hui-update-actions-card-feature-editor" + ); + return document.createElement("hui-update-actions-card-feature-editor"); + } + + static getStubConfig(): UpdateActionsCardFeatureConfig { + return { + type: "update-actions", + backup: DEFAULT_UPDATE_BACKUP_OPTION, + }; + } + + public setConfig(config: UpdateActionsCardFeatureConfig): void { + if (!config) { + throw new Error("Invalid configuration"); + } + this._config = config; + } + + private get _installDisabled(): boolean { + const stateObj = this.stateObj as UpdateEntity; + + if (stateObj.state === UNAVAILABLE) return true; + + const skippedVersion = + stateObj.attributes.latest_version && + stateObj.attributes.skipped_version === + stateObj.attributes.latest_version; + return ( + (!stateActive(stateObj) && !skippedVersion) || + updateIsInstalling(stateObj) + ); + } + + private get _skipDisabled(): boolean { + const stateObj = this.stateObj as UpdateEntity; + + if (stateObj.state === UNAVAILABLE) return true; + + const skippedVersion = + stateObj.attributes.latest_version && + stateObj.attributes.skipped_version === + stateObj.attributes.latest_version; + return ( + skippedVersion || !stateActive(stateObj) || updateIsInstalling(stateObj) + ); + } + + private async _install(): Promise { + const supportsBackup = supportsFeature( + this.stateObj!, + UpdateEntityFeature.BACKUP + ); + let backup = supportsBackup && this._config?.backup === "yes"; + + if (supportsBackup && this._config?.backup === "ask") { + const response = await showUpdateBackupDialogParams(this, {}); + if (response === null) return; + backup = response; + } + + this.hass!.callService("update", "install", { + entity_id: this.stateObj!.entity_id, + backup: backup, + }); + } + + private async _skip(): Promise { + this.hass!.callService("update", "skip", { + entity_id: this.stateObj!.entity_id, + }); + } + + protected render() { + if ( + !this._config || + !this.hass || + !this.stateObj || + !supportsUpdateActionsCardFeature(this.stateObj) + ) { + return nothing; + } + + return html` + + + + + + + + + `; + } + + static get styles() { + return css` + ha-control-button-group { + margin: 0 12px 12px 12px; + --control-button-group-spacing: 12px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-update-actions-card-feature": HuiUpdateActionsCardFeature; + } +} diff --git a/src/panels/lovelace/card-features/types.ts b/src/panels/lovelace/card-features/types.ts index f70c792bb7..e5c4d38858 100644 --- a/src/panels/lovelace/card-features/types.ts +++ b/src/panels/lovelace/card-features/types.ts @@ -109,6 +109,11 @@ export interface LawnMowerCommandsCardFeatureConfig { commands?: LawnMowerCommand[]; } +export interface UpdateActionsCardFeatureConfig { + type: "update-actions"; + backup?: "yes" | "no" | "ask"; +} + export type LovelaceCardFeatureConfig = | AlarmModesCardFeatureConfig | ClimateFanModesCardFeatureConfig @@ -129,7 +134,8 @@ export type LovelaceCardFeatureConfig = | TargetTemperatureCardFeatureConfig | WaterHeaterOperationModesCardFeatureConfig | SelectOptionsCardFeatureConfig - | NumericInputCardFeatureConfig; + | NumericInputCardFeatureConfig + | UpdateActionsCardFeatureConfig; export type LovelaceCardFeatureContext = { entity_id?: string; diff --git a/src/panels/lovelace/create-element/create-card-feature-element.ts b/src/panels/lovelace/create-element/create-card-feature-element.ts index a5d099c20d..5508221430 100644 --- a/src/panels/lovelace/create-element/create-card-feature-element.ts +++ b/src/panels/lovelace/create-element/create-card-feature-element.ts @@ -18,6 +18,8 @@ import "../card-features/hui-target-temperature-card-feature"; import "../card-features/hui-target-humidity-card-feature"; import "../card-features/hui-vacuum-commands-card-feature"; import "../card-features/hui-water-heater-operation-modes-card-feature"; +import "../card-features/hui-update-actions-card-feature"; + import { LovelaceCardFeatureConfig } from "../card-features/types"; import { createLovelaceElement, @@ -45,6 +47,7 @@ const TYPES: Set = new Set([ "target-temperature", "vacuum-commands", "water-heater-operation-modes", + "update-actions", ]); export const createCardFeatureElement = (config: LovelaceCardFeatureConfig) => diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts index 051f31e4d1..e7d44e0922 100644 --- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts @@ -30,8 +30,8 @@ import { supportsCoverPositionCardFeature } from "../../card-features/hui-cover- import { supportsCoverTiltCardFeature } from "../../card-features/hui-cover-tilt-card-feature"; import { supportsCoverTiltPositionCardFeature } from "../../card-features/hui-cover-tilt-position-card-feature"; import { supportsFanSpeedCardFeature } from "../../card-features/hui-fan-speed-card-feature"; -import { supportsHumidifierToggleCardFeature } from "../../card-features/hui-humidifier-toggle-card-feature"; import { supportsHumidifierModesCardFeature } from "../../card-features/hui-humidifier-modes-card-feature"; +import { supportsHumidifierToggleCardFeature } from "../../card-features/hui-humidifier-toggle-card-feature"; import { supportsLawnMowerCommandCardFeature } from "../../card-features/hui-lawn-mower-commands-card-feature"; import { supportsLightBrightnessCardFeature } from "../../card-features/hui-light-brightness-card-feature"; import { supportsLightColorTempCardFeature } from "../../card-features/hui-light-color-temp-card-feature"; @@ -43,6 +43,7 @@ import { supportsVacuumCommandsCardFeature } from "../../card-features/hui-vacuu import { supportsWaterHeaterOperationModesCardFeature } from "../../card-features/hui-water-heater-operation-modes-card-feature"; import { LovelaceCardFeatureConfig } from "../../card-features/types"; import { getCardFeatureElementClass } from "../../create-element/create-card-feature-element"; +import { supportsUpdateActionsCardFeature } from "../../card-features/hui-update-actions-card-feature"; export type FeatureType = LovelaceCardFeatureConfig["type"]; type SupportsFeature = (stateObj: HassEntity) => boolean; @@ -66,6 +67,7 @@ const UI_FEATURE_TYPES = [ "target-humidity", "target-temperature", "vacuum-commands", + "update-actions", "water-heater-operation-modes", "numeric-input", ] as const satisfies readonly FeatureType[]; @@ -81,6 +83,7 @@ const EDITABLES_FEATURE_TYPES = new Set([ "lawn-mower-commands", "climate-preset-modes", "numeric-input", + "update-actions", ]); const SUPPORTS_FEATURE_TYPES: Record< @@ -107,6 +110,7 @@ const SUPPORTS_FEATURE_TYPES: Record< "vacuum-commands": supportsVacuumCommandsCardFeature, "water-heater-operation-modes": supportsWaterHeaterOperationModesCardFeature, "select-options": supportsSelectOptionsCardFeature, + "update-actions": supportsUpdateActionsCardFeature, }; const customCardFeatures = getCustomCardFeatures(); diff --git a/src/panels/lovelace/editor/config-elements/hui-update-actions-card-feature-editor.ts b/src/panels/lovelace/editor/config-elements/hui-update-actions-card-feature-editor.ts new file mode 100644 index 0000000000..f1478f090e --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-update-actions-card-feature-editor.ts @@ -0,0 +1,131 @@ +import { html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import type { LocalizeFunc } from "../../../../common/translations/localize"; +import "../../../../components/ha-form/ha-form"; +import type { SchemaUnion } from "../../../../components/ha-form/types"; +import type { HomeAssistant } from "../../../../types"; +import { + LovelaceCardFeatureContext, + UpdateActionsCardFeatureConfig, +} from "../../card-features/types"; +import type { LovelaceCardFeatureEditor } from "../../types"; +import { supportsFeature } from "../../../../common/entity/supports-feature"; +import { UpdateEntityFeature } from "../../../../data/update"; +import { DEFAULT_UPDATE_BACKUP_OPTION } from "../../card-features/hui-update-actions-card-feature"; + +@customElement("hui-update-actions-card-feature-editor") +export class HuiUpdateActionsCardFeatureEditor + extends LitElement + implements LovelaceCardFeatureEditor +{ + @property({ attribute: false }) public hass?: HomeAssistant; + + @property({ attribute: false }) public context?: LovelaceCardFeatureContext; + + @state() private _config?: UpdateActionsCardFeatureConfig; + + public setConfig(config: UpdateActionsCardFeatureConfig): void { + this._config = config; + } + + private _schema = memoizeOne( + (localize: LocalizeFunc, supportsBackup: boolean) => + [ + { + name: "backup", + disabled: !supportsBackup, + selector: { + select: { + default: "yes", + mode: "dropdown", + options: ["ask", "yes", "no"].map((option) => ({ + value: option, + label: localize( + `ui.panel.lovelace.editor.features.types.update-actions.backup_options.${option}` + ), + })), + }, + }, + }, + ] as const + ); + + private get _stateObj() { + return this.context?.entity_id + ? this.hass!.states[this.context?.entity_id] + : undefined; + } + + protected render() { + if (!this.hass || !this._config) { + return nothing; + } + + const supportsBackup = + this._stateObj != null && + supportsFeature(this._stateObj, UpdateEntityFeature.BACKUP); + + const schema = this._schema(this.hass.localize, supportsBackup); + + const data = { ...this._config }; + + if (!this._config.backup && supportsBackup) { + data.backup = DEFAULT_UPDATE_BACKUP_OPTION; + } + + return html` + + `; + } + + private _valueChanged(ev: CustomEvent): void { + fireEvent(this, "config-changed", { config: ev.detail.value }); + } + + private _computeLabelCallback = ( + schema: SchemaUnion> + ) => { + switch (schema.name) { + case "backup": + return this.hass!.localize( + `ui.panel.lovelace.editor.features.types.update-actions.${schema.name}` + ); + default: + return ""; + } + }; + + private _computeHelperCallback = ( + schema: SchemaUnion> + ) => { + const supportsBackup = + this._stateObj != null && + supportsFeature(this._stateObj, UpdateEntityFeature.BACKUP); + + switch (schema.name) { + case "backup": + if (!supportsBackup) { + return this.hass!.localize( + "ui.panel.lovelace.editor.features.types.update-actions.backup_not_supported" + ); + } + return undefined; + } + return undefined; + }; +} + +declare global { + interface HTMLElementTagNameMap { + "hui-update-actions-card-feature-editor": HuiUpdateActionsCardFeatureEditor; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index bf94d0c85b..41edb442a3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1547,6 +1547,11 @@ "gateway": "Gateway: {gateway}", "method": "Method: {method}", "nameservers": "Name Servers: {nameservers}" + }, + "update_backup": { + "title": "Create backup?", + "text": "This will create a backup before installing.", + "create": "Create" } }, "weekdays": { @@ -5518,6 +5523,16 @@ "start_pause": "Start Pause", "dock": "[%key:ui::dialogs::more_info_control::lawn_mower::dock%]" } + }, + "update-actions": { + "label": "Update actions", + "backup": "Backup", + "backup_options": { + "yes": "[%key:ui::common::yes%]", + "no": "[%key:ui::common::no%]", + "ask": "Ask" + }, + "backup_not_supported": "Backup is not supported." } } },