diff --git a/gulp/tasks/gen-icons.js b/gulp/tasks/gen-icons.js
index b0afecb43a..c47b42f360 100644
--- a/gulp/tasks/gen-icons.js
+++ b/gulp/tasks/gen-icons.js
@@ -44,7 +44,7 @@ function transformXMLtoPolymer(name, xml) {
// Given an iconset name and icon names, generate a polymer iconset
function generateIconset(name, iconNames) {
- const iconDefs = iconNames
+ const iconDefs = Array.from(iconNames)
.map((name) => {
const iconDef = loadIcon(name);
if (!iconDef) {
@@ -95,12 +95,15 @@ function findIcons(path, iconsetName) {
}
mapFiles(path, ".js", processFile);
mapFiles(path, ".ts", processFile);
- return Array.from(icons);
+ return icons;
}
function genHassIcons() {
- const iconNames = findIcons("./src", "hass").concat(BUILT_IN_PANEL_ICONS);
- fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
+ const iconNames = findIcons("./src", "hass");
+ BUILT_IN_PANEL_ICONS.forEach((name) => iconNames.add(name));
+ if (!fs.existsSync(OUTPUT_DIR)) {
+ fs.mkdirSync(OUTPUT_DIR);
+ }
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
}
diff --git a/hassio/script/gen-icons.js b/hassio/script/gen-icons.js
index 0c952ad04d..61fc39e212 100755
--- a/hassio/script/gen-icons.js
+++ b/hassio/script/gen-icons.js
@@ -6,10 +6,13 @@ const {
genMDIIcons,
} = require("../../gulp/tasks/gen-icons.js");
-const MENU_BUTTON_ICON = "menu";
-
function genHassioIcons() {
- const iconNames = findIcons("./src", "hassio").concat(MENU_BUTTON_ICON);
+ const iconNames = findIcons("./src", "hassio");
+
+ for (const item of findIcons("../src", "hassio")) {
+ iconNames.add(item);
+ }
+
fs.writeFileSync("./hassio-icons.html", generateIconset("hassio", iconNames));
}
diff --git a/hassio/src/addon-store/hassio-addon-repository.js b/hassio/src/addon-store/hassio-addon-repository.js
deleted file mode 100644
index cc95f068bf..0000000000
--- a/hassio/src/addon-store/hassio-addon-repository.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import "@polymer/paper-card/paper-card";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../components/hassio-card-content";
-import "../resources/hassio-style";
-import NavigateMixin from "../../../src/mixins/navigate-mixin";
-
-class HassioAddonRepository extends NavigateMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- repo: Object,
- addons: Array,
- };
- }
-
- sortAddons(a, b) {
- return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
- }
-
- computeIcon(addon) {
- return addon.installed && addon.installed !== addon.version
- ? "hassio:arrow-up-bold-circle"
- : "hassio:puzzle";
- }
-
- computeIconTitle(addon) {
- if (addon.installed)
- return addon.installed !== addon.version
- ? "New version available"
- : "Add-on is installed";
- return addon.available
- ? "Add-on is not installed"
- : "Add-on is not available on your system";
- }
-
- computeIconClass(addon) {
- if (addon.installed)
- return addon.installed !== addon.version ? "update" : "installed";
- return !addon.available ? "not_available" : "";
- }
-
- computeClass(addon) {
- return !addon.available ? "not_available" : "";
- }
-
- addonTapped(ev) {
- this.navigate(`/hassio/addon/${ev.model.addon.slug}`);
- }
-}
-
-customElements.define("hassio-addon-repository", HassioAddonRepository);
diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts
new file mode 100644
index 0000000000..dd5a56ea46
--- /dev/null
+++ b/hassio/src/addon-store/hassio-addon-repository.ts
@@ -0,0 +1,112 @@
+import {
+ css,
+ TemplateResult,
+ html,
+ LitElement,
+ property,
+ CSSResultArray,
+} from "lit-element";
+import "@polymer/paper-card/paper-card";
+
+import "../components/hassio-card-content";
+import { hassioStyle } from "../resources/hassio-style";
+import { HomeAssistant } from "../../../src/types";
+import {
+ HassioAddonInfo,
+ HassioAddonRepository,
+} from "../../../src/data/hassio";
+import { navigate } from "../../../src/common/navigate";
+
+class HassioAddonRepositoryEl extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public repo!: HassioAddonRepository;
+ @property() public addons!: HassioAddonInfo[];
+
+ protected render(): TemplateResult | void {
+ const repo = this.repo;
+ return html`
+
+
+
+ ${this.addons
+ .sort((a, b) =>
+ a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
+ )
+ .map(
+ (addon) => html`
+
+
+
+
+
+ `
+ )}
+
+ `;
+ }
+
+ private computeIcon(addon) {
+ return addon.installed && addon.installed !== addon.version
+ ? "hassio:arrow-up-bold-circle"
+ : "hassio:puzzle";
+ }
+
+ private computeIconTitle(addon) {
+ if (addon.installed) {
+ return addon.installed !== addon.version
+ ? "New version available"
+ : "Add-on is installed";
+ }
+ return addon.available
+ ? "Add-on is not installed"
+ : "Add-on is not available on your system";
+ }
+
+ private computeIconClass(addon) {
+ if (addon.installed) {
+ return addon.installed !== addon.version ? "update" : "installed";
+ }
+ return !addon.available ? "not_available" : "";
+ }
+
+ private addonTapped(ev) {
+ navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}`);
+ }
+
+ static get styles(): CSSResultArray {
+ return [
+ hassioStyle,
+ css`
+ paper-card {
+ cursor: pointer;
+ }
+ .not_available {
+ opacity: 0.6;
+ }
+ a.repo {
+ color: var(--primary-text-color);
+ }
+ `,
+ ];
+ }
+}
+
+customElements.define("hassio-addon-repository", HassioAddonRepositoryEl);
diff --git a/hassio/src/addon-store/hassio-addon-store.js b/hassio/src/addon-store/hassio-addon-store.js
deleted file mode 100644
index 4e49bc6628..0000000000
--- a/hassio/src/addon-store/hassio-addon-store.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "./hassio-addon-repository";
-import "./hassio-repositories-editor";
-
-class HassioAddonStore extends PolymerElement {
- static get template() {
- return html`
-
-
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- addons: Array,
- repos: Array,
- };
- }
-
- ready() {
- super.ready();
- this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
- this.loadData();
- }
-
- apiCalled(ev) {
- if (ev.detail.success) {
- this.loadData();
- }
- }
-
- sortRepos(a, b) {
- if (a.slug === "local") {
- return -1;
- }
- if (b.slug === "local") {
- return 1;
- }
- if (a.slug === "core") {
- return -1;
- }
- if (b.slug === "core") {
- return 1;
- }
- return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
- }
-
- computeAddons(repo) {
- return this.addons.filter(function(addon) {
- return addon.repository === repo;
- });
- }
-
- loadData() {
- this.hass.callApi("get", "hassio/addons").then(
- (info) => {
- this.addons = info.data.addons;
- this.repos = info.data.repositories;
- },
- () => {
- this.addons = [];
- this.repos = [];
- }
- );
- }
-
- refreshData() {
- this.hass.callApi("post", "hassio/addons/reload").then(() => {
- this.loadData();
- });
- }
-}
-
-customElements.define("hassio-addon-store", HassioAddonStore);
diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts
new file mode 100644
index 0000000000..35440bb58e
--- /dev/null
+++ b/hassio/src/addon-store/hassio-addon-store.ts
@@ -0,0 +1,116 @@
+import "./hassio-addon-repository";
+import "./hassio-repositories-editor";
+import { TemplateResult, html } from "lit-html";
+import {
+ LitElement,
+ CSSResult,
+ css,
+ property,
+ PropertyValues,
+} from "lit-element";
+import { HomeAssistant } from "../../../src/types";
+import {
+ HassioAddonRepository,
+ HassioAddonInfo,
+ fetchHassioAddonsInfo,
+ reloadHassioAddons,
+} from "../../../src/data/hassio";
+import "../../../src/layouts/loading-screen";
+
+const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
+ if (a.slug === "local") {
+ return -1;
+ }
+ if (b.slug === "local") {
+ return 1;
+ }
+ if (a.slug === "core") {
+ return -1;
+ }
+ if (b.slug === "core") {
+ return 1;
+ }
+ return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1;
+};
+
+class HassioAddonStore extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() private _addons?: HassioAddonInfo[];
+ @property() private _repos?: HassioAddonRepository[];
+
+ public async refreshData() {
+ this._repos = undefined;
+ this._addons = undefined;
+ await reloadHassioAddons(this.hass);
+ await this._loadData();
+ }
+
+ protected render(): TemplateResult | void {
+ if (!this._addons || !this._repos) {
+ return html`
+
+ `;
+ }
+ const repos: TemplateResult[] = [];
+
+ for (const repo of this._repos) {
+ const addons = this._addons!.filter(
+ (addon) => addon.repository === repo.slug
+ );
+
+ if (addons.length === 0) {
+ continue;
+ }
+
+ repos.push(html`
+
+ `);
+ }
+
+ return html`
+
+
+ ${repos}
+ `;
+ }
+
+ protected firstUpdated(changedProps: PropertyValues) {
+ super.firstUpdated(changedProps);
+ this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
+ this._loadData();
+ }
+
+ private apiCalled(ev) {
+ if (ev.detail.success) {
+ this._loadData();
+ }
+ }
+
+ private async _loadData() {
+ try {
+ const addonsInfo = await fetchHassioAddonsInfo(this.hass);
+ this._repos = addonsInfo.repositories;
+ this._repos.sort(sortRepos);
+ this._addons = addonsInfo.addons;
+ } catch (err) {
+ alert("Failed to fetch add-on info");
+ }
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ hassio-addon-repository {
+ margin-top: 24px;
+ }
+ `;
+ }
+}
+
+customElements.define("hassio-addon-store", HassioAddonStore);
diff --git a/hassio/src/addon-store/hassio-repositories-editor.js b/hassio/src/addon-store/hassio-repositories-editor.js
deleted file mode 100644
index 93455375d8..0000000000
--- a/hassio/src/addon-store/hassio-repositories-editor.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import "@polymer/iron-icon/iron-icon";
-import "@polymer/paper-card/paper-card";
-import "@polymer/paper-input/paper-input";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../../../src/components/buttons/ha-call-api-button";
-import "../components/hassio-card-content";
-import "../resources/hassio-style";
-
-class HassioRepositoriesEditor extends PolymerElement {
- static get template() {
- return html`
-
-
-
- Repositories
-
- Configure which add-on repositories to fetch data from:
-
-
-
-
-
-
-
-
- Remove
-
-
-
-
-
-
- Add
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- repos: {
- type: Array,
- observer: "reposChanged",
- },
- repoList: Array,
- repoUrl: String,
- };
- }
-
- reposChanged(repos) {
- this.repoList = repos.filter(
- (repo) => repo.slug !== "core" && repo.slug !== "local"
- );
- this.repoUrl = "";
- }
-
- sortRepos(a, b) {
- return a.name < b.name ? -1 : 1;
- }
-
- computeRemoveRepoData(repoList, url) {
- const list = repoList
- .filter((repo) => repo.url !== url)
- .map((repo) => repo.source);
- return { addons_repositories: list };
- }
-
- computeAddRepoData(repoList, url) {
- const list = repoList ? repoList.map((repo) => repo.source) : [];
- list.push(url);
- return { addons_repositories: list };
- }
-}
-
-customElements.define("hassio-repositories-editor", HassioRepositoriesEditor);
diff --git a/hassio/src/addon-store/hassio-repositories-editor.ts b/hassio/src/addon-store/hassio-repositories-editor.ts
new file mode 100644
index 0000000000..f901ed5a35
--- /dev/null
+++ b/hassio/src/addon-store/hassio-repositories-editor.ts
@@ -0,0 +1,148 @@
+import {
+ LitElement,
+ html,
+ CSSResultArray,
+ css,
+ property,
+ TemplateResult,
+ customElement,
+ PropertyValues,
+} from "lit-element";
+import "@polymer/iron-icon/iron-icon";
+import "@polymer/paper-card/paper-card";
+import "@polymer/paper-input/paper-input";
+import memoizeOne from "memoize-one";
+
+import "../../../src/components/buttons/ha-call-api-button";
+import "../components/hassio-card-content";
+import { hassioStyle } from "../resources/hassio-style";
+import { HomeAssistant } from "../../../src/types";
+import { HassioAddonRepository } from "../../../src/data/hassio";
+import { PolymerChangedEvent } from "../../../src/polymer-types";
+import { repeat } from "lit-html/directives/repeat";
+
+@customElement("hassio-repositories-editor")
+class HassioRepositoriesEditor extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public repos!: HassioAddonRepository[];
+ @property() private _repoUrl = "";
+
+ private _sortedRepos = memoizeOne((repos: HassioAddonRepository[]) =>
+ repos
+ .filter((repo) => repo.slug !== "core" && repo.slug !== "local")
+ .sort((a, b) => (a.name < b.name ? -1 : 1))
+ );
+
+ protected render(): TemplateResult | void {
+ const repos = this._sortedRepos(this.repos);
+ return html`
+
+
+ Repositories
+
+ Configure which add-on repositories to fetch data from:
+
+
+ ${// Use repeat so that the fade-out from call-service-api-button
+ // stays with the correct repo after we add/delete one.
+ repeat(
+ repos,
+ (repo) => repo.slug,
+ (repo) => html`
+
+
+
+
+
+
+ Remove
+
+
+
+ `
+ )}
+
+
+
+
+
+ Add
+
+
+
+
+ `;
+ }
+
+ protected updated(changedProps: PropertyValues) {
+ super.updated(changedProps);
+
+ if (changedProps.has("repos")) {
+ this._repoUrl = "";
+ }
+ }
+
+ private _urlChanged(ev: PolymerChangedEvent) {
+ this._repoUrl = ev.detail.value;
+ }
+
+ private computeRemoveRepoData(repoList, url) {
+ const list = repoList
+ .filter((repo) => repo.url !== url)
+ .map((repo) => repo.source);
+ return { addons_repositories: list };
+ }
+
+ private computeAddRepoData(repoList, url) {
+ const list = repoList ? repoList.map((repo) => repo.source) : [];
+ list.push(url);
+ return { addons_repositories: list };
+ }
+
+ static get styles(): CSSResultArray {
+ return [
+ hassioStyle,
+ css`
+ .add {
+ padding: 12px 16px;
+ }
+ iron-icon {
+ color: var(--secondary-text-color);
+ margin-right: 16px;
+ display: inline-block;
+ }
+ paper-input {
+ width: calc(100% - 49px);
+ display: inline-block;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-repositories-editor": HassioRepositoriesEditor;
+ }
+}
diff --git a/hassio/src/addon-view/hassio-addon-info.js b/hassio/src/addon-view/hassio-addon-info.js
index 80db47a5ea..10d8de3ad5 100644
--- a/hassio/src/addon-view/hassio-addon-info.js
+++ b/hassio/src/addon-view/hassio-addon-info.js
@@ -168,12 +168,18 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
icon="hassio:arrow-up-bold-circle"
icon-class="update"
>
+
+ This update is no longer compatible with your system.
+
Update
+ Update
+
Changelog
diff --git a/hassio/src/addon-view/hassio-addon-view.js b/hassio/src/addon-view/hassio-addon-view.js
index ae4b1b6b29..cb72e1b011 100644
--- a/hassio/src/addon-view/hassio-addon-view.js
+++ b/hassio/src/addon-view/hassio-addon-view.js
@@ -5,7 +5,6 @@ import "@polymer/paper-icon-button/paper-icon-button";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
-import "../../../src/resources/ha-style";
import "./hassio-addon-audio";
import "./hassio-addon-config";
import "./hassio-addon-info";
@@ -15,7 +14,7 @@ import "./hassio-addon-network";
class HassioAddonView extends PolymerElement {
static get template() {
return html`
-
-
-
-
-
- Hass.io: add-on details
-
-
+
-
+
`;
}
@@ -141,10 +131,6 @@ class HassioAddonView extends PolymerElement {
);
}
- backTapped() {
- history.back();
- }
-
_computeSlug(route) {
return route.path.substr(1);
}
diff --git a/hassio/src/components/hassio-card-content.js b/hassio/src/components/hassio-card-content.js
deleted file mode 100644
index 16876bba68..0000000000
--- a/hassio/src/components/hassio-card-content.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import "@polymer/iron-icon/iron-icon";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../../../src/components/ha-relative-time";
-
-class HassioCardContent extends PolymerElement {
- static get template() {
- return html`
-
-
-
-
[[title]]
-
-
- [[description]]
-
-
- (Not available)
-
-
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- title: String,
- description: String,
- available: Boolean,
- datetime: String,
- icon: {
- type: String,
- value: "hass:help-circle",
- },
- iconTitle: String,
- iconClass: String,
- };
- }
-}
-customElements.define("hassio-card-content", HassioCardContent);
diff --git a/hassio/src/components/hassio-card-content.ts b/hassio/src/components/hassio-card-content.ts
new file mode 100644
index 0000000000..82d1f6ab6a
--- /dev/null
+++ b/hassio/src/components/hassio-card-content.ts
@@ -0,0 +1,97 @@
+import {
+ LitElement,
+ TemplateResult,
+ html,
+ CSSResult,
+ css,
+ property,
+ customElement,
+} from "lit-element";
+import "@polymer/iron-icon/iron-icon";
+
+import "../../../src/components/ha-relative-time";
+import { HomeAssistant } from "../../../src/types";
+
+@customElement("hassio-card-content")
+class HassioCardContent extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public title!: string;
+ @property() public description?: string;
+ @property() public available: boolean = true;
+ @property() public datetime?: string;
+ @property() public iconTitle?: string;
+ @property() public iconClass?: string;
+ @property() public icon = "hass:help-circle";
+
+ protected render(): TemplateResult | void {
+ return html`
+
+
+
${this.title}
+
+ ${this.description} ${this.available ? undefined : " (Not available"}
+ ${this.datetime
+ ? html`
+
+ `
+ : undefined}
+
+
+ `;
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ iron-icon {
+ margin-right: 16px;
+ margin-top: 16px;
+ float: left;
+ color: var(--secondary-text-color);
+ }
+ iron-icon.update {
+ color: var(--paper-orange-400);
+ }
+ iron-icon.running,
+ iron-icon.installed {
+ color: var(--paper-green-400);
+ }
+ iron-icon.hassupdate,
+ iron-icon.snapshot {
+ color: var(--paper-item-icon-color);
+ }
+ iron-icon.not_available {
+ color: var(--google-red-500);
+ }
+ .title {
+ color: var(--primary-text-color);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+ .addition {
+ color: var(--secondary-text-color);
+ overflow: hidden;
+ position: relative;
+ height: 2.4em;
+ line-height: 1.2em;
+ }
+ ha-relative-time {
+ display: block;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-card-content": HassioCardContent;
+ }
+}
diff --git a/hassio/src/dashboard/hassio-dashboard.js b/hassio/src/dashboard/hassio-dashboard.js
deleted file mode 100644
index 05a0671b17..0000000000
--- a/hassio/src/dashboard/hassio-dashboard.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "./hassio-addons";
-import "./hassio-hass-update";
-import EventsMixin from "../../../src/mixins/events-mixin";
-
-class HassioDashboard extends EventsMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- supervisorInfo: Object,
- hassInfo: Object,
- };
- }
-}
-
-customElements.define("hassio-dashboard", HassioDashboard);
diff --git a/hassio/src/dashboard/hassio-dashboard.ts b/hassio/src/dashboard/hassio-dashboard.ts
new file mode 100644
index 0000000000..aa312395b6
--- /dev/null
+++ b/hassio/src/dashboard/hassio-dashboard.ts
@@ -0,0 +1,52 @@
+import {
+ LitElement,
+ TemplateResult,
+ html,
+ CSSResult,
+ css,
+ property,
+ customElement,
+} from "lit-element";
+import "./hassio-addons";
+import "./hassio-hass-update";
+import { HomeAssistant } from "../../../src/types";
+import {
+ HassioSupervisorInfo,
+ HassioHomeAssistantInfo,
+} from "../../../src/data/hassio";
+
+@customElement("hassio-dashboard")
+class HassioDashboard extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public supervisorInfo!: HassioSupervisorInfo;
+ @property() public hassInfo!: HassioHomeAssistantInfo;
+
+ protected render(): TemplateResult | void {
+ return html`
+
+
+
+
+ `;
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ .content {
+ margin: 0 auto;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-dashboard": HassioDashboard;
+ }
+}
diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts
index 7fbf80a7fa..cc4123630c 100644
--- a/hassio/src/hassio-main.ts
+++ b/hassio/src/hassio-main.ts
@@ -14,6 +14,9 @@ import {
fetchHassioSupervisorInfo,
fetchHassioHostInfo,
fetchHassioHomeAssistantInfo,
+ HassioSupervisorInfo,
+ HassioHostInfo,
+ HassioHomeAssistantInfo,
} from "../../src/data/hassio";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
@@ -54,9 +57,9 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
},
};
- @property() private _supervisorInfo: any;
- @property() private _hostInfo: any;
- @property() private _hassInfo: any;
+ @property() private _supervisorInfo: HassioSupervisorInfo;
+ @property() private _hostInfo: HassioHostInfo;
+ @property() private _hassInfo: HassioHomeAssistantInfo;
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
diff --git a/hassio/src/hassio-pages-with-tabs.ts b/hassio/src/hassio-pages-with-tabs.ts
index 9e33d12c27..adb43d373f 100644
--- a/hassio/src/hassio-pages-with-tabs.ts
+++ b/hassio/src/hassio-pages-with-tabs.ts
@@ -23,6 +23,11 @@ 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";
+import {
+ HassioSupervisorInfo,
+ HassioHostInfo,
+ HassioHomeAssistantInfo,
+} from "../../src/data/hassio";
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
@@ -30,9 +35,9 @@ const HAS_REFRESH_BUTTON = ["store", "snapshots"];
class HassioPagesWithTabs extends LitElement {
@property() public hass!: HomeAssistant;
@property() public route!: Route;
- @property() public supervisorInfo!: any;
- @property() public hostInfo!: any;
- @property() public hassInfo!: any;
+ @property() public supervisorInfo!: HassioSupervisorInfo;
+ @property() public hostInfo!: HassioHostInfo;
+ @property() public hassInfo!: HassioHomeAssistantInfo;
protected render(): TemplateResult | void {
const page = this._page;
diff --git a/hassio/src/hassio-tabs-router.ts b/hassio/src/hassio-tabs-router.ts
index 11f8d12710..11726c8c36 100644
--- a/hassio/src/hassio-tabs-router.ts
+++ b/hassio/src/hassio-tabs-router.ts
@@ -7,13 +7,18 @@ 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";
+import {
+ HassioSupervisorInfo,
+ HassioHostInfo,
+ HassioHomeAssistantInfo,
+} from "../../src/data/hassio";
@customElement("hassio-tabs-router")
class HassioTabsRouter extends HassRouterPage {
@property() public hass!: HomeAssistant;
- @property() public supervisorInfo: any;
- @property() public hostInfo: any;
- @property() public hassInfo: any;
+ @property() public supervisorInfo: HassioSupervisorInfo;
+ @property() public hostInfo: HassioHostInfo;
+ @property() public hassInfo: HassioHomeAssistantInfo;
protected routerOptions: RouterOptions = {
routes: {
diff --git a/hassio/src/ingress-view/hassio-ingress-view.ts b/hassio/src/ingress-view/hassio-ingress-view.ts
index 303cfc4bbc..ff2b5f9221 100644
--- a/hassio/src/ingress-view/hassio-ingress-view.ts
+++ b/hassio/src/ingress-view/hassio-ingress-view.ts
@@ -11,7 +11,7 @@ import {
import { HomeAssistant, Route } from "../../../src/types";
import {
createHassioSession,
- HassioAddon,
+ HassioAddonDetails,
fetchHassioAddonInfo,
} from "../../../src/data/hassio";
import "../../../src/layouts/hass-loading-screen";
@@ -20,24 +20,27 @@ import "../../../src/layouts/hass-subpage";
@customElement("hassio-ingress-view")
class HassioIngressView extends LitElement {
@property() public hass!: HomeAssistant;
- @property() public route!: Route & { slug: string };
- @property() private _hasSession = false;
- @property() private _addon?: HassioAddon;
+ @property() public route!: Route;
+ @property() private _addon?: HassioAddonDetails;
protected render(): TemplateResult | void {
- if (!this._hasSession || !this._addon) {
+ if (!this._addon) {
return html`
`;
}
- return html`
-
-
-
-
-
-
+
+ const iframe = html`
+
`;
+
+ return location.search === "?kiosk"
+ ? iframe
+ : html`
+
+ ${iframe}
+
+ `;
}
protected updated(changedProps: PropertyValues) {
@@ -53,32 +56,30 @@ class HassioIngressView extends LitElement {
const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;
if (addon && addon !== oldAddon) {
- this._createSession();
- this._fetchAddonInfo(addon);
+ this._fetchData(addon);
}
}
- private async _fetchAddonInfo(addonSlug: string) {
+ private async _fetchData(addonSlug: string) {
try {
- const addon = await fetchHassioAddonInfo(this.hass, addonSlug);
- if (addon.ingress) {
- this._addon = addon;
- } else {
- alert("This add-on does not support ingress.");
- history.back();
+ const [addon] = await Promise.all([
+ fetchHassioAddonInfo(this.hass, addonSlug).catch(() => {
+ throw new Error("Failed to fetch add-on info");
+ }),
+ createHassioSession(this.hass).catch(() => {
+ throw new Error("Failed to create an ingress session");
+ }),
+ ]);
+
+ if (!addon.ingress) {
+ throw new Error("This add-on does not support ingress");
}
- } catch (err) {
- alert("Failed to fetch add-on info");
- history.back();
- }
- }
- private async _createSession() {
- try {
- await createHassioSession(this.hass);
- this._hasSession = true;
+ this._addon = addon;
} catch (err) {
- alert("Failed to generate a session");
+ // tslint:disable-next-line
+ console.error(err);
+ alert(err.message || "Unknown error starting ingress.");
history.back();
}
}
diff --git a/hassio/src/resources/hassio-style.js b/hassio/src/resources/hassio-style.js
index 1541329c45..6eb6c2340a 100644
--- a/hassio/src/resources/hassio-style.js
+++ b/hassio/src/resources/hassio-style.js
@@ -1,56 +1,64 @@
+import { css } from "lit-element";
+
const documentContainer = document.createElement("template");
documentContainer.setAttribute("style", "display: none;");
+export const hassioStyle = css`
+ .card-group {
+ margin-top: 24px;
+ }
+ .card-group .title {
+ color: var(--primary-text-color);
+ font-size: 2em;
+ padding-left: 8px;
+ margin-bottom: 8px;
+ }
+ .card-group .description {
+ font-size: 0.5em;
+ font-weight: 500;
+ margin-top: 4px;
+ }
+ .card-group paper-card {
+ --card-group-columns: 4;
+ width: calc(
+ (100% - 12px * var(--card-group-columns)) / var(--card-group-columns)
+ );
+ margin: 4px;
+ vertical-align: top;
+ }
+ @media screen and (max-width: 1200px) and (min-width: 901px) {
+ .card-group paper-card {
+ --card-group-columns: 3;
+ }
+ }
+ @media screen and (max-width: 900px) and (min-width: 601px) {
+ .card-group paper-card {
+ --card-group-columns: 2;
+ }
+ }
+ @media screen and (max-width: 600px) and (min-width: 0) {
+ .card-group paper-card {
+ width: 100%;
+ margin: 4px 0;
+ }
+ .content {
+ padding: 0;
+ }
+ }
+ ha-call-api-button {
+ font-weight: 500;
+ color: var(--primary-color);
+ }
+ .error {
+ color: var(--google-red-500);
+ margin-top: 16px;
+ }
+`;
+
documentContainer.innerHTML = `
`;
diff --git a/hassio/src/system/hassio-host-info.js b/hassio/src/system/hassio-host-info.js
index 929774165e..12ddb7b621 100644
--- a/hassio/src/system/hassio-host-info.js
+++ b/hassio/src/system/hassio-host-info.js
@@ -11,7 +11,7 @@ import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio
class HassioHostInfo extends EventsMixin(PolymerElement) {
static get template() {
return html`
-