Use user preferences for sidebar

This commit is contained in:
Wendelin 2025-02-17 12:56:20 +01:00
parent 3ee3cfa6cb
commit 7d7f8a9bc2
No known key found for this signature in database
2 changed files with 123 additions and 24 deletions

View File

@ -49,6 +49,10 @@ import "./ha-sortable";
import "./ha-svg-icon"; import "./ha-svg-icon";
import "./user/ha-user-badge"; import "./user/ha-user-badge";
import { preventDefault } from "../common/dom/prevent_default"; import { preventDefault } from "../common/dom/prevent_default";
import {
saveSidebarPreferences,
subscribeSidebarPreferences,
} from "../data/sidebar";
const SHOW_AFTER_SPACER = ["config", "developer-tools"]; const SHOW_AFTER_SPACER = ["config", "developer-tools"];
@ -212,25 +216,47 @@ class HaSidebar extends SubscribeMixin(LitElement) {
state: true, state: true,
subscribe: true, subscribe: true,
}) })
private _panelOrder: string[] = []; private _devicePanelOrder?: string[];
@storage({ @storage({
key: "sidebarHiddenPanels", key: "sidebarHiddenPanels",
state: true, state: true,
subscribe: true, subscribe: true,
}) })
private _hiddenPanels: string[] = []; private _deviceHiddenPanels?: string[];
@state()
private _userPanelOrder: string[] = [];
@state()
private _userHiddenPanels: string[] = [];
@state()
private _tempPanelOrder?: string[];
@state()
private _tempHiddenPanels?: string[];
public hassSubscribe(): UnsubscribeFunc[] { public hassSubscribe(): UnsubscribeFunc[] {
return this.hass.user?.is_admin const subscribeFunctions = [
? [ subscribeSidebarPreferences(this.hass, (sidebar) => {
subscribeRepairsIssueRegistry(this.hass.connection!, (repairs) => { if (!this._devicePanelOrder && !this._deviceHiddenPanels && sidebar) {
this._issuesCount = repairs.issues.filter( this._userPanelOrder = sidebar.panelOrder || [];
(issue) => !issue.ignored this._userHiddenPanels = sidebar.hiddenPanels || [];
).length; }
}), }),
] ];
: []; if (this.hass.user?.is_admin) {
subscribeFunctions.push(
subscribeRepairsIssueRegistry(this.hass.connection!, (repairs) => {
this._issuesCount = repairs.issues.filter(
(issue) => !issue.ignored
).length;
})
);
}
return subscribeFunctions;
} }
protected render() { protected render() {
@ -260,8 +286,12 @@ class HaSidebar extends SubscribeMixin(LitElement) {
changedProps.has("_updatesCount") || changedProps.has("_updatesCount") ||
changedProps.has("_issuesCount") || changedProps.has("_issuesCount") ||
changedProps.has("_notifications") || changedProps.has("_notifications") ||
changedProps.has("_hiddenPanels") || changedProps.has("_devicePanelOrder") ||
changedProps.has("_panelOrder") changedProps.has("_deviceHiddenPanels") ||
changedProps.has("_userPanelOrder") ||
changedProps.has("_userHiddenPanels") ||
changedProps.has("_tempPanelOrder") ||
changedProps.has("_tempHiddenPanels")
) { ) {
return true; return true;
} }
@ -382,11 +412,18 @@ class HaSidebar extends SubscribeMixin(LitElement) {
} }
private _renderAllPanels() { private _renderAllPanels() {
const panelOrder =
this._tempPanelOrder || this._devicePanelOrder || this._userPanelOrder;
const hiddenPanels =
this._tempHiddenPanels ||
this._deviceHiddenPanels ||
this._userHiddenPanels;
const [beforeSpacer, afterSpacer] = computePanels( const [beforeSpacer, afterSpacer] = computePanels(
this.hass.panels, this.hass.panels,
this.hass.defaultPanel, this.hass.defaultPanel,
this._panelOrder, panelOrder,
this._hiddenPanels, hiddenPanels,
this.hass.locale this.hass.locale
); );
@ -481,8 +518,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
const [beforeSpacer] = computePanels( const [beforeSpacer] = computePanels(
this.hass.panels, this.hass.panels,
this.hass.defaultPanel, this.hass.defaultPanel,
this._panelOrder, this._tempPanelOrder!,
this._hiddenPanels, this._tempHiddenPanels!,
this.hass.locale this.hass.locale
); );
@ -490,7 +527,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
const panel = panelOrder.splice(oldIndex, 1)[0]; const panel = panelOrder.splice(oldIndex, 1)[0];
panelOrder.splice(newIndex, 0, panel); panelOrder.splice(newIndex, 0, panel);
this._panelOrder = panelOrder; this._tempPanelOrder = panelOrder;
} }
private _renderPanelsEdit(beforeSpacer: PanelInfo[]) { private _renderPanelsEdit(beforeSpacer: PanelInfo[]) {
@ -507,8 +544,13 @@ class HaSidebar extends SubscribeMixin(LitElement) {
} }
private _renderHiddenPanels() { private _renderHiddenPanels() {
return html`${this._hiddenPanels.length const hiddenPanels =
? html`${this._hiddenPanels.map((url) => { this._tempHiddenPanels ||
this._deviceHiddenPanels ||
this._userHiddenPanels;
return html`${hiddenPanels.length
? html`${hiddenPanels.map((url) => {
const panel = this.hass.panels[url]; const panel = this.hass.panels[url];
if (!panel) { if (!panel) {
return ""; return "";
@ -709,6 +751,13 @@ class HaSidebar extends SubscribeMixin(LitElement) {
private async _editModeActivated() { private async _editModeActivated() {
await this._loadEditStyle(); await this._loadEditStyle();
this._tempPanelOrder = [
...(this._devicePanelOrder || this._userPanelOrder),
];
this._tempHiddenPanels = [
...(this._deviceHiddenPanels || this._userHiddenPanels),
];
} }
private async _loadEditStyle() { private async _loadEditStyle() {
@ -724,25 +773,42 @@ class HaSidebar extends SubscribeMixin(LitElement) {
} }
private _closeEditMode() { private _closeEditMode() {
// TODO confirm dialog if changes and radio if device or user
if (this._devicePanelOrder || this._deviceHiddenPanels) {
this._devicePanelOrder = this._tempPanelOrder;
this._deviceHiddenPanels = this._tempHiddenPanels;
} else {
this._userPanelOrder = this._tempPanelOrder!;
this._userHiddenPanels = this._tempHiddenPanels!;
saveSidebarPreferences(this.hass, {
panelOrder: this._userPanelOrder,
hiddenPanels: this._userHiddenPanels,
});
}
this._tempPanelOrder = undefined;
this._tempHiddenPanels = undefined;
fireEvent(this, "hass-edit-sidebar", { editMode: false }); fireEvent(this, "hass-edit-sidebar", { editMode: false });
} }
private async _hidePanel(ev: Event) { private async _hidePanel(ev: Event) {
ev.preventDefault(); ev.preventDefault();
const panel = (ev.currentTarget as any).panel; const panel = (ev.currentTarget as any).panel;
if (this._hiddenPanels.includes(panel)) { if ((this._deviceHiddenPanels || this._userHiddenPanels).includes(panel)) {
return; return;
} }
// Make a copy for Memoize // Make a copy for Memoize
this._hiddenPanels = [...this._hiddenPanels, panel]; this._tempHiddenPanels = [...this._tempHiddenPanels!, panel];
// Remove it from the panel order // Remove it from the panel order
this._panelOrder = this._panelOrder.filter((order) => order !== panel); this._tempPanelOrder = this._tempPanelOrder!.filter(
(order) => order !== panel
);
} }
private async _unhidePanel(ev: Event) { private async _unhidePanel(ev: Event) {
ev.preventDefault(); ev.preventDefault();
const panel = (ev.currentTarget as any).panel; const panel = (ev.currentTarget as any).panel;
this._hiddenPanels = this._hiddenPanels.filter( this._tempHiddenPanels = this._tempHiddenPanels!.filter(
(hidden) => hidden !== panel (hidden) => hidden !== panel
); );
} }

33
src/data/sidebar.ts Normal file
View File

@ -0,0 +1,33 @@
import type { HomeAssistant } from "../types";
import {
fetchFrontendUserData,
saveFrontendUserData,
subscribeFrontendUserData,
} from "./frontend";
export const SIDEBAR_PREFERENCES_KEY = "sidebar";
export interface SidebarPreferences {
panelOrder?: string[];
hiddenPanels?: string[];
}
declare global {
interface FrontendUserData {
sidebar?: SidebarPreferences;
}
}
export const fetchSidebarPreferences = (hass: HomeAssistant) =>
fetchFrontendUserData(hass.connection, SIDEBAR_PREFERENCES_KEY);
export const saveSidebarPreferences = (
hass: HomeAssistant,
data: SidebarPreferences
) => saveFrontendUserData(hass.connection, SIDEBAR_PREFERENCES_KEY, data);
export const subscribeSidebarPreferences = (
hass: HomeAssistant,
callback: (sidebar?: SidebarPreferences | null) => void
) =>
subscribeFrontendUserData(hass.connection, SIDEBAR_PREFERENCES_KEY, callback);