mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 01:06:35 +00:00
Clean up even more (#3074)
This commit is contained in:
parent
8df9ac9dfa
commit
1c17210948
@ -44,7 +44,7 @@ function transformXMLtoPolymer(name, xml) {
|
|||||||
|
|
||||||
// Given an iconset name and icon names, generate a polymer iconset
|
// Given an iconset name and icon names, generate a polymer iconset
|
||||||
function generateIconset(name, iconNames) {
|
function generateIconset(name, iconNames) {
|
||||||
const iconDefs = iconNames
|
const iconDefs = Array.from(iconNames)
|
||||||
.map((name) => {
|
.map((name) => {
|
||||||
const iconDef = loadIcon(name);
|
const iconDef = loadIcon(name);
|
||||||
if (!iconDef) {
|
if (!iconDef) {
|
||||||
@ -95,12 +95,15 @@ function findIcons(path, iconsetName) {
|
|||||||
}
|
}
|
||||||
mapFiles(path, ".js", processFile);
|
mapFiles(path, ".js", processFile);
|
||||||
mapFiles(path, ".ts", processFile);
|
mapFiles(path, ".ts", processFile);
|
||||||
return Array.from(icons);
|
return icons;
|
||||||
}
|
}
|
||||||
|
|
||||||
function genHassIcons() {
|
function genHassIcons() {
|
||||||
const iconNames = findIcons("./src", "hass").concat(BUILT_IN_PANEL_ICONS);
|
const iconNames = findIcons("./src", "hass");
|
||||||
fs.existsSync(OUTPUT_DIR) || fs.mkdirSync(OUTPUT_DIR);
|
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));
|
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,13 @@ const {
|
|||||||
genMDIIcons,
|
genMDIIcons,
|
||||||
} = require("../../gulp/tasks/gen-icons.js");
|
} = require("../../gulp/tasks/gen-icons.js");
|
||||||
|
|
||||||
const MENU_BUTTON_ICON = "menu";
|
|
||||||
|
|
||||||
function genHassioIcons() {
|
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));
|
fs.writeFileSync("./hassio-icons.html", generateIconset("hassio", iconNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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`
|
|
||||||
<style include="iron-flex ha-style hassio-style">
|
|
||||||
paper-card {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.not_available {
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
a.repo {
|
|
||||||
display: block;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<template is="dom-if" if="[[addons.length]]">
|
|
||||||
<div class="card-group">
|
|
||||||
<div class="title">
|
|
||||||
[[repo.name]]
|
|
||||||
<div class="description">
|
|
||||||
Maintained by [[repo.maintainer]]
|
|
||||||
<a class="repo" href="[[repo.url]]" target="_blank"
|
|
||||||
>[[repo.url]]</a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[addons]]"
|
|
||||||
as="addon"
|
|
||||||
sort="sortAddons"
|
|
||||||
>
|
|
||||||
<paper-card class$="[[computeClass(addon)]]" on-click="addonTapped">
|
|
||||||
<div class="card-content">
|
|
||||||
<hassio-card-content
|
|
||||||
hass="[[hass]]"
|
|
||||||
title="[[addon.name]]"
|
|
||||||
description="[[addon.description]]"
|
|
||||||
available="[[addon.available]]"
|
|
||||||
icon="[[computeIcon(addon)]]"
|
|
||||||
icon-title="[[computeIconTitle(addon)]]"
|
|
||||||
icon-class="[[computeIconClass(addon)]]"
|
|
||||||
></hassio-card-content>
|
|
||||||
</div>
|
|
||||||
</paper-card>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
112
hassio/src/addon-store/hassio-addon-repository.ts
Normal file
112
hassio/src/addon-store/hassio-addon-repository.ts
Normal file
@ -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`
|
||||||
|
<div class="card-group">
|
||||||
|
<div class="title">
|
||||||
|
${repo.name}
|
||||||
|
<div class="description">
|
||||||
|
Maintained by ${repo.maintainer}<br />
|
||||||
|
<a class="repo" href=${repo.url} target="_blank">${repo.url}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${this.addons
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
(addon) => html`
|
||||||
|
<paper-card
|
||||||
|
.addon=${addon}
|
||||||
|
class=${addon.available ? "" : "not_available"}
|
||||||
|
@click=${this.addonTapped}
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
<hassio-card-content
|
||||||
|
.hass=${this.hass}
|
||||||
|
.title=${addon.name}
|
||||||
|
.description=${addon.description}
|
||||||
|
.available=${addon.available}
|
||||||
|
.icon=${this.computeIcon(addon)}
|
||||||
|
.iconTitle=${this.computeIconTitle(addon)}
|
||||||
|
.iconClass=${this.computeIconClass(addon)}
|
||||||
|
></hassio-card-content>
|
||||||
|
</div>
|
||||||
|
</paper-card>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
@ -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`
|
|
||||||
<style include="iron-flex ha-style">
|
|
||||||
hassio-addon-repository {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<hassio-repositories-editor
|
|
||||||
hass="[[hass]]"
|
|
||||||
repos="[[repos]]"
|
|
||||||
></hassio-repositories-editor>
|
|
||||||
|
|
||||||
<template is="dom-repeat" items="[[repos]]" as="repo" sort="sortRepos">
|
|
||||||
<hassio-addon-repository
|
|
||||||
hass="[[hass]]"
|
|
||||||
repo="[[repo]]"
|
|
||||||
addons="[[computeAddons(repo.slug)]]"
|
|
||||||
></hassio-addon-repository>
|
|
||||||
</template>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
116
hassio/src/addon-store/hassio-addon-store.ts
Normal file
116
hassio/src/addon-store/hassio-addon-store.ts
Normal file
@ -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`
|
||||||
|
<loading-screen></loading-screen>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
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`
|
||||||
|
<hassio-addon-repository
|
||||||
|
.hass=${this.hass}
|
||||||
|
.repo=${repo}
|
||||||
|
.addons=${addons}
|
||||||
|
></hassio-addon-repository>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<hassio-repositories-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.repos=${this._repos}
|
||||||
|
></hassio-repositories-editor>
|
||||||
|
|
||||||
|
${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);
|
@ -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`
|
|
||||||
<style include="ha-style hassio-style">
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="card-group">
|
|
||||||
<div class="title">
|
|
||||||
Repositories
|
|
||||||
<div class="description">
|
|
||||||
Configure which add-on repositories to fetch data from:
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<template
|
|
||||||
id="list"
|
|
||||||
is="dom-repeat"
|
|
||||||
items="[[repoList]]"
|
|
||||||
as="repo"
|
|
||||||
sort="sortRepos"
|
|
||||||
>
|
|
||||||
<paper-card>
|
|
||||||
<div class="card-content">
|
|
||||||
<hassio-card-content
|
|
||||||
hass="[[hass]]"
|
|
||||||
title="[[repo.name]]"
|
|
||||||
description="[[repo.url]]"
|
|
||||||
icon="hassio:github-circle"
|
|
||||||
></hassio-card-content>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<ha-call-api-button
|
|
||||||
hass="[[hass]]"
|
|
||||||
path="hassio/supervisor/options"
|
|
||||||
data="[[computeRemoveRepoData(repoList, repo.url)]]"
|
|
||||||
class="warning"
|
|
||||||
>Remove</ha-call-api-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</paper-card>
|
|
||||||
</template>
|
|
||||||
<paper-card>
|
|
||||||
<div class="card-content add">
|
|
||||||
<iron-icon icon="hassio:github-circle"></iron-icon>
|
|
||||||
<paper-input
|
|
||||||
label="Add new repository by URL"
|
|
||||||
value="{{repoUrl}}"
|
|
||||||
></paper-input>
|
|
||||||
</div>
|
|
||||||
<div class="card-actions">
|
|
||||||
<ha-call-api-button
|
|
||||||
hass="[[hass]]"
|
|
||||||
path="hassio/supervisor/options"
|
|
||||||
data="[[computeAddRepoData(repoList, repoUrl)]]"
|
|
||||||
>Add</ha-call-api-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</paper-card>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
148
hassio/src/addon-store/hassio-repositories-editor.ts
Normal file
148
hassio/src/addon-store/hassio-repositories-editor.ts
Normal file
@ -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`
|
||||||
|
<div class="card-group">
|
||||||
|
<div class="title">
|
||||||
|
Repositories
|
||||||
|
<div class="description">
|
||||||
|
Configure which add-on repositories to fetch data from:
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
${// 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`
|
||||||
|
<paper-card>
|
||||||
|
<div class="card-content">
|
||||||
|
<hassio-card-content
|
||||||
|
.hass=${this.hass}
|
||||||
|
.title=${repo.name}
|
||||||
|
.description=${repo.url}
|
||||||
|
icon="hassio:github-circle"
|
||||||
|
></hassio-card-content>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<ha-call-api-button
|
||||||
|
path="hassio/supervisor/options"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${this.computeRemoveRepoData(repos, repo.url)}
|
||||||
|
class="warning"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</ha-call-api-button>
|
||||||
|
</div>
|
||||||
|
</paper-card>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
|
||||||
|
<paper-card>
|
||||||
|
<div class="card-content add">
|
||||||
|
<iron-icon icon="hassio:github-circle"></iron-icon>
|
||||||
|
<paper-input
|
||||||
|
label="Add new repository by URL"
|
||||||
|
.value=${this._repoUrl}
|
||||||
|
@value-changed=${this._urlChanged}
|
||||||
|
></paper-input>
|
||||||
|
</div>
|
||||||
|
<div class="card-actions">
|
||||||
|
<ha-call-api-button
|
||||||
|
path="hassio/supervisor/options"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${this.computeAddRepoData(repos, this._repoUrl)}
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</ha-call-api-button>
|
||||||
|
</div>
|
||||||
|
</paper-card>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
|
||||||
|
if (changedProps.has("repos")) {
|
||||||
|
this._repoUrl = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _urlChanged(ev: PolymerChangedEvent<string>) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -168,12 +168,18 @@ class HassioAddonInfo extends EventsMixin(PolymerElement) {
|
|||||||
icon="hassio:arrow-up-bold-circle"
|
icon="hassio:arrow-up-bold-circle"
|
||||||
icon-class="update"
|
icon-class="update"
|
||||||
></hassio-card-content>
|
></hassio-card-content>
|
||||||
|
<template is="dom-if" if="[[!addon.available]]">
|
||||||
|
<p>This update is no longer compatible with your system.</p>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
<ha-call-api-button
|
<ha-call-api-button
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
path="hassio/addons/[[addonSlug]]/update"
|
path="hassio/addons/[[addonSlug]]/update"
|
||||||
>Update</ha-call-api-button
|
disabled="[[!addon.available]]"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</ha-call-api-button
|
||||||
>
|
>
|
||||||
<template is="dom-if" if="[[addon.changelog]]">
|
<template is="dom-if" if="[[addon.changelog]]">
|
||||||
<mwc-button on-click="openChangelog">Changelog</mwc-button>
|
<mwc-button on-click="openChangelog">Changelog</mwc-button>
|
||||||
|
@ -5,7 +5,6 @@ import "@polymer/paper-icon-button/paper-icon-button";
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import "../../../src/resources/ha-style";
|
|
||||||
import "./hassio-addon-audio";
|
import "./hassio-addon-audio";
|
||||||
import "./hassio-addon-config";
|
import "./hassio-addon-config";
|
||||||
import "./hassio-addon-info";
|
import "./hassio-addon-info";
|
||||||
@ -15,7 +14,7 @@ import "./hassio-addon-network";
|
|||||||
class HassioAddonView extends PolymerElement {
|
class HassioAddonView extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="iron-flex ha-style">
|
<style>
|
||||||
:host {
|
:host {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
--paper-card-header-color: var(--primary-text-color);
|
--paper-card-header-color: var(--primary-text-color);
|
||||||
@ -48,16 +47,7 @@ class HassioAddonView extends PolymerElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<app-header-layout has-scrolling-region="">
|
<hass-subpage header="Hass.io: add-on details" hassio>
|
||||||
<app-header fixed="" slot="header">
|
|
||||||
<app-toolbar>
|
|
||||||
<paper-icon-button
|
|
||||||
icon="hassio:arrow-left"
|
|
||||||
on-click="backTapped"
|
|
||||||
></paper-icon-button>
|
|
||||||
<div main-title="">Hass.io: add-on details</div>
|
|
||||||
</app-toolbar>
|
|
||||||
</app-header>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<hassio-addon-info
|
<hassio-addon-info
|
||||||
hass="[[hass]]"
|
hass="[[hass]]"
|
||||||
@ -93,7 +83,7 @@ class HassioAddonView extends PolymerElement {
|
|||||||
></hassio-addon-logs>
|
></hassio-addon-logs>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</app-header-layout>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,10 +131,6 @@ class HassioAddonView extends PolymerElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
backTapped() {
|
|
||||||
history.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeSlug(route) {
|
_computeSlug(route) {
|
||||||
return route.path.substr(1);
|
return route.path.substr(1);
|
||||||
}
|
}
|
||||||
|
@ -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`
|
|
||||||
<style>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<iron-icon
|
|
||||||
icon="[[icon]]"
|
|
||||||
class\$="[[iconClass]]"
|
|
||||||
title="[[iconTitle]]"
|
|
||||||
></iron-icon>
|
|
||||||
<div>
|
|
||||||
<div class="title">[[title]]</div>
|
|
||||||
<div class="addition">
|
|
||||||
<template is="dom-if" if="[[description]]">
|
|
||||||
[[description]]
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if="[[!available]]">
|
|
||||||
(Not available)
|
|
||||||
</template>
|
|
||||||
<template is="dom-if" if="[[datetime]]">
|
|
||||||
<ha-relative-time
|
|
||||||
hass="[[hass]]"
|
|
||||||
class="addition"
|
|
||||||
datetime="[[datetime]]"
|
|
||||||
></ha-relative-time>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
97
hassio/src/components/hassio-card-content.ts
Normal file
97
hassio/src/components/hassio-card-content.ts
Normal file
@ -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`
|
||||||
|
<iron-icon
|
||||||
|
class=${this.iconClass}
|
||||||
|
.icon=${this.icon}
|
||||||
|
.title=${this.iconTitle}
|
||||||
|
></iron-icon>
|
||||||
|
<div>
|
||||||
|
<div class="title">${this.title}</div>
|
||||||
|
<div class="addition">
|
||||||
|
${this.description} ${this.available ? undefined : " (Not available"}
|
||||||
|
${this.datetime
|
||||||
|
? html`
|
||||||
|
<ha-relative-time
|
||||||
|
.hass=${this.hass}
|
||||||
|
class="addition"
|
||||||
|
.datetime=${this.datetime}
|
||||||
|
></ha-relative-time>
|
||||||
|
`
|
||||||
|
: undefined}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -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`
|
|
||||||
<style include="iron-flex ha-style">
|
|
||||||
.content {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="content">
|
|
||||||
<hassio-hass-update
|
|
||||||
hass="[[hass]]"
|
|
||||||
hass-info="[[hassInfo]]"
|
|
||||||
></hassio-hass-update>
|
|
||||||
<hassio-addons
|
|
||||||
hass="[[hass]]"
|
|
||||||
addons="[[supervisorInfo.addons]]"
|
|
||||||
></hassio-addons>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: Object,
|
|
||||||
supervisorInfo: Object,
|
|
||||||
hassInfo: Object,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("hassio-dashboard", HassioDashboard);
|
|
52
hassio/src/dashboard/hassio-dashboard.ts
Normal file
52
hassio/src/dashboard/hassio-dashboard.ts
Normal file
@ -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`
|
||||||
|
<div class="content">
|
||||||
|
<hassio-hass-update
|
||||||
|
.hass=${this.hass}
|
||||||
|
.hassInfo=${this.hassInfo}
|
||||||
|
></hassio-hass-update>
|
||||||
|
<hassio-addons
|
||||||
|
.hass=${this.hass}
|
||||||
|
.addons=${this.supervisorInfo.addons}
|
||||||
|
></hassio-addons>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
.content {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hassio-dashboard": HassioDashboard;
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,9 @@ import {
|
|||||||
fetchHassioSupervisorInfo,
|
fetchHassioSupervisorInfo,
|
||||||
fetchHassioHostInfo,
|
fetchHassioHostInfo,
|
||||||
fetchHassioHomeAssistantInfo,
|
fetchHassioHomeAssistantInfo,
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
HassioHostInfo,
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
} 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";
|
||||||
@ -54,9 +57,9 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@property() private _supervisorInfo: any;
|
@property() private _supervisorInfo: HassioSupervisorInfo;
|
||||||
@property() private _hostInfo: any;
|
@property() private _hostInfo: HassioHostInfo;
|
||||||
@property() private _hassInfo: any;
|
@property() private _hassInfo: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
|
@ -23,6 +23,11 @@ import scrollToTarget from "../../src/common/dom/scroll-to-target";
|
|||||||
import { haStyle } from "../../src/resources/styles";
|
import { haStyle } from "../../src/resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../src/types";
|
import { HomeAssistant, Route } from "../../src/types";
|
||||||
import { navigate } from "../../src/common/navigate";
|
import { navigate } from "../../src/common/navigate";
|
||||||
|
import {
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
HassioHostInfo,
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
} from "../../src/data/hassio";
|
||||||
|
|
||||||
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
|
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
|
||||||
|
|
||||||
@ -30,9 +35,9 @@ const HAS_REFRESH_BUTTON = ["store", "snapshots"];
|
|||||||
class HassioPagesWithTabs extends LitElement {
|
class HassioPagesWithTabs extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() public route!: Route;
|
@property() public route!: Route;
|
||||||
@property() public supervisorInfo!: any;
|
@property() public supervisorInfo!: HassioSupervisorInfo;
|
||||||
@property() public hostInfo!: any;
|
@property() public hostInfo!: HassioHostInfo;
|
||||||
@property() public hassInfo!: any;
|
@property() public hassInfo!: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
const page = this._page;
|
const page = this._page;
|
||||||
|
@ -7,13 +7,18 @@ import { PolymerElement } from "@polymer/polymer";
|
|||||||
import { HomeAssistant } from "../../src/types";
|
import { HomeAssistant } from "../../src/types";
|
||||||
// Don't codesplit it, that way the dashboard always loads fast.
|
// Don't codesplit it, that way the dashboard always loads fast.
|
||||||
import "./dashboard/hassio-dashboard";
|
import "./dashboard/hassio-dashboard";
|
||||||
|
import {
|
||||||
|
HassioSupervisorInfo,
|
||||||
|
HassioHostInfo,
|
||||||
|
HassioHomeAssistantInfo,
|
||||||
|
} from "../../src/data/hassio";
|
||||||
|
|
||||||
@customElement("hassio-tabs-router")
|
@customElement("hassio-tabs-router")
|
||||||
class HassioTabsRouter extends HassRouterPage {
|
class HassioTabsRouter extends HassRouterPage {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() public supervisorInfo: any;
|
@property() public supervisorInfo: HassioSupervisorInfo;
|
||||||
@property() public hostInfo: any;
|
@property() public hostInfo: HassioHostInfo;
|
||||||
@property() public hassInfo: any;
|
@property() public hassInfo: HassioHomeAssistantInfo;
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
routes: {
|
routes: {
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
import { HomeAssistant, Route } from "../../../src/types";
|
import { HomeAssistant, Route } from "../../../src/types";
|
||||||
import {
|
import {
|
||||||
createHassioSession,
|
createHassioSession,
|
||||||
HassioAddon,
|
HassioAddonDetails,
|
||||||
fetchHassioAddonInfo,
|
fetchHassioAddonInfo,
|
||||||
} from "../../../src/data/hassio";
|
} from "../../../src/data/hassio";
|
||||||
import "../../../src/layouts/hass-loading-screen";
|
import "../../../src/layouts/hass-loading-screen";
|
||||||
@ -20,22 +20,25 @@ import "../../../src/layouts/hass-subpage";
|
|||||||
@customElement("hassio-ingress-view")
|
@customElement("hassio-ingress-view")
|
||||||
class HassioIngressView extends LitElement {
|
class HassioIngressView extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
@property() public route!: Route & { slug: string };
|
@property() public route!: Route;
|
||||||
@property() private _hasSession = false;
|
@property() private _addon?: HassioAddonDetails;
|
||||||
@property() private _addon?: HassioAddon;
|
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
if (!this._hasSession || !this._addon) {
|
if (!this._addon) {
|
||||||
return html`
|
return html`
|
||||||
<hass-loading-screen rootnav></hass-loading-screen>
|
<hass-loading-screen rootnav></hass-loading-screen>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
|
||||||
<hass-subpage .header=${this._addon.name} hassio root>
|
const iframe = html`
|
||||||
<a .href=${this._addon.ingress_url} slot="toolbar-icon" target="_blank">
|
|
||||||
<paper-icon-button icon="hassio:open-in-new"></paper-icon-button>
|
|
||||||
</a>
|
|
||||||
<iframe src=${this._addon.ingress_url}></iframe>
|
<iframe src=${this._addon.ingress_url}></iframe>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return location.search === "?kiosk"
|
||||||
|
? iframe
|
||||||
|
: html`
|
||||||
|
<hass-subpage .header=${this._addon.name} hassio root>
|
||||||
|
${iframe}
|
||||||
</hass-subpage>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -53,32 +56,30 @@ class HassioIngressView extends LitElement {
|
|||||||
const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;
|
const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;
|
||||||
|
|
||||||
if (addon && addon !== oldAddon) {
|
if (addon && addon !== oldAddon) {
|
||||||
this._createSession();
|
this._fetchData(addon);
|
||||||
this._fetchAddonInfo(addon);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _fetchAddonInfo(addonSlug: string) {
|
private async _fetchData(addonSlug: string) {
|
||||||
try {
|
try {
|
||||||
const addon = await fetchHassioAddonInfo(this.hass, addonSlug);
|
const [addon] = await Promise.all([
|
||||||
if (addon.ingress) {
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
this._addon = addon;
|
this._addon = addon;
|
||||||
} else {
|
|
||||||
alert("This add-on does not support ingress.");
|
|
||||||
history.back();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert("Failed to fetch add-on info");
|
// tslint:disable-next-line
|
||||||
history.back();
|
console.error(err);
|
||||||
}
|
alert(err.message || "Unknown error starting ingress.");
|
||||||
}
|
|
||||||
|
|
||||||
private async _createSession() {
|
|
||||||
try {
|
|
||||||
await createHassioSession(this.hass);
|
|
||||||
this._hasSession = true;
|
|
||||||
} catch (err) {
|
|
||||||
alert("Failed to generate a session");
|
|
||||||
history.back();
|
history.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
|
import { css } from "lit-element";
|
||||||
|
|
||||||
const documentContainer = document.createElement("template");
|
const documentContainer = document.createElement("template");
|
||||||
documentContainer.setAttribute("style", "display: none;");
|
documentContainer.setAttribute("style", "display: none;");
|
||||||
|
|
||||||
documentContainer.innerHTML = `<dom-module id="hassio-style">
|
export const hassioStyle = css`
|
||||||
<template>
|
|
||||||
<style>
|
|
||||||
.card-group {
|
.card-group {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
}
|
}
|
||||||
@ -20,7 +20,9 @@ documentContainer.innerHTML = `<dom-module id="hassio-style">
|
|||||||
}
|
}
|
||||||
.card-group paper-card {
|
.card-group paper-card {
|
||||||
--card-group-columns: 4;
|
--card-group-columns: 4;
|
||||||
width: calc((100% - 12px * var(--card-group-columns)) / var(--card-group-columns));
|
width: calc(
|
||||||
|
(100% - 12px * var(--card-group-columns)) / var(--card-group-columns)
|
||||||
|
);
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
@ -51,6 +53,12 @@ documentContainer.innerHTML = `<dom-module id="hassio-style">
|
|||||||
color: var(--google-red-500);
|
color: var(--google-red-500);
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
documentContainer.innerHTML = `<dom-module id="hassio-style">
|
||||||
|
<template>
|
||||||
|
<style>
|
||||||
|
${hassioStyle.toString()}
|
||||||
</style>
|
</style>
|
||||||
</template>
|
</template>
|
||||||
</dom-module>`;
|
</dom-module>`;
|
||||||
|
@ -11,7 +11,7 @@ import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio
|
|||||||
class HassioHostInfo extends EventsMixin(PolymerElement) {
|
class HassioHostInfo extends EventsMixin(PolymerElement) {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="iron-flex ha-style">
|
<style>
|
||||||
paper-card {
|
paper-card {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
@ -9,7 +9,7 @@ import EventsMixin from "../../../src/mixins/events-mixin";
|
|||||||
class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="iron-flex ha-style">
|
<style>
|
||||||
paper-card {
|
paper-card {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ import "./hassio-supervisor-log";
|
|||||||
class HassioSystem extends PolymerElement {
|
class HassioSystem extends PolymerElement {
|
||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="iron-flex ha-style">
|
<style>
|
||||||
.content {
|
.content {
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
|
@ -9,7 +9,22 @@ interface CreateSessionResponse {
|
|||||||
session: string;
|
session: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HassioAddon {
|
export interface HassioAddonInfo {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
description: string;
|
||||||
|
repository: "core" | "local" | string;
|
||||||
|
version: string;
|
||||||
|
installed: string | undefined;
|
||||||
|
detached: boolean;
|
||||||
|
available: boolean;
|
||||||
|
build: boolean;
|
||||||
|
url: string | null;
|
||||||
|
icon: boolean;
|
||||||
|
logo: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HassioAddonDetails {
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
description: string;
|
description: string;
|
||||||
@ -64,6 +79,29 @@ export interface HassioAddon {
|
|||||||
ingress_url: null | string;
|
ingress_url: null | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface HassioAddonRepository {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
source: string;
|
||||||
|
url: string;
|
||||||
|
maintainer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HassioAddonsInfo {
|
||||||
|
addons: HassioAddonInfo[];
|
||||||
|
repositories: HassioAddonRepository[];
|
||||||
|
}
|
||||||
|
export interface HassioHassOSInfo {
|
||||||
|
version: string;
|
||||||
|
version_cli: string;
|
||||||
|
version_latest: string;
|
||||||
|
version_cli_latest: string;
|
||||||
|
board: "ova" | "rpi";
|
||||||
|
}
|
||||||
|
export type HassioHomeAssistantInfo = any;
|
||||||
|
export type HassioSupervisorInfo = any;
|
||||||
|
export type HassioHostInfo = any;
|
||||||
|
|
||||||
const hassioApiResultExtractor = <T>(response: HassioResponse<T>) =>
|
const hassioApiResultExtractor = <T>(response: HassioResponse<T>) =>
|
||||||
response.data;
|
response.data;
|
||||||
|
|
||||||
@ -77,22 +115,41 @@ export const createHassioSession = async (hass: HomeAssistant) => {
|
|||||||
};path=/api/hassio_ingress/`;
|
};path=/api/hassio_ingress/`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reloadHassioAddons = (hass: HomeAssistant) =>
|
||||||
|
hass
|
||||||
|
.callApi<HassioResponse<unknown>>("POST", `hassio/addons/reload`)
|
||||||
|
.then(hassioApiResultExtractor);
|
||||||
|
|
||||||
|
export const fetchHassioAddonsInfo = (hass: HomeAssistant) =>
|
||||||
|
hass
|
||||||
|
.callApi<HassioResponse<HassioAddonsInfo>>("GET", `hassio/addons`)
|
||||||
|
.then(hassioApiResultExtractor);
|
||||||
|
|
||||||
export const fetchHassioAddonInfo = (hass: HomeAssistant, addon: string) =>
|
export const fetchHassioAddonInfo = (hass: HomeAssistant, addon: string) =>
|
||||||
hass
|
hass
|
||||||
.callApi<HassioResponse<HassioAddon>>("GET", `hassio/addons/${addon}/info`)
|
.callApi<HassioResponse<HassioAddonDetails>>(
|
||||||
|
"GET",
|
||||||
|
`hassio/addons/${addon}/info`
|
||||||
|
)
|
||||||
.then(hassioApiResultExtractor);
|
.then(hassioApiResultExtractor);
|
||||||
|
|
||||||
export const fetchHassioSupervisorInfo = (hass: HomeAssistant) =>
|
export const fetchHassioSupervisorInfo = (hass: HomeAssistant) =>
|
||||||
hass
|
hass
|
||||||
.callApi<HassioResponse<any>>("GET", "hassio/supervisor/info")
|
.callApi<HassioResponse<HassioSupervisorInfo>>(
|
||||||
|
"GET",
|
||||||
|
"hassio/supervisor/info"
|
||||||
|
)
|
||||||
.then(hassioApiResultExtractor);
|
.then(hassioApiResultExtractor);
|
||||||
|
|
||||||
export const fetchHassioHostInfo = (hass: HomeAssistant) =>
|
export const fetchHassioHostInfo = (hass: HomeAssistant) =>
|
||||||
hass
|
hass
|
||||||
.callApi<HassioResponse<any>>("GET", "hassio/host/info")
|
.callApi<HassioResponse<HassioHostInfo>>("GET", "hassio/host/info")
|
||||||
.then(hassioApiResultExtractor);
|
.then(hassioApiResultExtractor);
|
||||||
|
|
||||||
export const fetchHassioHomeAssistantInfo = (hass: HomeAssistant) =>
|
export const fetchHassioHomeAssistantInfo = (hass: HomeAssistant) =>
|
||||||
hass
|
hass
|
||||||
.callApi<HassioResponse<any>>("GET", "hassio/homeassistant/info")
|
.callApi<HassioResponse<HassioHomeAssistantInfo>>(
|
||||||
|
"GET",
|
||||||
|
"hassio/homeassistant/info"
|
||||||
|
)
|
||||||
.then(hassioApiResultExtractor);
|
.then(hassioApiResultExtractor);
|
||||||
|
@ -122,7 +122,10 @@ export class HassRouterPage extends UpdatingElement {
|
|||||||
: Promise.resolve();
|
: Promise.resolve();
|
||||||
|
|
||||||
// Check when loading the page source failed.
|
// Check when loading the page source failed.
|
||||||
loadProm.catch(() => {
|
loadProm.catch((err) => {
|
||||||
|
// tslint:disable-next-line
|
||||||
|
console.error("Error loading page", newPage, err);
|
||||||
|
|
||||||
// Verify that we're still trying to show the same page.
|
// Verify that we're still trying to show the same page.
|
||||||
if (this._currentPage !== newPage) {
|
if (this._currentPage !== newPage) {
|
||||||
return;
|
return;
|
||||||
|
35
src/layouts/loading-screen.ts
Normal file
35
src/layouts/loading-screen.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import "@polymer/paper-spinner/paper-spinner-lite";
|
||||||
|
import {
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
customElement,
|
||||||
|
CSSResult,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
@customElement("loading-screen")
|
||||||
|
class LoadingScreen extends LitElement {
|
||||||
|
protected render(): TemplateResult | void {
|
||||||
|
return html`
|
||||||
|
<paper-spinner-lite active></paper-spinner-lite>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"loading-screen": LoadingScreen;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user