Clean up hassio tabs page (#3068)

* Clean up hassio tabs page

* Make load optional

* Fix bug
This commit is contained in:
Paulus Schoutsen 2019-04-07 11:58:51 -07:00 committed by GitHub
parent cda29fcd07
commit 70072786a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 211 additions and 147 deletions

View File

@ -16,6 +16,8 @@ import {
} from "../../src/data/hassio"; } from "../../src/data/hassio";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin"; import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
// Don't codesplit it, that way the dashboard always loads fast.
import "./hassio-pages-with-tabs";
@customElement("hassio-main") @customElement("hassio-main")
class HassioMain extends ProvideHassLitMixin(HassRouterPage) { class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
@ -25,10 +27,10 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
// Hass.io has a page with tabs, so we route all non-matching routes to it. // Hass.io has a page with tabs, so we route all non-matching routes to it.
defaultPage: "dashboard", defaultPage: "dashboard",
initialLoad: () => this._fetchData(), initialLoad: () => this._fetchData(),
showLoading: true,
routes: { routes: {
dashboard: { dashboard: {
tag: "hassio-pages-with-tabs", tag: "hassio-pages-with-tabs",
load: () => import("./hassio-pages-with-tabs"),
cache: true, cache: true,
}, },
snapshots: "dashboard", snapshots: "dashboard",
@ -82,6 +84,10 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
} }
protected updatePageEl(el) { protected updatePageEl(el) {
// the tabs page does its own routing so needs full route.
const route =
el.nodeName === "HASSIO-PAGES-WITH-TABS" ? this.route : this.routeTail;
if ("setProperties" in el) { if ("setProperties" in el) {
// As long as we have Polymer pages // As long as we have Polymer pages
(el as PolymerElement).setProperties({ (el as PolymerElement).setProperties({
@ -89,16 +95,14 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
supervisorInfo: this._supervisorInfo, supervisorInfo: this._supervisorInfo,
hostInfo: this._hostInfo, hostInfo: this._hostInfo,
hassInfo: this._hassInfo, hassInfo: this._hassInfo,
// @ts-ignore not fighting TS today route,
route: this.routeTail,
}); });
} else { } else {
el.hass = this.hass; el.hass = this.hass;
el.supervisorInfo = this._supervisorInfo; el.supervisorInfo = this._supervisorInfo;
el.hostInfo = this._hostInfo; el.hostInfo = this._hostInfo;
el.hassInfo = this._hassInfo; el.hassInfo = this._hassInfo;
// @ts-ignore not fighting TS today el.route = route;
el.route = this.routeTail;
} }
} }

View File

@ -1,129 +0,0 @@
import "@polymer/app-layout/app-header-layout/app-header-layout";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../src/components/ha-menu-button";
import "../../src/resources/ha-style";
import "./addon-store/hassio-addon-store";
import "./dashboard/hassio-dashboard";
import "./snapshots/hassio-snapshots";
import "./system/hassio-system";
import scrollToTarget from "../../src/common/dom/scroll-to-target";
import NavigateMixin from "../../src/mixins/navigate-mixin";
class HassioPagesWithTabs extends NavigateMixin(PolymerElement) {
static get template() {
return html`
<style include="iron-flex iron-positioning ha-style">
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
paper-tabs {
margin-left: 12px;
--paper-tabs-selection-bar-color: #fff;
text-transform: uppercase;
}
</style>
<app-header-layout id="layout" has-scrolling-region>
<app-header fixed slot="header">
<app-toolbar>
<ha-menu-button hassio></ha-menu-button>
<div main-title>Hass.io</div>
<template is="dom-if" if="[[showRefreshButton(page)]]">
<paper-icon-button
icon="hassio:refresh"
on-click="refreshClicked"
></paper-icon-button>
</template>
</app-toolbar>
<paper-tabs
scrollable=""
selected="[[page]]"
attr-for-selected="page-name"
on-iron-activate="handlePageSelected"
>
<paper-tab page-name="dashboard">Dashboard</paper-tab>
<paper-tab page-name="snapshots">Snapshots</paper-tab>
<paper-tab page-name="store">Add-on store</paper-tab>
<paper-tab page-name="system">System</paper-tab>
</paper-tabs>
</app-header>
<template is="dom-if" if='[[equals(page, "dashboard")]]'>
<hassio-dashboard
hass="[[hass]]"
supervisor-info="[[supervisorInfo]]"
hass-info="[[hassInfo]]"
></hassio-dashboard>
</template>
<template is="dom-if" if='[[equals(page, "snapshots")]]'>
<hassio-snapshots
hass="[[hass]]"
installed-addons="[[supervisorInfo.addons]]"
></hassio-snapshots>
</template>
<template is="dom-if" if='[[equals(page, "store")]]'>
<hassio-addon-store hass="[[hass]]"></hassio-addon-store>
</template>
<template is="dom-if" if='[[equals(page, "system")]]'>
<hassio-system
hass="[[hass]]"
supervisor-info="[[supervisorInfo]]"
host-info="[[hostInfo]]"
></hassio-system>
</template>
</app-header-layout>
`;
}
static get properties() {
return {
hass: Object,
page: {
type: String,
computed: "_computePage(route)",
},
route: Object,
supervisorInfo: Object,
hostInfo: Object,
hassInfo: Object,
};
}
handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute("page-name");
if (newPage !== this.page) {
this.navigate(`/hassio/${newPage}`);
}
scrollToTarget(this, this.$.layout.header.scrollTarget);
}
equals(a, b) {
return a === b;
}
showRefreshButton(page) {
return page === "store" || page === "snapshots";
}
refreshClicked() {
if (this.page === "snapshots") {
this.shadowRoot.querySelector("hassio-snapshots").refreshData();
} else {
this.shadowRoot.querySelector("hassio-addon-store").refreshData();
}
}
_computePage(route) {
return route.prefix.substr(route.prefix.indexOf("/", 1) + 1);
}
}
customElements.define("hassio-pages-with-tabs", HassioPagesWithTabs);

View File

@ -0,0 +1,126 @@
import {
LitElement,
TemplateResult,
html,
CSSResultArray,
css,
customElement,
property,
} from "lit-element";
import "@polymer/app-layout/app-header-layout/app-header-layout";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs";
import "../../src/components/ha-menu-button";
import "../../src/resources/ha-style";
import "./hassio-tabs-router";
import scrollToTarget from "../../src/common/dom/scroll-to-target";
import { haStyle } from "../../src/resources/styles";
import { HomeAssistant, Route } from "../../src/types";
import { navigate } from "../../src/common/navigate";
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
@customElement("hassio-pages-with-tabs")
class HassioPagesWithTabs extends LitElement {
@property() public hass!: HomeAssistant;
@property() public route!: Route;
@property() public supervisorInfo!: any;
@property() public hostInfo!: any;
@property() public hassInfo!: any;
protected render(): TemplateResult | void {
const page = this._page;
return html`
<app-header-layout has-scrolling-region>
<app-header fixed slot="header">
<app-toolbar>
<ha-menu-button hassio></ha-menu-button>
<div main-title>Hass.io</div>
${HAS_REFRESH_BUTTON.includes(page)
? html`
<paper-icon-button
icon="hassio:refresh"
@click=${this.refreshClicked}
></paper-icon-button>
`
: undefined}
</app-toolbar>
<paper-tabs
scrollable
attr-for-selected="page-name"
.selected=${page}
@iron-activate=${this.handlePageSelected}
>
<paper-tab page-name="dashboard">Dashboard</paper-tab>
<paper-tab page-name="snapshots">Snapshots</paper-tab>
<paper-tab page-name="store">Add-on store</paper-tab>
<paper-tab page-name="system">System</paper-tab>
</paper-tabs>
</app-header>
<hassio-tabs-router
.route=${this.route}
.hass=${this.hass}
.supervisorInfo=${this.supervisorInfo}
.hostInfo=${this.hostInfo}
.hassInfo=${this.hassInfo}
></hassio-tabs-router>
</app-header-layout>
`;
}
private handlePageSelected(ev) {
const newPage = ev.detail.item.getAttribute("page-name");
if (newPage !== this._page) {
navigate(this, `/hassio/${newPage}`);
}
scrollToTarget(
this,
// @ts-ignore
this.shadowRoot!.querySelector("app-header-layout").header.scrollTarget
);
}
private refreshClicked() {
if (this._page === "snapshots") {
// @ts-ignore
this.shadowRoot.querySelector("hassio-snapshots").refreshData();
} else {
// @ts-ignore
this.shadowRoot.querySelector("hassio-addon-store").refreshData();
}
}
private get _page() {
return this.route.path.substr(1);
}
static get styles(): CSSResultArray {
return [
haStyle,
css`
:host {
color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color);
}
paper-tabs {
margin-left: 12px;
--paper-tabs-selection-bar-color: #fff;
text-transform: uppercase;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"hassio-pages-with-tabs": HassioPagesWithTabs;
}
}

View File

@ -0,0 +1,60 @@
import {
HassRouterPage,
RouterOptions,
} from "../../src/layouts/hass-router-page";
import { customElement, property } from "lit-element";
import { PolymerElement } from "@polymer/polymer";
import { HomeAssistant } from "../../src/types";
// Don't codesplit it, that way the dashboard always loads fast.
import "./dashboard/hassio-dashboard";
@customElement("hassio-tabs-router")
class HassioTabsRouter extends HassRouterPage {
@property() public hass!: HomeAssistant;
@property() public supervisorInfo: any;
@property() public hostInfo: any;
@property() public hassInfo: any;
protected routerOptions: RouterOptions = {
routes: {
dashboard: {
tag: "hassio-dashboard",
},
snapshots: {
tag: "hassio-snapshots",
load: () => import("./snapshots/hassio-snapshots"),
},
store: {
tag: "hassio-addon-store",
load: () => import("./addon-store/hassio-addon-store"),
},
system: {
tag: "hassio-system",
load: () => import("./system/hassio-system"),
},
},
};
protected updatePageEl(el) {
if ("setProperties" in el) {
// As long as we have Polymer pages
(el as PolymerElement).setProperties({
hass: this.hass,
supervisorInfo: this.supervisorInfo,
hostInfo: this.hostInfo,
hassInfo: this.hassInfo,
});
} else {
el.hass = this.hass;
el.supervisorInfo = this.supervisorInfo;
el.hostInfo = this.hostInfo;
el.hassInfo = this.hassInfo;
}
}
}
declare global {
interface HTMLElementTagNameMap {
"hassio-tabs-router": HassioTabsRouter;
}
}

View File

@ -152,8 +152,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
type: Array, type: Array,
value: [], value: [],
}, },
supervisorInfo: Object,
installedAddons: { installedAddons: {
type: Array, type: Array,
computed: "_computeAddons(supervisorInfo)",
observer: "_installedAddonsChanged", observer: "_installedAddonsChanged",
}, },
addonList: Array, addonList: Array,
@ -305,6 +307,10 @@ class HassioSnapshots extends EventsMixin(PolymerElement) {
this._updateSnapshots(); this._updateSnapshots();
}); });
} }
_computeAddons(supervisorInfo) {
return supervisorInfo.addons;
}
} }
customElements.define("hassio-snapshots", HassioSnapshots); customElements.define("hassio-snapshots", HassioSnapshots);

View File

@ -19,7 +19,7 @@ export interface RouteOptions {
// HTML tag of the route page. // HTML tag of the route page.
tag: string; tag: string;
// Function to load the page. // Function to load the page.
load: () => Promise<unknown>; load?: () => Promise<unknown>;
cache?: boolean; cache?: boolean;
} }
@ -48,13 +48,6 @@ export class HassRouterPage extends UpdatingElement {
protected routerOptions!: RouterOptions; protected routerOptions!: RouterOptions;
/**
* Optional variable to define extra routes dynamically.
* It is preferred to use static routes.
*/
protected extraRoutes?: {
[route: string]: RouteOptions;
};
private _currentPage = ""; private _currentPage = "";
private _currentLoadProm?: Promise<void>; private _currentLoadProm?: Promise<void>;
private _cache = {}; private _cache = {};
@ -91,13 +84,15 @@ export class HassRouterPage extends UpdatingElement {
} }
const route = this.route; const route = this.route;
const defaultPage = routerOptions.defaultPage || ""; const defaultPage = routerOptions.defaultPage;
if (route && route.path === "") { if (route && route.path === "" && defaultPage !== undefined) {
navigate(this, `${route.prefix}/${defaultPage}`, true); navigate(this, `${route.prefix}/${defaultPage}`, true);
} }
let newPage = route ? extractPage(route.path, defaultPage) : "not_found"; let newPage = route
? extractPage(route.path, defaultPage || "")
: "not_found";
let routeOptions = routerOptions.routes[newPage]; let routeOptions = routerOptions.routes[newPage];
// Handle redirects // Handle redirects
@ -122,7 +117,9 @@ export class HassRouterPage extends UpdatingElement {
} }
this._currentPage = newPage; this._currentPage = newPage;
const loadProm = routeOptions.load(); const loadProm = routeOptions.load
? routeOptions.load()
: Promise.resolve();
// Check when loading the page source failed. // Check when loading the page source failed.
loadProm.catch(() => { loadProm.catch(() => {
@ -196,7 +193,7 @@ export class HassRouterPage extends UpdatingElement {
if (options.preloadAll) { if (options.preloadAll) {
Object.values(options.routes).forEach( Object.values(options.routes).forEach(
(route) => typeof route === "object" && route.load() (route) => typeof route === "object" && route.load && route.load()
); );
} }