From 365db51526ff9906ea528b57b01391abcbae5ea0 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 5 Jun 2025 17:37:47 +0100 Subject: [PATCH] move default dashboard setting to user settings --- src/components/ha-navigation-picker.ts | 2 +- src/components/ha-sidebar.ts | 55 +++++++++++-------- src/data/frontend.ts | 1 + src/data/panel.ts | 12 +--- src/dialogs/sidebar/dialog-edit-sidebar.ts | 7 ++- .../dialog-lovelace-dashboard-detail.ts | 17 +++--- .../ha-config-lovelace-dashboards.ts | 2 +- .../hui-dialog-select-dashboard.ts | 2 +- .../select-view/hui-dialog-select-view.ts | 2 +- src/panels/profile/ha-pick-dashboard-row.ts | 14 +++-- .../profile/ha-profile-section-general.ts | 8 +-- src/state/connection-mixin.ts | 6 +- src/state/sidebar-mixin.ts | 14 ++--- src/types.ts | 6 +- src/util/ha-pref-storage.ts | 2 +- 15 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/components/ha-navigation-picker.ts b/src/components/ha-navigation-picker.ts index 7740e325f3..58093e423e 100644 --- a/src/components/ha-navigation-picker.ts +++ b/src/components/ha-navigation-picker.ts @@ -44,7 +44,7 @@ const createPanelNavigationItem = (hass: HomeAssistant, panel: PanelInfo) => ({ path: `/${panel.url_path}`, icon: panel.icon ?? "mdi:view-dashboard", title: - panel.url_path === hass.defaultPanel + panel.url_path === hass.sidebar.defaultPanel ? hass.localize("panel.states") : hass.localize(`panel.${panel.title}`) || panel.title || diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 8ccaad0d95..9539eb6920 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -50,6 +50,7 @@ import type { HaMdListItem } from "./ha-md-list-item"; import "./ha-spinner"; import "./ha-svg-icon"; import "./user/ha-user-badge"; +import { DEFAULT_PANEL } from "../data/panel"; const SHOW_AFTER_SPACER = ["config", "developer-tools"]; @@ -140,9 +141,9 @@ const defaultPanelSorter = ( export const computePanels = memoizeOne( ( panels: HomeAssistant["panels"], - defaultPanel: HomeAssistant["defaultPanel"], - panelsOrder: string[], - hiddenPanels: string[], + defaultPanel: HomeAssistant["sidebar"]["defaultPanel"], + panelsOrder: HomeAssistant["sidebar"]["panelOrder"], + hiddenPanels: HomeAssistant["sidebar"]["hiddenPanels"], locale: HomeAssistant["locale"] ): [PanelInfo[], PanelInfo[]] => { if (!panels) { @@ -195,10 +196,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { @state() private _issuesCount = 0; - @state() private _panelOrder?: string[]; - - @state() private _hiddenPanels?: string[]; - private _mouseLeaveTimeout?: number; private _tooltipHideTimeout?: number; @@ -213,18 +210,32 @@ class HaSidebar extends SubscribeMixin(LitElement) { this.hass.connection, "sidebar", ({ value }) => { - this._panelOrder = value?.panelOrder; - this._hiddenPanels = value?.hiddenPanels; + let panelOrder = value?.panelOrder; + let hiddenPanels = value?.hiddenPanels; + let defaultPanel = value?.defaultPanel; // fallback to old localStorage values - if (!this._panelOrder) { + if (!panelOrder) { const storedOrder = localStorage.getItem("sidebarPanelOrder"); - this._panelOrder = storedOrder ? JSON.parse(storedOrder) : []; + panelOrder = storedOrder ? JSON.parse(storedOrder) : []; } - if (!this._hiddenPanels) { + if (!hiddenPanels) { const storedHidden = localStorage.getItem("sidebarHiddenPanels"); - this._hiddenPanels = storedHidden ? JSON.parse(storedHidden) : []; + hiddenPanels = storedHidden ? JSON.parse(storedHidden) : []; } + if (!defaultPanel) { + const storedDefault = localStorage.getItem("defaultPanel"); + defaultPanel = storedDefault + ? JSON.parse(storedDefault) + : DEFAULT_PANEL; + } + + fireEvent(this, "hass-set-sidebar-data", { + ...value, + defaultPanel: defaultPanel as string, + panelOrder: panelOrder as string[], + hiddenPanels: hiddenPanels as string[], + }); } ), subscribeNotifications(this.hass.connection, (notifications) => { @@ -275,8 +286,8 @@ class HaSidebar extends SubscribeMixin(LitElement) { changedProps.has("_updatesCount") || changedProps.has("_issuesCount") || changedProps.has("_notifications") || - changedProps.has("_hiddenPanels") || - changedProps.has("_panelOrder") + (changedProps.has("hass") && + changedProps.get("hass")?.sidebar !== this.hass.sidebar) ) { return true; } @@ -295,7 +306,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { hass.localize !== oldHass.localize || hass.locale !== oldHass.locale || hass.states !== oldHass.states || - hass.defaultPanel !== oldHass.defaultPanel || + hass.sidebar !== oldHass.sidebar || hass.connected !== oldHass.connected ); } @@ -365,7 +376,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { } private _renderAllPanels(selectedPanel: string) { - if (!this._panelOrder || !this._hiddenPanels) { + if (!this.hass.sidebar.panelOrder || !this.hass.sidebar.hiddenPanels) { return html` this._renderPanel( panel.url_path, - panel.url_path === this.hass.defaultPanel + panel.url_path === this.hass.sidebar.defaultPanel ? panel.title || this.hass.localize("panel.states") : this.hass.localize(`panel.${panel.title}`) || panel.title, panel.icon, - panel.url_path === this.hass.defaultPanel && !panel.icon + panel.url_path === this.hass.sidebar.defaultPanel && !panel.icon ? PANEL_ICONS.lovelace : panel.url_path in PANEL_ICONS ? PANEL_ICONS[panel.url_path] diff --git a/src/data/frontend.ts b/src/data/frontend.ts index 8f0c6749cc..f6afdf0a87 100644 --- a/src/data/frontend.ts +++ b/src/data/frontend.ts @@ -8,6 +8,7 @@ export interface CoreFrontendUserData { export interface SidebarFrontendUserData { panelOrder: string[]; hiddenPanels: string[]; + defaultPanel?: string; } declare global { diff --git a/src/data/panel.ts b/src/data/panel.ts index 14012b1059..b7a160bd79 100644 --- a/src/data/panel.ts +++ b/src/data/panel.ts @@ -1,4 +1,3 @@ -import { fireEvent } from "../common/dom/fire_event"; import type { HomeAssistant, PanelInfo } from "../types"; /** Panel to show when no panel is picked. */ @@ -10,16 +9,9 @@ export const getStorageDefaultPanelUrlPath = (): string => { return defaultPanel ? JSON.parse(defaultPanel) : DEFAULT_PANEL; }; -export const setDefaultPanel = ( - element: HTMLElement, - urlPath: string -): void => { - fireEvent(element, "hass-default-panel", { defaultPanel: urlPath }); -}; - export const getDefaultPanel = (hass: HomeAssistant): PanelInfo => - hass.panels[hass.defaultPanel] - ? hass.panels[hass.defaultPanel] + hass.panels[hass.sidebar.defaultPanel] + ? hass.panels[hass.sidebar.defaultPanel] : hass.panels[DEFAULT_PANEL]; export const getPanelNameTranslationKey = (panel: PanelInfo) => { diff --git a/src/dialogs/sidebar/dialog-edit-sidebar.ts b/src/dialogs/sidebar/dialog-edit-sidebar.ts index fed10ad593..579e0d7580 100644 --- a/src/dialogs/sidebar/dialog-edit-sidebar.ts +++ b/src/dialogs/sidebar/dialog-edit-sidebar.ts @@ -96,7 +96,7 @@ class DialogEditSidebar extends LitElement { const [beforeSpacer, afterSpacer] = computePanels( this.hass.panels, - this.hass.defaultPanel, + this.hass.sidebar.defaultPanel, this._order, this._hidden, this.hass.locale @@ -109,12 +109,12 @@ class DialogEditSidebar extends LitElement { ].map((panel) => ({ value: panel.url_path, label: - panel.url_path === this.hass.defaultPanel + panel.url_path === this.hass.sidebar.defaultPanel ? panel.title || this.hass.localize("panel.states") : this.hass.localize(`panel.${panel.title}`) || panel.title || "?", icon: panel.icon || undefined, iconPath: - panel.url_path === this.hass.defaultPanel && !panel.icon + panel.url_path === this.hass.sidebar.defaultPanel && !panel.icon ? PANEL_ICONS.lovelace : panel.url_path in PANEL_ICONS ? PANEL_ICONS[panel.url_path] @@ -195,6 +195,7 @@ class DialogEditSidebar extends LitElement { await saveFrontendUserData(this.hass.connection, "sidebar", { panelOrder: this._order!, hiddenPanels: this._hidden!, + defaultPanel: this.hass.sidebar.defaultPanel, }); } catch (err: any) { this._error = err.message || err; 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 633c430892..a067aca964 100644 --- a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts +++ b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts @@ -13,10 +13,11 @@ import type { LovelaceDashboardCreateParams, LovelaceDashboardMutableParams, } from "../../../../data/lovelace/dashboard"; -import { DEFAULT_PANEL, setDefaultPanel } from "../../../../data/panel"; +import { DEFAULT_PANEL } from "../../../../data/panel"; import { haStyleDialog } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; import type { LovelaceDashboardDetailsDialogParams } from "./show-dialog-lovelace-dashboard-detail"; +import { saveFrontendUserData } from "../../../../data/frontend"; @customElement("dialog-lovelace-dashboard-detail") export class DialogLovelaceDashboardDetail extends LitElement { @@ -59,7 +60,7 @@ export class DialogLovelaceDashboardDetail extends LitElement { if (!this._params || !this._data) { return nothing; } - const defaultPanelUrlPath = this.hass.defaultPanel; + const defaultPanelUrlPath = this.hass.sidebar.defaultPanel; const titleInvalid = !this._data.title || !this._data.title.trim(); return html` @@ -249,15 +250,17 @@ export class DialogLovelaceDashboardDetail extends LitElement { }; } - private _toggleDefault() { + private async _toggleDefault() { const urlPath = this._params?.urlPath; if (!urlPath) { return; } - setDefaultPanel( - this, - urlPath === this.hass.defaultPanel ? DEFAULT_PANEL : urlPath - ); + await saveFrontendUserData(this.hass!.connection, "sidebar", { + panelOrder: this.hass!.sidebar.panelOrder, + hiddenPanels: this.hass!.sidebar.hiddenPanels, + defaultPanel: + urlPath === this.hass.sidebar.defaultPanel ? DEFAULT_PANEL : urlPath, + }); } private async _updateDashboard() { 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 1dce7fa90f..e7a3e39d76 100644 --- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts +++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts @@ -255,7 +255,7 @@ export class HaConfigLovelaceDashboards extends LitElement { const defaultMode = ( this.hass.panels?.lovelace?.config as LovelacePanelConfig ).mode; - const defaultUrlPath = this.hass.defaultPanel; + const defaultUrlPath = this.hass.sidebar.defaultPanel; const isDefault = defaultUrlPath === "lovelace"; const result: DataTableItem[] = [ { diff --git a/src/panels/lovelace/editor/select-dashboard/hui-dialog-select-dashboard.ts b/src/panels/lovelace/editor/select-dashboard/hui-dialog-select-dashboard.ts index da18eb45ca..5bd01c2282 100644 --- a/src/panels/lovelace/editor/select-dashboard/hui-dialog-select-dashboard.ts +++ b/src/panels/lovelace/editor/select-dashboard/hui-dialog-select-dashboard.ts @@ -139,7 +139,7 @@ export class HuiDialogSelectDashboard extends LitElement { ...(this._params!.dashboards || (await fetchDashboards(this.hass))), ]; - const currentPath = this._fromUrlPath || this.hass.defaultPanel; + const currentPath = this._fromUrlPath || this.hass.sidebar.defaultPanel; for (const dashboard of this._dashboards!) { if (dashboard.url_path !== currentPath) { this._toUrlPath = dashboard.url_path; diff --git a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts index 4b23bd6501..1f675bcfc8 100644 --- a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts +++ b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts @@ -77,7 +77,7 @@ export class HuiDialogSelectView extends LitElement { "ui.panel.lovelace.editor.select_view.dashboard_label" )} .disabled=${!this._dashboards.length} - .value=${this._urlPath || this.hass.defaultPanel} + .value=${this._urlPath || this.hass.sidebar.defaultPanel} @selected=${this._dashboardChanged} @closed=${stopPropagation} fixedMenuPosition diff --git a/src/panels/profile/ha-pick-dashboard-row.ts b/src/panels/profile/ha-pick-dashboard-row.ts index d5a9a14149..b28d173940 100644 --- a/src/panels/profile/ha-pick-dashboard-row.ts +++ b/src/panels/profile/ha-pick-dashboard-row.ts @@ -6,8 +6,8 @@ import "../../components/ha-select"; import "../../components/ha-settings-row"; import type { LovelaceDashboard } from "../../data/lovelace/dashboard"; import { fetchDashboards } from "../../data/lovelace/dashboard"; -import { setDefaultPanel } from "../../data/panel"; import type { HomeAssistant } from "../../types"; +import { saveFrontendUserData } from "../../data/frontend"; @customElement("ha-pick-dashboard-row") class HaPickDashboardRow extends LitElement { @@ -37,7 +37,7 @@ class HaPickDashboardRow extends LitElement { "ui.panel.profile.dashboard.dropdown_label" )} .disabled=${!this._dashboards?.length} - .value=${this.hass.defaultPanel} + .value=${this.hass.sidebar.defaultPanel} @selected=${this._dashboardChanged} naturalMenuWidth > @@ -71,12 +71,16 @@ class HaPickDashboardRow extends LitElement { this._dashboards = await fetchDashboards(this.hass); } - private _dashboardChanged(ev) { + private async _dashboardChanged(ev) { const urlPath = ev.target.value; - if (!urlPath || urlPath === this.hass.defaultPanel) { + if (!urlPath || urlPath === this.hass.sidebar.defaultPanel) { return; } - setDefaultPanel(this, urlPath); + await saveFrontendUserData(this.hass!.connection, "sidebar", { + panelOrder: this.hass!.sidebar.panelOrder, + hiddenPanels: this.hass!.sidebar.hiddenPanels, + defaultPanel: urlPath, + }); } } diff --git a/src/panels/profile/ha-profile-section-general.ts b/src/panels/profile/ha-profile-section-general.ts index 46cbc1c268..93e0a52a88 100644 --- a/src/panels/profile/ha-profile-section-general.ts +++ b/src/panels/profile/ha-profile-section-general.ts @@ -167,6 +167,10 @@ class HaProfileSectionGeneral extends LitElement { )} + ${this.hass.user!.is_admin ? html` - ${this.hass.dockedSidebar !== "auto" || !this.narrow ? html` >( services: null as any, user: null as any, panelUrl: (this as any)._panelUrl, - defaultPanel: DEFAULT_PANEL, + sidebar: { + defaultPanel: DEFAULT_PANEL, + hiddenPanels: [], + panelOrder: [], + }, language, selectedLanguage: null, locale: { diff --git a/src/state/sidebar-mixin.ts b/src/state/sidebar-mixin.ts index 59d258da4e..e15fa48aa6 100644 --- a/src/state/sidebar-mixin.ts +++ b/src/state/sidebar-mixin.ts @@ -7,20 +7,16 @@ interface DockSidebarParams { dock: HomeAssistant["dockedSidebar"]; } -interface DefaultPanelParams { - defaultPanel: HomeAssistant["defaultPanel"]; -} - declare global { // for fire event interface HASSDomEvents { "hass-dock-sidebar": DockSidebarParams; - "hass-default-panel": DefaultPanelParams; + "hass-set-sidebar-data": HomeAssistant["sidebar"]; } // for add event listener interface HTMLElementEventMap { "hass-dock-sidebar": HASSDomEvent; - "hass-default-panel": HASSDomEvent; + "hass-set-sidebar-data": HASSDomEvent; } } @@ -32,8 +28,10 @@ export default >(superClass: T) => this._updateHass({ dockedSidebar: ev.detail.dock }); storeState(this.hass!); }); - this.addEventListener("hass-default-panel", (ev) => { - this._updateHass({ defaultPanel: ev.detail.defaultPanel }); + this.addEventListener("hass-set-sidebar-data", async (ev) => { + this._updateHass({ + sidebar: ev.detail, + }); storeState(this.hass!); }); } diff --git a/src/types.ts b/src/types.ts index 02d50a82ab..9cab777e6d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -243,7 +243,11 @@ export interface HomeAssistant { vibrate: boolean; debugConnection: boolean; dockedSidebar: "docked" | "always_hidden" | "auto"; - defaultPanel: string; + sidebar: { + defaultPanel: string; + panelOrder: string[]; + hiddenPanels: string[]; + }; moreInfoEntityId: string | null; user?: CurrentUser; userData?: CoreFrontendUserData | null; diff --git a/src/util/ha-pref-storage.ts b/src/util/ha-pref-storage.ts index 4ef259ff0c..8832eaa6db 100644 --- a/src/util/ha-pref-storage.ts +++ b/src/util/ha-pref-storage.ts @@ -8,7 +8,7 @@ const STORED_STATE = [ "debugConnection", "suspendWhenHidden", "enableShortcuts", - "defaultPanel", + "sidebar", ]; export function storeState(hass: HomeAssistant) {