Bram Kragten 2025-06-16 10:09:07 +02:00 committed by GitHub
commit 43a8b1d5c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 84 additions and 66 deletions

View File

@ -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 ||

View File

@ -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`
<ha-fade-in .delay=${500}
><ha-spinner size="small"></ha-spinner
@ -375,9 +386,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
const [beforeSpacer, afterSpacer] = computePanels(
this.hass.panels,
this.hass.defaultPanel,
this._panelOrder,
this._hiddenPanels,
this.hass.sidebar.defaultPanel,
this.hass.sidebar.panelOrder,
this.hass.sidebar.hiddenPanels,
this.hass.locale
);
@ -402,11 +413,11 @@ class HaSidebar extends SubscribeMixin(LitElement) {
return panels.map((panel) =>
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]

View File

@ -8,6 +8,7 @@ export interface CoreFrontendUserData {
export interface SidebarFrontendUserData {
panelOrder: string[];
hiddenPanels: string[];
defaultPanel?: string;
}
declare global {

View File

@ -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) => {

View File

@ -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;

View File

@ -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() {

View File

@ -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[] = [
{

View File

@ -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;

View File

@ -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

View File

@ -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,
});
}
}

View File

@ -167,6 +167,10 @@ class HaProfileSectionGeneral extends LitElement {
)}
</mwc-button>
</ha-settings-row>
<ha-pick-dashboard-row
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-dashboard-row>
${this.hass.user!.is_admin
? html`
<ha-advanced-mode-row
@ -200,10 +204,6 @@ class HaProfileSectionGeneral extends LitElement {
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-theme-row>
<ha-pick-dashboard-row
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-dashboard-row>
${this.hass.dockedSidebar !== "auto" || !this.narrow
? html`
<ha-force-narrow-row

View File

@ -59,7 +59,11 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
services: null as any,
user: null as any,
panelUrl: (this as any)._panelUrl,
sidebar: {
defaultPanel: DEFAULT_PANEL,
hiddenPanels: [],
panelOrder: [],
},
language,
selectedLanguage: null,
locale: {

View File

@ -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<DockSidebarParams>;
"hass-default-panel": HASSDomEvent<DefaultPanelParams>;
"hass-set-sidebar-data": HASSDomEvent<HomeAssistant["sidebar"]>;
}
}
@ -32,8 +28,10 @@ export default <T extends Constructor<HassBaseEl>>(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!);
});
}

View File

@ -243,7 +243,11 @@ export interface HomeAssistant {
vibrate: boolean;
debugConnection: boolean;
dockedSidebar: "docked" | "always_hidden" | "auto";
sidebar: {
defaultPanel: string;
panelOrder: string[];
hiddenPanels: string[];
};
moreInfoEntityId: string | null;
user?: CurrentUser;
userData?: CoreFrontendUserData | null;

View File

@ -8,7 +8,7 @@ const STORED_STATE = [
"debugConnection",
"suspendWhenHidden",
"enableShortcuts",
"defaultPanel",
"sidebar",
];
export function storeState(hass: HomeAssistant) {