Change config panel navigation (#4377)

* Change config panel navigation

* Show active + don't show toolbar?

* Update ha-panel-config.ts

* Change color of menu toolbar

* Update ha-config-router.ts

* Review comments
This commit is contained in:
Bram Kragten 2020-01-12 17:57:38 +01:00 committed by GitHub
parent a8ed87298a
commit 22792c70c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 562 additions and 352 deletions

View File

@ -9,12 +9,14 @@ import {
} from "lit-element";
import "../components/ha-menu-button";
import "../components/ha-paper-icon-button-arrow-prev";
import { classMap } from "lit-html/directives/class-map";
@customElement("hass-subpage")
class HassSubpage extends LitElement {
@property()
public header?: string;
@property({ type: Boolean })
public showBackButton = true;
@property({ type: Boolean })
public hassio = false;
@ -25,6 +27,7 @@ class HassSubpage extends LitElement {
aria-label="Back"
.hassio=${this.hassio}
@click=${this._backTapped}
class=${classMap({ hidden: !this.showBackButton })}
></ha-paper-icon-button-arrow-prev>
<div main-title>${this.header}</div>
@ -64,6 +67,10 @@ class HassSubpage extends LitElement {
pointer-events: auto;
}
ha-paper-icon-button-arrow-prev.hidden {
visibility: hidden;
}
[main-title] {
margin: 0 0 0 24px;
line-height: 20px;

View File

@ -5,6 +5,7 @@ import {
css,
CSSResult,
property,
customElement,
} from "lit-element";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
@ -30,7 +31,8 @@ import { classMap } from "lit-html/directives/class-map";
import { computeRTL } from "../../../common/util/compute_rtl";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
class HaConfigAreaRegistry extends LitElement {
@customElement("ha-config-areas")
export class HaConfigAreas extends LitElement {
@property() public hass!: HomeAssistant;
@property() public isWide?: boolean;
@property() private _areas?: AreaRegistryEntry[];
@ -51,7 +53,8 @@ class HaConfigAreaRegistry extends LitElement {
}
return html`
<hass-subpage
header="${this.hass.localize("ui.panel.config.area_registry.caption")}"
.header="${this.hass.localize("ui.panel.config.area_registry.caption")}"
.showBackButton=${!this.isWide}
>
<ha-config-section .isWide=${this.isWide}>
<span slot="header">
@ -208,5 +211,3 @@ All devices in this area will become unassigned.`)
`;
}
}
customElements.define("ha-config-area-registry", HaConfigAreaRegistry);

View File

@ -42,6 +42,7 @@ class HaAutomationPicker extends LitElement {
protected render(): TemplateResult | void {
return html`
<hass-subpage
.showBackButton=${!this.isWide}
.header=${this.hass.localize("ui.panel.config.automation.caption")}
>
<ha-config-section .isWide=${this.isWide}>

View File

@ -63,7 +63,10 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) {
color: var(--primary-color);
}
</style>
<hass-subpage header="[[localize('ui.panel.config.cloud.caption')]]">
<hass-subpage
showBackButton="[[!isWide]]"
header="[[localize('ui.panel.config.cloud.caption')]]"
>
<div class="content">
<ha-config-section is-wide="[[isWide]]">
<span slot="header"

View File

@ -72,7 +72,10 @@ class CloudLogin extends LocalizeMixin(
color: var(--secondary-text-color);
}
</style>
<hass-subpage header="[[localize('ui.panel.config.cloud.caption')]]">
<hass-subpage
showBackButton="[[!isWide]]"
header="[[localize('ui.panel.config.cloud.caption')]]"
>
<div class="content">
<ha-config-section is-wide="[[isWide]]">
<span slot="header"

View File

@ -33,7 +33,10 @@ class HaConfigCore extends LocalizeMixin(PolymerElement) {
}
</style>
<hass-subpage header="[[localize('ui.panel.config.core.caption')]]">
<hass-subpage
header="[[localize('ui.panel.config.core.caption')]]"
showBackButton="[[!isWide]]"
>
<div class$="[[computeClasses(isWide)]]">
<ha-config-section-core
is-wide="[[isWide]]"

View File

@ -23,12 +23,17 @@ import LocalizeMixin from "../../../mixins/localize-mixin";
class HaConfigCustomize extends LocalizeMixin(PolymerElement) {
static get template() {
return html`
<style include="ha-style"></style>
<style include="ha-style">
ha-paper-icon-button-arrow-prev[hide] {
visibility: hidden;
}
</style>
<app-header-layout has-scrolling-region="">
<app-header slot="header" fixed="">
<app-toolbar>
<ha-paper-icon-button-arrow-prev
hide$="[[isWide]]"
on-click="_backTapped"
></ha-paper-icon-button-arrow-prev>
<div main-title="">

View File

@ -55,65 +55,67 @@ class HaConfigDashboard extends LitElement {
${isComponentLoaded(this.hass, "cloud")
? html`
<ha-card>
<a href='/config/cloud' tabindex="-1">
<paper-item>
<paper-item-body two-line="">
${this.hass.localize("ui.panel.config.cloud.caption")}
${
this.cloudStatus.logged_in
? html`
<div secondary="">
${this.hass.localize(
"ui.panel.config.cloud.description_login",
"email",
(this.cloudStatus as CloudStatusLoggedIn).email
)}
</div>
`
: html`
<div secondary="">
${this.hass.localize(
"ui.panel.config.cloud.description_features"
)}
</div>
`
}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</ha-card>
</a>
`
<ha-card>
<a href="/config/cloud" tabindex="-1">
<paper-item>
<paper-item-body two-line="">
${this.hass.localize("ui.panel.config.cloud.caption")}
${this.cloudStatus.logged_in
? html`
<div secondary="">
${this.hass.localize(
"ui.panel.config.cloud.description_login",
"email",
(this.cloudStatus as CloudStatusLoggedIn)
.email
)}
</div>
`
: html`
<div secondary="">
${this.hass.localize(
"ui.panel.config.cloud.description_features"
)}
</div>
`}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
</ha-card>
`
: ""}
<ha-config-navigation
.hass=${this.hass}
.showAdvanced=${this.showAdvanced}
.pages=${[
{ page: "integrations", core: true },
{ page: "devices", core: true },
{ page: "automation" },
{ page: "script" },
{ page: "scene" },
]}
></ha-config-navigation>
<ha-config-navigation
.hass=${this.hass}
.showAdvanced=${this.showAdvanced}
.pages=${[
{ page: "core", core: true },
{ page: "server_control", core: true },
{ page: "entity_registry", core: true },
{ page: "area_registry", core: true },
{ page: "person" },
{ page: "users", core: true },
{ page: "zha" },
{ page: "zwave" },
{ page: "customize", core: true, advanced: true },
]}
></ha-config-navigation>
<ha-card>
<ha-config-navigation
.hass=${this.hass}
.showAdvanced=${this.showAdvanced}
.pages=${[
{ page: "integrations", core: true },
{ page: "devices", core: true },
{ page: "automation" },
{ page: "script" },
{ page: "scene" },
]}
></ha-config-navigation>
</ha-card>
<ha-card>
<ha-config-navigation
.hass=${this.hass}
.showAdvanced=${this.showAdvanced}
.pages=${[
{ page: "core", core: true },
{ page: "server_control", core: true },
{ page: "entities", core: true },
{ page: "areas", core: true },
{ page: "person" },
{ page: "users", core: true },
{ page: "zha" },
{ page: "zwave" },
{ page: "customize", core: true, advanced: true },
]}
></ha-config-navigation>
</ha-card>
${!this.showAdvanced
? html`

View File

@ -16,11 +16,13 @@ import {
css,
} from "lit-element";
import { HomeAssistant } from "../../../types";
import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud";
export interface ConfigPageNavigation {
page: string;
core?: boolean;
advanced?: boolean;
info?: any;
}
@customElement("ha-config-navigation")
@ -28,31 +30,56 @@ class HaConfigNavigation extends LitElement {
@property() public hass!: HomeAssistant;
@property() public showAdvanced!: boolean;
@property() public pages!: ConfigPageNavigation[];
@property() public curPage!: string;
protected render(): TemplateResult | void {
return html`
<ha-card>
${this.pages.map(({ page, core, advanced }) =>
<paper-listbox attr-for-selected="data-page" .selected=${this.curPage}>
${this.pages.map(({ page, core, advanced, info }) =>
(core || isComponentLoaded(this.hass, page)) &&
(!advanced || this.showAdvanced)
? html`
<a href=${`/config/${page}`}>
<a
href=${`/config/${page}`}
aria-role="option"
data-page="${page}"
tabindex="-1"
>
<paper-item>
<paper-item-body two-line="">
<paper-item-body two-line>
${this.hass.localize(`ui.panel.config.${page}.caption`)}
<div secondary>
${this.hass.localize(
`ui.panel.config.${page}.description`
)}
</div>
${page === "cloud" && (info as CloudStatus)
? info.logged_in
? html`
<div secondary>
${this.hass.localize(
"ui.panel.config.cloud.description_login",
"email",
(info as CloudStatusLoggedIn).email
)}
</div>
`
: html`
<div secondary>
${this.hass.localize(
"ui.panel.config.cloud.description_features"
)}
</div>
`
: html`
<div secondary>
${this.hass.localize(
`ui.panel.config.${page}.description`
)}
</div>
`}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
`
: ""
)}
</ha-card>
</paper-listbox>
`;
}
@ -62,6 +89,24 @@ class HaConfigNavigation extends LitElement {
text-decoration: none;
color: var(--primary-text-color);
}
.iron-selected paper-item:before {
border-radius: 4px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: none;
content: "";
background-color: var(--sidebar-selected-icon-color);
opacity: 0.12;
transition: opacity 15ms linear;
will-change: opacity;
}
.iron-selected paper-item[pressed]:before {
opacity: 0.37;
}
`;
}
}

View File

@ -20,7 +20,7 @@ import "@polymer/paper-item/paper-item-body";
import "../../../../components/ha-card";
import "../../../../components/ha-icon";
import "../../../../components/ha-switch";
import { showEntityRegistryDetailDialog } from "../../entity_registry/show-dialog-entity-registry-detail";
import { showEntityRegistryDetailDialog } from "../../entities/show-dialog-entity-registry-detail";
import { fireEvent } from "../../../../common/dom/fire_event";
import { computeDomain } from "../../../../common/entity/compute_domain";
import { domainIcon } from "../../../../common/entity/domain_icon";

View File

@ -20,6 +20,7 @@ import { AreaRegistryEntry } from "../../../data/area_registry";
export class HaConfigDeviceDashboard extends LitElement {
@property() public hass!: HomeAssistant;
@property() public narrow = false;
@property() public isWide = false;
@property() public devices!: DeviceRegistryEntry[];
@property() public entries!: ConfigEntry[];
@property() public entities!: EntityRegistryEntry[];
@ -29,7 +30,8 @@ export class HaConfigDeviceDashboard extends LitElement {
protected render(): TemplateResult {
return html`
<hass-subpage
header=${this.hass.localize("ui.panel.config.devices.caption")}
.showBackButton=${!this.isWide}
.header=${this.hass.localize("ui.panel.config.devices.caption")}
>
<div class="content">
<ha-devices-data-table

View File

@ -28,6 +28,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
class HaConfigDevices extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() public isWide!: boolean;
@property() public showAdvanced!: boolean;
protected routerOptions: RouterOptions = {
@ -97,6 +98,7 @@ class HaConfigDevices extends HassRouterPage {
pageEl.devices = this._deviceRegistryEntries;
pageEl.areas = this._areas;
pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide;
pageEl.showAdvanced = this.showAdvanced;
}

View File

@ -6,6 +6,7 @@ import {
CSSResult,
property,
query,
customElement,
} from "lit-element";
import { styleMap } from "lit-html/directives/style-map";
@ -46,7 +47,8 @@ import {
} from "../../../components/data-table/ha-data-table";
import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialog-confirmation";
class HaConfigEntityRegistry extends LitElement {
@customElement("ha-config-entities")
export class HaConfigEntities extends LitElement {
@property() public hass!: HomeAssistant;
@property() public isWide!: boolean;
@property() public narrow!: boolean;
@ -211,9 +213,10 @@ class HaConfigEntityRegistry extends LitElement {
}
return html`
<hass-subpage
header="${this.hass.localize(
.header="${this.hass.localize(
"ui.panel.config.entity_registry.caption"
)}"
.showBackButton=${!this.isWide}
>
<div class="content">
<div class="intro">
@ -496,14 +499,14 @@ class HaConfigEntityRegistry extends LitElement {
}
h2 {
margin-top: 0;
font-family: var(--paper-font-display1_-_font-family);
font-family: var(--paper-font-headline_-_font-family);
-webkit-font-smoothing: var(
--paper-font-display1_-_-webkit-font-smoothing
--paper-font-headline_-_-webkit-font-smoothing
);
font-size: var(--paper-font-display1_-_font-size);
font-weight: var(--paper-font-display1_-_font-weight);
letter-spacing: var(--paper-font-display1_-_letter-spacing);
line-height: var(--paper-font-display1_-_line-height);
font-size: var(--paper-font-headline_-_font-size);
font-weight: var(--paper-font-headline_-_font-weight);
letter-spacing: var(--paper-font-headline_-_letter-spacing);
line-height: var(--paper-font-headline_-_line-height);
opacity: var(--dark-primary-opacity);
}
p {
@ -511,10 +514,8 @@ class HaConfigEntityRegistry extends LitElement {
-webkit-font-smoothing: var(
--paper-font-subhead_-_-webkit-font-smoothing
);
font-size: var(--paper-font-subhead_-_font-size);
font-weight: var(--paper-font-subhead_-_font-weight);
line-height: var(--paper-font-subhead_-_line-height);
opacity: var(--dark-primary-opacity);
}
.intro {
padding: 24px 16px;
@ -549,5 +550,3 @@ class HaConfigEntityRegistry extends LitElement {
`;
}
}
customElements.define("ha-config-entity-registry", HaConfigEntityRegistry);

View File

@ -0,0 +1,170 @@
import { property, customElement } from "lit-element";
import "../../layouts/hass-loading-screen";
import { HomeAssistant } from "../../types";
import { CloudStatus } from "../../data/cloud";
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
import { PolymerElement } from "@polymer/polymer";
declare global {
// for fire event
interface HASSDomEvents {
"ha-refresh-cloud-status": undefined;
}
}
@customElement("ha-config-router")
class HaConfigRouter extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() public wideSidebar: boolean = false;
@property() public wide: boolean = false;
@property() public isWide: boolean = false;
@property() public showAdvanced: boolean = false;
@property() public cloudStatus?: CloudStatus;
protected routerOptions: RouterOptions = {
defaultPage: "dashboard",
cacheAll: true,
preloadAll: true,
routes: {
areas: {
tag: "ha-config-areas",
load: () =>
import(
/* webpackChunkName: "panel-config-areas" */ "./areas/ha-config-areas"
),
},
automation: {
tag: "ha-config-automation",
load: () =>
import(
/* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation"
),
},
cloud: {
tag: "ha-config-cloud",
load: () =>
import(
/* webpackChunkName: "panel-config-cloud" */ "./cloud/ha-config-cloud"
),
},
core: {
tag: "ha-config-core",
load: () =>
import(
/* webpackChunkName: "panel-config-core" */ "./core/ha-config-core"
),
},
devices: {
tag: "ha-config-devices",
load: () =>
import(
/* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices"
),
},
server_control: {
tag: "ha-config-server-control",
load: () =>
import(
/* webpackChunkName: "panel-config-server-control" */ "./server_control/ha-config-server-control"
),
},
customize: {
tag: "ha-config-customize",
load: () =>
import(
/* webpackChunkName: "panel-config-customize" */ "./customize/ha-config-customize"
),
},
dashboard: {
tag: "ha-config-dashboard",
load: () =>
import(
/* webpackChunkName: "panel-config-dashboard" */ "./dashboard/ha-config-dashboard"
),
},
entities: {
tag: "ha-config-entities",
load: () =>
import(
/* webpackChunkName: "panel-config-entities" */ "./entities/ha-config-entities"
),
},
integrations: {
tag: "ha-config-integrations",
load: () =>
import(
/* webpackChunkName: "panel-config-integrations" */ "./integrations/ha-config-integrations"
),
},
person: {
tag: "ha-config-person",
load: () =>
import(
/* webpackChunkName: "panel-config-person" */ "./person/ha-config-person"
),
},
script: {
tag: "ha-config-script",
load: () =>
import(
/* webpackChunkName: "panel-config-script" */ "./script/ha-config-script"
),
},
scene: {
tag: "ha-config-scene",
load: () =>
import(
/* webpackChunkName: "panel-config-scene" */ "./scene/ha-config-scene"
),
},
users: {
tag: "ha-config-users",
load: () =>
import(
/* webpackChunkName: "panel-config-users" */ "./users/ha-config-users"
),
},
zha: {
tag: "zha-config-dashboard-router",
load: () =>
import(
/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router"
),
},
zwave: {
tag: "ha-config-zwave",
load: () =>
import(
/* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave"
),
},
},
};
protected updatePageEl(el) {
if ("setProperties" in el) {
// As long as we have Polymer panels
(el as PolymerElement).setProperties({
route: this.routeTail,
hass: this.hass,
showAdvanced: this.showAdvanced,
isWide: this.isWide,
narrow: this.narrow,
cloudStatus: this.cloudStatus,
});
} else {
el.route = this.routeTail;
el.hass = this.hass;
el.showAdvanced = this.showAdvanced;
el.isWide = this.isWide;
el.narrow = this.narrow;
el.cloudStatus = this.cloudStatus;
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-config-router": HaConfigRouter;
}
}

View File

@ -1,98 +0,0 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../resources/ha-style";
class HaConfigSection extends PolymerElement {
static get template() {
return html`
<style include="iron-flex ha-style">
.content {
padding: 28px 20px 0;
max-width: 1040px;
margin: 0 auto;
}
.header {
@apply --paper-font-display1;
opacity: var(--dark-primary-opacity);
}
.together {
margin-top: 32px;
}
.intro {
@apply --paper-font-subhead;
width: 100%;
max-width: 400px;
margin-right: 40px;
opacity: var(--dark-primary-opacity);
}
.panel {
margin-top: -24px;
}
.panel ::slotted(*) {
margin-top: 24px;
display: block;
}
.narrow.content {
max-width: 640px;
}
.narrow .together {
margin-top: 20px;
}
.narrow .header {
@apply --paper-font-headline;
}
.narrow .intro {
font-size: 14px;
padding-bottom: 20px;
margin-right: 0;
max-width: 500px;
}
</style>
<div class$="[[computeContentClasses(isWide)]]">
<div class="header"><slot name="header"></slot></div>
<div class$="[[computeClasses(isWide)]]">
<div class="intro"><slot name="introduction"></slot></div>
<div class="panel flex-auto"><slot></slot></div>
</div>
</div>
`;
}
static get properties() {
return {
hass: {
type: Object,
},
narrow: {
type: Boolean,
},
isWide: {
type: Boolean,
value: false,
},
};
}
computeContentClasses(isWide) {
var classes = "content ";
return isWide ? classes : classes + "narrow";
}
computeClasses(isWide) {
var classes = "together layout ";
return classes + (isWide ? "horizontal" : "vertical narrow");
}
}
customElements.define("ha-config-section", HaConfigSection);

View File

@ -0,0 +1,65 @@
import { customElement } from "lit-element";
@customElement("ha-config-section")
export class HaConfigSection extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.shadowRoot!.innerHTML = `
<style>
.content {
padding: 28px 20px 0;
max-width: 640px;
margin: 0 auto;
}
.header {
font-family: var(--paper-font-headline_-_font-family);
-webkit-font-smoothing: var(
--paper-font-headline_-_-webkit-font-smoothing
);
font-size: var(--paper-font-headline_-_font-size);
font-weight: var(--paper-font-headline_-_font-weight);
letter-spacing: var(--paper-font-headline_-_letter-spacing);
line-height: var(--paper-font-headline_-_line-height);
opacity: var(--dark-primary-opacity);
}
.together {
margin-top: 20px;
}
.intro {
font-family: var(--paper-font-subhead_-_font-family);
-webkit-font-smoothing: var(
--paper-font-subhead_-_-webkit-font-smoothing
);
font-weight: var(--paper-font-subhead_-_font-weight);
line-height: var(--paper-font-subhead_-_line-height);
width: 100%;
width: 100%;
max-width: 500px;
opacity: var(--dark-primary-opacity);
font-size: 14px;
padding-bottom: 20px;
}
.panel {
margin-top: -24px;
}
.panel ::slotted(*) {
margin-top: 24px;
display: block;
}
</style>
<div class="content">
<div class="header"><slot name="header"></slot></div>
<div class="together">
<div class="intro"><slot name="introduction"></slot></div>
<div class="panel"><slot></slot></div>
</div>
</div>
`;
}
}

View File

@ -1,15 +1,26 @@
import { property, PropertyValues, customElement } from "lit-element";
import {
property,
PropertyValues,
customElement,
LitElement,
html,
CSSResult,
css,
} from "lit-element";
import "@polymer/paper-item/paper-item-body";
import "@polymer/paper-item/paper-item";
import "../../layouts/hass-loading-screen";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { HomeAssistant } from "../../types";
import { HomeAssistant, Route } from "../../types";
import { CloudStatus, fetchCloudStatus } from "../../data/cloud";
import { listenMediaQuery } from "../../common/dom/media_query";
import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page";
import {
CoreFrontendUserData,
getOptimisticFrontendUserDataCollection,
CoreFrontendUserData,
} from "../../data/frontend";
import { PolymerElement } from "@polymer/polymer";
import "./ha-config-router";
import "./dashboard/ha-config-navigation";
import { classMap } from "lit-html/directives/class-map";
declare global {
// for fire event
@ -19,133 +30,15 @@ declare global {
}
@customElement("ha-panel-config")
class HaPanelConfig extends HassRouterPage {
class HaPanelConfig extends LitElement {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
protected routerOptions: RouterOptions = {
defaultPage: "dashboard",
cacheAll: true,
preloadAll: true,
routes: {
area_registry: {
tag: "ha-config-area-registry",
load: () =>
import(
/* webpackChunkName: "panel-config-area-registry" */ "./area_registry/ha-config-area-registry"
),
},
automation: {
tag: "ha-config-automation",
load: () =>
import(
/* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation"
),
},
cloud: {
tag: "ha-config-cloud",
load: () =>
import(
/* webpackChunkName: "panel-config-cloud" */ "./cloud/ha-config-cloud"
),
},
core: {
tag: "ha-config-core",
load: () =>
import(
/* webpackChunkName: "panel-config-core" */ "./core/ha-config-core"
),
},
devices: {
tag: "ha-config-devices",
load: () =>
import(
/* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices"
),
},
server_control: {
tag: "ha-config-server-control",
load: () =>
import(
/* webpackChunkName: "panel-config-server-control" */ "./server_control/ha-config-server-control"
),
},
customize: {
tag: "ha-config-customize",
load: () =>
import(
/* webpackChunkName: "panel-config-customize" */ "./customize/ha-config-customize"
),
},
dashboard: {
tag: "ha-config-dashboard",
load: () =>
import(
/* webpackChunkName: "panel-config-dashboard" */ "./dashboard/ha-config-dashboard"
),
},
entity_registry: {
tag: "ha-config-entity-registry",
load: () =>
import(
/* webpackChunkName: "panel-config-entity-registry" */ "./entity_registry/ha-config-entity-registry"
),
},
integrations: {
tag: "ha-config-integrations",
load: () =>
import(
/* webpackChunkName: "panel-config-integrations" */ "./integrations/ha-config-integrations"
),
},
person: {
tag: "ha-config-person",
load: () =>
import(
/* webpackChunkName: "panel-config-person" */ "./person/ha-config-person"
),
},
script: {
tag: "ha-config-script",
load: () =>
import(
/* webpackChunkName: "panel-config-script" */ "./script/ha-config-script"
),
},
scene: {
tag: "ha-config-scene",
load: () =>
import(
/* webpackChunkName: "panel-config-scene" */ "./scene/ha-config-scene"
),
},
users: {
tag: "ha-config-users",
load: () =>
import(
/* webpackChunkName: "panel-config-users" */ "./users/ha-config-users"
),
},
zha: {
tag: "zha-config-dashboard-router",
load: () =>
import(
/* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router"
),
},
zwave: {
tag: "ha-config-zwave",
load: () =>
import(
/* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave"
),
},
},
};
@property() public route!: Route;
@property() private _wideSidebar: boolean = false;
@property() private _wide: boolean = false;
@property() private _coreUserData?: CoreFrontendUserData;
@property() private _showAdvanced = false;
@property() private _cloudStatus?: CloudStatus;
private _listeners: Array<() => void> = [];
@ -168,6 +61,9 @@ class HaPanelConfig extends HassRouterPage {
"core"
).subscribe((coreUserData) => {
this._coreUserData = coreUserData || {};
this._showAdvanced = !!(
this._coreUserData && this._coreUserData.showAdvanced
);
})
);
}
@ -189,31 +85,60 @@ class HaPanelConfig extends HassRouterPage {
);
}
protected updatePageEl(el) {
const showAdvanced = !!(
this._coreUserData && this._coreUserData.showAdvanced
);
protected render() {
const dividerPos = this.route.path.indexOf("/", 1);
const curPage =
dividerPos === -1
? this.route.path.substr(1)
: this.route.path.substr(1, dividerPos - 1);
const isWide =
this.hass.dockedSidebar === "docked" ? this._wideSidebar : this._wide;
if ("setProperties" in el) {
// As long as we have Polymer panels
(el as PolymerElement).setProperties({
route: this.routeTail,
hass: this.hass,
showAdvanced,
isWide,
narrow: this.narrow,
cloudStatus: this._cloudStatus,
});
} else {
el.route = this.routeTail;
el.hass = this.hass;
el.showAdvanced = showAdvanced;
el.isWide = isWide;
el.narrow = this.narrow;
el.cloudStatus = this._cloudStatus;
}
return html`
${isWide
? html`
<div class="side-bar">
<div class="toolbar">Configuration</div>
<div class="navigation">
<ha-config-navigation
.hass=${this.hass}
.showAdvanced=${this._showAdvanced}
.curPage=${curPage}
.pages=${[
{ page: "cloud", info: this._cloudStatus },
{ page: "integrations", core: true },
{ page: "devices", core: true },
{ page: "automation" },
{ page: "script" },
{ page: "scene" },
{ page: "core", core: true },
{ page: "server_control", core: true },
{ page: "entities", core: true },
{ page: "areas", core: true },
{ page: "person" },
{ page: "users", core: true },
{ page: "zha" },
{ page: "zwave" },
{ page: "customize", core: true, advanced: true },
]}
></ha-config-navigation>
</div>
</div>
`
: ""}
<ha-config-router
.hass=${this.hass}
.route=${this.route}
.narrow=${this.narrow}
.isWide=${isWide}
.wide=${this._wide}
.wideSidebar=${this._wideSidebar}
.showAdvanced=${this._showAdvanced}
.cloudStatus=${this._cloudStatus}
class=${classMap({ "wide-config": isWide })}
></ha-config-router>
`;
}
private async _updateCloudStatus() {
@ -223,6 +148,54 @@ class HaPanelConfig extends HassRouterPage {
setTimeout(() => this._updateCloudStatus(), 5000);
}
}
static get styles(): CSSResult {
return css`
:host {
display: block;
height: 100%;
background-color: var(--primary-background-color);
}
a {
text-decoration: none;
color: var(--primary-text-color);
}
.side-bar {
border-right: 1px solid #e0e0e0;
background: white;
width: 320px;
float: left;
box-sizing: border-box;
position: fixed;
}
.toolbar {
display: flex;
align-items: center;
font-size: 20px;
height: 64px;
padding: 0 16px 0 16px;
pointer-events: none;
background-color: var(--primary-background-color);
font-weight: 400;
color: var(--primary-text-color);
border-bottom: 1px solid var(--divider-color);
}
.wide-config {
float: right;
width: calc(100% - 320px);
height: 100%;
}
.navigation {
height: calc(100vh - 64px);
overflow: auto;
}
`;
}
}
declare global {

View File

@ -49,6 +49,7 @@ import { showConfirmationDialog } from "../../../dialogs/confirmation/show-dialo
export class HaConfigManagerDashboard extends LitElement {
@property() public hass!: HomeAssistant;
@property() public showAdvanced!: boolean;
@property() public isWide!: boolean;
@property() private configEntries!: ConfigEntry[];
@ -72,7 +73,8 @@ export class HaConfigManagerDashboard extends LitElement {
protected render(): TemplateResult {
return html`
<hass-subpage
header=${this.hass.localize("ui.panel.config.integrations.caption")}
.showBackButton=${!this.isWide}
.header=${this.hass.localize("ui.panel.config.integrations.caption")}
>
<paper-menu-button
close-on-activate

View File

@ -39,6 +39,7 @@ declare global {
class HaConfigIntegrations extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() public isWide!: boolean;
@property() public showAdvanced!: boolean;
protected routerOptions: RouterOptions = {
@ -101,6 +102,7 @@ class HaConfigIntegrations extends HassRouterPage {
pageEl.entityRegistryEntries = this._entityRegistryEntries;
pageEl.configEntries = this._configEntries;
pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide;
pageEl.showAdvanced = this.showAdvanced;
if (this._currentPage === "dashboard") {

View File

@ -48,7 +48,10 @@ class HaConfigPerson extends LitElement {
}
const hass = this.hass;
return html`
<hass-subpage header=${hass.localize("ui.panel.config.person.caption")}>
<hass-subpage
.header=${hass.localize("ui.panel.config.person.caption")}
.showBackButton=${!this.isWide}
>
<ha-config-section .isWide=${this.isWide}>
<span slot="header"
>${hass.localize("ui.panel.config.person.caption")}</span

View File

@ -20,6 +20,7 @@ import { HassEntities } from "home-assistant-js-websocket";
class HaConfigScene extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() public isWide!: boolean;
@property() public showAdvanced!: boolean;
@property() public scenes: SceneEntity[] = [];
@ -52,6 +53,7 @@ class HaConfigScene extends HassRouterPage {
protected updatePageEl(pageEl, changedProps: PropertyValues) {
pageEl.hass = this.hass;
pageEl.narrow = this.narrow;
pageEl.isWide = this.isWide;
pageEl.showAdvanced = this.showAdvanced;
if (this.hass) {

View File

@ -30,14 +30,16 @@ import { forwardHaptic } from "../../../data/haptics";
class HaSceneDashboard extends LitElement {
@property() public hass!: HomeAssistant;
@property() public narrow!: boolean;
@property() public isWide!: boolean;
@property() public scenes!: SceneEntity[];
protected render(): TemplateResult | void {
return html`
<hass-subpage
.showBackButton=${!this.isWide}
.header=${this.hass.localize("ui.panel.config.scene.caption")}
>
<ha-config-section .isWide=${!this.narrow}>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.scene.picker.header")}
</div>

View File

@ -69,7 +69,7 @@ interface DeviceEntitiesLookup {
@customElement("ha-scene-editor")
export class HaSceneEditor extends SubscribeMixin(LitElement) {
@property() public hass!: HomeAssistant;
@property() public narrow?: boolean;
@property() public isWide?: boolean;
@property() public scene?: SceneEntity;
@property() public creatingNew?: boolean;
@property() public showAdvanced!: boolean;
@ -196,7 +196,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
rtl: computeRTL(this.hass),
})}"
>
<ha-config-section .isWide=${!this.narrow}>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.scene
? computeStateName(this.scene)
@ -222,7 +222,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
</ha-card>
</ha-config-section>
<ha-config-section .isWide=${!this.narrow}>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.devices.header"
@ -293,7 +293,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
${this.showAdvanced
? html`
<ha-config-section .isWide=${!this.narrow}>
<ha-config-section .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize(
"ui.panel.config.scene.editor.entities.header"
@ -371,7 +371,7 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) {
</div>
<ha-fab
slot="fab"
?is-wide="${!this.narrow}"
?is-wide="${this.isWide}"
?dirty="${this._dirty}"
icon="hass:content-save"
.title="${this.hass.localize("ui.panel.config.scene.editor.save")}"

View File

@ -35,6 +35,7 @@ class HaScriptPicker extends LitElement {
protected render(): TemplateResult | void {
return html`
<hass-subpage
.showBackButton=${!this.isWide}
.header=${this.hass.localize("ui.panel.config.script.caption")}
>
<ha-config-section .isWide=${this.isWide}>
@ -77,7 +78,7 @@ class HaScriptPicker extends LitElement {
)}"
@click=${this._runScript}
></paper-icon-button>
<paper-item-body>
<paper-item-body two-line>
<div>${computeStateName(script)}</div>
</paper-item-body>
<div class="actions">

View File

@ -35,6 +35,7 @@ class HaConfigServerControl extends LocalizeMixin(PolymerElement) {
<hass-subpage
header="[[localize('ui.panel.config.server_control.caption')]]"
showBackButton="[[!isWide]]"
>
<div class$="[[computeClasses(isWide)]]">
<ha-config-section-server-control

View File

@ -58,7 +58,10 @@ class HaUserPicker extends EventsMixin(
}
</style>
<hass-subpage header="[[localize('ui.panel.config.users.picker.title')]]">
<hass-subpage
header="[[localize('ui.panel.config.users.picker.title')]]"
showBackButton="[[!isWide]]"
>
<ha-card>
<template is="dom-repeat" items="[[users]]" as="user">
<a href="[[_computeUrl(user)]]">
@ -94,7 +97,7 @@ class HaUserPicker extends EventsMixin(
return {
hass: Object,
users: Array,
isWide: Boolean,
rtl: {
type: Boolean,
reflectToAttribute: true,

View File

@ -27,6 +27,7 @@ class HaConfigUsers extends NavigateMixin(PolymerElement) {
<ha-config-user-picker
hass="[[hass]]"
users="[[_users]]"
is-wide="[[isWide]]"
></ha-config-user-picker>
</template>
<template
@ -45,6 +46,7 @@ class HaConfigUsers extends NavigateMixin(PolymerElement) {
static get properties() {
return {
hass: Object,
isWide: Boolean,
route: {
type: Object,
observer: "_checkRoute",

View File

@ -103,7 +103,10 @@ class ZHAConfigDashboard extends LitElement {
protected render(): TemplateResult | void {
return html`
<hass-subpage .header=${this.hass.localize("ui.panel.config.zha.title")}>
<hass-subpage
.header=${this.hass.localize("ui.panel.config.zha.title")}
.showBackButton=${this.isWide}
>
<ha-config-section .narrow=${this.narrow} .isWide=${this.isWide}>
<div slot="header">
${this.hass.localize("ui.panel.config.zha.header")}

View File

@ -50,6 +50,7 @@ export class ZHADevicePage extends LitElement {
return html`
<hass-subpage
.header=${this.hass!.localize("ui.panel.config.zha.devices.header")}
.back=${!this.isWide}
>
<zha-node
.isWide="${this.isWide}"

View File

@ -76,10 +76,14 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
color: grey;
}
[hidden] {
ha-service-description[hidden] {
display: none;
}
ha-paper-icon-button-arrow-prev[hide] {
visibility: hidden;
}
.toggle-help-icon {
position: absolute;
top: -6px;
@ -91,6 +95,7 @@ class HaConfigZwave extends LocalizeMixin(EventsMixin(PolymerElement)) {
<app-header slot="header" fixed="">
<app-toolbar>
<ha-paper-icon-button-arrow-prev
hide$="[[isWide]]"
on-click="_backTapped"
></ha-paper-icon-button-arrow-prev>
<div main-title="">

View File

@ -673,7 +673,7 @@
"confirm_unsaved": "You have unsaved changes. Are you sure you want to leave?"
}
},
"area_registry": {
"areas": {
"caption": "Areas",
"description": "Overview of all areas in your home.",
"picker": {
@ -1253,7 +1253,7 @@
"battery": "Battery"
}
},
"entity_registry": {
"entities": {
"caption": "Entities",
"description": "Overview of all known entities.",
"picker": {