Add default dashboard selection to profile page (#5360)

* Add default dashboard selection to profile page

* Comments

* Console.bye
This commit is contained in:
Bram Kragten 2020-03-30 16:08:36 +02:00 committed by GitHub
parent 263138a388
commit 8a6bd04543
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 146 additions and 28 deletions

View File

@ -32,7 +32,7 @@ import { classMap } from "lit-html/directives/class-map";
import { PaperIconItemElement } from "@polymer/paper-item/paper-icon-item"; import { PaperIconItemElement } from "@polymer/paper-item/paper-icon-item";
import { computeRTL } from "../common/util/compute_rtl"; import { computeRTL } from "../common/util/compute_rtl";
import { compare } from "../common/string/compare"; import { compare } from "../common/string/compare";
import { getDefaultPanelUrlPath, getDefaultPanel } from "../data/panel"; import { getDefaultPanel } from "../data/panel";
const SHOW_AFTER_SPACER = ["config", "developer-tools", "hassio"]; const SHOW_AFTER_SPACER = ["config", "developer-tools", "hassio"];
@ -87,10 +87,8 @@ const computePanels = (hass: HomeAssistant): [PanelInfo[], PanelInfo[]] => {
const beforeSpacer: PanelInfo[] = []; const beforeSpacer: PanelInfo[] = [];
const afterSpacer: PanelInfo[] = []; const afterSpacer: PanelInfo[] = [];
const defaultPage = getDefaultPanelUrlPath();
Object.values(panels).forEach((panel) => { Object.values(panels).forEach((panel) => {
if (!panel.title || panel.url_path === defaultPage) { if (!panel.title || panel.url_path === hass.defaultPanel) {
return; return;
} }
(SHOW_AFTER_SPACER.includes(panel.url_path) (SHOW_AFTER_SPACER.includes(panel.url_path)
@ -143,7 +141,7 @@ class HaSidebar extends LitElement {
} }
} }
const defaultPanel = getDefaultPanel(hass.panels); const defaultPanel = getDefaultPanel(hass);
return html` return html`
<div class="menu"> <div class="menu">
@ -297,7 +295,8 @@ class HaSidebar extends LitElement {
hass.panelUrl !== oldHass.panelUrl || hass.panelUrl !== oldHass.panelUrl ||
hass.user !== oldHass.user || hass.user !== oldHass.user ||
hass.localize !== oldHass.localize || hass.localize !== oldHass.localize ||
hass.states !== oldHass.states hass.states !== oldHass.states ||
hass.defaultPanel !== oldHass.defaultPanel
); );
} }

View File

@ -1,13 +1,20 @@
import { HomeAssistant, PanelInfo } from "../types"; import { HomeAssistant, PanelInfo } from "../types";
import { fireEvent } from "../common/dom/fire_event";
/** Panel to show when no panel is picked. */ /** Panel to show when no panel is picked. */
const DEFAULT_PANEL = "lovelace"; export const DEFAULT_PANEL = "lovelace";
export const getDefaultPanelUrlPath = () => export const getStorageDefaultPanelUrlPath = () =>
localStorage.defaultPage || DEFAULT_PANEL; localStorage.defaultPanel
? JSON.parse(localStorage.defaultPanel)
: DEFAULT_PANEL;
export const getDefaultPanel = (panels: HomeAssistant["panels"]) => export const setDefaultPanel = (element: HTMLElement, urlPath: string) => {
panels[localStorage.defaultPage] || panels[DEFAULT_PANEL]; fireEvent(element, "hass-default-panel", { defaultPanel: urlPath });
};
export const getDefaultPanel = (hass: HomeAssistant) =>
hass.panels[hass.defaultPanel];
export const getPanelTitle = (hass: HomeAssistant): string | undefined => { export const getPanelTitle = (hass: HomeAssistant): string | undefined => {
if (!hass.panels) { if (!hass.panels) {

View File

@ -11,6 +11,7 @@ import { HomeAssistant } from "../types";
import { HassEntities } from "home-assistant-js-websocket"; import { HassEntities } from "home-assistant-js-websocket";
import { getLocalLanguage } from "../util/hass-translation"; import { getLocalLanguage } from "../util/hass-translation";
import { translationMetadata } from "../resources/translations-metadata"; import { translationMetadata } from "../resources/translations-metadata";
import { DEFAULT_PANEL } from "../data/panel";
const ensureArray = <T>(val: T | T[]): T[] => const ensureArray = <T>(val: T | T[]): T[] =>
Array.isArray(val) ? val : [val]; Array.isArray(val) ? val : [val];
@ -172,6 +173,7 @@ export const provideHass = (
name: "Demo User", name: "Demo User",
}, },
panelUrl: "lovelace", panelUrl: "lovelace",
defaultPanel: DEFAULT_PANEL,
language: localLanguage, language: localLanguage,
selectedLanguage: localLanguage, selectedLanguage: localLanguage,

View File

@ -10,7 +10,7 @@ import { registerServiceWorker } from "../util/register-service-worker";
import { Route, HomeAssistant } from "../types"; import { Route, HomeAssistant } from "../types";
import { navigate } from "../common/navigate"; import { navigate } from "../common/navigate";
import { HassElement } from "../state/hass-element"; import { HassElement } from "../state/hass-element";
import { getDefaultPanelUrlPath } from "../data/panel"; import { getStorageDefaultPanelUrlPath } from "../data/panel";
export class HomeAssistantAppEl extends HassElement { export class HomeAssistantAppEl extends HassElement {
@property() private _route?: Route; @property() private _route?: Route;
@ -86,7 +86,7 @@ export class HomeAssistantAppEl extends HassElement {
this._route === undefined && this._route === undefined &&
(route.path === "" || route.path === "/") (route.path === "" || route.path === "/")
) { ) {
navigate(window, `/${getDefaultPanelUrlPath()}`, true); navigate(window, getStorageDefaultPanelUrlPath(), true);
return; return;
} }

View File

@ -19,6 +19,7 @@ import { PolymerChangedEvent } from "../../../../polymer-types";
import { HaSwitch } from "../../../../components/ha-switch"; import { HaSwitch } from "../../../../components/ha-switch";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import { haStyleDialog } from "../../../../resources/styles"; import { haStyleDialog } from "../../../../resources/styles";
import { setDefaultPanel, DEFAULT_PANEL } from "../../../../data/panel";
@customElement("dialog-lovelace-dashboard-detail") @customElement("dialog-lovelace-dashboard-detail")
export class DialogLovelaceDashboardDetail extends LitElement { export class DialogLovelaceDashboardDetail extends LitElement {
@ -57,6 +58,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
if (!this._params) { if (!this._params) {
return html``; return html``;
} }
const defaultPanelUrlPath = this.hass.defaultPanel;
const urlInvalid = const urlInvalid =
this._params.urlPath !== "lovelace" && this._params.urlPath !== "lovelace" &&
!/^[a-zA-Z0-9_-]+-[a-zA-Z0-9_-]+$/.test(this._urlPath); !/^[a-zA-Z0-9_-]+-[a-zA-Z0-9_-]+$/.test(this._urlPath);
@ -169,12 +171,9 @@ export class DialogLovelaceDashboardDetail extends LitElement {
slot="secondaryAction" slot="secondaryAction"
@click=${this._toggleDefault} @click=${this._toggleDefault}
.disabled=${this._params.urlPath === "lovelace" && .disabled=${this._params.urlPath === "lovelace" &&
(!localStorage.defaultPage || defaultPanelUrlPath === "lovelace"}
localStorage.defaultPage === "lovelace")}
> >
${this._params.urlPath === localStorage.defaultPage || ${this._params.urlPath === defaultPanelUrlPath
(this._params.urlPath === "lovelace" &&
!localStorage.defaultPage)
? this.hass.localize( ? this.hass.localize(
"ui.panel.config.lovelace.dashboards.detail.remove_default" "ui.panel.config.lovelace.dashboards.detail.remove_default"
) )
@ -244,12 +243,10 @@ export class DialogLovelaceDashboardDetail extends LitElement {
if (!urlPath) { if (!urlPath) {
return; return;
} }
if (urlPath === localStorage.defaultPage) { setDefaultPanel(
delete localStorage.defaultPage; this,
} else { urlPath === this.hass.defaultPanel ? DEFAULT_PANEL : urlPath
localStorage.defaultPage = urlPath; );
}
location.reload();
} }
private async _updateDashboard() { private async _updateDashboard() {

View File

@ -184,8 +184,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
private _getItems = memoize((dashboards: LovelaceDashboard[]) => { private _getItems = memoize((dashboards: LovelaceDashboard[]) => {
const defaultMode = (this.hass.panels?.lovelace const defaultMode = (this.hass.panels?.lovelace
?.config as LovelacePanelConfig).mode; ?.config as LovelacePanelConfig).mode;
const isDefault = const defaultUrlPath = this.hass.defaultPanel;
!localStorage.defaultPage || localStorage.defaultPage === "lovelace"; const isDefault = defaultUrlPath === "lovelace";
return [ return [
{ {
icon: "hass:view-dashboard", icon: "hass:view-dashboard",
@ -201,7 +201,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
return { return {
filename: "", filename: "",
...dashboard, ...dashboard,
default: localStorage.defaultPage === dashboard.url_path, default: defaultUrlPath === dashboard.url_path,
}; };
}), }),
]; ];

View File

@ -20,6 +20,7 @@ import "./ha-long-lived-access-tokens-card";
import "./ha-advanced-mode-row"; import "./ha-advanced-mode-row";
import "./ha-pick-language-row"; import "./ha-pick-language-row";
import "./ha-pick-theme-row"; import "./ha-pick-theme-row";
import "./ha-pick-dashboard-row";
import "./ha-push-notifications-row"; import "./ha-push-notifications-row";
import "./ha-force-narrow-row"; import "./ha-force-narrow-row";
import "./ha-set-vibrate-row"; import "./ha-set-vibrate-row";
@ -98,6 +99,10 @@ class HaPanelProfile extends LitElement {
.narrow=${this.narrow} .narrow=${this.narrow}
.hass=${this.hass} .hass=${this.hass}
></ha-pick-theme-row> ></ha-pick-theme-row>
<ha-pick-dashboard-row
.narrow=${this.narrow}
.hass=${this.hass}
></ha-pick-dashboard-row>
${this.hass.dockedSidebar !== "auto" || !this.narrow ${this.hass.dockedSidebar !== "auto" || !this.narrow
? html` ? html`
<ha-force-narrow-row <ha-force-narrow-row

View File

@ -0,0 +1,86 @@
import {
LitElement,
TemplateResult,
html,
property,
customElement,
PropertyValues,
} from "lit-element";
import "./ha-settings-row";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-listbox/paper-listbox";
import "../../components/ha-paper-dropdown-menu";
import { HomeAssistant } from "../../types";
import { LovelaceDashboard, fetchDashboards } from "../../data/lovelace";
import { setDefaultPanel } from "../../data/panel";
@customElement("ha-pick-dashboard-row")
class HaPickDashboardRow extends LitElement {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() private _dashboards: LovelaceDashboard[] = [];
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this._getDashboards();
}
protected render(): TemplateResult {
return html`
<ha-settings-row .narrow=${this.narrow}>
<span slot="heading">
${this.hass.localize("ui.panel.profile.dashboard.header")}
</span>
<span slot="description">
${this.hass.localize("ui.panel.profile.dashboard.description")}
</span>
<ha-paper-dropdown-menu
.label=${this.hass.localize(
"ui.panel.profile.dashboard.dropdown_label"
)}
dynamic-align
.disabled=${!this._dashboards.length}
>
<paper-listbox
slot="dropdown-content"
.selected=${this.hass.defaultPanel}
@iron-select=${this._dashboardChanged}
attr-for-selected="url-path"
>
<paper-item url-path="lovelace">default</paper-item>
${this._dashboards.map((dashboard) => {
if (!this.hass.user!.is_admin && dashboard.require_admin) {
return "";
}
return html`
<paper-item url-path=${dashboard.url_path}
>${dashboard.title}</paper-item
>
`;
})}
</paper-listbox>
</ha-paper-dropdown-menu>
</ha-settings-row>
`;
}
private async _getDashboards() {
this._dashboards = await fetchDashboards(this.hass);
}
private _dashboardChanged(ev: CustomEvent) {
const urlPath = ev.detail.item.getAttribute("url-path");
if (!urlPath || urlPath === this.hass.defaultPanel) {
return;
}
setDefaultPanel(this, urlPath);
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-pick-dashboard-row": HaPickDashboardRow;
}
}

View File

@ -21,6 +21,7 @@ import { Constructor, ServiceCallResponse } from "../types";
import { HassBaseEl } from "./hass-base-mixin"; import { HassBaseEl } from "./hass-base-mixin";
import { broadcastConnectionStatus } from "../data/connection-status"; import { broadcastConnectionStatus } from "../data/connection-status";
import { subscribeFrontendUserData } from "../data/frontend"; import { subscribeFrontendUserData } from "../data/frontend";
import { DEFAULT_PANEL } from "../data/panel";
export const connectionMixin = <T extends Constructor<HassBaseEl>>( export const connectionMixin = <T extends Constructor<HassBaseEl>>(
superClass: T superClass: T
@ -38,7 +39,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
services: null as any, services: null as any,
user: null as any, user: null as any,
panelUrl: (this as any)._panelUrl, panelUrl: (this as any)._panelUrl,
defaultPanel: DEFAULT_PANEL,
language: getLocalLanguage(), language: getLocalLanguage(),
selectedLanguage: null, selectedLanguage: null,
resources: null as any, resources: null as any,

View File

@ -7,15 +7,25 @@ interface DockSidebarParams {
dock: HomeAssistant["dockedSidebar"]; dock: HomeAssistant["dockedSidebar"];
} }
interface DefaultPanelParams {
defaultPanel: HomeAssistant["defaultPanel"];
}
declare global { declare global {
// for fire event // for fire event
interface HASSDomEvents { interface HASSDomEvents {
"hass-dock-sidebar": DockSidebarParams; "hass-dock-sidebar": DockSidebarParams;
} }
interface HASSDomEvents {
"hass-default-panel": DefaultPanelParams;
}
// for add event listener // for add event listener
interface HTMLElementEventMap { interface HTMLElementEventMap {
"hass-dock-sidebar": HASSDomEvent<DockSidebarParams>; "hass-dock-sidebar": HASSDomEvent<DockSidebarParams>;
} }
interface HTMLElementEventMap {
"hass-default-panel": HASSDomEvent<DefaultPanelParams>;
}
} }
export default <T extends Constructor<HassBaseEl>>(superClass: T) => export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
@ -26,5 +36,9 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
this._updateHass({ dockedSidebar: ev.detail.dock }); this._updateHass({ dockedSidebar: ev.detail.dock });
storeState(this.hass!); storeState(this.hass!);
}); });
this.addEventListener("hass-default-panel", (ev) => {
this._updateHass({ defaultPanel: ev.detail.defaultPanel });
storeState(this.hass!);
});
} }
}; };

View File

@ -2209,6 +2209,11 @@
"link_promo": "Learn about themes", "link_promo": "Learn about themes",
"dropdown_label": "Theme" "dropdown_label": "Theme"
}, },
"dashboard": {
"header": "Dashboard",
"description": "Pick a default dashboard for this device.",
"dropdown_label": "Dashboard"
},
"change_password": { "change_password": {
"header": "Change Password", "header": "Change Password",
"current_password": "Current Password", "current_password": "Current Password",

View File

@ -154,6 +154,7 @@ export interface HomeAssistant {
vibrate: boolean; vibrate: boolean;
dockedSidebar: "docked" | "always_hidden" | "auto"; dockedSidebar: "docked" | "always_hidden" | "auto";
defaultPanel: string;
moreInfoEntityId: string | null; moreInfoEntityId: string | null;
user?: CurrentUser; user?: CurrentUser;
userData?: CoreFrontendUserData | null; userData?: CoreFrontendUserData | null;

View File

@ -5,6 +5,7 @@ const STORED_STATE = [
"selectedTheme", "selectedTheme",
"selectedLanguage", "selectedLanguage",
"vibrate", "vibrate",
"defaultPanel",
]; ];
const STORAGE = window.localStorage || {}; const STORAGE = window.localStorage || {};