Introduce supervisor object (#7800)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Joakim Sørensen 2020-11-25 18:22:05 +01:00 committed by GitHub
parent 7de7d1d926
commit 6f0c79ec25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 211 additions and 280 deletions

View File

@ -12,7 +12,7 @@ import { atLeastVersion } from "../../../src/common/config/version";
import { navigate } from "../../../src/common/navigate"; import { navigate } from "../../../src/common/navigate";
import { compare } from "../../../src/common/string/compare"; import { compare } from "../../../src/common/string/compare";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
import { HassioAddonInfo } from "../../../src/data/hassio/addon"; import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../src/resources/styles"; import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types"; import { HomeAssistant } from "../../../src/types";
import "../components/hassio-card-content"; import "../components/hassio-card-content";
@ -22,14 +22,14 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioAddons extends LitElement { class HassioAddons extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public addons?: HassioAddonInfo[]; @property({ attribute: false }) public supervisor!: Supervisor;
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<div class="content"> <div class="content">
<h1>Add-ons</h1> <h1>Add-ons</h1>
<div class="card-group"> <div class="card-group">
${!this.addons?.length ${!this.supervisor.supervisor.addons?.length
? html` ? html`
<ha-card> <ha-card>
<div class="card-content"> <div class="card-content">
@ -41,7 +41,7 @@ class HassioAddons extends LitElement {
</div> </div>
</ha-card> </ha-card>
` `
: this.addons : this.supervisor.supervisor.addons
.sort((a, b) => compare(a.name, b.name)) .sort((a, b) => compare(a.name, b.name))
.map( .map(
(addon) => html` (addon) => html`

View File

@ -7,11 +7,7 @@ import {
property, property,
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import { HassioHassOSInfo } from "../../../src/data/hassio/host"; import { Supervisor } from "../../../src/data/supervisor/supervisor";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import "../../../src/layouts/hass-tabs-subpage"; import "../../../src/layouts/hass-tabs-subpage";
import { haStyle } from "../../../src/resources/styles"; import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant, Route } from "../../../src/types"; import { HomeAssistant, Route } from "../../../src/types";
@ -23,16 +19,12 @@ import "./hassio-update";
class HassioDashboard extends LitElement { class HassioDashboard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route; @property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<hass-tabs-subpage <hass-tabs-subpage
@ -47,13 +39,11 @@ class HassioDashboard extends LitElement {
<div class="content"> <div class="content">
<hassio-update <hassio-update
.hass=${this.hass} .hass=${this.hass}
.hassInfo=${this.hassInfo} .supervisor=${this.supervisor}
.supervisorInfo=${this.supervisorInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-update> ></hassio-update>
<hassio-addons <hassio-addons
.hass=${this.hass} .hass=${this.hass}
.addons=${this.supervisorInfo.addons} .supervisor=${this.supervisor}
></hassio-addons> ></hassio-addons>
</div> </div>
</hass-tabs-subpage> </hass-tabs-subpage>

View File

@ -23,6 +23,7 @@ import {
HassioHomeAssistantInfo, HassioHomeAssistantInfo,
HassioSupervisorInfo, HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor"; } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
@ -35,31 +36,20 @@ import { hassioStyle } from "../resources/hassio-style";
export class HassioUpdate extends LitElement { export class HassioUpdate extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public hassInfo?: HassioHomeAssistantInfo; @property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public hassOsInfo?: HassioHassOSInfo; private _pendingUpdates = memoizeOne((supervisor: Supervisor): number => {
return Object.keys(supervisor).filter(
@property({ attribute: false }) public supervisorInfo?: HassioSupervisorInfo; (value) => supervisor[value].update_available
).length;
private _pendingUpdates = memoizeOne( });
(
core?: HassioHomeAssistantInfo,
supervisor?: HassioSupervisorInfo,
os?: HassioHassOSInfo
): number => {
return [core, supervisor, os].filter(
(value) => !!value && value?.update_available
).length;
}
);
protected render(): TemplateResult { protected render(): TemplateResult {
const updatesAvailable = this._pendingUpdates( if (!this.supervisor) {
this.hassInfo, return html``;
this.supervisorInfo, }
this.hassOsInfo
);
const updatesAvailable = this._pendingUpdates(this.supervisor);
if (!updatesAvailable) { if (!updatesAvailable) {
return html``; return html``;
} }
@ -74,26 +64,26 @@ export class HassioUpdate extends LitElement {
<div class="card-group"> <div class="card-group">
${this._renderUpdateCard( ${this._renderUpdateCard(
"Home Assistant Core", "Home Assistant Core",
this.hassInfo!, this.supervisor.core,
"hassio/homeassistant/update", "hassio/homeassistant/update",
`https://${ `https://${
this.hassInfo?.version_latest.includes("b") ? "rc" : "www" this.supervisor.core.version_latest.includes("b") ? "rc" : "www"
}.home-assistant.io/latest-release-notes/` }.home-assistant.io/latest-release-notes/`
)} )}
${this._renderUpdateCard( ${this._renderUpdateCard(
"Supervisor", "Supervisor",
this.supervisorInfo!, this.supervisor.supervisor,
"hassio/supervisor/update", "hassio/supervisor/update",
`https://github.com//home-assistant/hassio/releases/tag/${ `https://github.com//home-assistant/hassio/releases/tag/${
this.supervisorInfo!.version_latest this.supervisor.supervisor.version_latest
}` }`
)} )}
${this.hassOsInfo ${this.supervisor.host.features.includes("hassos")
? this._renderUpdateCard( ? this._renderUpdateCard(
"Operating System", "Operating System",
this.hassOsInfo, this.supervisor.os,
"hassio/os/update", "hassio/os/update",
`https://github.com//home-assistant/hassos/releases/tag/${this.hassOsInfo.version_latest}` `https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
) )
: ""} : ""}
</div> </div>

View File

@ -1,29 +1,22 @@
import { import { html, PropertyValues, customElement, property } from "lit-element";
html,
PropertyValues,
customElement,
LitElement,
property,
} from "lit-element";
import "./hassio-router"; import "./hassio-router";
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { HomeAssistant, Route } from "../../src/types"; import { HomeAssistant, Route } from "../../src/types";
import { HassioPanelInfo } from "../../src/data/hassio/supervisor"; import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element"; import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
import { fireEvent } from "../../src/common/dom/fire_event"; import { fireEvent } from "../../src/common/dom/fire_event";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
import { atLeastVersion } from "../../src/common/config/version"; import { atLeastVersion } from "../../src/common/config/version";
import { SupervisorBaseElement } from "./supervisor-base-element";
@customElement("hassio-main") @customElement("hassio-main")
export class HassioMain extends urlSyncMixin(ProvideHassLitMixin(LitElement)) { export class HassioMain extends SupervisorBaseElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public panel!: HassioPanelInfo; @property({ attribute: false }) public panel!: HassioPanelInfo;
@property() public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property() public route?: Route; @property({ attribute: false }) public route?: Route;
protected firstUpdated(changedProps: PropertyValues) { protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps); super.firstUpdated(changedProps);
@ -77,9 +70,13 @@ export class HassioMain extends urlSyncMixin(ProvideHassLitMixin(LitElement)) {
} }
protected render() { protected render() {
if (!this.supervisor || !this.hass) {
return html``;
}
return html` return html`
<hassio-router <hassio-router
.hass=${this.hass} .hass=${this.hass}
.supervisor=${this.supervisor}
.route=${this.route} .route=${this.route}
.panel=${this.panel} .panel=${this.panel}
.narrow=${this.narrow} .narrow=${this.narrow}

View File

@ -1,10 +1,5 @@
import { customElement, property } from "lit-element"; import { customElement, property } from "lit-element";
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host"; import { Supervisor } from "../../src/data/supervisor/supervisor";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
HassioInfo,
} from "../../src/data/hassio/supervisor";
import { import {
HassRouterPage, HassRouterPage,
RouterOptions, RouterOptions,
@ -21,20 +16,12 @@ import "./system/hassio-system";
class HassioPanelRouter extends HassRouterPage { class HassioPanelRouter extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public route!: Route; @property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public supervisorInfo?: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hostInfo?: HassioHostInfo;
@property({ attribute: false }) public hassInfo?: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected routerOptions: RouterOptions = { protected routerOptions: RouterOptions = {
routes: { routes: {
dashboard: { dashboard: {
@ -54,13 +41,9 @@ class HassioPanelRouter extends HassRouterPage {
protected updatePageEl(el) { protected updatePageEl(el) {
el.hass = this.hass; el.hass = this.hass;
el.supervisor = this.supervisor;
el.route = this.route; el.route = this.route;
el.narrow = this.narrow; el.narrow = this.narrow;
el.supervisorInfo = this.supervisorInfo;
el.hassioInfo = this.hassioInfo;
el.hostInfo = this.hostInfo;
el.hassInfo = this.hassInfo;
el.hassOsInfo = this.hassOsInfo;
} }
} }

View File

@ -1,18 +1,13 @@
import { import {
css,
CSSResult,
customElement, customElement,
html, html,
LitElement, LitElement,
property, property,
TemplateResult, TemplateResult,
css,
CSSResult,
} from "lit-element"; } from "lit-element";
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host"; import { Supervisor } from "../../src/data/supervisor/supervisor";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
HassioInfo,
} from "../../src/data/hassio/supervisor";
import { HomeAssistant, Route } from "../../src/types"; import { HomeAssistant, Route } from "../../src/types";
import "./hassio-panel-router"; import "./hassio-panel-router";
@ -20,34 +15,19 @@ import "./hassio-panel-router";
class HassioPanel extends LitElement { class HassioPanel extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route; @property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hostInfo!: HassioHostInfo;
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult { protected render(): TemplateResult {
if (!this.supervisorInfo) {
return html``;
}
return html` return html`
<hassio-panel-router <hassio-panel-router
.route=${this.route}
.hass=${this.hass} .hass=${this.hass}
.supervisor=${this.supervisor}
.route=${this.route}
.narrow=${this.narrow} .narrow=${this.narrow}
.supervisorInfo=${this.supervisorInfo}
.hassioInfo=${this.hassioInfo}
.hostInfo=${this.hostInfo}
.hassInfo=${this.hassInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-panel-router> ></hassio-panel-router>
`; `;
} }

View File

@ -1,24 +1,6 @@
import { import { customElement, property } from "lit-element";
customElement, import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
property, import { Supervisor } from "../../src/data/supervisor/supervisor";
internalProperty,
PropertyValues,
} from "lit-element";
import {
fetchHassioHassOsInfo,
fetchHassioHostInfo,
HassioHassOSInfo,
HassioHostInfo,
} from "../../src/data/hassio/host";
import {
fetchHassioHomeAssistantInfo,
fetchHassioSupervisorInfo,
fetchHassioInfo,
HassioHomeAssistantInfo,
HassioInfo,
HassioPanelInfo,
HassioSupervisorInfo,
} from "../../src/data/hassio/supervisor";
import { import {
HassRouterPage, HassRouterPage,
RouterOptions, RouterOptions,
@ -32,9 +14,11 @@ import "./hassio-panel";
class HassioRouter extends HassRouterPage { class HassioRouter extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public panel!: HassioPanelInfo; @property({ attribute: false }) public supervisor!: Supervisor;
@property() public narrow!: boolean; @property({ attribute: false }) public panel!: HassioPanelInfo;
@property({ type: Boolean }) public narrow!: boolean;
protected routerOptions: RouterOptions = { protected routerOptions: RouterOptions = {
// Hass.io has a page with tabs, so we route all non-matching routes to it. // Hass.io has a page with tabs, so we route all non-matching routes to it.
@ -60,32 +44,13 @@ class HassioRouter extends HassRouterPage {
}, },
}; };
@internalProperty() private _supervisorInfo?: HassioSupervisorInfo;
@internalProperty() private _hostInfo?: HassioHostInfo;
@internalProperty() private _hassioInfo?: HassioInfo;
@internalProperty() private _hassOsInfo?: HassioHassOSInfo;
@internalProperty() private _hassInfo?: HassioHomeAssistantInfo;
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
}
protected updatePageEl(el) { protected updatePageEl(el) {
// the tabs page does its own routing so needs full route. // the tabs page does its own routing so needs full route.
const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail; const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail;
el.hass = this.hass; el.hass = this.hass;
el.supervisor = this.supervisor;
el.narrow = this.narrow; el.narrow = this.narrow;
el.supervisorInfo = this._supervisorInfo;
el.hassioInfo = this._hassioInfo;
el.hostInfo = this._hostInfo;
el.hassInfo = this._hassInfo;
el.hassOsInfo = this._hassOsInfo;
el.route = route; el.route = route;
if (el.localName === "hassio-ingress-view") { if (el.localName === "hassio-ingress-view") {
@ -96,45 +61,12 @@ class HassioRouter extends HassRouterPage {
private async _fetchData() { private async _fetchData() {
if (this.panel.config && this.panel.config.ingress) { if (this.panel.config && this.panel.config.ingress) {
this._redirectIngress(this.panel.config.ingress); this._redirectIngress(this.panel.config.ingress);
return;
}
const [supervisorInfo, hostInfo, hassInfo, hassioInfo] = await Promise.all([
fetchHassioSupervisorInfo(this.hass),
fetchHassioHostInfo(this.hass),
fetchHassioHomeAssistantInfo(this.hass),
fetchHassioInfo(this.hass),
]);
this._supervisorInfo = supervisorInfo;
this._hassioInfo = hassioInfo;
this._hostInfo = hostInfo;
this._hassInfo = hassInfo;
if (this._hostInfo.features && this._hostInfo.features.includes("hassos")) {
this._hassOsInfo = await fetchHassioHassOsInfo(this.hass);
} }
} }
private _redirectIngress(addonSlug: string) { private _redirectIngress(addonSlug: string) {
this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` }; this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` };
} }
private _apiCalled(ev) {
if (!ev.detail.success) {
return;
}
let tries = 1;
const tryUpdate = () => {
this._fetchData().catch(() => {
tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
});
};
tryUpdate();
}
} }
declare global { declare global {

View File

@ -26,7 +26,6 @@ import {
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import { atLeastVersion } from "../../../src/common/config/version"; import { atLeastVersion } from "../../../src/common/config/version";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
@ -41,7 +40,7 @@ import {
HassioSnapshot, HassioSnapshot,
reloadHassioSnapshots, reloadHassioSnapshots,
} from "../../../src/data/hassio/snapshot"; } from "../../../src/data/hassio/snapshot";
import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor"; import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-tabs-subpage"; import "../../../src/layouts/hass-tabs-subpage";
import { PolymerChangedEvent } from "../../../src/polymer-types"; import { PolymerChangedEvent } from "../../../src/polymer-types";
import { haStyle } from "../../../src/resources/styles"; import { haStyle } from "../../../src/resources/styles";
@ -67,7 +66,7 @@ class HassioSnapshots extends LitElement {
@property({ attribute: false }) public route!: Route; @property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo; @property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _snapshotName = ""; @internalProperty() private _snapshotName = "";
@ -266,7 +265,7 @@ class HassioSnapshots extends LitElement {
protected updated(changedProps: PropertyValues) { protected updated(changedProps: PropertyValues) {
if (changedProps.has("supervisorInfo")) { if (changedProps.has("supervisorInfo")) {
this._addonList = this.supervisorInfo.addons this._addonList = this.supervisor.supervisor.addons
.map((addon) => ({ .map((addon) => ({
slug: addon.slug, slug: addon.slug,
name: addon.name, name: addon.name,
@ -372,7 +371,6 @@ class HassioSnapshots extends LitElement {
await createHassioPartialSnapshot(this.hass, data); await createHassioPartialSnapshot(this.hass, data);
} }
this._updateSnapshots(); this._updateSnapshots();
fireEvent(this, "hass-api-called", { success: true, response: null });
} catch (err) { } catch (err) {
this._error = extractApiErrorMessage(err); this._error = extractApiErrorMessage(err);
} }

View File

@ -0,0 +1,69 @@
import { LitElement, property, PropertyValues } from "lit-element";
import {
fetchHassioHassOsInfo,
fetchHassioHostInfo,
} from "../../src/data/hassio/host";
import { fetchNetworkInfo } from "../../src/data/hassio/network";
import { fetchHassioResolution } from "../../src/data/hassio/resolution";
import {
fetchHassioHomeAssistantInfo,
fetchHassioInfo,
fetchHassioSupervisorInfo,
} from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
declare global {
interface HASSDomEvents {
"supervisor-update": Partial<Supervisor>;
}
}
export class SupervisorBaseElement extends urlSyncMixin(
ProvideHassLitMixin(LitElement)
) {
@property({ attribute: false }) public supervisor?: Supervisor;
protected _updateSupervisor(obj: Partial<Supervisor>): void {
this.supervisor = { ...this.supervisor!, ...obj };
}
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
this._initSupervisor();
this.addEventListener("supervisor-update", (ev) =>
this._updateSupervisor(ev.detail)
);
}
private async _initSupervisor(): Promise<void> {
const [
supervisor,
host,
core,
info,
os,
network,
resolution,
] = await Promise.all([
fetchHassioSupervisorInfo(this.hass),
fetchHassioHostInfo(this.hass),
fetchHassioHomeAssistantInfo(this.hass),
fetchHassioInfo(this.hass),
fetchHassioHassOsInfo(this.hass),
fetchNetworkInfo(this.hass),
fetchHassioResolution(this.hass),
]);
this.supervisor = {
supervisor,
host,
core,
info,
os,
network,
resolution,
};
}
}

View File

@ -8,12 +8,12 @@ import {
CSSResult, CSSResult,
customElement, customElement,
html, html,
internalProperty,
LitElement, LitElement,
property, property,
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card"; import "../../../src/components/ha-card";
@ -27,8 +27,6 @@ import {
changeHostOptions, changeHostOptions,
configSyncOS, configSyncOS,
fetchHassioHostInfo, fetchHassioHostInfo,
HassioHassOSInfo,
HassioHostInfo as HassioHostInfoType,
rebootHost, rebootHost,
shutdownHost, shutdownHost,
updateOS, updateOS,
@ -37,7 +35,7 @@ import {
fetchNetworkInfo, fetchNetworkInfo,
NetworkInfo, NetworkInfo,
} from "../../../src/data/hassio/network"; } from "../../../src/data/hassio/network";
import { HassioInfo } from "../../../src/data/hassio/supervisor"; import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
@ -53,28 +51,22 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioHostInfo extends LitElement { class HassioHostInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public hostInfo!: HassioHostInfoType; @property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
@internalProperty() public _networkInfo?: NetworkInfo;
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
const primaryIpAddress = this.hostInfo.features.includes("network") const primaryIpAddress = this.supervisor.host.features.includes("network")
? this._primaryIpAddress(this._networkInfo!) ? this._primaryIpAddress(this.supervisor.network!)
: ""; : "";
return html` return html`
<ha-card header="Host System"> <ha-card header="Host System">
<div class="card-content"> <div class="card-content">
${this.hostInfo.features.includes("hostname") ${this.supervisor.host.features.includes("hostname")
? html`<ha-settings-row> ? html`<ha-settings-row>
<span slot="heading"> <span slot="heading">
Hostname Hostname
</span> </span>
<span slot="description"> <span slot="description">
${this.hostInfo.hostname} ${this.supervisor.host.hostname}
</span> </span>
<mwc-button <mwc-button
title="Change the hostname" title="Change the hostname"
@ -84,7 +76,7 @@ class HassioHostInfo extends LitElement {
</mwc-button> </mwc-button>
</ha-settings-row>` </ha-settings-row>`
: ""} : ""}
${this.hostInfo.features.includes("network") ${this.supervisor.host.features.includes("network")
? html` <ha-settings-row> ? html` <ha-settings-row>
<span slot="heading"> <span slot="heading">
IP Address IP Address
@ -106,10 +98,9 @@ class HassioHostInfo extends LitElement {
Operating System Operating System
</span> </span>
<span slot="description"> <span slot="description">
${this.hostInfo.operating_system} ${this.supervisor.host.operating_system}
</span> </span>
${this.hostInfo.features.includes("hassos") && ${this.supervisor.os.update_available
this.hassOsInfo.update_available
? html` ? html`
<ha-progress-button <ha-progress-button
title="Update the host OS" title="Update the host OS"
@ -120,29 +111,29 @@ class HassioHostInfo extends LitElement {
` `
: ""} : ""}
</ha-settings-row> </ha-settings-row>
${!this.hostInfo.features.includes("hassos") ${!this.supervisor.host.features.includes("hassos")
? html`<ha-settings-row> ? html`<ha-settings-row>
<span slot="heading"> <span slot="heading">
Docker version Docker version
</span> </span>
<span slot="description"> <span slot="description">
${this.hassioInfo.docker} ${this.supervisor.info.docker}
</span> </span>
</ha-settings-row>` </ha-settings-row>`
: ""} : ""}
${this.hostInfo.deployment ${this.supervisor.host.deployment
? html`<ha-settings-row> ? html`<ha-settings-row>
<span slot="heading"> <span slot="heading">
Deployment Deployment
</span> </span>
<span slot="description"> <span slot="description">
${this.hostInfo.deployment} ${this.supervisor.host.deployment}
</span> </span>
</ha-settings-row>` </ha-settings-row>`
: ""} : ""}
</div> </div>
<div class="card-actions"> <div class="card-actions">
${this.hostInfo.features.includes("reboot") ${this.supervisor.host.features.includes("reboot")
? html` ? html`
<ha-progress-button <ha-progress-button
title="Reboot the host OS" title="Reboot the host OS"
@ -153,7 +144,7 @@ class HassioHostInfo extends LitElement {
</ha-progress-button> </ha-progress-button>
` `
: ""} : ""}
${this.hostInfo.features.includes("shutdown") ${this.supervisor.host.features.includes("shutdown")
? html` ? html`
<ha-progress-button <ha-progress-button
title="Shutdown the host OS" title="Shutdown the host OS"
@ -175,7 +166,7 @@ class HassioHostInfo extends LitElement {
<mwc-list-item title="Show a list of hardware"> <mwc-list-item title="Show a list of hardware">
Hardware Hardware
</mwc-list-item> </mwc-list-item>
${this.hostInfo.features.includes("hassos") ${this.supervisor.host.features.includes("hassos")
? html`<mwc-list-item ? html`<mwc-list-item
title="Load HassOS configs or updates from USB" title="Load HassOS configs or updates from USB"
> >
@ -314,13 +305,13 @@ class HassioHostInfo extends LitElement {
private async _changeNetworkClicked(): Promise<void> { private async _changeNetworkClicked(): Promise<void> {
showNetworkDialog(this, { showNetworkDialog(this, {
network: this._networkInfo!, network: this.supervisor.network!,
loadData: () => this._loadData(), loadData: () => this._loadData(),
}); });
} }
private async _changeHostnameClicked(): Promise<void> { private async _changeHostnameClicked(): Promise<void> {
const curHostname: string = this.hostInfo.hostname; const curHostname: string = this.supervisor.host.hostname;
const hostname = await showPromptDialog(this, { const hostname = await showPromptDialog(this, {
title: "Change Hostname", title: "Change Hostname",
inputLabel: "Please enter a new hostname:", inputLabel: "Please enter a new hostname:",
@ -331,7 +322,8 @@ class HassioHostInfo extends LitElement {
if (hostname && hostname !== curHostname) { if (hostname && hostname !== curHostname) {
try { try {
await changeHostOptions(this.hass, { hostname }); await changeHostOptions(this.hass, { hostname });
this.hostInfo = await fetchHassioHostInfo(this.hass); const host = await fetchHassioHostInfo(this.hass);
fireEvent(this, "supervisor-update", { host });
} catch (err) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Setting hostname failed", title: "Setting hostname failed",
@ -344,7 +336,8 @@ class HassioHostInfo extends LitElement {
private async _importFromUSB(): Promise<void> { private async _importFromUSB(): Promise<void> {
try { try {
await configSyncOS(this.hass); await configSyncOS(this.hass);
this.hostInfo = await fetchHassioHostInfo(this.hass); const host = await fetchHassioHostInfo(this.hass);
fireEvent(this, "supervisor-update", { host });
} catch (err) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Failed to import from USB", title: "Failed to import from USB",
@ -354,7 +347,8 @@ class HassioHostInfo extends LitElement {
} }
private async _loadData(): Promise<void> { private async _loadData(): Promise<void> {
this._networkInfo = await fetchNetworkInfo(this.hass); const network = await fetchNetworkInfo(this.hass);
fireEvent(this, "supervisor-update", { network });
} }
static get styles(): CSSResult[] { static get styles(): CSSResult[] {

View File

@ -13,17 +13,15 @@ import "../../../src/components/ha-card";
import "../../../src/components/ha-settings-row"; import "../../../src/components/ha-settings-row";
import "../../../src/components/ha-switch"; import "../../../src/components/ha-switch";
import { extractApiErrorMessage } from "../../../src/data/hassio/common"; import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { HassioHostInfo as HassioHostInfoType } from "../../../src/data/hassio/host";
import { fetchHassioResolution } from "../../../src/data/hassio/resolution";
import { import {
fetchHassioSupervisorInfo, fetchHassioSupervisorInfo,
HassioSupervisorInfo as HassioSupervisorInfoType,
reloadSupervisor, reloadSupervisor,
restartSupervisor, restartSupervisor,
setSupervisorOption, setSupervisorOption,
SupervisorOptions, SupervisorOptions,
updateSupervisor, updateSupervisor,
} from "../../../src/data/hassio/supervisor"; } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
@ -87,15 +85,9 @@ const UNHEALTHY_REASON = {
class HassioSupervisorInfo extends LitElement { class HassioSupervisorInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) @property({ attribute: false }) public supervisor!: Supervisor;
public supervisorInfo!: HassioSupervisorInfoType;
@property({ attribute: false }) public hostInfo!: HassioHostInfoType;
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
if (!this.hass || !this.supervisorInfo || !this.hostInfo) {
return html``;
}
return html` return html`
<ha-card header="Supervisor"> <ha-card header="Supervisor">
<div class="card-content"> <div class="card-content">
@ -104,7 +96,7 @@ class HassioSupervisorInfo extends LitElement {
Version Version
</span> </span>
<span slot="description"> <span slot="description">
${this.supervisorInfo.version} ${this.supervisor.supervisor.version}
</span> </span>
</ha-settings-row> </ha-settings-row>
<ha-settings-row> <ha-settings-row>
@ -112,9 +104,9 @@ class HassioSupervisorInfo extends LitElement {
Newest Version Newest Version
</span> </span>
<span slot="description"> <span slot="description">
${this.supervisorInfo.version_latest} ${this.supervisor.supervisor.version_latest}
</span> </span>
${this.supervisorInfo.update_available ${this.supervisor.supervisor.update_available
? html` ? html`
<ha-progress-button <ha-progress-button
title="Update the supervisor" title="Update the supervisor"
@ -130,9 +122,9 @@ class HassioSupervisorInfo extends LitElement {
Channel Channel
</span> </span>
<span slot="description"> <span slot="description">
${this.supervisorInfo.channel} ${this.supervisor.supervisor.channel}
</span> </span>
${this.supervisorInfo.channel === "beta" ${this.supervisor.supervisor.channel === "beta"
? html` ? html`
<ha-progress-button <ha-progress-button
@click=${this._toggleBeta} @click=${this._toggleBeta}
@ -141,7 +133,7 @@ class HassioSupervisorInfo extends LitElement {
Leave beta channel Leave beta channel
</ha-progress-button> </ha-progress-button>
` `
: this.supervisorInfo.channel === "stable" : this.supervisor.supervisor.channel === "stable"
? html` ? html`
<ha-progress-button <ha-progress-button
@click=${this._toggleBeta} @click=${this._toggleBeta}
@ -153,7 +145,7 @@ class HassioSupervisorInfo extends LitElement {
: ""} : ""}
</ha-settings-row> </ha-settings-row>
${this.supervisorInfo.supported ${this.supervisor.supervisor.supported
? html` <ha-settings-row three-line> ? html` <ha-settings-row three-line>
<span slot="heading"> <span slot="heading">
Share Diagnostics Share Diagnostics
@ -170,7 +162,7 @@ class HassioSupervisorInfo extends LitElement {
</div> </div>
<ha-switch <ha-switch
haptic haptic
.checked=${this.supervisorInfo.diagnostics} .checked=${this.supervisor.supervisor.diagnostics}
@change=${this._toggleDiagnostics} @change=${this._toggleDiagnostics}
></ha-switch> ></ha-switch>
</ha-settings-row>` </ha-settings-row>`
@ -184,7 +176,7 @@ class HassioSupervisorInfo extends LitElement {
Learn more Learn more
</button> </button>
</div>`} </div>`}
${!this.supervisorInfo.healthy ${!this.supervisor.supervisor.healthy
? html`<div class="error"> ? html`<div class="error">
Your installtion is running in an unhealthy state. Your installtion is running in an unhealthy state.
<button <button
@ -220,7 +212,7 @@ class HassioSupervisorInfo extends LitElement {
const button = ev.currentTarget as any; const button = ev.currentTarget as any;
button.progress = true; button.progress = true;
if (this.supervisorInfo.channel === "stable") { if (this.supervisor.supervisor.channel === "stable") {
const confirmed = await showConfirmationDialog(this, { const confirmed = await showConfirmationDialog(this, {
title: "WARNING", title: "WARNING",
text: html` Beta releases are for testers and early adopters and can text: html` Beta releases are for testers and early adopters and can
@ -249,11 +241,11 @@ class HassioSupervisorInfo extends LitElement {
try { try {
const data: Partial<SupervisorOptions> = { const data: Partial<SupervisorOptions> = {
channel: this.supervisorInfo.channel === "stable" ? "beta" : "stable", channel:
this.supervisor.supervisor.channel === "stable" ? "beta" : "stable",
}; };
await setSupervisorOption(this.hass, data); await setSupervisorOption(this.hass, data);
await reloadSupervisor(this.hass); await this._reloadSupervisor();
fireEvent(this, "hass-api-called", { success: true, response: null });
} catch (err) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Failed to set supervisor option", title: "Failed to set supervisor option",
@ -269,8 +261,7 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true; button.progress = true;
try { try {
await reloadSupervisor(this.hass); await this._reloadSupervisor();
this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
} catch (err) { } catch (err) {
showAlertDialog(this, { showAlertDialog(this, {
title: "Failed to reload the supervisor", title: "Failed to reload the supervisor",
@ -281,6 +272,12 @@ class HassioSupervisorInfo extends LitElement {
} }
} }
private async _reloadSupervisor(): Promise<void> {
await reloadSupervisor(this.hass);
const supervisor = await fetchHassioSupervisorInfo(this.hass);
fireEvent(this, "supervisor-update", { supervisor });
}
private async _supervisorRestart(ev: CustomEvent): Promise<void> { private async _supervisorRestart(ev: CustomEvent): Promise<void> {
const button = ev.currentTarget as any; const button = ev.currentTarget as any;
button.progress = true; button.progress = true;
@ -303,7 +300,7 @@ class HassioSupervisorInfo extends LitElement {
const confirmed = await showConfirmationDialog(this, { const confirmed = await showConfirmationDialog(this, {
title: "Update Supervisor", title: "Update Supervisor",
text: `Are you sure you want to update supervisor to version ${this.supervisorInfo.version_latest}?`, text: `Are you sure you want to update supervisor to version ${this.supervisor.supervisor.version_latest}?`,
confirmText: "update", confirmText: "update",
dismissText: "cancel", dismissText: "cancel",
}); });
@ -341,13 +338,12 @@ class HassioSupervisorInfo extends LitElement {
} }
private async _unsupportedDialog(): Promise<void> { private async _unsupportedDialog(): Promise<void> {
const resolution = await fetchHassioResolution(this.hass);
await showAlertDialog(this, { await showAlertDialog(this, {
title: "You are running an unsupported installation", title: "You are running an unsupported installation",
text: html`Below is a list of issues found with your installation, click text: html`Below is a list of issues found with your installation, click
on the links to learn how you can resolve the issues. <br /><br /> on the links to learn how you can resolve the issues. <br /><br />
<ul> <ul>
${resolution.unsupported.map( ${this.supervisor.resolution.unsupported.map(
(issue) => html` (issue) => html`
<li> <li>
${UNSUPPORTED_REASON[issue] ${UNSUPPORTED_REASON[issue]
@ -370,14 +366,13 @@ class HassioSupervisorInfo extends LitElement {
} }
private async _unhealthyDialog(): Promise<void> { private async _unhealthyDialog(): Promise<void> {
const resolution = await fetchHassioResolution(this.hass);
await showAlertDialog(this, { await showAlertDialog(this, {
title: "Your installation is unhealthy", title: "Your installation is unhealthy",
text: html`Running an unhealthy installation will cause issues. Below is a text: html`Running an unhealthy installation will cause issues. Below is a
list of issues found with your installation, click on the links to learn list of issues found with your installation, click on the links to learn
how you can resolve the issues. <br /><br /> how you can resolve the issues. <br /><br />
<ul> <ul>
${resolution.unhealthy.map( ${this.supervisor.resolution.unhealthy.map(
(issue) => html` (issue) => html`
<li> <li>
${UNHEALTHY_REASON[issue] ${UNHEALTHY_REASON[issue]
@ -402,7 +397,7 @@ class HassioSupervisorInfo extends LitElement {
private async _toggleDiagnostics(): Promise<void> { private async _toggleDiagnostics(): Promise<void> {
try { try {
const data: SupervisorOptions = { const data: SupervisorOptions = {
diagnostics: !this.supervisorInfo?.diagnostics, diagnostics: !this.supervisor.supervisor?.diagnostics,
}; };
await setSupervisorOption(this.hass, data); await setSupervisorOption(this.hass, data);
} catch (err) { } catch (err) {

View File

@ -19,6 +19,7 @@ import "../../../src/components/ha-card";
import "../../../src/components/ha-settings-row"; import "../../../src/components/ha-settings-row";
import { fetchHassioStats, HassioStats } from "../../../src/data/hassio/common"; import { fetchHassioStats, HassioStats } from "../../../src/data/hassio/common";
import { HassioHostInfo } from "../../../src/data/hassio/host"; import { HassioHostInfo } from "../../../src/data/hassio/host";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../src/resources/styles"; import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types"; import { HomeAssistant } from "../../../src/types";
import { bytesToString } from "../../../src/util/bytes-to-string"; import { bytesToString } from "../../../src/util/bytes-to-string";
@ -32,7 +33,7 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioSystemMetrics extends LitElement { class HassioSystemMetrics extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property() public hostInfo!: HassioHostInfo; @property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _supervisorMetrics?: HassioStats; @internalProperty() private _supervisorMetrics?: HassioStats;
@ -64,8 +65,8 @@ class HassioSystemMetrics extends LitElement {
}, },
{ {
description: "Used Space", description: "Used Space",
value: this._getUsedSpace(this.hostInfo), value: this._getUsedSpace(this.supervisor.host),
tooltip: `${this.hostInfo.disk_used} GB/${this.hostInfo.disk_total} GB`, tooltip: `${this.supervisor.host.disk_used} GB/${this.supervisor.host.disk_total} GB`,
}, },
]; ];

View File

@ -7,14 +7,7 @@ import {
property, property,
TemplateResult, TemplateResult,
} from "lit-element"; } from "lit-element";
import { import { Supervisor } from "../../../src/data/supervisor/supervisor";
HassioHassOSInfo,
HassioHostInfo,
} from "../../../src/data/hassio/host";
import {
HassioInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import "../../../src/layouts/hass-tabs-subpage"; import "../../../src/layouts/hass-tabs-subpage";
import { haStyle } from "../../../src/resources/styles"; import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant, Route } from "../../../src/types"; import { HomeAssistant, Route } from "../../../src/types";
@ -29,18 +22,12 @@ import "./hassio-system-metrics";
class HassioSystem extends LitElement { class HassioSystem extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route; @property({ attribute: false }) public route!: Route;
@property() public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property() public hostInfo!: HassioHostInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
return html` return html`
<hass-tabs-subpage <hass-tabs-subpage
@ -56,18 +43,15 @@ class HassioSystem extends LitElement {
<div class="card-group"> <div class="card-group">
<hassio-supervisor-info <hassio-supervisor-info
.hass=${this.hass} .hass=${this.hass}
.hostInfo=${this.hostInfo} .supervisor=${this.supervisor}
.supervisorInfo=${this.supervisorInfo}
></hassio-supervisor-info> ></hassio-supervisor-info>
<hassio-host-info <hassio-host-info
.hass=${this.hass} .hass=${this.hass}
.hassioInfo=${this.hassioInfo} .supervisor=${this.supervisor}
.hostInfo=${this.hostInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-host-info> ></hassio-host-info>
<hassio-system-metrics <hassio-system-metrics
.hass=${this.hass} .hass=${this.hass}
.hostInfo=${this.hostInfo} .supervisor=${this.supervisor}
></hassio-system-metrics> ></hassio-system-metrics>
</div> </div>
<hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log> <hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log>

View File

@ -15,11 +15,11 @@ export type HassioHostInfo = {
}; };
export interface HassioHassOSInfo { export interface HassioHassOSInfo {
board: string; board: string | null;
boot: string; boot: string | null;
update_available: boolean; update_available: boolean;
version_latest: string; version_latest: string | null;
version: string; version: string | null;
} }
export const fetchHassioHostInfo = async (hass: HomeAssistant) => { export const fetchHassioHostInfo = async (hass: HomeAssistant) => {

View File

@ -0,0 +1,18 @@
import { HassioHassOSInfo, HassioHostInfo } from "../hassio/host";
import { NetworkInfo } from "../hassio/network";
import { HassioResolution } from "../hassio/resolution";
import {
HassioHomeAssistantInfo,
HassioInfo,
HassioSupervisorInfo,
} from "../hassio/supervisor";
export interface Supervisor {
host: HassioHostInfo;
supervisor: HassioSupervisorInfo;
info: HassioInfo;
core: HassioHomeAssistantInfo;
network: NetworkInfo;
resolution: HassioResolution;
os: HassioHassOSInfo;
}