Fix hassio

This commit is contained in:
Paulus Schoutsen 2019-04-09 15:50:02 -07:00
parent cbe5355d38
commit fe73213643
4 changed files with 118 additions and 72 deletions

View File

@ -11,18 +11,51 @@ import { getSignedPath } from "../../../../src/auth/data";
import "../../../../src/resources/ha-style"; import "../../../../src/resources/ha-style";
import "../../../../src/components/dialog/ha-paper-dialog"; import "../../../../src/components/dialog/ha-paper-dialog";
import { customElement } from "lit-element"; import { customElement } from "lit-element";
import { HomeAssistant } from "../../../../src/types";
import { PaperDialogElement } from "@polymer/paper-dialog"; import { PaperDialogElement } from "@polymer/paper-dialog";
import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot"; import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot";
import { fetchHassioSnapshotInfo } from "../../../../src/data/hassio";
const _computeFolders = (folders) => {
const list: Array<{ slug: string; name: string; checked: boolean }> = [];
if (folders.includes("homeassistant")) {
list.push({
slug: "homeassistant",
name: "Home Assistant configuration",
checked: true,
});
}
if (folders.includes("ssl")) {
list.push({ slug: "ssl", name: "SSL", checked: true });
}
if (folders.includes("share")) {
list.push({ slug: "share", name: "Share", checked: true });
}
if (folders.includes("addons/local")) {
list.push({ slug: "addons/local", name: "Local add-ons", checked: true });
}
return list;
};
const _computeAddons = (addons) => {
return addons.map((addon) => ({
slug: addon.slug,
name: addon.name,
version: addon.version,
checked: true,
}));
};
@customElement("dialog-hassio-snapshot") @customElement("dialog-hassio-snapshot")
class HassioSnapshotDialog extends PolymerElement { class HassioSnapshotDialog extends PolymerElement {
public hass!: HomeAssistant; // Commented out because it breaks Polymer! Kept around for when we migrate
protected error?: string; // to Lit. Now just putting ts-ignore everywhere because we need this out.
private snapshot?: any; // Sorry future developer.
private dialogParams?: HassioSnapshotDialogParams; // public hass!: HomeAssistant;
private restoreHass!: boolean; // protected error?: string;
private snapshotPassword!: string; // private snapshot?: any;
// private dialogParams?: HassioSnapshotDialogParams;
// private restoreHass!: boolean;
// private snapshotPassword!: string;
static get template() { static get template() {
return html` return html`
@ -89,22 +122,18 @@ class HassioSnapshotDialog extends PolymerElement {
<paper-checkbox checked="{{restoreHass}}"> <paper-checkbox checked="{{restoreHass}}">
Home Assistant [[snapshot.homeassistant]] Home Assistant [[snapshot.homeassistant]]
</paper-checkbox> </paper-checkbox>
<template is="dom-if" if="[[snapshot.addons.length]]"> <template is="dom-if" if="[[_folders.length]]">
<div>Folders:</div> <div>Folders:</div>
<template is="dom-repeat" items="[[snapshot.folders]]"> <template is="dom-repeat" items="[[_folders]]">
<paper-checkbox checked="{{item.checked}}"> <paper-checkbox checked="{{item.checked}}">
[[item.name]] [[item.name]]
</paper-checkbox> </paper-checkbox>
</template> </template>
</template> </template>
<template is="dom-if" if="[[snapshot.addons.length]]"> <template is="dom-if" if="[[_addons.length]]">
<div>Add-ons:</div> <div>Add-ons:</div>
<paper-dialog-scrollable> <paper-dialog-scrollable>
<template <template is="dom-repeat" items="[[_addons]]" sort="_sortAddons">
is="dom-repeat"
items="[[snapshot.addons]]"
sort="_sortAddons"
>
<paper-checkbox checked="{{item.checked}}"> <paper-checkbox checked="{{item.checked}}">
[[item.name]] <span class="details">([[item.version]])</span> [[item.name]] <span class="details">([[item.version]])</span>
</paper-checkbox> </paper-checkbox>
@ -151,7 +180,10 @@ class HassioSnapshotDialog extends PolymerElement {
static get properties() { static get properties() {
return { return {
hass: Object, hass: Object,
dialogParams: Object,
snapshot: Object, snapshot: Object,
_folders: Object,
_addons: Object,
restoreHass: { restoreHass: {
type: Boolean, type: Boolean,
value: true, value: true,
@ -161,49 +193,16 @@ class HassioSnapshotDialog extends PolymerElement {
}; };
} }
public showDialog(params: HassioSnapshotDialogParams) { public async showDialog(params: HassioSnapshotDialogParams) {
this.dialogParams = params; // @ts-ignore
this.hass.callApi("GET", `hassio/snapshots/${params.slug}/info`).then( const snapshot = await fetchHassioSnapshotInfo(this.hass, params.slug);
(info: any) => { this.setProperties({
info.data.folders = this._computeFolders(info.data.folders); dialogParams: params,
info.data.addons = this._computeAddons(info.data.addons); snapshot,
this.setProperties({ snapshot: info.data }); _folders: _computeFolders(snapshot.folders),
(this.$.dialog as PaperDialogElement).open(); _addons: _computeAddons(snapshot.addons),
}, });
() => { (this.$.dialog as PaperDialogElement).open();
this.dialogParams = undefined;
}
);
}
protected _computeFolders(folders) {
const list: Array<{ slug: string; name: string; checked: boolean }> = [];
if (folders.includes("homeassistant")) {
list.push({
slug: "homeassistant",
name: "Home Assistant configuration",
checked: true,
});
}
if (folders.includes("ssl")) {
list.push({ slug: "ssl", name: "SSL", checked: true });
}
if (folders.includes("share")) {
list.push({ slug: "share", name: "Share", checked: true });
}
if (folders.includes("addons/local")) {
list.push({ slug: "addons/local", name: "Local add-ons", checked: true });
}
return list;
}
protected _computeAddons(addons) {
return addons.map((addon) => ({
slug: addon.slug,
name: addon.name,
version: addon.version,
checked: true,
}));
} }
protected _isFullSnapshot(type) { protected _isFullSnapshot(type) {
@ -214,26 +213,32 @@ class HassioSnapshotDialog extends PolymerElement {
if (!confirm("Are you sure you want to restore this snapshot?")) { if (!confirm("Are you sure you want to restore this snapshot?")) {
return; return;
} }
const addons = this.snapshot.addons // @ts-ignore
const addons = this._addons
.filter((addon) => addon.checked) .filter((addon) => addon.checked)
.map((addon) => addon.slug); .map((addon) => addon.slug);
const folders = this.snapshot.folders // @ts-ignore
const folders = this._folders
.filter((folder) => folder.checked) .filter((folder) => folder.checked)
.map((folder) => folder.slug); .map((folder) => folder.slug);
const data = { const data = {
// @ts-ignore
homeassistant: this.restoreHass, homeassistant: this.restoreHass,
addons, addons,
folders, folders,
}; };
// @ts-ignore
if (this.snapshot.protected) { if (this.snapshot.protected) {
// @ts-ignore // @ts-ignore
data.password = this.snapshotPassword; data.password = this.snapshotPassword;
} }
// @ts-ignore
this.hass this.hass
.callApi( .callApi(
"POST", "POST",
// @ts-ignore
`hassio/snapshots/${this.dialogParams!.slug}/restore/partial`, `hassio/snapshots/${this.dialogParams!.slug}/restore/partial`,
data data
) )
@ -243,6 +248,7 @@ class HassioSnapshotDialog extends PolymerElement {
(this.$.dialog as PaperDialogElement).close(); (this.$.dialog as PaperDialogElement).close();
}, },
(error) => { (error) => {
// @ts-ignore
this.error = error.body.message; this.error = error.body.message;
} }
); );
@ -252,12 +258,19 @@ class HassioSnapshotDialog extends PolymerElement {
if (!confirm("Are you sure you want to restore this snapshot?")) { if (!confirm("Are you sure you want to restore this snapshot?")) {
return; return;
} }
// @ts-ignore
const data = this.snapshot.protected const data = this.snapshot.protected
? { password: this.snapshotPassword } ? {
password:
// @ts-ignore
this.snapshotPassword,
}
: undefined; : undefined;
// @ts-ignore
this.hass this.hass
.callApi( .callApi(
"POST", "POST",
// @ts-ignore
`hassio/snapshots/${this.dialogParams!.slug}/restore/full`, `hassio/snapshots/${this.dialogParams!.slug}/restore/full`,
data data
) )
@ -267,6 +280,7 @@ class HassioSnapshotDialog extends PolymerElement {
(this.$.dialog as PaperDialogElement).close(); (this.$.dialog as PaperDialogElement).close();
}, },
(error) => { (error) => {
// @ts-ignore
this.error = error.body.message; this.error = error.body.message;
} }
); );
@ -276,14 +290,18 @@ class HassioSnapshotDialog extends PolymerElement {
if (!confirm("Are you sure you want to delete this snapshot?")) { if (!confirm("Are you sure you want to delete this snapshot?")) {
return; return;
} }
// @ts-ignore
this.hass this.hass
// @ts-ignore
.callApi("POST", `hassio/snapshots/${this.dialogParams!.slug}/remove`) .callApi("POST", `hassio/snapshots/${this.dialogParams!.slug}/remove`)
.then( .then(
() => { () => {
(this.$.dialog as PaperDialogElement).close(); (this.$.dialog as PaperDialogElement).close();
// @ts-ignore
this.dialogParams!.onDelete(); this.dialogParams!.onDelete();
}, },
(error) => { (error) => {
// @ts-ignore
this.error = error.body.message; this.error = error.body.message;
} }
); );
@ -293,13 +311,16 @@ class HassioSnapshotDialog extends PolymerElement {
let signedPath; let signedPath;
try { try {
signedPath = await getSignedPath( signedPath = await getSignedPath(
// @ts-ignore
this.hass, this.hass,
// @ts-ignore
`/api/hassio/snapshots/${this.dialogParams!.slug}/download` `/api/hassio/snapshots/${this.dialogParams!.slug}/download`
); );
} catch (err) { } catch (err) {
alert(`Error: ${err.message}`); alert(`Error: ${err.message}`);
return; return;
} }
// @ts-ignore
const name = this._computeName(this.snapshot).replace(/[^a-z0-9]+/gi, "_"); const name = this._computeName(this.snapshot).replace(/[^a-z0-9]+/gi, "_");
const a = document.createElement("a"); const a = document.createElement("a");
a.href = signedPath.path; a.href = signedPath.path;
@ -310,7 +331,7 @@ class HassioSnapshotDialog extends PolymerElement {
} }
protected _computeName(snapshot) { protected _computeName(snapshot) {
return snapshot.name || snapshot.slug; return snapshot ? snapshot.name || snapshot.slug : "Unnamed snapshot";
} }
protected _computeType(type) { protected _computeType(type) {
@ -337,8 +358,12 @@ class HassioSnapshotDialog extends PolymerElement {
} }
protected _dialogClosed() { protected _dialogClosed() {
this.dialogParams = undefined; this.setProperties({
this.snapshot = undefined; dialogParams: undefined,
snapshot: undefined,
_addons: [],
_folders: [],
});
} }
} }

View File

@ -7,6 +7,10 @@ import { PolymerElement } from "@polymer/polymer";
import { HomeAssistant } from "../../src/types"; import { HomeAssistant } from "../../src/types";
// Don't codesplit it, that way the dashboard always loads fast. // Don't codesplit it, that way the dashboard always loads fast.
import "./dashboard/hassio-dashboard"; import "./dashboard/hassio-dashboard";
// Don't codesplit the others, because it breaks the UI when pushed to a Pi
import "./snapshots/hassio-snapshots";
import "./addon-store/hassio-addon-store";
import "./system/hassio-system";
import { import {
HassioSupervisorInfo, HassioSupervisorInfo,
HassioHostInfo, HassioHostInfo,
@ -27,15 +31,12 @@ class HassioTabsRouter extends HassRouterPage {
}, },
snapshots: { snapshots: {
tag: "hassio-snapshots", tag: "hassio-snapshots",
load: () => import("./snapshots/hassio-snapshots"),
}, },
store: { store: {
tag: "hassio-addon-store", tag: "hassio-addon-store",
load: () => import("./addon-store/hassio-addon-store"),
}, },
system: { system: {
tag: "hassio-system", tag: "hassio-system",
load: () => import("./system/hassio-system"),
}, },
}, },
}; };

View File

@ -31,11 +31,7 @@ module.exports = {
}, },
], ],
}, },
optimization: { optimization: webpackBase.optimization(latestBuild),
...webpackBase.optimization(latestBuild),
// Try #4323432 to get hass.io to wrk on es5
concatenateModules: false,
},
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
__DEV__: JSON.stringify(!isProdBuild), __DEV__: JSON.stringify(!isProdBuild),

View File

@ -110,6 +110,19 @@ export interface HassioSnapshot {
protected: boolean; 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 { export interface HassioFullSnapshotCreateParams {
name: string; name: string;
password?: string; password?: string;
@ -191,3 +204,14 @@ export const createHassioPartialSnapshot = (
hass: HomeAssistant, hass: HomeAssistant,
data: HassioPartialSnapshotCreateParams data: HassioPartialSnapshotCreateParams
) => hass.callApi<unknown>("POST", "hassio/snapshots/new/partial", data); ) => hass.callApi<unknown>("POST", "hassio/snapshots/new/partial", data);
export const fetchHassioSnapshotInfo = (
hass: HomeAssistant,
snapshot: string
) =>
hass
.callApi<HassioResponse<HassioSnapshotDetail>>(
"GET",
`hassio/snapshots/${snapshot}/info`
)
.then(hassioApiResultExtractor);