Add hassio supervisor and os update notice (#3798)

* Add hassio supervisor and os update notice

* Cleanup

* Update hassio-dashboard.ts

* Fix styling

* Check if system has HassOs

* Remove unused import
This commit is contained in:
Bram Kragten 2019-09-26 13:47:34 +02:00 committed by GitHub
parent f4bd42dfd4
commit 05a258c886
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 187 additions and 115 deletions

View File

@ -8,26 +8,31 @@ import {
customElement,
} from "lit-element";
import "./hassio-addons";
import "./hassio-hass-update";
import "./hassio-update";
import { HomeAssistant } from "../../../src/types";
import {
HassioSupervisorInfo,
HassioHomeAssistantInfo,
HassioHassOSInfo,
} from "../../../src/data/hassio";
@customElement("hassio-dashboard")
class HassioDashboard extends LitElement {
@property() public hass!: HomeAssistant;
@property() public supervisorInfo!: HassioSupervisorInfo;
@property() public hassInfo!: HassioHomeAssistantInfo;
@property() public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult | void {
return html`
<div class="content">
<hassio-hass-update
<hassio-update
.hass=${this.hass}
.hassInfo=${this.hassInfo}
></hassio-hass-update>
.supervisorInfo=${this.supervisorInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-update>
<hassio-addons
.hass=${this.hass}
.addons=${this.supervisorInfo.addons}

View File

@ -1,96 +0,0 @@
import "@material/mwc-button";
import "@polymer/paper-card/paper-card";
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 HassioHassUpdate extends PolymerElement {
static get template() {
return html`
<style include="ha-style hassio-style">
paper-card {
display: block;
margin-bottom: 32px;
}
.errors {
color: var(--google-red-500);
margin-top: 16px;
}
a {
color: var(--primary-color);
}
</style>
<template is="dom-if" if="[[computeUpdateAvailable(hassInfo)]]">
<div class="content">
<div class="card-group">
<paper-card heading="Update available! 🎉">
<div class="card-content">
Home Assistant [[hassInfo.last_version]] is available and you
are currently running Home Assistant [[hassInfo.version]].
<template is="dom-if" if="[[error]]">
<div class="error">Error: [[error]]</div>
</template>
</div>
<div class="card-actions">
<ha-call-api-button
hass="[[hass]]"
path="hassio/homeassistant/update"
>Update</ha-call-api-button
>
<a
href="[[computeReleaseNotesUrl(hassInfo.version)]]"
target="_blank"
>
<mwc-button>Release notes</mwc-button>
</a>
</div>
</paper-card>
</div>
</div>
</template>
`;
}
static get properties() {
return {
hass: Object,
hassInfo: Object,
error: String,
};
}
ready() {
super.ready();
this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
}
apiCalled(ev) {
if (ev.detail.success) {
this.errors = null;
return;
}
const response = ev.detail.response;
if (typeof response.body === "object") {
this.errors = response.body.message || "Unknown error";
} else {
this.errors = response.body;
}
}
computeUpdateAvailable(hassInfo) {
return hassInfo.version !== hassInfo.last_version;
}
computeReleaseNotesUrl(version) {
return `https://${
version.includes("b") ? "rc" : "www"
}.home-assistant.io/latest-release-notes/`;
}
}
customElements.define("hassio-hass-update", HassioHassUpdate);

View File

@ -0,0 +1,153 @@
import {
LitElement,
TemplateResult,
html,
CSSResult,
css,
property,
customElement,
} from "lit-element";
import { HomeAssistant } from "../../../src/types";
import {
HassioHomeAssistantInfo,
HassioHassOSInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio";
import { hassioStyle } from "../resources/hassio-style";
import "@material/mwc-button";
import "@polymer/paper-card/paper-card";
import "../../../src/components/buttons/ha-call-api-button";
import "../components/hassio-card-content";
@customElement("hassio-update")
export class HassioUpdate extends LitElement {
@property() public hass!: HomeAssistant;
@property() public hassInfo: HassioHomeAssistantInfo;
@property() public hassOsInfo?: HassioHassOSInfo;
@property() public supervisorInfo: HassioSupervisorInfo;
@property() public error?: string;
protected render(): TemplateResult | void {
if (
this.hassInfo.version === this.hassInfo.last_version &&
this.supervisorInfo.version === this.supervisorInfo.last_version &&
(!this.hassOsInfo ||
this.hassOsInfo.version === this.hassOsInfo.version_latest)
) {
return html``;
}
return html`
<div class="content">
${this.error
? html`
<div class="error">Error: ${this.error}</div>
`
: ""}
<div class="card-group">
${this._renderUpdateCard(
"Home Assistant",
this.hassInfo.version,
this.hassInfo.last_version,
"hassio/homeassistant/update",
`https://${
this.hassInfo.last_version.includes("b") ? "rc" : "www"
}.home-assistant.io/latest-release-notes/`
)}
${this._renderUpdateCard(
"Hass.io Supervisor",
this.supervisorInfo.version,
this.supervisorInfo.last_version,
"hassio/supervisor/update",
`https://github.com//home-assistant/hassio/releases/tag/${
this.supervisorInfo.last_version
}`
)}
${this.hassOsInfo
? this._renderUpdateCard(
"HassOS",
this.hassOsInfo.version,
this.hassOsInfo.version_latest,
"hassio/hassos/update",
`https://github.com//home-assistant/hassos/releases/tag/${
this.hassOsInfo.version_latest
}`
)
: ""}
</div>
</div>
`;
}
private _renderUpdateCard(
name: string,
curVersion: string,
lastVersion: string,
apiPath: string,
releaseNotesUrl: string
): TemplateResult {
if (lastVersion === curVersion) {
return html``;
}
return html`
<paper-card heading="${name} update available! 🎉">
<div class="card-content">
${name} ${lastVersion} is available and you are currently running
${name} ${curVersion}.
</div>
<div class="card-actions">
<ha-call-api-button
.hass=${this.hass}
.path=${apiPath}
@hass-api-called=${this._apiCalled}
>
Update
</ha-call-api-button>
<a href="${releaseNotesUrl}" target="_blank">
<mwc-button>Release notes</mwc-button>
</a>
</div>
</paper-card>
`;
}
private _apiCalled(ev) {
if (ev.detail.success) {
this.error = "";
return;
}
const response = ev.detail.response;
typeof response.body === "object"
? (this.error = response.body.message || "Unknown error")
: (this.error = response.body);
}
static get styles(): CSSResult[] {
return [
hassioStyle,
css`
:host {
width: 33%;
}
paper-card {
display: inline-block;
margin-bottom: 32px;
}
.errors {
color: var(--google-red-500);
padding: 16px;
}
a {
text-decoration: none;
}
`,
];
}
}

View File

@ -13,9 +13,11 @@ import { HomeAssistant } from "../../src/types";
import {
fetchHassioSupervisorInfo,
fetchHassioHostInfo,
fetchHassioHassOsInfo,
fetchHassioHomeAssistantInfo,
HassioSupervisorInfo,
HassioHostInfo,
HassioHassOSInfo,
HassioHomeAssistantInfo,
fetchHassioAddonInfo,
createHassioSession,
@ -66,6 +68,7 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
@property() private _supervisorInfo: HassioSupervisorInfo;
@property() private _hostInfo: HassioHostInfo;
@property() private _hassOsInfo?: HassioHassOSInfo;
@property() private _hassInfo: HassioHomeAssistantInfo;
protected firstUpdated(changedProps: PropertyValues) {
@ -113,6 +116,7 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
supervisorInfo: this._supervisorInfo,
hostInfo: this._hostInfo,
hassInfo: this._hassInfo,
hassOsInfo: this._hassOsInfo,
route,
});
} else {
@ -121,6 +125,7 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
el.supervisorInfo = this._supervisorInfo;
el.hostInfo = this._hostInfo;
el.hassInfo = this._hassInfo;
el.hassOsInfo = this._hassOsInfo;
el.route = route;
}
}
@ -139,6 +144,10 @@ class HassioMain extends ProvideHassLitMixin(HassRouterPage) {
this._supervisorInfo = supervisorInfo;
this._hostInfo = hostInfo;
this._hassInfo = hassInfo;
if (this._hostInfo.features && this._hostInfo.features.includes("hassos")) {
this._hassOsInfo = await fetchHassioHassOsInfo(this.hass);
}
}
private async _redirectIngress(addonSlug: string) {

View File

@ -27,6 +27,7 @@ import {
HassioSupervisorInfo,
HassioHostInfo,
HassioHomeAssistantInfo,
HassioHassOSInfo,
} from "../../src/data/hassio";
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
@ -39,6 +40,7 @@ class HassioPagesWithTabs extends LitElement {
@property() public supervisorInfo!: HassioSupervisorInfo;
@property() public hostInfo!: HassioHostInfo;
@property() public hassInfo!: HassioHomeAssistantInfo;
@property() public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult | void {
const page = this._page;
@ -79,6 +81,7 @@ class HassioPagesWithTabs extends LitElement {
.supervisorInfo=${this.supervisorInfo}
.hostInfo=${this.hostInfo}
.hassInfo=${this.hassInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-tabs-router>
</app-header-layout>
`;

View File

@ -15,6 +15,7 @@ import {
HassioSupervisorInfo,
HassioHostInfo,
HassioHomeAssistantInfo,
HassioHassOSInfo,
} from "../../src/data/hassio";
@customElement("hassio-tabs-router")
@ -23,6 +24,7 @@ class HassioTabsRouter extends HassRouterPage {
@property() public supervisorInfo: HassioSupervisorInfo;
@property() public hostInfo: HassioHostInfo;
@property() public hassInfo: HassioHomeAssistantInfo;
@property() public hassOsInfo!: HassioHassOSInfo;
protected routerOptions: RouterOptions = {
routes: {
@ -49,12 +51,14 @@ class HassioTabsRouter extends HassRouterPage {
supervisorInfo: this.supervisorInfo,
hostInfo: this.hostInfo,
hassInfo: this.hassInfo,
hassOsInfo: this.hassOsInfo,
});
} else {
el.hass = this.hass;
el.supervisorInfo = this.supervisorInfo;
el.hostInfo = this.hostInfo;
el.hassInfo = this.hassInfo;
el.hassOsInfo = this.hassOsInfo;
}
}
}

View File

@ -107,7 +107,7 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
>Import from USB</ha-call-api-button
>
</template>
<template is="dom-if" if="[[_computeUpdateAvailable(_hassOs)]]">
<template is="dom-if" if="[[_computeUpdateAvailable(hassOsInfo)]]">
<ha-call-api-button hass="[[hass]]" path="hassio/hassos/update"
>Update</ha-call-api-button
>
@ -120,12 +120,9 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
static get properties() {
return {
hass: Object,
data: {
type: Object,
observer: "_dataChanged",
},
data: Object,
hassOsInfo: Object,
errors: String,
_hassOs: Object,
};
}
@ -149,16 +146,6 @@ class HassioHostInfo extends EventsMixin(PolymerElement) {
}
}
_dataChanged(data) {
if (data.features && data.features.includes("hassos")) {
this.hass.callApi("get", "hassio/hassos/info").then((resp) => {
this._hassOs = resp.data;
});
} else {
this._hassOs = {};
}
}
_computeUpdateAvailable(data) {
return data && data.version !== data.version_latest;
}

View File

@ -30,6 +30,7 @@ class HassioSystem extends PolymerElement {
<hassio-host-info
hass="[[hass]]"
data="[[hostInfo]]"
hass-os-info="[[hassOsInfo]]"
></hassio-host-info>
<div class="title">System log</div>
<hassio-supervisor-log hass="[[hass]]"></hassio-supervisor-log>
@ -42,6 +43,7 @@ class HassioSystem extends PolymerElement {
hass: Object,
supervisorInfo: Object,
hostInfo: Object,
hassOsInfo: Object,
};
}
}

View File

@ -183,6 +183,11 @@ export const fetchHassioHostInfo = (hass: HomeAssistant) =>
.callApi<HassioResponse<HassioHostInfo>>("GET", "hassio/host/info")
.then(hassioApiResultExtractor);
export const fetchHassioHassOsInfo = (hass: HomeAssistant) =>
hass
.callApi<HassioResponse<HassioHassOSInfo>>("GET", "hassio/hassos/info")
.then(hassioApiResultExtractor);
export const fetchHassioHomeAssistantInfo = (hass: HomeAssistant) =>
hass
.callApi<HassioResponse<HassioHomeAssistantInfo>>(