@@ -134,19 +133,20 @@ export class HassioUpdate extends LitElement {
private _apiCalled(ev) {
if (ev.detail.success) {
- this.error = "";
+ this._error = "";
return;
}
const response = ev.detail.response;
typeof response.body === "object"
- ? (this.error = response.body.message || "Unknown error")
- : (this.error = response.body);
+ ? (this._error = response.body.message || "Unknown error")
+ : (this._error = response.body);
}
static get styles(): CSSResult[] {
return [
+ haStyle,
hassioStyle,
css`
:host {
diff --git a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts
index 87eb12e765..8cab6703cd 100644
--- a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts
+++ b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts
@@ -1,20 +1,59 @@
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "@polymer/paper-icon-button/paper-icon-button";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "../../../../src/components/ha-markdown";
-import "../../../../src/resources/ha-style";
-import "../../../../src/components/dialog/ha-paper-dialog";
-import { customElement } from "lit-element";
import { PaperDialogElement } from "@polymer/paper-dialog";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+
+import { hassioStyle } from "../../resources/hassio-style";
+import { haStyleDialog } from "../../../../src/resources/styles";
+import { HassioMarkdownDialogParams } from "./show-dialog-hassio-markdown";
+
+import "../../../../src/components/dialog/ha-paper-dialog";
+import "../../../../src/components/ha-markdown";
@customElement("dialog-hassio-markdown")
-class HassioMarkdownDialog extends PolymerElement {
- static get template() {
+class HassioMarkdownDialog extends LitElement {
+ @property() public title!: string;
+ @property() public content!: string;
+ @query("#dialog") private _dialog!: PaperDialogElement;
+
+ public showDialog(params: HassioMarkdownDialogParams) {
+ this.title = params.title;
+ this.content = params.content;
+ this._dialog.open();
+ }
+
+ protected render(): TemplateResult | void {
return html`
-
-
-
-
- [[title]]
-
-
-
-
-
- `;
- }
-
- static get properties() {
- return {
- title: String,
- content: String,
- };
- }
-
- public showDialog(params) {
- this.setProperties(params);
- (this.$.dialog as PaperDialogElement).open();
+ `,
+ ];
}
}
diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
index f0ae53eac4..a54782ac57 100755
--- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
+++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
@@ -1,20 +1,33 @@
-import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@material/mwc-button";
-import "@polymer/paper-checkbox/paper-checkbox";
+import "@polymer/app-layout/app-toolbar/app-toolbar";
+import "@polymer/iron-icon/iron-icon";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "@polymer/paper-icon-button/paper-icon-button";
-import "@polymer/iron-icon/iron-icon";
import "@polymer/paper-input/paper-input";
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-import { getSignedPath } from "../../../../src/data/auth";
-
-import "../../../../src/resources/ha-style";
-import "../../../../src/components/dialog/ha-paper-dialog";
-import { customElement } from "lit-element";
import { PaperDialogElement } from "@polymer/paper-dialog";
+import { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+
+import {
+ fetchHassioSnapshotInfo,
+ HassioSnapshotDetail,
+} from "../../../../src/data/hassio/snapshot";
+import { getSignedPath } from "../../../../src/data/auth";
import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot";
-import { fetchHassioSnapshotInfo } from "../../../../src/data/hassio";
+import { haStyleDialog } from "../../../../src/resources/styles";
+import { HomeAssistant } from "../../../../src/types";
+import { PolymerChangedEvent } from "../../../../src/polymer-types";
+
+import "../../../../src/components/dialog/ha-paper-dialog";
const _computeFolders = (folders) => {
const list: Array<{ slug: string; name: string; checked: boolean }> = [];
@@ -46,21 +59,179 @@ const _computeAddons = (addons) => {
}));
};
-@customElement("dialog-hassio-snapshot")
-class HassioSnapshotDialog extends PolymerElement {
- // Commented out because it breaks Polymer! Kept around for when we migrate
- // to Lit. Now just putting ts-ignore everywhere because we need this out.
- // Sorry future developer.
- // public hass!: HomeAssistant;
- // protected error?: string;
- // private snapshot?: any;
- // private dialogParams?: HassioSnapshotDialogParams;
- // private restoreHass!: boolean;
- // private snapshotPassword!: string;
+interface AddonItem {
+ slug: string;
+ name: string;
+ version: string;
+ checked: boolean | null | undefined;
+}
- static get template() {
+interface FolderItem {
+ slug: string;
+ name: string;
+ checked: boolean | null | undefined;
+}
+
+@customElement("dialog-hassio-snapshot")
+class HassioSnapshotDialog extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() private _error?: string;
+ @property() private snapshot?: HassioSnapshotDetail;
+ @property() private _folders!: FolderItem[];
+ @property() private _addons!: AddonItem[];
+ @property() private _dialogParams?: HassioSnapshotDialogParams;
+ @property() private _snapshotPassword!: string;
+ @property() private _restoreHass: boolean | null | undefined = true;
+ @query("#dialog") private _dialog!: PaperDialogElement;
+
+ public async showDialog(params: HassioSnapshotDialogParams) {
+ this.snapshot = await fetchHassioSnapshotInfo(this.hass, params.slug);
+ this._folders = _computeFolders(
+ this.snapshot.folders
+ ).sort((a: FolderItem, b: FolderItem) => (a.name > b.name ? 1 : -1));
+ this._addons = _computeAddons(
+ this.snapshot.addons
+ ).sort((a: AddonItem, b: AddonItem) => (a.name > b.name ? 1 : -1));
+
+ this._dialogParams = params;
+
+ try {
+ this._dialog.open();
+ } catch {
+ await this.showDialog(params);
+ }
+ }
+
+ protected render(): TemplateResult | void {
+ if (!this.snapshot) {
+ return html``;
+ }
return html`
-
-
-
-
- [[_computeName(snapshot)]]
-
-
- [[_computeType(snapshot.type)]] ([[_computeSize(snapshot.size)]])
- [[_formatDatetime(snapshot.date)]]
-
- Home Assistant:
-
- Home Assistant [[snapshot.homeassistant]]
-
-
- Folders:
-
-
- [[item.name]]
-
-
-
-
- Add-ons:
-
-
-
- [[item.name]] ([[item.version]])
-
-
-
-
-
-
-
-
- Error: [[error]]
-
- Actions:
-
-
- `;
+ `,
+ ];
}
- static get properties() {
- return {
- hass: Object,
- dialogParams: Object,
- snapshot: Object,
- _folders: Object,
- _addons: Object,
- restoreHass: {
- type: Boolean,
- value: true,
- },
- snapshotPassword: String,
- error: String,
- };
- }
-
- public async showDialog(params: HassioSnapshotDialogParams) {
- // @ts-ignore
- const snapshot = await fetchHassioSnapshotInfo(this.hass, params.slug);
- this.setProperties({
- dialogParams: params,
- snapshot,
- _folders: _computeFolders(snapshot.folders),
- _addons: _computeAddons(snapshot.addons),
+ private _updateFolders(item: FolderItem, value: boolean | null | undefined) {
+ this._folders = this._folders.map((folder) => {
+ if (folder.slug === item.slug) {
+ folder.checked = value;
+ }
+ return folder;
});
- (this.$.dialog as PaperDialogElement).open();
}
- protected _isFullSnapshot(type) {
- return type === "full";
+ private _updateAddons(item: AddonItem, value: boolean | null | undefined) {
+ this._addons = this._addons.map((addon) => {
+ if (addon.slug === item.slug) {
+ addon.checked = value;
+ }
+ return addon;
+ });
}
- protected _partialRestoreClicked() {
+ private _passwordInput(ev: PolymerChangedEvent
) {
+ this._snapshotPassword = ev.detail.value;
+ }
+
+ private _partialRestoreClicked() {
if (!confirm("Are you sure you want to restore this snapshot?")) {
return;
}
- // @ts-ignore
+
const addons = this._addons
.filter((addon) => addon.checked)
.map((addon) => addon.slug);
- // @ts-ignore
+
const folders = this._folders
.filter((folder) => folder.checked)
.map((folder) => folder.slug);
- const data = {
- // @ts-ignore
- homeassistant: this.restoreHass,
+ const data: {
+ homeassistant: boolean | null | undefined;
+ addons: any;
+ folders: any;
+ password?: string;
+ } = {
+ homeassistant: this._restoreHass,
addons,
folders,
};
- // @ts-ignore
- if (this.snapshot.protected) {
- // @ts-ignore
- data.password = this.snapshotPassword;
+
+ if (this.snapshot!.protected) {
+ data.password = this._snapshotPassword;
}
- // @ts-ignore
this.hass
.callApi(
"POST",
- // @ts-ignore
- `hassio/snapshots/${this.dialogParams!.slug}/restore/partial`,
+
+ `hassio/snapshots/${this.snapshot!.slug}/restore/partial`,
data
)
.then(
() => {
alert("Snapshot restored!");
- (this.$.dialog as PaperDialogElement).close();
+ this._dialog.close();
},
(error) => {
- // @ts-ignore
- this.error = error.body.message;
+ this._error = error.body.message;
}
);
}
- protected _fullRestoreClicked() {
+ private _fullRestoreClicked() {
if (!confirm("Are you sure you want to restore this snapshot?")) {
return;
}
- // @ts-ignore
- const data = this.snapshot.protected
- ? {
- password:
- // @ts-ignore
- this.snapshotPassword,
- }
+
+ const data = this.snapshot!.protected
+ ? { password: this._snapshotPassword }
: undefined;
- // @ts-ignore
+
this.hass
.callApi(
"POST",
- // @ts-ignore
- `hassio/snapshots/${this.dialogParams!.slug}/restore/full`,
+ `hassio/snapshots/${this.snapshot!.slug}/restore/full`,
data
)
.then(
() => {
alert("Snapshot restored!");
- (this.$.dialog as PaperDialogElement).close();
+ this._dialog.close();
},
(error) => {
- // @ts-ignore
- this.error = error.body.message;
+ this._error = error.body.message;
}
);
}
- protected _deleteClicked() {
+ private _deleteClicked() {
if (!confirm("Are you sure you want to delete this snapshot?")) {
return;
}
- // @ts-ignore
+
this.hass
- // @ts-ignore
- .callApi("POST", `hassio/snapshots/${this.dialogParams!.slug}/remove`)
+
+ .callApi("POST", `hassio/snapshots/${this.snapshot!.slug}/remove`)
.then(
() => {
- (this.$.dialog as PaperDialogElement).close();
- // @ts-ignore
- this.dialogParams!.onDelete();
+ this._dialog.close();
+ this._dialogParams!.onDelete();
},
(error) => {
- // @ts-ignore
- this.error = error.body.message;
+ this._error = error.body.message;
}
);
}
- protected async _downloadClicked() {
- let signedPath;
+ private async _downloadClicked() {
+ let signedPath: { path: string };
try {
signedPath = await getSignedPath(
- // @ts-ignore
this.hass,
- // @ts-ignore
- `/api/hassio/snapshots/${this.dialogParams!.slug}/download`
+ `/api/hassio/snapshots/${this.snapshot!.slug}/download`
);
} catch (err) {
alert(`Error: ${err.message}`);
return;
}
- // @ts-ignore
- const name = this._computeName(this.snapshot).replace(/[^a-z0-9]+/gi, "_");
+
+ const name = this._computeName.replace(/[^a-z0-9]+/gi, "_");
const a = document.createElement("a");
a.href = signedPath.path;
a.download = `Hass_io_${name}.tar`;
- this.$.dialog.appendChild(a);
+ this._dialog.appendChild(a);
a.click();
- this.$.dialog.removeChild(a);
+ this._dialog.removeChild(a);
}
- protected _computeName(snapshot) {
- return snapshot ? snapshot.name || snapshot.slug : "Unnamed snapshot";
+ private get _computeName() {
+ return this.snapshot
+ ? this.snapshot.name || this.snapshot.slug
+ : "Unnamed snapshot";
}
- protected _computeType(type) {
- return type === "full" ? "Full snapshot" : "Partial snapshot";
+ private get _computeSize() {
+ return Math.ceil(this.snapshot!.size * 10) / 10 + " MB";
}
- protected _computeSize(size) {
- return Math.ceil(size * 10) / 10 + " MB";
- }
-
- protected _sortAddons(a, b) {
- return a.name < b.name ? -1 : 1;
- }
-
- protected _formatDatetime(datetime) {
+ private _formatDatetime(datetime) {
return new Date(datetime).toLocaleDateString(navigator.language, {
weekday: "long",
year: "numeric",
@@ -375,13 +442,12 @@ class HassioSnapshotDialog extends PolymerElement {
});
}
- protected _dialogClosed() {
- this.setProperties({
- dialogParams: undefined,
- snapshot: undefined,
- _addons: [],
- _folders: [],
- });
+ private _dialogClosed() {
+ this._dialogParams = undefined;
+ this.snapshot = undefined;
+ this._snapshotPassword = "";
+ this._folders = [];
+ this._addons = [];
}
}
diff --git a/hassio/src/entrypoint.js b/hassio/src/entrypoint.ts
similarity index 100%
rename from hassio/src/entrypoint.js
rename to hassio/src/entrypoint.ts
diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts
index 4109572bcd..78954a6675 100644
--- a/hassio/src/hassio-main.ts
+++ b/hassio/src/hassio-main.ts
@@ -12,17 +12,19 @@ import {
import { HomeAssistant } from "../../src/types";
import {
fetchHassioSupervisorInfo,
- fetchHassioHostInfo,
- fetchHassioHassOsInfo,
fetchHassioHomeAssistantInfo,
HassioSupervisorInfo,
- HassioHostInfo,
- HassioHassOSInfo,
HassioHomeAssistantInfo,
- fetchHassioAddonInfo,
createHassioSession,
HassioPanelInfo,
-} from "../../src/data/hassio";
+} from "../../src/data/hassio/supervisor";
+import {
+ fetchHassioHostInfo,
+ fetchHassioHassOsInfo,
+ HassioHostInfo,
+ HassioHassOSInfo,
+} from "../../src/data/hassio/host";
+import { fetchHassioAddonInfo } from "../../src/data/hassio/addon";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
// Don't codesplit it, that way the dashboard always loads fast.
diff --git a/hassio/src/hassio-pages-with-tabs.ts b/hassio/src/hassio-pages-with-tabs.ts
index fad59ec5d9..0e40851be0 100644
--- a/hassio/src/hassio-pages-with-tabs.ts
+++ b/hassio/src/hassio-pages-with-tabs.ts
@@ -23,12 +23,11 @@ import scrollToTarget from "../../src/common/dom/scroll-to-target";
import { haStyle } from "../../src/resources/styles";
import { HomeAssistant, Route } from "../../src/types";
import { navigate } from "../../src/common/navigate";
+import { HassioHostInfo, HassioHassOSInfo } from "../../src/data/hassio/host";
import {
HassioSupervisorInfo,
- HassioHostInfo,
HassioHomeAssistantInfo,
- HassioHassOSInfo,
-} from "../../src/data/hassio";
+} from "../../src/data/hassio/supervisor";
const HAS_REFRESH_BUTTON = ["store", "snapshots"];
@@ -127,6 +126,10 @@ class HassioPagesWithTabs extends LitElement {
--paper-tabs-selection-bar-color: #fff;
text-transform: uppercase;
}
+ app-header,
+ app-toolbar {
+ background-color: var(--primary-color);
+ }
`,
];
}
diff --git a/hassio/src/hassio-tabs-router.ts b/hassio/src/hassio-tabs-router.ts
index a90a683fc0..a77d821bc8 100644
--- a/hassio/src/hassio-tabs-router.ts
+++ b/hassio/src/hassio-tabs-router.ts
@@ -11,12 +11,11 @@ import "./dashboard/hassio-dashboard";
import "./snapshots/hassio-snapshots";
import "./addon-store/hassio-addon-store";
import "./system/hassio-system";
+import { HassioHostInfo, HassioHassOSInfo } from "../../src/data/hassio/host";
import {
HassioSupervisorInfo,
- HassioHostInfo,
HassioHomeAssistantInfo,
- HassioHassOSInfo,
-} from "../../src/data/hassio";
+} from "../../src/data/hassio/supervisor";
@customElement("hassio-tabs-router")
class HassioTabsRouter extends HassRouterPage {
diff --git a/hassio/src/ingress-view/hassio-ingress-view.ts b/hassio/src/ingress-view/hassio-ingress-view.ts
index bcf6ed0e4a..1b42b46944 100644
--- a/hassio/src/ingress-view/hassio-ingress-view.ts
+++ b/hassio/src/ingress-view/hassio-ingress-view.ts
@@ -9,11 +9,11 @@ import {
css,
} from "lit-element";
import { HomeAssistant, Route } from "../../../src/types";
+import { createHassioSession } from "../../../src/data/hassio/supervisor";
import {
- createHassioSession,
HassioAddonDetails,
fetchHassioAddonInfo,
-} from "../../../src/data/hassio";
+} from "../../../src/data/hassio/addon";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-subpage";
diff --git a/hassio/src/resources/hassio-style.js b/hassio/src/resources/hassio-style.ts
similarity index 100%
rename from hassio/src/resources/hassio-style.js
rename to hassio/src/resources/hassio-style.ts
diff --git a/hassio/src/snapshots/hassio-snapshots.ts b/hassio/src/snapshots/hassio-snapshots.ts
index 73cc92bd5c..da968d7319 100644
--- a/hassio/src/snapshots/hassio-snapshots.ts
+++ b/hassio/src/snapshots/hassio-snapshots.ts
@@ -17,19 +17,20 @@ import "@polymer/paper-radio-group/paper-radio-group";
import "../components/hassio-card-content";
import { hassioStyle } from "../resources/hassio-style";
+import { haStyle } from "../../../src/resources/styles";
import { showHassioSnapshotDialog } from "../dialogs/snapshot/show-dialog-hassio-snapshot";
import { HomeAssistant } from "../../../src/types";
import {
HassioSnapshot,
- HassioSupervisorInfo,
fetchHassioSnapshots,
reloadHassioSnapshots,
HassioFullSnapshotCreateParams,
HassioPartialSnapshotCreateParams,
createHassioFullSnapshot,
createHassioPartialSnapshot,
-} from "../../../src/data/hassio";
+} from "../../../src/data/hassio/snapshot";
+import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
import { PolymerChangedEvent } from "../../../src/polymer-types";
import { fireEvent } from "../../../src/common/dom/fire_event";
@@ -334,6 +335,7 @@ class HassioSnapshots extends LitElement {
static get styles(): CSSResultArray {
return [
+ haStyle,
hassioStyle,
css`
paper-radio-group {
diff --git a/hassio/src/system/hassio-host-info.js b/hassio/src/system/hassio-host-info.js
deleted file mode 100644
index e64d2a83dc..0000000000
--- a/hassio/src/system/hassio-host-info.js
+++ /dev/null
@@ -1,201 +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 { EventsMixin } from "../../../src/mixins/events-mixin";
-
-import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio-markdown";
-
-class HassioHostInfo extends EventsMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
-
Host system
-
-
-
- Hostname |
- [[data.hostname]] |
-
-
- System |
- [[data.operating_system]] |
-
-
-
- Deployment |
- [[data.deployment]] |
-
-
-
-
-
- Hardware
-
-
-
- Change hostname
-
-
-
- Error: [[errors]]
-
-
-
-
- Reboot
-
-
- Shutdown
-
-
- Import from USB
-
-
- Update
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- data: Object,
- hassOsInfo: Object,
- errors: String,
- };
- }
-
- ready() {
- super.ready();
- this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
- }
-
- apiCalled(ev) {
- if (ev.detail.success) {
- this.errors = null;
- return;
- }
-
- var response = ev.detail.response;
-
- if (typeof response.body === "object") {
- this.errors = response.body.message || "Unknown error";
- } else {
- this.errors = response.body;
- }
- }
-
- _computeUpdateAvailable(data) {
- return data && data.version !== data.version_latest;
- }
-
- _featureAvailable(data, feature) {
- return data && data.features && data.features.includes(feature);
- }
-
- _showHardware() {
- this.hass
- .callApi("get", "hassio/hardware/info")
- .then(
- (resp) => this._objectToMarkdown(resp.data),
- () => "Error getting hardware info"
- )
- .then((content) => {
- showHassioMarkdownDialog(this, {
- title: "Hardware",
- content: content,
- });
- });
- }
-
- _objectToMarkdown(obj, indent = "") {
- let data = "";
- Object.keys(obj).forEach((key) => {
- if (typeof obj[key] !== "object") {
- data += `${indent}- ${key}: ${obj[key]}\n`;
- } else {
- data += `${indent}- ${key}:\n`;
- if (Array.isArray(obj[key])) {
- if (obj[key].length) {
- data +=
- `${indent} - ` + obj[key].join(`\n${indent} - `) + "\n";
- }
- } else {
- data += this._objectToMarkdown(obj[key], ` ${indent}`);
- }
- }
- });
- return data;
- }
-
- _changeHostnameClicked() {
- const curHostname = this.data.hostname;
- const hostname = prompt("Please enter a new hostname:", curHostname);
- if (hostname && hostname !== curHostname) {
- this.hass.callApi("post", "hassio/host/options", { hostname });
- }
- }
-}
-
-customElements.define("hassio-host-info", HassioHostInfo);
diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts
new file mode 100644
index 0000000000..b02dbf1b92
--- /dev/null
+++ b/hassio/src/system/hassio-host-info.ts
@@ -0,0 +1,239 @@
+import "@material/mwc-button";
+import "@polymer/paper-card/paper-card";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+} from "lit-element";
+
+import { hassioStyle } from "../resources/hassio-style";
+import { haStyle } from "../../../src/resources/styles";
+import {
+ HassioHostInfo as HassioHostInfoType,
+ HassioHassOSInfo,
+} from "../../../src/data/hassio/host";
+import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware";
+import { HomeAssistant } from "../../../src/types";
+import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio-markdown";
+
+import "../../../src/components/buttons/ha-call-api-button";
+
+@customElement("hassio-host-info")
+class HassioHostInfo extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public hostInfo!: HassioHostInfoType;
+ @property() public hassOsInfo!: HassioHassOSInfo;
+ @property() private _errors?: string;
+
+ public render(): TemplateResult | void {
+ return html`
+
+
+
Host system
+
+
+
+ Hostname |
+ ${this.hostInfo.hostname} |
+
+
+ System |
+ ${this.hostInfo.operating_system} |
+
+ ${this.hostInfo.deployment
+ ? html`
+
+ Deployment |
+ ${this.hostInfo.deployment} |
+
+ `
+ : ""}
+
+
+
+ Hardware
+
+ ${this.hostInfo.features.includes("hostname")
+ ? html`
+
+ Change hostname
+
+ `
+ : ""}
+ ${this._errors
+ ? html`
+
Error: ${this._errors}
+ `
+ : ""}
+
+
+ ${this.hostInfo.features.includes("reboot")
+ ? html`
+ Reboot
+ `
+ : ""}
+ ${this.hostInfo.features.includes("shutdown")
+ ? html`
+ Shutdown
+ `
+ : ""}
+ ${this.hostInfo.features.includes("hassos")
+ ? html`
+ Import from USB
+ `
+ : ""}
+ ${this.hostInfo.version !== this.hostInfo.version_latest
+ ? html`
+ Update
+ `
+ : ""}
+
+
+ `;
+ }
+
+ static get styles(): CSSResult[] {
+ return [
+ haStyle,
+ hassioStyle,
+ css`
+ paper-card {
+ display: inline-block;
+ width: 400px;
+ margin-left: 8px;
+ }
+ .card-content {
+ height: 200px;
+ color: var(--primary-text-color);
+ }
+ @media screen and (max-width: 830px) {
+ paper-card {
+ margin-top: 8px;
+ margin-left: 0;
+ width: 100%;
+ }
+ .card-content {
+ height: auto;
+ }
+ }
+ .info {
+ width: 100%;
+ }
+ .info td:nth-child(2) {
+ text-align: right;
+ }
+ .errors {
+ color: var(--google-red-500);
+ margin-top: 16px;
+ }
+ mwc-button.info {
+ max-width: calc(50% - 12px);
+ }
+ table.info {
+ margin-bottom: 10px;
+ }
+ .warning {
+ --mdc-theme-primary: var(--google-red-500);
+ }
+ `,
+ ];
+ }
+
+ protected firstUpdated(): void {
+ this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
+ }
+
+ private _apiCalled(ev): void {
+ if (ev.detail.success) {
+ this._errors = undefined;
+ return;
+ }
+
+ const response = ev.detail.response;
+
+ this._errors =
+ typeof response.body === "object"
+ ? response.body.message || "Unknown error"
+ : response.body;
+ }
+
+ private async _showHardware(): Promise {
+ try {
+ const content = this._objectToMarkdown(
+ await fetchHassioHardwareInfo(this.hass)
+ );
+ showHassioMarkdownDialog(this, {
+ title: "Hardware",
+ content,
+ });
+ } catch (err) {
+ showHassioMarkdownDialog(this, {
+ title: "Hardware",
+ content: "Error getting hardware info",
+ });
+ }
+ }
+
+ private _objectToMarkdown(obj, indent = ""): string {
+ let data = "";
+ Object.keys(obj).forEach((key) => {
+ if (typeof obj[key] !== "object") {
+ data += `${indent}- ${key}: ${obj[key]}\n`;
+ } else {
+ data += `${indent}- ${key}:\n`;
+ if (Array.isArray(obj[key])) {
+ if (obj[key].length) {
+ data +=
+ `${indent} - ` + obj[key].join(`\n${indent} - `) + "\n";
+ }
+ } else {
+ data += this._objectToMarkdown(obj[key], ` ${indent}`);
+ }
+ }
+ });
+
+ return data;
+ }
+
+ private _changeHostnameClicked(): void {
+ const curHostname = this.hostInfo.hostname;
+ const hostname = prompt("Please enter a new hostname:", curHostname);
+ if (hostname && hostname !== curHostname) {
+ this.hass.callApi("POST", "hassio/host/options", { hostname });
+ }
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-host-info": HassioHostInfo;
+ }
+}
diff --git a/hassio/src/system/hassio-supervisor-info.js b/hassio/src/system/hassio-supervisor-info.js
deleted file mode 100644
index b2a87b3dd4..0000000000
--- a/hassio/src/system/hassio-supervisor-info.js
+++ /dev/null
@@ -1,175 +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 { EventsMixin } from "../../../src/mixins/events-mixin";
-
-class HassioSupervisorInfo extends EventsMixin(PolymerElement) {
- static get template() {
- return html`
-
-
-
-
Hass.io supervisor
-
-
-
- Version |
- [[data.version]] |
-
-
- Latest version |
- [[data.last_version]] |
-
-
-
- Channel |
- [[data.channel]] |
-
-
-
-
-
- Error: [[errors]]
-
-
-
- Reload
-
- Update
-
-
- Leave beta channel
-
-
- Join beta channel
-
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- data: Object,
- errors: String,
- leaveBeta: {
- type: Object,
- value: { channel: "stable" },
- },
- };
- }
-
- ready() {
- super.ready();
- this.addEventListener("hass-api-called", (ev) => this.apiCalled(ev));
- }
-
- apiCalled(ev) {
- if (ev.detail.success) {
- this.errors = null;
- return;
- }
-
- var response = ev.detail.response;
-
- if (typeof response.body === "object") {
- this.errors = response.body.message || "Unknown error";
- } else {
- this.errors = response.body;
- }
- }
-
- computeUpdateAvailable(data) {
- return data.version !== data.last_version;
- }
-
- _equals(a, b) {
- return a === b;
- }
-
- _joinBeta() {
- if (
- !confirm(`WARNING:
-Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature.
-
-This inludes beta releases for:
-- Home Assistant (Release Candidates)
-- Hass.io supervisor
-- Host system`)
- ) {
- return;
- }
- const method = "post";
- const path = "hassio/supervisor/options";
- const data = { channel: "beta" };
-
- const eventData = {
- method: method,
- path: path,
- data: data,
- };
-
- this.hass
- .callApi(method, path, data)
- .then(
- (resp) => {
- eventData.success = true;
- eventData.response = resp;
- },
- (resp) => {
- eventData.success = false;
- eventData.response = resp;
- }
- )
- .then(() => {
- this.fire("hass-api-called", eventData);
- });
- }
-}
-
-customElements.define("hassio-supervisor-info", HassioSupervisorInfo);
diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts
new file mode 100644
index 0000000000..91854c0952
--- /dev/null
+++ b/hassio/src/system/hassio-supervisor-info.ts
@@ -0,0 +1,184 @@
+import "@material/mwc-button";
+import "@polymer/paper-card/paper-card";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+} from "lit-element";
+
+import { fireEvent } from "../../../src/common/dom/fire_event";
+import {
+ HassioSupervisorInfo as HassioSupervisorInfoType,
+ setSupervisorOption,
+ SupervisorOptions,
+} from "../../../src/data/hassio/supervisor";
+import { HomeAssistant } from "../../../src/types";
+import { hassioStyle } from "../resources/hassio-style";
+import { haStyle } from "../../../src/resources/styles";
+
+import "../../../src/components/buttons/ha-call-api-button";
+
+@customElement("hassio-supervisor-info")
+class HassioSupervisorInfo extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public supervisorInfo!: HassioSupervisorInfoType;
+ @property() private _errors?: string;
+
+ public render(): TemplateResult | void {
+ return html`
+
+
+
Hass.io supervisor
+
+
+
+ Version |
+ ${this.supervisorInfo.version} |
+
+
+ Latest version |
+ ${this.supervisorInfo.last_version} |
+
+ ${this.supervisorInfo.channel !== "stable"
+ ? html`
+
+ Channel |
+ ${this.supervisorInfo.channel} |
+
+ `
+ : ""}
+
+
+ ${this._errors
+ ? html`
+
Error: ${this._errors}
+ `
+ : ""}
+
+
+ Reload
+ ${this.supervisorInfo.version !== this.supervisorInfo.last_version
+ ? html`
+ Update
+ `
+ : ""}
+ ${this.supervisorInfo.channel === "beta"
+ ? html`
+ Leave beta channel
+ `
+ : ""}
+ ${this.supervisorInfo.channel === "stable"
+ ? html`
+ Join beta channel
+ `
+ : ""}
+
+
+ `;
+ }
+
+ static get styles(): CSSResult[] {
+ return [
+ haStyle,
+ hassioStyle,
+ css`
+ paper-card {
+ display: inline-block;
+ width: 400px;
+ }
+ .card-content {
+ height: 200px;
+ color: var(--primary-text-color);
+ }
+ @media screen and (max-width: 830px) {
+ paper-card {
+ width: 100%;
+ }
+ .card-content {
+ height: auto;
+ }
+ }
+ .info {
+ width: 100%;
+ }
+ .info td:nth-child(2) {
+ text-align: right;
+ }
+ .errors {
+ color: var(--google-red-500);
+ margin-top: 16px;
+ }
+ `,
+ ];
+ }
+
+ protected firstUpdated(): void {
+ this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
+ }
+
+ private _apiCalled(ev): void {
+ if (ev.detail.success) {
+ this._errors = undefined;
+ return;
+ }
+
+ const response = ev.detail.response;
+
+ this._errors =
+ typeof response.body === "object"
+ ? response.body.message || "Unknown error"
+ : response.body;
+ }
+
+ private async _joinBeta() {
+ if (
+ !confirm(`WARNING:
+Beta releases are for testers and early adopters and can contain unstable code changes. Make sure you have backups of your data before you activate this feature.
+
+This inludes beta releases for:
+- Home Assistant (Release Candidates)
+- Hass.io supervisor
+- Host system`)
+ ) {
+ return;
+ }
+ try {
+ const data: SupervisorOptions = { channel: "beta" };
+ await setSupervisorOption(this.hass, data);
+ const eventdata = {
+ success: true,
+ response: undefined,
+ path: "option",
+ };
+ fireEvent(this, "hass-api-called", eventdata);
+ } catch (err) {
+ this._errors = `Error joining beta channel, ${err.body?.message || err}`;
+ }
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-supervisor-info": HassioSupervisorInfo;
+ }
+}
diff --git a/hassio/src/system/hassio-supervisor-log.js b/hassio/src/system/hassio-supervisor-log.js
deleted file mode 100644
index e9b48c2e48..0000000000
--- a/hassio/src/system/hassio-supervisor-log.js
+++ /dev/null
@@ -1,64 +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 { ANSI_HTML_STYLE, parseTextToColoredPre } from "../ansi-to-html";
-
-class HassioSupervisorLog extends PolymerElement {
- static get template() {
- return html`
-
- ${ANSI_HTML_STYLE}
-
-
-
- Refresh
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- };
- }
-
- ready() {
- super.ready();
- this.loadData();
- }
-
- loadData() {
- this.hass.callApi("get", "hassio/supervisor/logs").then(
- (text) => {
- while (this.$.content.lastChild) {
- this.$.content.removeChild(this.$.content.lastChild);
- }
- this.$.content.appendChild(parseTextToColoredPre(text));
- },
- () => {
- this.$.content.innerHTML =
- 'Error fetching logs';
- }
- );
- }
-
- refresh() {
- this.loadData();
- }
-}
-
-customElements.define("hassio-supervisor-log", HassioSupervisorLog);
diff --git a/hassio/src/system/hassio-supervisor-log.ts b/hassio/src/system/hassio-supervisor-log.ts
new file mode 100644
index 0000000000..9524aac54c
--- /dev/null
+++ b/hassio/src/system/hassio-supervisor-log.ts
@@ -0,0 +1,87 @@
+import "@material/mwc-button";
+import "@polymer/paper-card/paper-card";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+ query,
+} from "lit-element";
+
+import { ANSI_HTML_STYLE, parseTextToColoredPre } from "../ansi-to-html";
+import { hassioStyle } from "../resources/hassio-style";
+import { haStyle } from "../../../src/resources/styles";
+import { HomeAssistant } from "../../../src/types";
+import { fetchSupervisorLogs } from "../../../src/data/hassio/supervisor";
+
+@customElement("hassio-supervisor-log")
+class HassioSupervisorLog extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() private _error?: string;
+ @query("#content") private _logContent!: HTMLDivElement;
+
+ public async connectedCallback(): Promise {
+ super.connectedCallback();
+ await this._loadData();
+ }
+
+ public render(): TemplateResult | void {
+ return html`
+
+ ${this._error
+ ? html`
+ ${this._error}
+ `
+ : ""}
+
+
+ Refresh
+
+
+ `;
+ }
+
+ static get styles(): CSSResult[] {
+ return [
+ haStyle,
+ hassioStyle,
+ ANSI_HTML_STYLE,
+ css`
+ pre {
+ white-space: pre-wrap;
+ }
+ .errors {
+ color: var(--google-red-500);
+ margin-bottom: 16px;
+ }
+ `,
+ ];
+ }
+
+ private async _loadData(): Promise {
+ this._error = undefined;
+ try {
+ const content = await fetchSupervisorLogs(this.hass);
+ while (this._logContent.lastChild) {
+ this._logContent.removeChild(this._logContent.lastChild as Node);
+ }
+ this._logContent.appendChild(parseTextToColoredPre(content));
+ } catch (err) {
+ this._error = `Failed to get supervisor logs, ${err.body?.message ||
+ err}`;
+ }
+ }
+
+ private async _refresh(): Promise {
+ await this._loadData();
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-supervisor-log": HassioSupervisorLog;
+ }
+}
diff --git a/hassio/src/system/hassio-system.js b/hassio/src/system/hassio-system.js
deleted file mode 100644
index a4d67b56ba..0000000000
--- a/hassio/src/system/hassio-system.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import { html } from "@polymer/polymer/lib/utils/html-tag";
-import { PolymerElement } from "@polymer/polymer/polymer-element";
-
-import "./hassio-host-info";
-import "./hassio-supervisor-info";
-import "./hassio-supervisor-log";
-
-class HassioSystem extends PolymerElement {
- static get template() {
- return html`
-
-
-
Information
-
-
-
System log
-
-
- `;
- }
-
- static get properties() {
- return {
- hass: Object,
- supervisorInfo: Object,
- hostInfo: Object,
- hassOsInfo: Object,
- };
- }
-}
-
-customElements.define("hassio-system", HassioSystem);
diff --git a/hassio/src/system/hassio-system.ts b/hassio/src/system/hassio-system.ts
new file mode 100644
index 0000000000..5fbff5de08
--- /dev/null
+++ b/hassio/src/system/hassio-system.ts
@@ -0,0 +1,76 @@
+import "@polymer/paper-menu-button/paper-menu-button";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ TemplateResult,
+} from "lit-element";
+
+import { hassioStyle } from "../resources/hassio-style";
+import { haStyle } from "../../../src/resources/styles";
+import {
+ HassioHostInfo,
+ HassioHassOSInfo,
+} from "../../../src/data/hassio/host";
+import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
+import { HomeAssistant } from "../../../src/types";
+
+import "./hassio-host-info";
+import "./hassio-supervisor-info";
+import "./hassio-supervisor-log";
+
+@customElement("hassio-system")
+class HassioSystem extends LitElement {
+ @property() public hass!: HomeAssistant;
+ @property() public supervisorInfo!: HassioSupervisorInfo;
+ @property() public hostInfo!: HassioHostInfo;
+ @property() public hassOsInfo!: HassioHassOSInfo;
+
+ public render(): TemplateResult | void {
+ return html`
+
+
Information
+
+
+
System log
+
+
+ `;
+ }
+
+ static get styles(): CSSResult[] {
+ return [
+ haStyle,
+ hassioStyle,
+ css`
+ .content {
+ margin: 4px;
+ color: var(--primary-text-color);
+ }
+ .title {
+ margin-top: 24px;
+ color: var(--primary-text-color);
+ font-size: 2em;
+ padding-left: 8px;
+ margin-bottom: 8px;
+ }
+ `,
+ ];
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-system": HassioSystem;
+ }
+}
diff --git a/package.json b/package.json
index 170891b349..80a981ee46 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"scripts": {
"build": "script/build_frontend",
"lint": "eslint src hassio/src gallery/src && tslint 'src/**/*.ts' 'hassio/src/**/*.ts' 'gallery/src/**/*.ts' 'cast/src/**/*.ts' 'test-mocha/**/*.ts' && tsc",
+ "lint-hassio": "eslint hassio/src && tslint 'hassio/src/**/*.ts'",
"mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts",
"test": "npm run lint && npm run mocha",
"docker_build": "sh ./script/docker_run.sh build $npm_package_version",
diff --git a/src/data/hassio.ts b/src/data/hassio.ts
deleted file mode 100644
index 46cbf64515..0000000000
--- a/src/data/hassio.ts
+++ /dev/null
@@ -1,227 +0,0 @@
-import { HomeAssistant, PanelInfo } from "../types";
-
-export type HassioPanelInfo = PanelInfo<
- | undefined
- | {
- ingress?: string;
- }
->;
-
-interface HassioResponse {
- data: T;
- result: "ok";
-}
-
-interface CreateSessionResponse {
- session: string;
-}
-
-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;
- slug: string;
- description: string;
- long_description: null | string;
- auto_update: boolean;
- url: null | string;
- detached: boolean;
- available: boolean;
- arch: "armhf" | "aarch64" | "i386" | "amd64";
- machine: any;
- homeassistant: string;
- repository: null | string;
- version: null | string;
- last_version: string;
- state: "none" | "started" | "stopped";
- boot: "auto" | "manual";
- build: boolean;
- options: object;
- network: null | object;
- host_network: boolean;
- host_pid: boolean;
- host_ipc: boolean;
- host_dbus: boolean;
- privileged: any;
- apparmor: "disable" | "default" | "profile";
- devices: string[];
- auto_uart: boolean;
- icon: boolean;
- logo: boolean;
- changelog: boolean;
- hassio_api: boolean;
- hassio_role: "default" | "homeassistant" | "manager" | "admin";
- homeassistant_api: boolean;
- auth_api: boolean;
- full_access: boolean;
- protected: boolean;
- rating: "1-6";
- stdin: boolean;
- webui: null | string;
- gpio: boolean;
- kernel_modules: boolean;
- devicetree: boolean;
- docker_api: boolean;
- audio: boolean;
- audio_input: null | string;
- audio_output: null | string;
- services_role: string[];
- discovery: string[];
- ip_address: string;
- ingress: boolean;
- ingress_entry: 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;
-
-export interface HassioSnapshot {
- slug: string;
- date: string;
- name: string;
- type: "full" | "partial";
- protected: boolean;
-}
-
-export interface HassioSnapshotDetail extends HassioSnapshot {
- size: string;
- homeassistant: string;
- addons: Array<{
- slug: "ADDON_SLUG";
- name: "NAME";
- version: "INSTALLED_VERSION";
- size: "SIZE_IN_MB";
- }>;
- repositories: string[];
- folders: string[];
-}
-
-export interface HassioFullSnapshotCreateParams {
- name: string;
- password?: string;
-}
-export interface HassioPartialSnapshotCreateParams {
- name: string;
- folders: string[];
- addons: string[];
- password?: string;
-}
-
-const hassioApiResultExtractor = (response: HassioResponse) =>
- response.data;
-
-export const createHassioSession = async (hass: HomeAssistant) => {
- const response = await hass.callApi>(
- "POST",
- "hassio/ingress/session"
- );
- document.cookie = `ingress_session=${response.data.session};path=/api/hassio_ingress/`;
-};
-
-export const reloadHassioAddons = (hass: HomeAssistant) =>
- hass.callApi("POST", `hassio/addons/reload`);
-
-export const fetchHassioAddonsInfo = (hass: HomeAssistant) =>
- hass
- .callApi>("GET", `hassio/addons`)
- .then(hassioApiResultExtractor);
-
-export const fetchHassioAddonInfo = (hass: HomeAssistant, addon: string) =>
- hass
- .callApi>(
- "GET",
- `hassio/addons/${addon}/info`
- )
- .then(hassioApiResultExtractor);
-
-export const fetchHassioSupervisorInfo = (hass: HomeAssistant) =>
- hass
- .callApi>(
- "GET",
- "hassio/supervisor/info"
- )
- .then(hassioApiResultExtractor);
-
-export const fetchHassioHostInfo = (hass: HomeAssistant) =>
- hass
- .callApi>("GET", "hassio/host/info")
- .then(hassioApiResultExtractor);
-
-export const fetchHassioHassOsInfo = (hass: HomeAssistant) =>
- hass
- .callApi>("GET", "hassio/hassos/info")
- .then(hassioApiResultExtractor);
-
-export const fetchHassioHomeAssistantInfo = (hass: HomeAssistant) =>
- hass
- .callApi>(
- "GET",
- "hassio/homeassistant/info"
- )
- .then(hassioApiResultExtractor);
-
-export const fetchHassioSnapshots = (hass: HomeAssistant) =>
- hass
- .callApi>(
- "GET",
- "hassio/snapshots"
- )
- .then((resp) => resp.data.snapshots);
-
-export const reloadHassioSnapshots = (hass: HomeAssistant) =>
- hass.callApi("POST", `hassio/snapshots/reload`);
-
-export const createHassioFullSnapshot = (
- hass: HomeAssistant,
- data: HassioFullSnapshotCreateParams
-) => hass.callApi("POST", "hassio/snapshots/new/full", data);
-
-export const createHassioPartialSnapshot = (
- hass: HomeAssistant,
- data: HassioPartialSnapshotCreateParams
-) => hass.callApi("POST", "hassio/snapshots/new/partial", data);
-
-export const fetchHassioSnapshotInfo = (
- hass: HomeAssistant,
- snapshot: string
-) =>
- hass
- .callApi>(
- "GET",
- `hassio/snapshots/${snapshot}/info`
- )
- .then(hassioApiResultExtractor);
diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts
new file mode 100644
index 0000000000..58eb5e47b2
--- /dev/null
+++ b/src/data/hassio/addon.ts
@@ -0,0 +1,176 @@
+import { HomeAssistant } from "../../types";
+import { HassioResponse, hassioApiResultExtractor } from "./common";
+
+export interface HassioAddonInfo {
+ name: string;
+ slug: string;
+ description: string;
+ repository: "core" | "local" | string;
+ version: string;
+ state: "none" | "started" | "stopped";
+ installed: string | undefined;
+ detached: boolean;
+ available: boolean;
+ build: boolean;
+ url: string | null;
+ icon: boolean;
+ logo: boolean;
+}
+
+export interface HassioAddonDetails extends HassioAddonInfo {
+ name: string;
+ slug: string;
+ description: string;
+ long_description: null | string;
+ auto_update: boolean;
+ url: null | string;
+ detached: boolean;
+ available: boolean;
+ arch: "armhf" | "aarch64" | "i386" | "amd64";
+ machine: any;
+ homeassistant: string;
+ last_version: string;
+ boot: "auto" | "manual";
+ build: boolean;
+ options: object;
+ network: null | object;
+ network_description: null | object;
+ host_network: boolean;
+ host_pid: boolean;
+ host_ipc: boolean;
+ host_dbus: boolean;
+ privileged: any;
+ apparmor: "disable" | "default" | "profile";
+ devices: string[];
+ auto_uart: boolean;
+ icon: boolean;
+ logo: boolean;
+ changelog: boolean;
+ hassio_api: boolean;
+ hassio_role: "default" | "homeassistant" | "manager" | "admin";
+ homeassistant_api: boolean;
+ auth_api: boolean;
+ full_access: boolean;
+ protected: boolean;
+ rating: "1-6";
+ stdin: boolean;
+ webui: null | string;
+ gpio: boolean;
+ kernel_modules: boolean;
+ devicetree: boolean;
+ docker_api: boolean;
+ audio: boolean;
+ audio_input: null | string;
+ audio_output: null | string;
+ services_role: string[];
+ discovery: string[];
+ ip_address: string;
+ ingress: boolean;
+ ingress_panel: boolean;
+ ingress_entry: null | string;
+ ingress_url: null | string;
+}
+
+export interface HassioAddonsInfo {
+ addons: HassioAddonInfo[];
+ repositories: HassioAddonRepository[];
+}
+
+export interface HassioAddonSetSecurityParams {
+ protected?: boolean;
+}
+
+export interface HassioAddonRepository {
+ slug: string;
+ name: string;
+ source: string;
+ url: string;
+ maintainer: string;
+}
+
+export interface HassioAddonSetOptionParams {
+ audio_input?: string | null;
+ audio_output?: string | null;
+ options?: object | null;
+ boot?: "auto" | "manual";
+ auto_update?: boolean;
+ ingress_panel?: boolean;
+ network?: object | null;
+}
+
+export const reloadHassioAddons = async (hass: HomeAssistant) => {
+ await hass.callApi>("POST", `hassio/addons/reload`);
+};
+
+export const fetchHassioAddonsInfo = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>("GET", `hassio/addons`)
+ );
+};
+
+export const fetchHassioAddonInfo = async (
+ hass: HomeAssistant,
+ slug: string
+) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ `hassio/addons/${slug}/info`
+ )
+ );
+};
+
+export const fetchHassioAddonChangelog = async (
+ hass: HomeAssistant,
+ slug: string
+) => {
+ return hass.callApi("GET", `hassio/addons/${slug}/changelog`);
+};
+
+export const fetchHassioAddonLogs = async (
+ hass: HomeAssistant,
+ slug: string
+) => {
+ return hass.callApi("GET", `hassio/addons/${slug}/logs`);
+};
+
+export const setHassioAddonOption = async (
+ hass: HomeAssistant,
+ slug: string,
+ data: HassioAddonSetOptionParams
+) => {
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/options`,
+ data
+ );
+};
+
+export const setHassioAddonSecurity = async (
+ hass: HomeAssistant,
+ slug: string,
+ data: HassioAddonSetSecurityParams
+) => {
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/security`,
+ data
+ );
+};
+
+export const installHassioAddon = async (hass: HomeAssistant, slug: string) => {
+ return hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/install`
+ );
+};
+
+export const uninstallHassioAddon = async (
+ hass: HomeAssistant,
+ slug: string
+) => {
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/uninstall`
+ );
+};
diff --git a/src/data/hassio/common.ts b/src/data/hassio/common.ts
new file mode 100644
index 0000000000..b96d410c51
--- /dev/null
+++ b/src/data/hassio/common.ts
@@ -0,0 +1,7 @@
+export interface HassioResponse {
+ data: T;
+ result: "ok";
+}
+
+export const hassioApiResultExtractor = (response: HassioResponse) =>
+ response.data;
diff --git a/src/data/hassio/hardware.ts b/src/data/hassio/hardware.ts
new file mode 100644
index 0000000000..ee18581f2b
--- /dev/null
+++ b/src/data/hassio/hardware.ts
@@ -0,0 +1,37 @@
+import { HomeAssistant } from "../../types";
+import { HassioResponse, hassioApiResultExtractor } from "./common";
+
+export interface HassioHardwareAudioDevice {
+ device?: string;
+ name: string;
+}
+
+interface HassioHardwareAudioList {
+ audio: { input: any; output: any };
+}
+
+export interface HassioHardwareInfo {
+ serial: string[];
+ input: string[];
+ disk: string[];
+ gpio: string[];
+ audio: object;
+}
+
+export const fetchHassioHardwareAudio = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/hardware/audio"
+ )
+ );
+};
+
+export const fetchHassioHardwareInfo = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/hardware/info"
+ )
+ );
+};
diff --git a/src/data/hassio/host.ts b/src/data/hassio/host.ts
new file mode 100644
index 0000000000..f058114c27
--- /dev/null
+++ b/src/data/hassio/host.ts
@@ -0,0 +1,29 @@
+import { HomeAssistant } from "../../types";
+import { HassioResponse, hassioApiResultExtractor } from "./common";
+
+export type HassioHostInfo = any;
+
+export interface HassioHassOSInfo {
+ version: string;
+ version_cli: string;
+ version_latest: string;
+ version_cli_latest: string;
+ board: "ova" | "rpi";
+}
+
+export const fetchHassioHostInfo = async (hass: HomeAssistant) => {
+ const response = await hass.callApi>(
+ "GET",
+ "hassio/host/info"
+ );
+ return hassioApiResultExtractor(response);
+};
+
+export const fetchHassioHassOsInfo = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/hassos/info"
+ )
+ );
+};
diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts
new file mode 100644
index 0000000000..1dabe53559
--- /dev/null
+++ b/src/data/hassio/snapshot.ts
@@ -0,0 +1,81 @@
+import { HomeAssistant } from "../../types";
+import { HassioResponse, hassioApiResultExtractor } from "./common";
+
+export interface HassioSnapshot {
+ slug: string;
+ date: string;
+ name: string;
+ type: "full" | "partial";
+ protected: boolean;
+}
+
+export interface HassioSnapshotDetail extends HassioSnapshot {
+ size: number;
+ homeassistant: string;
+ addons: Array<{
+ slug: "ADDON_SLUG";
+ name: "NAME";
+ version: "INSTALLED_VERSION";
+ size: "SIZE_IN_MB";
+ }>;
+ repositories: string[];
+ folders: string[];
+}
+
+export interface HassioFullSnapshotCreateParams {
+ name: string;
+ password?: string;
+}
+export interface HassioPartialSnapshotCreateParams {
+ name: string;
+ folders: string[];
+ addons: string[];
+ password?: string;
+}
+
+export const fetchHassioSnapshots = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/snapshots"
+ )
+ ).snapshots;
+};
+
+export const fetchHassioSnapshotInfo = async (
+ hass: HomeAssistant,
+ snapshot: string
+) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ `hassio/snapshots/${snapshot}/info`
+ )
+ );
+};
+
+export const reloadHassioSnapshots = async (hass: HomeAssistant) => {
+ await hass.callApi>("POST", `hassio/snapshots/reload`);
+};
+
+export const createHassioFullSnapshot = async (
+ hass: HomeAssistant,
+ data: HassioFullSnapshotCreateParams
+) => {
+ await hass.callApi>(
+ "POST",
+ `hassio/snapshots/new/full`,
+ data
+ );
+};
+
+export const createHassioPartialSnapshot = async (
+ hass: HomeAssistant,
+ data: HassioFullSnapshotCreateParams
+) => {
+ await hass.callApi>(
+ "POST",
+ `hassio/snapshots/new/partial`,
+ data
+ );
+};
diff --git a/src/data/hassio/supervisor.ts b/src/data/hassio/supervisor.ts
new file mode 100644
index 0000000000..166cea837f
--- /dev/null
+++ b/src/data/hassio/supervisor.ts
@@ -0,0 +1,61 @@
+import { HomeAssistant, PanelInfo } from "../../types";
+import { HassioResponse, hassioApiResultExtractor } from "./common";
+
+export type HassioHomeAssistantInfo = any;
+export type HassioSupervisorInfo = any;
+
+export type HassioPanelInfo = PanelInfo<
+ | undefined
+ | {
+ ingress?: string;
+ }
+>;
+
+export interface CreateSessionResponse {
+ session: string;
+}
+
+export interface SupervisorOptions {
+ channel: "beta" | "dev" | "stable";
+}
+
+export const fetchHassioHomeAssistantInfo = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/homeassistant/info"
+ )
+ );
+};
+
+export const fetchHassioSupervisorInfo = async (hass: HomeAssistant) => {
+ return hassioApiResultExtractor(
+ await hass.callApi>(
+ "GET",
+ "hassio/supervisor/info"
+ )
+ );
+};
+
+export const fetchSupervisorLogs = async (hass: HomeAssistant) => {
+ return hass.callApi("GET", "hassio/supervisor/logs");
+};
+
+export const createHassioSession = async (hass: HomeAssistant) => {
+ const response = await hass.callApi>(
+ "POST",
+ "hassio/ingress/session"
+ );
+ document.cookie = `ingress_session=${response.data.session};path=/api/hassio_ingress/`;
+};
+
+export const setSupervisorOption = async (
+ hass: HomeAssistant,
+ data: SupervisorOptions
+) => {
+ await hass.callApi>(
+ "POST",
+ "hassio/supervisor/options",
+ data
+ );
+};