From 7a7bd87f500ffa94911a5815f6385114785e2928 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 29 May 2024 12:29:52 +0200 Subject: [PATCH] Unify usage of dashboard title (#20853) --- cast/src/launcher/layout/hc-cast.ts | 12 +- cast/src/receiver/layout/hc-lovelace.ts | 8 +- cast/src/receiver/layout/hc-main.ts | 7 +- src/data/lovelace/config/types.ts | 1 - src/data/panel.ts | 20 ++- .../dialog-lovelace-dashboard-detail.ts | 2 +- .../ha-config-lovelace-dashboards.ts | 26 ++-- .../show-dialog-lovelace-dashboard-detail.ts | 2 +- .../hui-dialog-edit-lovelace.ts | 124 ------------------ .../lovelace-editor/hui-lovelace-editor.ts | 77 ----------- .../show-edit-lovelace-dialog.ts | 31 ----- src/panels/lovelace/ha-panel-lovelace.ts | 1 + src/panels/lovelace/hui-root.ts | 85 +++++++++--- .../iframe/iframe-dashboard-strategy.ts | 1 - .../strategies/map/map-dashboard-strategy.ts | 5 +- .../original-states-dashboard-strategy.ts | 7 +- src/state/panel-title-mixin.ts | 4 +- 17 files changed, 122 insertions(+), 291 deletions(-) delete mode 100644 src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts delete mode 100644 src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts delete mode 100644 src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts diff --git a/cast/src/launcher/layout/hc-cast.ts b/cast/src/launcher/layout/hc-cast.ts index 27de4e0198..67a5f08c1c 100644 --- a/cast/src/launcher/layout/hc-cast.ts +++ b/cast/src/launcher/layout/hc-cast.ts @@ -1,5 +1,5 @@ import "@material/mwc-button/mwc-button"; -import { mdiCast, mdiCastConnected } from "@mdi/js"; +import { mdiCast, mdiCastConnected, mdiViewDashboard } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import { Auth, Connection } from "home-assistant-js-websocket"; @@ -104,8 +104,11 @@ class HcCast extends LitElement { slot="item-icon" > ` - : ""} - ${view.title || view.path} + : html``} + ${view.title || view.path || "Unnamed view"} ` )} @@ -250,7 +253,8 @@ class HcCast extends LitElement { padding-top: 0; } - paper-listbox ha-icon { + paper-listbox ha-icon, + paper-listbox ha-svg-icon { padding: 12px; color: var(--secondary-text-color); } diff --git a/cast/src/receiver/layout/hc-lovelace.ts b/cast/src/receiver/layout/hc-lovelace.ts index 01b6f03fb0..ede937743a 100644 --- a/cast/src/receiver/layout/hc-lovelace.ts +++ b/cast/src/receiver/layout/hc-lovelace.ts @@ -2,6 +2,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import { LovelaceConfig } from "../../../../src/data/lovelace/config/types"; +import { getPanelTitleFromUrlPath } from "../../../../src/data/panel"; import { Lovelace } from "../../../../src/panels/lovelace/types"; import "../../../../src/panels/lovelace/views/hui-view"; import { HomeAssistant } from "../../../../src/types"; @@ -61,7 +62,12 @@ class HcLovelace extends LitElement { const index = this._viewIndex; if (index !== undefined) { - const dashboardTitle = this.lovelaceConfig.title || this.urlPath; + const title = getPanelTitleFromUrlPath( + this.hass, + this.urlPath || "lovelace" + ); + + const dashboardTitle = title || this.urlPath; const viewTitle = this.lovelaceConfig.views[index].title || diff --git a/cast/src/receiver/layout/hc-main.ts b/cast/src/receiver/layout/hc-main.ts index cc0f3bc48f..c729b14556 100644 --- a/cast/src/receiver/layout/hc-main.ts +++ b/cast/src/receiver/layout/hc-main.ts @@ -35,6 +35,7 @@ import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/lo import { HassElement } from "../../../../src/state/hass-element"; import { castContext } from "../cast_context"; import "./hc-launch-screen"; +import { getPanelTitleFromUrlPath } from "../../../../src/data/panel"; const DEFAULT_CONFIG: LovelaceDashboardStrategyConfig = { strategy: { @@ -359,7 +360,11 @@ export class HcMain extends HassElement { } private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) { - castContext.setApplicationState(lovelaceConfig.title || ""); + const title = getPanelTitleFromUrlPath( + this.hass!, + this._urlPath || "lovelace" + ); + castContext.setApplicationState(title || ""); this._lovelaceConfig = lovelaceConfig; } diff --git a/src/data/lovelace/config/types.ts b/src/data/lovelace/config/types.ts index 8104493c64..7de222dab8 100644 --- a/src/data/lovelace/config/types.ts +++ b/src/data/lovelace/config/types.ts @@ -7,7 +7,6 @@ import type { LovelaceViewRawConfig } from "./view"; export interface LovelaceDashboardBaseConfig {} export interface LovelaceConfig extends LovelaceDashboardBaseConfig { - title?: string; background?: string; views: LovelaceViewRawConfig[]; } diff --git a/src/data/panel.ts b/src/data/panel.ts index fb6013e0fd..76c716e56c 100644 --- a/src/data/panel.ts +++ b/src/data/panel.ts @@ -33,22 +33,32 @@ export const getPanelNameTranslationKey = (panel: PanelInfo) => { return `panel.${panel.title}` as const; }; -export const getPanelTitle = (hass: HomeAssistant): string | undefined => { +export const getPanelTitle = ( + hass: HomeAssistant, + panel: PanelInfo +): string | undefined => { + const translationKey = getPanelNameTranslationKey(panel); + + return hass.localize(translationKey) || panel.title || undefined; +}; + +export const getPanelTitleFromUrlPath = ( + hass: HomeAssistant, + urlPath: string +): string | undefined => { if (!hass.panels) { return undefined; } const panel = Object.values(hass.panels).find( - (p: PanelInfo): boolean => p.url_path === hass.panelUrl + (p: PanelInfo): boolean => p.url_path === urlPath ); if (!panel) { return undefined; } - const translationKey = getPanelNameTranslationKey(panel); - - return hass.localize(translationKey) || panel.title || undefined; + return getPanelTitle(hass, panel); }; export const getPanelIcon = (panel: PanelInfo): string | null => { diff --git a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts index 4937da71ad..7e00f7c957 100644 --- a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts +++ b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts @@ -277,7 +277,7 @@ export class DialogLovelaceDashboardDetail extends LitElement { title: this._data!.title, }; await this._params!.updateDashboard(values); - } else { + } else if (this._params!.createDashboard) { await this._params!.createDashboard( this._data as LovelaceDashboardCreateParams ); diff --git a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts index a089218c8c..fcdf220845 100644 --- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts +++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts @@ -423,22 +423,20 @@ export class HaConfigLovelaceDashboards extends LitElement { ); }, removeDashboard: async () => { - if ( - !(await showConfirmationDialog(this, { - title: this.hass!.localize( - "ui.panel.config.lovelace.dashboards.confirm_delete_title", - { dashboard_title: dashboard!.title } - ), - text: this.hass!.localize( - "ui.panel.config.lovelace.dashboards.confirm_delete_text" - ), - confirmText: this.hass!.localize("ui.common.delete"), - destructive: true, - })) - ) { + const confirm = await showConfirmationDialog(this, { + title: this.hass!.localize( + "ui.panel.config.lovelace.dashboards.confirm_delete_title", + { dashboard_title: dashboard!.title } + ), + text: this.hass!.localize( + "ui.panel.config.lovelace.dashboards.confirm_delete_text" + ), + confirmText: this.hass!.localize("ui.common.delete"), + destructive: true, + }); + if (!confirm) { return false; } - try { await deleteDashboard(this.hass!, dashboard!.id); this._dashboards = this._dashboards!.filter( diff --git a/src/panels/config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail.ts b/src/panels/config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail.ts index 85fc0f04bd..cf08844211 100644 --- a/src/panels/config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail.ts +++ b/src/panels/config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail.ts @@ -8,7 +8,7 @@ import { export interface LovelaceDashboardDetailsDialogParams { dashboard?: LovelaceDashboard; urlPath?: string; - createDashboard: (values: LovelaceDashboardCreateParams) => Promise; + createDashboard?: (values: LovelaceDashboardCreateParams) => Promise; updateDashboard: ( updates: Partial ) => Promise; diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts deleted file mode 100644 index ea03f1f6b0..0000000000 --- a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts +++ /dev/null @@ -1,124 +0,0 @@ -import "@material/mwc-button"; -import { CSSResultGroup, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-circular-progress"; -import "../../../../components/ha-dialog"; -import { haStyleDialog } from "../../../../resources/styles"; -import type { HomeAssistant } from "../../../../types"; -import type { Lovelace } from "../../types"; -import "./hui-lovelace-editor"; -import { LovelaceConfig } from "../../../../data/lovelace/config/types"; - -@customElement("hui-dialog-edit-lovelace") -export class HuiDialogEditLovelace extends LitElement { - @property({ attribute: false }) public hass?: HomeAssistant; - - @state() private _lovelace?: Lovelace; - - @state() private _config?: LovelaceConfig; - - private _saving = false; - - public showDialog(lovelace: Lovelace): void { - this._lovelace = lovelace; - const { views, ...lovelaceConfig } = this._lovelace!.config; - this._config = lovelaceConfig as LovelaceConfig; - } - - public closeDialog(): void { - this._config = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render() { - if (!this._config) { - return nothing; - } - return html` - -
- ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_lovelace.explanation" - )} - -
- - ${this.hass!.localize("ui.common.cancel")} - - - ${this._saving - ? html`` - : ""} - ${this.hass!.localize("ui.common.save")} -
- `; - } - - private async _save(): Promise { - if (!this._config) { - return; - } - if (!this._isConfigChanged()) { - this.closeDialog(); - return; - } - - this._saving = true; - const lovelace = this._lovelace!; - - const config: LovelaceConfig = { - ...lovelace.config, - ...this._config, - }; - - try { - await lovelace.saveConfig(config); - this.closeDialog(); - } catch (err: any) { - alert(`Saving failed: ${err.message}`); - } finally { - this._saving = false; - } - } - - private _ConfigChanged(ev: CustomEvent): void { - if (ev.detail && ev.detail.config) { - this._config = ev.detail.config; - } - } - - private _isConfigChanged(): boolean { - const { views, ...lovelaceConfig } = this._lovelace!.config; - return JSON.stringify(this._config) !== JSON.stringify(lovelaceConfig); - } - - static get styles(): CSSResultGroup { - return haStyleDialog; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-dialog-edit-lovelace": HuiDialogEditLovelace; - } -} diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts deleted file mode 100644 index b735db367c..0000000000 --- a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property } from "lit/decorators"; -import { fireEvent } from "../../../../common/dom/fire_event"; -import "../../../../components/ha-textfield"; -import type { LovelaceConfig } from "../../../../data/lovelace/config/types"; -import { HomeAssistant } from "../../../../types"; -import { EditorTarget } from "../types"; - -declare global { - interface HASSDomEvents { - "lovelace-config-changed": { - config: LovelaceConfig; - }; - } -} - -@customElement("hui-lovelace-editor") -export class HuiLovelaceEditor extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public config?: LovelaceConfig; - - get _title(): string { - if (!this.config) { - return ""; - } - return this.config.title || ""; - } - - protected render(): TemplateResult { - return html` - - `; - } - - private _valueChanged(ev: Event): void { - if (!this.config) { - return; - } - - const target = ev.currentTarget! as EditorTarget; - - if (this[`_${target.configValue}`] === target.value) { - return; - } - - let newConfig; - - if (target.configValue) { - newConfig = { - ...this.config, - [target.configValue]: target.value, - }; - } - - fireEvent(this, "lovelace-config-changed", { config: newConfig }); - } - - static styles: CSSResultGroup = css` - ha-textfield { - display: block; - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "hui-lovelace-editor": HuiLovelaceEditor; - } -} diff --git a/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts b/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts deleted file mode 100644 index e3c3b7101b..0000000000 --- a/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { fireEvent } from "../../../../common/dom/fire_event"; -import { Lovelace } from "../../types"; - -declare global { - // for fire event - interface HASSDomEvents { - "show-edit-lovelace": Lovelace; - } -} - -let registeredDialog = false; -const dialogShowEvent = "show-edit-lovelace"; -const dialogTag = "hui-dialog-edit-lovelace"; - -const registerEditLovelaceDialog = (element: HTMLElement): Event => - fireEvent(element, "register-dialog", { - dialogShowEvent, - dialogTag, - dialogImport: () => import("./hui-dialog-edit-lovelace"), - }); - -export const showEditLovelaceDialog = ( - element: HTMLElement, - lovelace: Lovelace -): void => { - if (!registeredDialog) { - registeredDialog = true; - registerEditLovelaceDialog(element); - } - fireEvent(element, dialogShowEvent, lovelace); -}; diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index 0103b7e2d2..a69f8ef6a4 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -120,6 +120,7 @@ export class LovelacePanel extends LitElement { if (panelState === "loaded") { return html` ; + @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public lovelace?: Lovelace; @@ -279,6 +287,10 @@ class HUIRoot extends LitElement { const curViewConfig = typeof this._curView === "number" ? views[this._curView] : undefined; + const dashboardTitle = this.panel + ? getPanelTitle(this.hass, this.panel) + : undefined; + return html`
- ${this.config.title || + ${dashboardTitle || this.hass!.localize("ui.panel.lovelace.editor.header")}
${this._renderActionItems()}
@@ -360,9 +372,11 @@ class HUIRoot extends LitElement { )} ` - : html`
- ${this.config.title} -
`} + : html` +
+ ${views[0]?.title ?? dashboardTitle} +
+ `}
${this._renderActionItems()}
`} @@ -758,8 +772,41 @@ class HUIRoot extends LitElement { this.lovelace!.setEditMode(false); } - private _editLovelace() { - showEditLovelaceDialog(this, this.lovelace!); + private async _editDashboard() { + const urlPath = this.route?.prefix.slice(1); + await this.hass.loadFragmentTranslation("config"); + const dashboards = await fetchDashboards(this.hass); + const dashboard = dashboards.find((d) => d.url_path === urlPath); + + showDashboardDetailDialog(this, { + dashboard, + urlPath, + updateDashboard: async (values) => { + await updateDashboard(this.hass!, dashboard!.id, values); + }, + removeDashboard: async () => { + const confirm = await showConfirmationDialog(this, { + title: this.hass!.localize( + "ui.panel.config.lovelace.dashboards.confirm_delete_title", + { dashboard_title: dashboard!.title } + ), + text: this.hass!.localize( + "ui.panel.config.lovelace.dashboards.confirm_delete_text" + ), + confirmText: this.hass!.localize("ui.common.delete"), + destructive: true, + }); + if (!confirm) { + return false; + } + try { + await deleteDashboard(this.hass!, dashboard!.id); + return true; + } catch (err: any) { + return false; + } + }, + }); } private _navigateToView(path: string | number, replace?: boolean) { diff --git a/src/panels/lovelace/strategies/iframe/iframe-dashboard-strategy.ts b/src/panels/lovelace/strategies/iframe/iframe-dashboard-strategy.ts index 471823af8c..7fbf6d82e5 100644 --- a/src/panels/lovelace/strategies/iframe/iframe-dashboard-strategy.ts +++ b/src/panels/lovelace/strategies/iframe/iframe-dashboard-strategy.ts @@ -12,7 +12,6 @@ export class IframeDashboardStrategy extends ReactiveElement { config: IframeDashboardStrategyConfig ): Promise { return { - title: config.title, views: [ { strategy: config, diff --git a/src/panels/lovelace/strategies/map/map-dashboard-strategy.ts b/src/panels/lovelace/strategies/map/map-dashboard-strategy.ts index 91c217ce08..edc5bb2609 100644 --- a/src/panels/lovelace/strategies/map/map-dashboard-strategy.ts +++ b/src/panels/lovelace/strategies/map/map-dashboard-strategy.ts @@ -1,7 +1,6 @@ import { ReactiveElement } from "lit"; import { customElement } from "lit/decorators"; import { LovelaceConfig } from "../../../../data/lovelace/config/types"; -import { HomeAssistant } from "../../../../types"; import { MapViewStrategyConfig } from "./map-view-strategy"; export type MapDashboardStrategyConfig = MapViewStrategyConfig; @@ -9,11 +8,9 @@ export type MapDashboardStrategyConfig = MapViewStrategyConfig; @customElement("map-dashboard-strategy") export class MapDashboardStrategy extends ReactiveElement { static async generate( - config: MapDashboardStrategyConfig, - hass: HomeAssistant + config: MapDashboardStrategyConfig ): Promise { return { - title: hass.localize("panel.map"), views: [ { strategy: config, diff --git a/src/panels/lovelace/strategies/original-states/original-states-dashboard-strategy.ts b/src/panels/lovelace/strategies/original-states/original-states-dashboard-strategy.ts index 3f7faae9f4..f1daa56edd 100644 --- a/src/panels/lovelace/strategies/original-states/original-states-dashboard-strategy.ts +++ b/src/panels/lovelace/strategies/original-states/original-states-dashboard-strategy.ts @@ -1,9 +1,8 @@ import { ReactiveElement } from "lit"; import { customElement } from "lit/decorators"; import { LovelaceConfig } from "../../../../data/lovelace/config/types"; -import { HomeAssistant } from "../../../../types"; -import { OriginalStatesViewStrategyConfig } from "./original-states-view-strategy"; import { LovelaceStrategyEditor } from "../types"; +import { OriginalStatesViewStrategyConfig } from "./original-states-view-strategy"; export type OriginalStatesDashboardStrategyConfig = OriginalStatesViewStrategyConfig; @@ -11,11 +10,9 @@ export type OriginalStatesDashboardStrategyConfig = @customElement("original-states-dashboard-strategy") export class OriginalStatesDashboardStrategy extends ReactiveElement { static async generate( - config: OriginalStatesDashboardStrategyConfig, - hass: HomeAssistant + config: OriginalStatesDashboardStrategyConfig ): Promise { return { - title: hass.config.location_name, views: [ { strategy: config, diff --git a/src/state/panel-title-mixin.ts b/src/state/panel-title-mixin.ts index 9a5bdfe6de..a31e3f7744 100644 --- a/src/state/panel-title-mixin.ts +++ b/src/state/panel-title-mixin.ts @@ -1,4 +1,4 @@ -import { getPanelTitle } from "../data/panel"; +import { getPanelTitleFromUrlPath } from "../data/panel"; import { Constructor, HomeAssistant } from "../types"; import { HassBaseEl } from "./hass-base-mixin"; @@ -24,7 +24,7 @@ export const panelTitleMixin = >( oldHass.panelUrl !== this.hass.panelUrl || oldHass.localize !== this.hass.localize ) { - setTitle(getPanelTitle(this.hass)); + setTitle(getPanelTitleFromUrlPath(this.hass, this.hass.panelUrl)); } } };