diff --git a/src/components/ha-icon-overflow-menu.ts b/src/components/ha-icon-overflow-menu.ts index dbbe30762cb0..12a6701f3100 100644 --- a/src/components/ha-icon-overflow-menu.ts +++ b/src/components/ha-icon-overflow-menu.ts @@ -66,7 +66,7 @@ export class HaIconOverflowMenu extends LitElement { .path=${item.path} > ${item.label} - ` + ` )} ` : html` @@ -103,6 +103,7 @@ export class HaIconOverflowMenu extends LitElement { :host { display: flex; justify-content: flex-end; + cursor: initial; } div[role="separator"] { border-right: 1px solid var(--divider-color); diff --git a/src/components/ha-items-display-editor.ts b/src/components/ha-items-display-editor.ts index e8128c93bf43..e4f251d7c433 100644 --- a/src/components/ha-items-display-editor.ts +++ b/src/components/ha-items-display-editor.ts @@ -27,6 +27,7 @@ export interface DisplayItem { label: string; description?: string; disableSorting?: boolean; + disableHiding?: boolean; } export interface DisplayValue { @@ -101,6 +102,7 @@ export class HaItemDisplayEditor extends LitElement { icon, iconPath, disableSorting, + disableHiding, } = item; return html` ` : nothing} - + ${!isVisible || !disableHiding + ? html`` + : nothing} ${isVisible && !disableSorting ? html` ({ path: `/${panel.url_path}`, - icon: panel.icon ?? "mdi:view-dashboard", - title: - panel.url_path === getDefaultPanelUrlPath(hass) - ? hass.localize("panel.states") - : hass.localize(`panel.${panel.title}`) || - panel.title || - (panel.url_path ? titleCase(panel.url_path) : ""), + icon: getPanelIcon(panel) || "mdi:view-dashboard", + title: getPanelTitle(hass, panel) || "", }); @customElement("ha-navigation-picker") diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index d811b82e4b78..108a9450cf93 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -1,22 +1,13 @@ import { mdiBell, - mdiCalendar, mdiCellphoneCog, - mdiChartBox, - mdiClipboardList, mdiCog, - mdiFormatListBulletedType, - mdiHammer, - mdiLightningBolt, mdiMenu, mdiMenuOpen, - mdiPlayBoxMultiple, - mdiTooltipAccount, - mdiViewDashboard, } from "@mdi/js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import type { CSSResultGroup, PropertyValues } from "lit"; -import { LitElement, css, html, nothing } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, eventOptions, @@ -33,7 +24,14 @@ import { computeRTL } from "../common/util/compute_rtl"; import { throttle } from "../common/util/throttle"; import { subscribeFrontendUserData } from "../data/frontend"; import type { ActionHandlerDetail } from "../data/lovelace/action_handler"; -import { getDefaultPanelUrlPath } from "../data/panel"; +import { + FIXED_PANELS, + getDefaultPanelUrlPath, + getPanelIcon, + getPanelIconPath, + getPanelTitle, + SHOW_AFTER_SPACER_PANELS, +} from "../data/panel"; import type { PersistentNotification } from "../data/persistent_notification"; import { subscribeNotifications } from "../data/persistent_notification"; import { subscribeRepairsIssueRegistry } from "../data/repairs"; @@ -54,8 +52,6 @@ import "./ha-spinner"; import "./ha-svg-icon"; import "./user/ha-user-badge"; -const SHOW_AFTER_SPACER = ["config", "developer-tools"]; - const SUPPORT_SCROLL_IF_NEEDED = "scrollIntoViewIfNeeded" in document.body; const SORT_VALUE_URL_PATHS = { @@ -67,18 +63,6 @@ const SORT_VALUE_URL_PATHS = { config: 11, }; -export const PANEL_ICONS = { - calendar: mdiCalendar, - "developer-tools": mdiHammer, - energy: mdiLightningBolt, - history: mdiChartBox, - logbook: mdiFormatListBulletedType, - lovelace: mdiViewDashboard, - map: mdiTooltipAccount, - "media-browser": mdiPlayBoxMultiple, - todo: mdiClipboardList, -}; - const panelSorter = ( reverseSort: string[], defaultPanel: string, @@ -155,16 +139,23 @@ export const computePanels = memoizeOne( const beforeSpacer: PanelInfo[] = []; const afterSpacer: PanelInfo[] = []; - Object.values(panels).forEach((panel) => { + const allPanels = Object.values(panels).filter( + (panel) => !FIXED_PANELS.includes(panel.url_path) + ); + + allPanels.forEach((panel) => { + const isDefaultPanel = panel.url_path === defaultPanel; + if ( - hiddenPanels.includes(panel.url_path) || - (!panel.title && panel.url_path !== defaultPanel) || - (panel.default_visible === false && - !panelsOrder.includes(panel.url_path)) + !isDefaultPanel && + (!panel.title || + hiddenPanels.includes(panel.url_path) || + (panel.default_visible === false && + !panelsOrder.includes(panel.url_path))) ) { return; } - (SHOW_AFTER_SPACER.includes(panel.url_path) + (SHOW_AFTER_SPACER_PANELS.includes(panel.url_path) ? afterSpacer : beforeSpacer ).push(panel); @@ -251,10 +242,7 @@ class HaSidebar extends SubscribeMixin(LitElement) { return nothing; } - // Show the supervisor as being part of configuration - const selectedPanel = this.route.path?.startsWith("/hassio/") - ? "config" - : this.hass.panelUrl; + const selectedPanel = this.hass.panelUrl; // prettier-ignore return html` @@ -397,9 +385,9 @@ class HaSidebar extends SubscribeMixin(LitElement) { private _renderAllPanels(selectedPanel: string) { if (!this._panelOrder || !this._hiddenPanels) { return html` - + + + `; } @@ -413,7 +401,6 @@ class HaSidebar extends SubscribeMixin(LitElement) { this.hass.locale ); - // prettier-ignore return html` - ${this._renderPanels(beforeSpacer, selectedPanel, defaultPanel)} + ${this._renderPanels(beforeSpacer, selectedPanel)} ${this._renderSpacer()} - ${this._renderPanels(afterSpacer, selectedPanel, defaultPanel)} - ${this._renderExternalConfiguration()} + ${this._renderPanels(afterSpacer, selectedPanel)} + ${this.hass.user?.is_admin + ? this._renderConfiguration(selectedPanel) + : this._renderExternalConfiguration()} `; } - private _renderPanels( - panels: PanelInfo[], - selectedPanel: string, - defaultPanel: string - ) { + private _renderPanels(panels: PanelInfo[], selectedPanel: string) { return panels.map((panel) => - this._renderPanel( - panel.url_path, - panel.url_path === defaultPanel - ? panel.title || this.hass.localize("panel.states") - : this.hass.localize(`panel.${panel.title}`) || panel.title, - panel.icon, - panel.url_path === defaultPanel && !panel.icon - ? PANEL_ICONS.lovelace - : panel.url_path in PANEL_ICONS - ? PANEL_ICONS[panel.url_path] - : undefined, - selectedPanel - ) + this._renderPanel(panel, panel.url_path === selectedPanel) ); } - private _renderPanel( - urlPath: string, - title: string | null, - icon: string | null | undefined, - iconPath: string | null | undefined, - selectedPanel: string - ) { - return urlPath === "config" - ? this._renderConfiguration(title, selectedPanel) - : html` - - ${iconPath - ? html`` - : html``} - ${title} - - `; + private _renderPanel(panel: PanelInfo, isSelected: boolean) { + const title = getPanelTitle(this.hass, panel); + const urlPath = panel.url_path; + const icon = getPanelIcon(panel); + const iconPath = getPanelIconPath(panel); + + return html` + + ${iconPath + ? html`` + : html``} + ${title} + + `; } private _renderDivider() { @@ -487,10 +455,15 @@ class HaSidebar extends SubscribeMixin(LitElement) { return html`
`; } - private _renderConfiguration(title: string | null, selectedPanel: string) { + private _renderConfiguration(selectedPanel: string) { + if (!this.hass.user?.is_admin) { + return nothing; + } + const isSelected = + selectedPanel === "config" || this.route.path?.startsWith("/hassio/"); return html` ` - : ""} - ${title} + : nothing} + ${this.hass.localize("panel.config")} ${this.alwaysExpand && (this._updatesCount > 0 || this._issuesCount > 0) ? html` ${this._updatesCount + this._issuesCount} ` - : ""} + : nothing} `; } @@ -535,19 +510,20 @@ class HaSidebar extends SubscribeMixin(LitElement) { ? html` ${notificationCount} ` - : ""} + : nothing} ${this.hass.localize("ui.notification_drawer.title")} ${this.alwaysExpand && notificationCount > 0 ? html`${notificationCount}` - : ""} + : nothing}
`; } private _renderUserItem(selectedPanel: string) { const isRTL = computeRTL(this.hass); + const isSelected = selectedPanel === "profile"; return html` - - ${this.hass.user ? this.hass.user.name : ""} + + ${this.hass.user ? this.hass.user.name : ""} + `; } private _renderExternalConfiguration() { - return html`${!this.hass.user?.is_admin && - this.hass.auth.external?.config.hasSettingsScreen - ? html` - - - - ${this.hass.localize("ui.sidebar.external_app_configuration")} - - - ` - : ""}`; + if (!this.hass.auth.external?.config.hasSettingsScreen) { + return nothing; + } + return html` + + + + ${this.hass.localize("ui.sidebar.external_app_configuration")} + + + `; } private _handleExternalAppConfiguration(ev: Event) { diff --git a/src/data/frontend.ts b/src/data/frontend.ts index d4c3d00e27d2..7746cefb38e2 100644 --- a/src/data/frontend.ts +++ b/src/data/frontend.ts @@ -7,8 +7,8 @@ export interface CoreFrontendUserData { } export interface SidebarFrontendUserData { - panelOrder: string[]; - hiddenPanels: string[]; + panelOrder?: string[]; + hiddenPanels?: string[]; } export interface CoreFrontendSystemData { diff --git a/src/data/panel.ts b/src/data/panel.ts index 08ad42d8925f..b1a86d8893f2 100644 --- a/src/data/panel.ts +++ b/src/data/panel.ts @@ -1,3 +1,15 @@ +import { + mdiAccount, + mdiCalendar, + mdiChartBox, + mdiClipboardList, + mdiFormatListBulletedType, + mdiHammer, + mdiLightningBolt, + mdiPlayBoxMultiple, + mdiTooltipAccount, + mdiViewDashboard, +} from "@mdi/js"; import type { HomeAssistant, PanelInfo } from "../types"; /** Panel to show when no panel is picked. */ @@ -60,7 +72,7 @@ export const getPanelTitleFromUrlPath = ( return getPanelTitle(hass, panel); }; -export const getPanelIcon = (panel: PanelInfo): string | null => { +export const getPanelIcon = (panel: PanelInfo): string | undefined => { if (!panel.icon) { switch (panel.component_name) { case "profile": @@ -70,5 +82,24 @@ export const getPanelIcon = (panel: PanelInfo): string | null => { } } - return panel.icon; + return panel.icon || undefined; }; + +export const PANEL_ICON_PATHS = { + calendar: mdiCalendar, + "developer-tools": mdiHammer, + energy: mdiLightningBolt, + history: mdiChartBox, + logbook: mdiFormatListBulletedType, + lovelace: mdiViewDashboard, + profile: mdiAccount, + map: mdiTooltipAccount, + "media-browser": mdiPlayBoxMultiple, + todo: mdiClipboardList, +}; + +export const getPanelIconPath = (panel: PanelInfo): string | undefined => + PANEL_ICON_PATHS[panel.url_path]; + +export const FIXED_PANELS = ["profile", "config"]; +export const SHOW_AFTER_SPACER_PANELS = ["developer-tools"]; diff --git a/src/dialogs/sidebar/dialog-edit-sidebar.ts b/src/dialogs/sidebar/dialog-edit-sidebar.ts index 413c6fed602c..6e1ab7b19593 100644 --- a/src/dialogs/sidebar/dialog-edit-sidebar.ts +++ b/src/dialogs/sidebar/dialog-edit-sidebar.ts @@ -1,5 +1,5 @@ import "@material/mwc-linear-progress/mwc-linear-progress"; -import { mdiClose } from "@mdi/js"; +import { mdiClose, mdiDotsVertical, mdiRestart } from "@mdi/js"; import { css, html, LitElement, nothing, type TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; @@ -9,18 +9,30 @@ import "../../components/ha-dialog-header"; import "../../components/ha-fade-in"; import "../../components/ha-icon-button"; import "../../components/ha-items-display-editor"; -import type { DisplayValue } from "../../components/ha-items-display-editor"; +import type { + DisplayItem, + DisplayValue, +} from "../../components/ha-items-display-editor"; +import "../../components/ha-md-button-menu"; import "../../components/ha-md-dialog"; import type { HaMdDialog } from "../../components/ha-md-dialog"; -import { computePanels, PANEL_ICONS } from "../../components/ha-sidebar"; +import "../../components/ha-md-menu-item"; +import { computePanels } from "../../components/ha-sidebar"; import "../../components/ha-spinner"; +import "../../components/ha-svg-icon"; import { fetchFrontendUserData, saveFrontendUserData, } from "../../data/frontend"; +import { + getDefaultPanelUrlPath, + getPanelIcon, + getPanelIconPath, + getPanelTitle, + SHOW_AFTER_SPACER_PANELS, +} from "../../data/panel"; import type { HomeAssistant } from "../../types"; import { showConfirmationDialog } from "../generic/show-dialog-box"; -import { getDefaultPanelUrlPath } from "../../data/panel"; @customElement("dialog-edit-sidebar") class DialogEditSidebar extends LitElement { @@ -105,48 +117,53 @@ class DialogEditSidebar extends LitElement { this.hass.locale ); - // Add default hidden panels that are missing in hidden + const orderSet = new Set(this._order); + const hiddenSet = new Set(this._hidden); + for (const panel of panels) { if ( panel.default_visible === false && - !this._order.includes(panel.url_path) && - !this._hidden.includes(panel.url_path) + !orderSet.has(panel.url_path) && + !hiddenSet.has(panel.url_path) ) { - this._hidden.push(panel.url_path); + hiddenSet.add(panel.url_path); } } + if (hiddenSet.has(defaultPanel)) { + hiddenSet.delete(defaultPanel); + } + + const hiddenPanels = Array.from(hiddenSet); + const items = [ ...beforeSpacer, - ...panels.filter((panel) => this._hidden!.includes(panel.url_path)), - ...afterSpacer.filter((panel) => panel.url_path !== "config"), - ].map((panel) => ({ + ...panels.filter((panel) => hiddenPanels.includes(panel.url_path)), + ...afterSpacer, + ].map((panel) => ({ value: panel.url_path, label: - panel.url_path === defaultPanel - ? panel.title || this.hass.localize("panel.states") - : this.hass.localize(`panel.${panel.title}`) || panel.title || "?", - icon: panel.icon || undefined, - iconPath: - panel.url_path === defaultPanel && !panel.icon - ? PANEL_ICONS.lovelace - : panel.url_path in PANEL_ICONS - ? PANEL_ICONS[panel.url_path] - : undefined, - disableSorting: panel.url_path === "developer-tools", + (getPanelTitle(this.hass, panel) || panel.url_path) + + `${defaultPanel === panel.url_path ? " (default)" : ""}`, + icon: getPanelIcon(panel), + iconPath: getPanelIconPath(panel), + disableSorting: SHOW_AFTER_SPACER_PANELS.includes(panel.url_path), + disableHiding: panel.url_path === defaultPanel, })); - return html` - `; + return html` + + + `; } protected render() { @@ -171,6 +188,22 @@ class DialogEditSidebar extends LitElement { >${this.hass.localize("ui.sidebar.edit_subtitle")}` : nothing} + + + + + ${this.hass.localize("ui.sidebar.reset_to_defaults")} + +
${this._renderContent()}
@@ -194,6 +227,26 @@ class DialogEditSidebar extends LitElement { this._hidden = [...hidden]; } + private _resetToDefaults = async () => { + const confirmation = await showConfirmationDialog(this, { + text: this.hass.localize("ui.sidebar.reset_confirmation"), + confirmText: this.hass.localize("ui.common.reset"), + }); + + if (!confirmation) { + return; + } + + this._order = []; + this._hidden = []; + try { + await saveFrontendUserData(this.hass.connection, "sidebar", {}); + } catch (err: any) { + this._error = err.message || err; + } + this.closeDialog(); + }; + private async _save() { if (this._migrateToUserData) { const confirmation = await showConfirmationDialog(this, { 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 a113f06b47b0..01ce8be93756 100644 --- a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts +++ b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts @@ -8,16 +8,13 @@ import "../../../../components/ha-button"; import { createCloseHeading } from "../../../../components/ha-dialog"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; -import { saveFrontendSystemData } from "../../../../data/frontend"; import type { LovelaceDashboard, LovelaceDashboardCreateParams, LovelaceDashboardMutableParams, } from "../../../../data/lovelace/dashboard"; -import { DEFAULT_PANEL } from "../../../../data/panel"; import { haStyleDialog } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; -import { showConfirmationDialog } from "../../../lovelace/custom-card-helpers"; import type { LovelaceDashboardDetailsDialogParams } from "./show-dialog-lovelace-dashboard-detail"; @customElement("dialog-lovelace-dashboard-detail") @@ -61,9 +58,9 @@ export class DialogLovelaceDashboardDetail extends LitElement { if (!this._params || !this._data) { return nothing; } - const defaultPanelUrlPath = - this.hass.systemData?.default_panel || DEFAULT_PANEL; + const titleInvalid = !this._data.title || !this._data.title.trim(); + const isLovelaceDashboard = this._params.urlPath === "lovelace"; return html` ` - : ""} - - ${this._params.urlPath === defaultPanelUrlPath - ? this.hass.localize( - "ui.panel.config.lovelace.dashboards.detail.remove_default" - ) - : this.hass.localize( - "ui.panel.config.lovelace.dashboards.detail.set_default" - )} - + : nothing} ` - : ""} + : nothing} & { default: boolean; filename: string; + localized_type: string; type: string; }; @@ -112,7 +126,7 @@ export class HaConfigLovelaceDashboards extends LitElement { state: false, subscribe: false, }) - private _activeGrouping?: string = "type"; + private _activeGrouping?: string = "localized_type"; @storage({ key: "lovelace-dashboards-table-collapsed", @@ -167,7 +181,7 @@ export class HaConfigLovelaceDashboards extends LitElement { this._handleSetAsDefault(dashboard), + disabled: dashboard.default, + }, + ...(dashboard.type === "user_created" ? [ { path: mdiPencil, @@ -262,10 +284,6 @@ export class HaConfigLovelaceDashboards extends LitElement { ), action: () => this._handleEdit(dashboard), }, - ] - : []), - ...(this._canDelete(dashboard.url_path) - ? [ { label: this.hass.localize( "ui.panel.config.lovelace.dashboards.picker.delete" @@ -288,92 +306,43 @@ export class HaConfigLovelaceDashboards extends LitElement { private _getItems = memoize( (dashboards: LovelaceDashboard[], defaultUrlPath: string | null) => { - const defaultMode = ( - this.hass.panels?.lovelace?.config as LovelacePanelConfig - ).mode; + const mode = (this.hass.panels?.lovelace?.config as LovelacePanelConfig) + .mode; const isDefault = defaultUrlPath === "lovelace"; const result: DataTableItem[] = [ { icon: "mdi:view-dashboard", title: this.hass.localize("panel.states"), default: isDefault, - show_in_sidebar: isDefault, + show_in_sidebar: true, require_admin: false, url_path: "lovelace", - mode: defaultMode, - filename: defaultMode === "yaml" ? "ui-lovelace.yaml" : "", - type: this._localizeType("built_in"), + mode: mode, + filename: mode === "yaml" ? "ui-lovelace.yaml" : "", + type: "built_in", + localized_type: this._localizeType("built_in"), }, ]; - if (isComponentLoaded(this.hass, "energy")) { - result.push({ - icon: "mdi:lightning-bolt", - title: this.hass.localize(`ui.panel.config.dashboard.energy.main`), - show_in_sidebar: true, - mode: "storage", - url_path: "energy", - filename: "", - default: false, - require_admin: false, - type: this._localizeType("built_in"), - }); - } - - if (this.hass.panels.light) { - result.push({ - icon: this.hass.panels.light.icon || "mdi:lamps", - title: this.hass.localize("panel.light"), - show_in_sidebar: true, - mode: "storage", - url_path: "light", - filename: "", - default: false, - require_admin: false, - type: this._localizeType("built_in"), - }); - } - if (this.hass.panels.security) { - result.push({ - icon: this.hass.panels.security.icon || "mdi:security", - title: this.hass.localize("panel.security"), - show_in_sidebar: true, - mode: "storage", - url_path: "security", - filename: "", - default: false, - require_admin: false, - type: this._localizeType("built_in"), - }); - } - - if (this.hass.panels.climate) { - result.push({ - icon: this.hass.panels.climate.icon || "mdi:home-thermometer", - title: this.hass.localize("panel.climate"), - show_in_sidebar: true, - mode: "storage", - url_path: "climate", - filename: "", - default: false, - require_admin: false, - type: this._localizeType("built_in"), - }); - } - - if (this.hass.panels.home) { - result.push({ - icon: this.hass.panels.home.icon || "mdi:home", - title: this.hass.localize("panel.home"), + PANEL_DASHBOARDS.forEach((panel) => { + const panelInfo = this.hass.panels[panel]; + if (!panel) { + return; + } + const item: DataTableItem = { + icon: getPanelIcon(panelInfo), + title: getPanelTitle(this.hass, panelInfo) || panelInfo.url_path, show_in_sidebar: true, mode: "storage", - url_path: "home", + url_path: panelInfo.url_path, filename: "", - default: false, + default: defaultUrlPath === panelInfo.url_path, require_admin: false, - type: this._localizeType("built_in"), - }); - } + type: "built_in", + localized_type: this._localizeType("built_in"), + }; + result.push(item); + }); result.push( ...dashboards @@ -386,7 +355,8 @@ export class HaConfigLovelaceDashboards extends LitElement { filename: "", ...dashboard, default: defaultUrlPath === dashboard.url_path, - type: this._localizeType("user_created"), + type: "user_created", + localized_type: this._localizeType("user_created"), }) satisfies DataTableItem ) ); @@ -486,20 +456,32 @@ export class HaConfigLovelaceDashboards extends LitElement { this._openDetailDialog(dashboard, urlPath); } - private _canDelete(urlPath: string) { - return ![ - "lovelace", - "energy", - "light", - "security", - "climate", - "home", - ].includes(urlPath); - } + private _handleSetAsDefault = async (item: DataTableItem) => { + if (item.default) { + return; + } - private _canEdit(urlPath: string) { - return !["light", "security", "climate", "home"].includes(urlPath); - } + const confirm = await showConfirmationDialog(this, { + title: this.hass.localize( + "ui.panel.config.lovelace.dashboards.detail.set_default_confirm_title" + ), + text: this.hass.localize( + "ui.panel.config.lovelace.dashboards.detail.set_default_confirm_text" + ), + confirmText: this.hass.localize("ui.common.ok"), + dismissText: this.hass.localize("ui.common.cancel"), + destructive: false, + }); + + if (!confirm) { + return; + } + + await saveFrontendSystemData(this.hass.connection, "core", { + ...this.hass.systemData, + default_panel: item.url_path, + }); + }; private _handleDelete = async (item: DataTableItem) => { const dashboard = this._dashboards.find( @@ -581,10 +563,6 @@ export class HaConfigLovelaceDashboards extends LitElement { private async _deleteDashboard( dashboard: LovelaceDashboard ): Promise { - if (!this._canDelete(dashboard.url_path)) { - return false; - } - const confirm = await showConfirmationDialog(this, { title: this.hass!.localize( "ui.panel.config.lovelace.dashboards.confirm_delete_title", diff --git a/src/panels/profile/ha-pick-dashboard-row.ts b/src/panels/profile/ha-pick-dashboard-row.ts index bb4163cf736e..4df5e24e38b8 100644 --- a/src/panels/profile/ha-pick-dashboard-row.ts +++ b/src/panels/profile/ha-pick-dashboard-row.ts @@ -1,13 +1,16 @@ import type { PropertyValues, TemplateResult } from "lit"; -import { html, LitElement } from "lit"; +import { html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import "../../components/ha-divider"; import "../../components/ha-list-item"; import "../../components/ha-select"; import "../../components/ha-settings-row"; +import { saveFrontendUserData } from "../../data/frontend"; import type { LovelaceDashboard } from "../../data/lovelace/dashboard"; import { fetchDashboards } from "../../data/lovelace/dashboard"; -import type { HomeAssistant } from "../../types"; -import { saveFrontendUserData } from "../../data/frontend"; +import { getPanelTitle } from "../../data/panel"; +import type { HomeAssistant, PanelInfo } from "../../types"; +import { PANEL_DASHBOARDS } from "../config/lovelace/dashboards/ha-config-lovelace-dashboards"; const USE_SYSTEM_VALUE = "___use_system___"; @@ -47,12 +50,24 @@ class HaPickDashboardRow extends LitElement { ${this.hass.localize("ui.panel.profile.dashboard.system")} + ${this.hass.localize("ui.panel.profile.dashboard.lovelace")} - - ${this.hass.localize("ui.panel.profile.dashboard.home")} - + ${PANEL_DASHBOARDS.map((panel) => { + const panelInfo = this.hass.panels[panel] as + | PanelInfo + | undefined; + if (!panelInfo) { + return nothing; + } + return html` + + ${getPanelTitle(this.hass, panelInfo)} + + `; + })} + ${this._dashboards.map((dashboard) => { if (!this.hass.user!.is_admin && dashboard.require_admin) { return ""; diff --git a/src/translations/en.json b/src/translations/en.json index 5e96e900c591..e43531522a98 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2217,7 +2217,9 @@ "sidebar_toggle": "Sidebar toggle", "edit_sidebar": "Edit sidebar", "edit_subtitle": "Synced on all devices", - "migrate_to_user_data": "This will change the sidebar on all the devices you are logged in to. To create a sidebar per device, you should use a different user for that device." + "migrate_to_user_data": "This will change the sidebar on all the devices you are logged in to. To create a sidebar per device, you should use a different user for that device.", + "reset_to_defaults": "Reset to defaults", + "reset_confirmation": "Are you sure you want to reset the sidebar to its default configuration? This will restore the original order and visibility of all panels." }, "panel": { "home": { @@ -3508,6 +3510,7 @@ "edit": "Edit", "delete": "Delete", "add_dashboard": "Add dashboard", + "set_as_default": "Set as default", "type": { "user_created": "User created", "built_in": "Built-in" @@ -3516,7 +3519,7 @@ "confirm_delete_title": "Delete {dashboard_title}?", "confirm_delete_text": "This dashboard will be permanently deleted.", "cant_edit_yaml": "Dashboards created in YAML cannot be edited from the UI. Change them in configuration.yaml.", - "cant_edit_default": "The default dashboard, Overview, cannot be edited from the UI. You can hide it by setting another dashboard as default.", + "cant_edit_lovelace": "The Overview dashboard title and icon cannot be changed. You can create a new dashboard to get more customization options.", "detail": { "edit_dashboard": "Edit dashboard", "new_dashboard": "Add new dashboard", @@ -3533,9 +3536,7 @@ "set_default": "Set as default", "remove_default": "Remove as default", "set_default_confirm_title": "Set as default dashboard?", - "set_default_confirm_text": "This will replace the current default dashboard. Users can still override their default dashboard in their profile settings.", - "remove_default_confirm_title": "Remove default dashboard?", - "remove_default_confirm_text": "The default dashboard will be changed to Overview for every user. Users can still override their default dashboard in their profile settings." + "set_default_confirm_text": "This dashboard will be shown to all users when opening Home Assistant. Each user can change this in their profile." } }, "resources": {