From 282710dacd2513a2927afcf1c9fedd82ac1ea826 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 16 Oct 2024 14:56:38 +0200 Subject: [PATCH] Add confirm dialog when deleting a badge --- .../components/hui-badge-edit-mode.ts | 8 +- .../badge-editor/hui-dialog-delete-badge.ts | 104 ++++++++++++++++++ .../badge-editor/show-delete-badge-dialog.ts | 21 ++++ src/panels/lovelace/editor/config-util.ts | 4 +- src/panels/lovelace/editor/delete-badge.ts | 47 ++++++++ src/panels/lovelace/views/hui-view.ts | 11 +- src/translations/en.json | 5 +- 7 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 src/panels/lovelace/editor/badge-editor/hui-dialog-delete-badge.ts create mode 100644 src/panels/lovelace/editor/badge-editor/show-delete-badge-dialog.ts create mode 100644 src/panels/lovelace/editor/delete-badge.ts diff --git a/src/panels/lovelace/components/hui-badge-edit-mode.ts b/src/panels/lovelace/components/hui-badge-edit-mode.ts index bf57aae9b6..6edf4151da 100644 --- a/src/panels/lovelace/components/hui-badge-edit-mode.ts +++ b/src/panels/lovelace/components/hui-badge-edit-mode.ts @@ -180,14 +180,14 @@ export class HuiBadgeEditMode extends LitElement { this._cutBadge(); break; case 3: - this._deleteBadge(); + this._deleteBadge(true); break; } } private _cutBadge(): void { this._copyBadge(); - this._deleteBadge(); + this._deleteBadge(false); } private _copyBadge(): void { @@ -220,8 +220,8 @@ export class HuiBadgeEditMode extends LitElement { fireEvent(this, "ll-edit-badge", { path: this.path! }); } - private _deleteBadge(): void { - fireEvent(this, "ll-delete-badge", { path: this.path! }); + private _deleteBadge(confirm: boolean): void { + fireEvent(this, "ll-delete-badge", { path: this.path!, confirm }); } static get styles(): CSSResultGroup { diff --git a/src/panels/lovelace/editor/badge-editor/hui-dialog-delete-badge.ts b/src/panels/lovelace/editor/badge-editor/hui-dialog-delete-badge.ts new file mode 100644 index 0000000000..d5398f841a --- /dev/null +++ b/src/panels/lovelace/editor/badge-editor/hui-dialog-delete-badge.ts @@ -0,0 +1,104 @@ +import deepFreeze from "deep-freeze"; +import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import type { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge"; +import { haStyleDialog } from "../../../../resources/styles"; +import type { HomeAssistant } from "../../../../types"; +import "../../badges/hui-badge"; +import type { DeleteBadgeDialogParams } from "./show-delete-badge-dialog"; + +@customElement("hui-dialog-delete-badge") +export class HuiDialogDeleteBadge extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _params?: DeleteBadgeDialogParams; + + @state() private _badgeConfig?: LovelaceBadgeConfig; + + public async showDialog(params: DeleteBadgeDialogParams): Promise { + this._params = params; + this._badgeConfig = params.badgeConfig; + if (!Object.isFrozen(this._badgeConfig)) { + this._badgeConfig = deepFreeze(this._badgeConfig); + } + } + + public closeDialog(): void { + this._params = undefined; + this._badgeConfig = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render() { + if (!this._params) { + return nothing; + } + + return html` + +
+ ${this._badgeConfig + ? html` +
+ +
+ ` + : ""} +
+ + ${this.hass!.localize("ui.common.cancel")} + + + ${this.hass!.localize("ui.common.delete")} + +
+ `; + } + + static get styles(): CSSResultGroup { + return [ + haStyleDialog, + css` + .element-preview { + position: relative; + max-width: 500px; + display: block; + width: 100%; + display: flex; + } + hui-badge { + margin: 4px auto; + } + `, + ]; + } + + private _delete(): void { + if (!this._params?.deleteBadge) { + return; + } + this._params.deleteBadge(); + this.closeDialog(); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-dialog-delete-badge": HuiDialogDeleteBadge; + } +} diff --git a/src/panels/lovelace/editor/badge-editor/show-delete-badge-dialog.ts b/src/panels/lovelace/editor/badge-editor/show-delete-badge-dialog.ts new file mode 100644 index 0000000000..a7240cad76 --- /dev/null +++ b/src/panels/lovelace/editor/badge-editor/show-delete-badge-dialog.ts @@ -0,0 +1,21 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; +import { LovelaceBadgeConfig } from "../../../../data/lovelace/config/badge"; + +export interface DeleteBadgeDialogParams { + deleteBadge: () => void; + badgeConfig?: LovelaceBadgeConfig; +} + +export const importDeleteBadgeDialog = () => + import("./hui-dialog-delete-badge"); + +export const showDeleteBadgeDialog = ( + element: HTMLElement, + deleteBadgeDialogParams: DeleteBadgeDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "hui-dialog-delete-badge", + dialogImport: importDeleteBadgeDialog, + dialogParams: deleteBadgeDialogParams, + }); +}; diff --git a/src/panels/lovelace/editor/config-util.ts b/src/panels/lovelace/editor/config-util.ts index 7d467d9aaa..473b8d2448 100644 --- a/src/panels/lovelace/editor/config-util.ts +++ b/src/panels/lovelace/editor/config-util.ts @@ -372,13 +372,13 @@ export const deleteBadge = ( config: LovelaceConfig, path: LovelaceCardPath ): LovelaceConfig => { - const { cardIndex } = parseLovelaceCardPath(path); + const { cardIndex: badgeIndex } = parseLovelaceCardPath(path); const containerPath = getLovelaceContainerPath(path); const badges = findLovelaceItems("badges", config, containerPath); const newBadges = (badges ?? []).filter( - (_origConf, ind) => ind !== cardIndex + (_origConf, ind) => ind !== badgeIndex ); const newConfig = updateLovelaceItems( diff --git a/src/panels/lovelace/editor/delete-badge.ts b/src/panels/lovelace/editor/delete-badge.ts new file mode 100644 index 0000000000..859182f5fa --- /dev/null +++ b/src/panels/lovelace/editor/delete-badge.ts @@ -0,0 +1,47 @@ +import { ensureBadgeConfig } from "../../../data/lovelace/config/badge"; +import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; +import { HomeAssistant } from "../../../types"; +import { showDeleteSuccessToast } from "../../../util/toast-deleted-success"; +import { Lovelace } from "../types"; +import { showDeleteBadgeDialog } from "./badge-editor/show-delete-badge-dialog"; +import { deleteBadge, insertBadge } from "./config-util"; +import { + LovelaceCardPath, + findLovelaceItems, + getLovelaceContainerPath, + parseLovelaceCardPath, +} from "./lovelace-path"; + +export async function confDeleteBadge( + element: HTMLElement, + hass: HomeAssistant, + lovelace: Lovelace, + path: LovelaceCardPath +): Promise { + const { cardIndex: badgeIndex } = parseLovelaceCardPath(path); + const containerPath = getLovelaceContainerPath(path); + + const badges = findLovelaceItems("badges", lovelace.config, containerPath); + + const badgeConfig = ensureBadgeConfig(badges![badgeIndex]); + + showDeleteBadgeDialog(element, { + badgeConfig, + deleteBadge: async () => { + try { + const newLovelace = deleteBadge(lovelace.config, path); + await lovelace.saveConfig(newLovelace); + const action = async () => { + await lovelace.saveConfig( + insertBadge(newLovelace, path, badgeConfig) + ); + }; + showDeleteSuccessToast(element, hass!, action); + } catch (err: any) { + showAlertDialog(element, { + text: `Deleting failed: ${err.message}`, + }); + } + }, + }); +} diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index 5d0feb7fb4..9fba858021 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -37,6 +37,7 @@ import { generateLovelaceViewStrategy } from "../strategies/get-strategy"; import type { Lovelace } from "../types"; import { DEFAULT_VIEW_LAYOUT, PANEL_VIEW_LAYOUT } from "./const"; import { showCreateBadgeDialog } from "../editor/badge-editor/show-create-badge-dialog"; +import { confDeleteBadge } from "../editor/delete-badge"; declare global { // for fire event @@ -46,7 +47,7 @@ declare global { "ll-delete-card": { path: LovelaceCardPath; confirm: boolean }; "ll-create-badge": undefined; "ll-edit-badge": { path: LovelaceCardPath }; - "ll-delete-badge": { path: LovelaceCardPath }; + "ll-delete-badge": { path: LovelaceCardPath; confirm: boolean }; } interface HTMLElementEventMap { "ll-create-card": HASSDomEvent; @@ -348,8 +349,12 @@ export class HUIView extends ReactiveElement { }); }); this._layoutElement.addEventListener("ll-delete-badge", (ev) => { - const newLovelace = deleteBadge(this.lovelace!.config, ev.detail.path); - this.lovelace.saveConfig(newLovelace); + if (ev.detail.confirm) { + confDeleteBadge(this, this.hass!, this.lovelace!, ev.detail.path); + } else { + const newLovelace = deleteBadge(this.lovelace!.config, ev.detail.path); + this.lovelace.saveConfig(newLovelace); + } }); } diff --git a/src/translations/en.json b/src/translations/en.json index faaad698a3..2b362ee42e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -5360,7 +5360,7 @@ } }, "cards": { - "confirm_delete": "Are you sure you want to delete this card?", + "confirm_delete": "Delete card?", "show_more_info": "Show more information", "actions": { "action_confirmation": "Are you sure you want to run action ''{action}''?", @@ -5496,6 +5496,9 @@ "default_heading": "Kitchen" } }, + "badges": { + "confirm_delete": "Delete badge?" + }, "unused_entities": { "title": "Unused entities", "available_entities": "These are the entities that you have available, but are not in your dashboard yet.",