diff --git a/hassio/src/components/supervisor-formfield-label.ts b/hassio/src/components/supervisor-formfield-label.ts
new file mode 100644
index 0000000000..e173c0c44c
--- /dev/null
+++ b/hassio/src/components/supervisor-formfield-label.ts
@@ -0,0 +1,55 @@
+import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators";
+import "../../../src/components/ha-svg-icon";
+
+@customElement("supervisor-formfield-label")
+class SupervisorFormfieldLabel extends LitElement {
+ @property({ type: String }) public label!: string;
+
+ @property({ type: String }) public imageUrl?: string;
+
+ @property({ type: String }) public iconPath?: string;
+
+ @property({ type: String }) public version?: string;
+
+ protected render(): TemplateResult {
+ return html`
+ ${this.imageUrl
+ ? html`
`
+ : this.iconPath
+ ? html``
+ : ""}
+ ${this.label}
+ ${this.version
+ ? html`(${this.version})`
+ : ""}
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ :host {
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ }
+ .label {
+ margin-right: 4px;
+ }
+ .version {
+ color: var(--secondary-text-color);
+ }
+ .icon {
+ max-height: 22px;
+ max-width: 22px;
+ margin-right: 8px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "supervisor-formfield-label": SupervisorFormfieldLabel;
+ }
+}
diff --git a/hassio/src/components/supervisor-snapshot-content.ts b/hassio/src/components/supervisor-snapshot-content.ts
new file mode 100644
index 0000000000..8c87976329
--- /dev/null
+++ b/hassio/src/components/supervisor-snapshot-content.ts
@@ -0,0 +1,418 @@
+import { mdiFolder, mdiHomeAssistant, mdiPuzzle } from "@mdi/js";
+import { PaperInputElement } from "@polymer/paper-input/paper-input";
+import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
+import { customElement, property } from "lit/decorators";
+import { atLeastVersion } from "../../../src/common/config/version";
+import { formatDate } from "../../../src/common/datetime/format_date";
+import { formatDateTime } from "../../../src/common/datetime/format_date_time";
+import "../../../src/components/ha-checkbox";
+import "../../../src/components/ha-formfield";
+import "../../../src/components/ha-radio";
+import type { HaRadio } from "../../../src/components/ha-radio";
+import {
+ HassioFullSnapshotCreateParams,
+ HassioPartialSnapshotCreateParams,
+ HassioSnapshotDetail,
+} from "../../../src/data/hassio/snapshot";
+import { Supervisor } from "../../../src/data/supervisor/supervisor";
+import { PolymerChangedEvent } from "../../../src/polymer-types";
+import { HomeAssistant } from "../../../src/types";
+import "./supervisor-formfield-label";
+
+interface CheckboxItem {
+ slug: string;
+ checked: boolean;
+ name: string;
+}
+
+interface AddonCheckboxItem extends CheckboxItem {
+ version: string;
+}
+
+const _computeFolders = (folders): CheckboxItem[] => {
+ const list: CheckboxItem[] = [];
+ if (folders.includes("homeassistant")) {
+ list.push({
+ slug: "homeassistant",
+ name: "Home Assistant configuration",
+ checked: false,
+ });
+ }
+ if (folders.includes("ssl")) {
+ list.push({ slug: "ssl", name: "SSL", checked: false });
+ }
+ if (folders.includes("share")) {
+ list.push({ slug: "share", name: "Share", checked: false });
+ }
+ if (folders.includes("addons/local")) {
+ list.push({ slug: "addons/local", name: "Local add-ons", checked: false });
+ }
+ return list.sort((a, b) => (a.name > b.name ? 1 : -1));
+};
+
+const _computeAddons = (addons): AddonCheckboxItem[] =>
+ addons
+ .map((addon) => ({
+ slug: addon.slug,
+ name: addon.name,
+ version: addon.version,
+ checked: false,
+ }))
+ .sort((a, b) => (a.name > b.name ? 1 : -1));
+
+@customElement("supervisor-snapshot-content")
+export class SupervisorSnapshotContent extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property({ attribute: false }) public supervisor?: Supervisor;
+
+ @property({ attribute: false }) public snapshot?: HassioSnapshotDetail;
+
+ @property() public snapshotType: HassioSnapshotDetail["type"] = "full";
+
+ @property({ attribute: false }) public folders?: CheckboxItem[];
+
+ @property({ attribute: false }) public addons?: AddonCheckboxItem[];
+
+ @property({ type: Boolean }) public homeAssistant = false;
+
+ @property({ type: Boolean }) public snapshotHasPassword = false;
+
+ @property() public snapshotName = "";
+
+ @property() public snapshotPassword = "";
+
+ public willUpdate(changedProps) {
+ super.willUpdate(changedProps);
+ if (!this.hasUpdated) {
+ this.folders = _computeFolders(
+ this.snapshot
+ ? this.snapshot.folders
+ : ["homeassistant", "ssl", "share", "media", "addons/local"]
+ );
+ this.addons = _computeAddons(
+ this.snapshot
+ ? this.snapshot.addons
+ : this.supervisor?.supervisor.addons
+ );
+ this.snapshotType = this.snapshot?.type || "full";
+ this.snapshotName = this.snapshot?.name || "";
+ this.snapshotHasPassword = this.snapshot?.protected || false;
+ }
+ }
+
+ protected render(): TemplateResult {
+ if (!this.supervisor) {
+ return html``;
+ }
+ const foldersSection =
+ this.snapshotType === "partial" ? this._getSection("folders") : undefined;
+ const addonsSection =
+ this.snapshotType === "partial" ? this._getSection("addons") : undefined;
+
+ return html`
+ ${this.snapshot
+ ? html`
+ ${this.snapshot.type === "full"
+ ? this.supervisor.localize("snapshot.full_snapshot")
+ : this.supervisor.localize("snapshot.partial_snapshot")}
+ (${Math.ceil(this.snapshot.size * 10) / 10 + " MB"})
+ ${formatDateTime(new Date(this.snapshot.date), this.hass.locale)}
+
`
+ : html`
+ `}
+ ${!this.snapshot || this.snapshot.type === "full"
+ ? html`
+
+
+
+
+
+
+
+
+
+
`
+ : ""}
+ ${this.snapshot && this.snapshotType === "partial"
+ ? html`
+ ${this.snapshot.homeassistant
+ ? html`
+
+ `}
+ >
+ {
+ this.homeAssistant = !this.homeAssistant;
+ }}
+ >
+
+
+ `
+ : ""}
+ `
+ : ""}
+ ${this.snapshotType === "partial"
+ ? html`
+ ${foldersSection?.templates.length
+ ? html`
+
+ `}
+ >
+
+
+
+ ${foldersSection.templates}
+ `
+ : ""}
+ ${addonsSection?.templates.length
+ ? html`
+
+ `}
+ >
+
+
+
+ ${addonsSection.templates}
+ `
+ : ""}
+ `
+ : ""}
+ ${!this.snapshot
+ ? html`
+
+ `
+ : ""}
+ ${this.snapshotHasPassword
+ ? html`
+
+
+ `
+ : ""}
+ `;
+ }
+
+ static get styles(): CSSResultGroup {
+ return css`
+ ha-checkbox {
+ --mdc-checkbox-touch-target-size: 16px;
+ display: block;
+ margin: 4px 12px 8px 0;
+ }
+ ha-formfield {
+ display: contents;
+ }
+ supervisor-formfield-label {
+ display: inline-flex;
+ align-items: center;
+ }
+ paper-input[type="password"] {
+ display: block;
+ margin: 4px 0 4px 16px;
+ }
+ .details {
+ color: var(--secondary-text-color);
+ }
+ .section-content {
+ display: flex;
+ flex-direction: column;
+ margin-left: 16px;
+ }
+ .security {
+ margin-top: 16px;
+ }
+ .snapshot-types {
+ display: flex;
+ }
+ .sub-header {
+ margin-top: 8px;
+ }
+ `;
+ }
+
+ public snapshotDetails():
+ | HassioPartialSnapshotCreateParams
+ | HassioFullSnapshotCreateParams {
+ const data: any = {};
+
+ if (!this.snapshot) {
+ data.name = this.snapshotName || formatDate(new Date(), this.hass.locale);
+ }
+
+ if (this.snapshotHasPassword) {
+ data.password = this.snapshotPassword;
+ }
+
+ if (this.snapshotType === "full") {
+ return data;
+ }
+
+ const addons = this.addons
+ ?.filter((addon) => addon.checked)
+ .map((addon) => addon.slug);
+ const folders = this.folders
+ ?.filter((folder) => folder.checked)
+ .map((folder) => folder.slug);
+
+ if (addons?.length) {
+ data.addons = addons;
+ }
+ if (folders?.length) {
+ data.folders = folders;
+ }
+ if (this.homeAssistant) {
+ data.homeassistant = this.homeAssistant;
+ }
+
+ return data;
+ }
+
+ private _getSection(section: string) {
+ const templates: TemplateResult[] = [];
+ const addons =
+ section === "addons"
+ ? new Map(
+ this.supervisor!.addon.addons.map((item) => [item.slug, item])
+ )
+ : undefined;
+ let checkedItems = 0;
+ this[section].forEach((item) => {
+ templates.push(html`
+ `}
+ >
+
+
+ `);
+
+ if (item.checked) {
+ checkedItems++;
+ }
+ });
+
+ const checked = checkedItems === this[section].length;
+
+ return {
+ templates,
+ checked,
+ indeterminate: !checked && checkedItems !== 0,
+ };
+ }
+
+ private _handleRadioValueChanged(ev: CustomEvent) {
+ const input = ev.currentTarget as HaRadio;
+ this[input.name] = input.value;
+ }
+
+ private _handleTextValueChanged(ev: PolymerChangedEvent) {
+ const input = ev.currentTarget as PaperInputElement;
+ this[input.name!] = ev.detail.value;
+ }
+
+ private _toggleHasPassword(): void {
+ this.snapshotHasPassword = !this.snapshotHasPassword;
+ }
+
+ private _toggleSection(ev): void {
+ const section = ev.currentTarget.section;
+
+ this[section] = (section === "addons" ? this.addons : this.folders)!.map(
+ (item) => ({
+ ...item,
+ checked: ev.currentTarget.checked,
+ })
+ );
+ }
+
+ private _updateSectionEntry(ev): void {
+ const item = ev.currentTarget.item;
+ const section = ev.currentTarget.section;
+ this[section] = this[section].map((entry) =>
+ entry.slug === item.slug
+ ? {
+ ...entry,
+ checked: ev.currentTarget.checked,
+ }
+ : entry
+ );
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "supervisor-snapshot-content": SupervisorSnapshotContent;
+ }
+}
diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts
index 4afbf0acae..2bc817fe2b 100755
--- a/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts
+++ b/hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts
@@ -1,91 +1,43 @@
import "@material/mwc-button";
-import "@polymer/paper-input/paper-input";
-import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
-import { customElement, property, state } from "lit/decorators";
-import { formatDate } from "../../../../src/common/datetime/format_date";
+import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../../src/common/dom/fire_event";
-import { compare } from "../../../../src/common/string/compare";
import "../../../../src/components/buttons/ha-progress-button";
-import "../../../../src/components/ha-checkbox";
-import type { HaCheckbox } from "../../../../src/components/ha-checkbox";
import { createCloseHeading } from "../../../../src/components/ha-dialog";
-import "../../../../src/components/ha-formfield";
-import "../../../../src/components/ha-radio";
-import type { HaRadio } from "../../../../src/components/ha-radio";
-import "../../../../src/components/ha-settings-row";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import {
createHassioFullSnapshot,
createHassioPartialSnapshot,
- HassioFullSnapshotCreateParams,
- HassioPartialSnapshotCreateParams,
- HassioSnapshot,
} from "../../../../src/data/hassio/snapshot";
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
-import { PolymerChangedEvent } from "../../../../src/polymer-types";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
+import "../../components/supervisor-snapshot-content";
+import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content";
import { HassioCreateSnapshotDialogParams } from "./show-dialog-hassio-create-snapshot";
-interface CheckboxItem {
- slug: string;
- checked: boolean;
- name?: string;
- version?: string;
-}
-
-const folderList = () => [
- {
- slug: "homeassistant",
- checked: true,
- },
- { slug: "ssl", checked: true },
- { slug: "share", checked: true },
- { slug: "media", checked: true },
- { slug: "addons/local", checked: true },
-];
-
@customElement("dialog-hassio-create-snapshot")
class HassioCreateSnapshotDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
- @state() private _snapshotName = "";
-
- @state() private _snapshotPassword = "";
-
- @state() private _snapshotHasPassword = false;
-
- @state() private _snapshotType: HassioSnapshot["type"] = "full";
-
@state() private _dialogParams?: HassioCreateSnapshotDialogParams;
- @state() private _addonList: CheckboxItem[] = [];
+ @state() private _error?: string;
- @state() private _folderList: CheckboxItem[] = folderList();
+ @state() private _creatingSnapshot = false;
- @state() private _error = "";
+ @query("supervisor-snapshot-content")
+ private _snapshotContent!: SupervisorSnapshotContent;
public showDialog(params: HassioCreateSnapshotDialogParams) {
this._dialogParams = params;
- this._addonList = this._dialogParams.supervisor.supervisor.addons
- .map((addon) => ({
- slug: addon.slug,
- name: addon.name,
- version: addon.version,
- checked: true,
- }))
- .sort((a, b) => compare(a.name, b.name));
- this._snapshotType = "full";
- this._error = "";
- this._folderList = folderList();
- this._snapshotHasPassword = false;
- this._snapshotPassword = "";
- this._snapshotName = "";
+ this._creatingSnapshot = false;
}
public closeDialog() {
this._dialogParams = undefined;
+ this._creatingSnapshot = false;
+ this._error = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
@@ -102,173 +54,29 @@ class HassioCreateSnapshotDialog extends LitElement {
this._dialogParams.supervisor.localize("snapshot.create_snapshot")
)}
>
-
-
-
-
- ${this._dialogParams.supervisor.localize("snapshot.type")}:
-
-
`
+ : html`
-
-
-
-
-
-
-
-
-
- ${
- this._snapshotType === "full"
- ? undefined
- : html`
- ${this._dialogParams.supervisor.localize("snapshot.folders")}:
-
- ${this._folderList.map(
- (folder, idx) => html`
-
-
-
-
- ${this._dialogParams!.supervisor.localize(
- `snapshot.folder.${folder.slug}`
- )}
-
-
- `
- )}
-
-
- ${this._dialogParams.supervisor.localize("snapshot.addons")}:
-
- ${this._addonList.map(
- (addon, idx) => html`
-
-
-
-
- ${addon.name}
- (${addon.version})
-
-
-
- `
- )}
-
- `
- }
- ${this._dialogParams.supervisor.localize("snapshot.security")}:
-
-
-
-
-
- ${this._dialogParams.supervisor.localize(
- "snapshot.password_protection"
- )}
-
-
-
-
-
- ${
- this._snapshotHasPassword
- ? html`
-
-
- `
- : undefined
- }
- ${
- this._error !== ""
- ? html` ${this._error}
`
- : undefined
- }
+ `}
+ ${this._error ? html`Error: ${this._error}
` : ""}
${this._dialogParams.supervisor.localize("common.close")}
-
+
${this._dialogParams.supervisor.localize("snapshot.create")}
-
+
`;
}
- private _handleTextValueChanged(ev: PolymerChangedEvent) {
- const input = ev.currentTarget as PaperInputElement;
- this[`_${input.name}`] = ev.detail.value;
- }
-
- private _handleCheckboxValueChanged(ev: CustomEvent) {
- const input = ev.currentTarget as HaCheckbox;
- this._snapshotHasPassword = input.checked;
- }
-
- private _handleRadioValueChanged(ev: CustomEvent) {
- const input = ev.currentTarget as HaRadio;
- this[`_${input.name}`] = input.value;
- }
-
- private _folderChecked(ev) {
- const { idx, checked } = ev.currentTarget!;
- this._folderList = this._folderList.map((folder, curIdx) =>
- curIdx === idx ? { ...folder, checked } : folder
- );
- }
-
- private _addonChecked(ev) {
- const { idx, checked } = ev.currentTarget!;
- this._addonList = this._addonList.map((addon, curIdx) =>
- curIdx === idx ? { ...addon, checked } : addon
- );
- }
-
- private async _createSnapshot(ev: CustomEvent): Promise {
+ private async _createSnapshot(): Promise {
if (this._dialogParams!.supervisor.info.state !== "running") {
showAlertDialog(this, {
title: this._dialogParams!.supervisor.localize(
@@ -282,40 +90,26 @@ class HassioCreateSnapshotDialog extends LitElement {
});
return;
}
- const button = ev.currentTarget as any;
- button.progress = true;
+ const snapshotDetails = this._snapshotContent.snapshotDetails();
+ this._creatingSnapshot = true;
this._error = "";
- if (this._snapshotHasPassword && !this._snapshotPassword.length) {
+ if (
+ this._snapshotContent.snapshotHasPassword &&
+ !this._snapshotContent.snapshotPassword.length
+ ) {
this._error = this._dialogParams!.supervisor.localize(
"snapshot.enter_password"
);
- button.progress = false;
+ this._creatingSnapshot = false;
return;
}
- const name = this._snapshotName || formatDate(new Date(), this.hass.locale);
try {
- if (this._snapshotType === "full") {
- const data: HassioFullSnapshotCreateParams = { name };
- if (this._snapshotHasPassword) {
- data.password = this._snapshotPassword;
- }
- await createHassioFullSnapshot(this.hass, data);
+ if (this._snapshotContent.snapshotType === "full") {
+ await createHassioFullSnapshot(this.hass, snapshotDetails);
} else {
- const data: HassioPartialSnapshotCreateParams = {
- name,
- folders: this._folderList
- .filter((folder) => folder.checked)
- .map((folder) => folder.slug),
- addons: this._addonList
- .filter((addon) => addon.checked)
- .map((addon) => addon.slug),
- };
- if (this._snapshotHasPassword) {
- data.password = this._snapshotPassword;
- }
- await createHassioPartialSnapshot(this.hass, data);
+ await createHassioPartialSnapshot(this.hass, snapshotDetails);
}
this._dialogParams!.onCreate();
@@ -323,7 +117,7 @@ class HassioCreateSnapshotDialog extends LitElement {
} catch (err) {
this._error = extractApiErrorMessage(err);
}
- button.progress = false;
+ this._creatingSnapshot = false;
}
static get styles(): CSSResultGroup {
@@ -331,22 +125,9 @@ class HassioCreateSnapshotDialog extends LitElement {
haStyle,
haStyleDialog,
css`
- .error {
- color: var(--error-color);
- }
- paper-input[type="password"] {
+ ha-circular-progress {
display: block;
- margin: 4px 0 4px 16px;
- }
- span.version {
- color: var(--secondary-text-color);
- }
- .checkbox-section {
- display: grid;
- }
- .checkbox-line {
- display: inline-flex;
- align-items: center;
+ text-align: center;
}
`,
];
diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
index 81f21bb908..3ffbfcd53d 100755
--- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
+++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts
@@ -1,13 +1,12 @@
-import "@material/mwc-button";
-import { mdiClose, mdiDelete, mdiDownload, mdiHistory } from "@mdi/js";
-import "@polymer/paper-checkbox/paper-checkbox";
-import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox";
-import "@polymer/paper-input/paper-input";
+import { ActionDetail } from "@material/mwc-list";
+import "@material/mwc-list/mwc-list-item";
+import { mdiDotsVertical } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
-import { customElement, property, state } from "lit/decorators";
-import { formatDateTime } from "../../../../src/common/datetime/format_date_time";
+import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../../src/common/dom/fire_event";
-import "../../../../src/components/ha-header-bar";
+import "../../../../src/components/buttons/ha-progress-button";
+import "../../../../src/components/ha-button-menu";
+import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-svg-icon";
import { getSignedPath } from "../../../../src/data/auth";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
@@ -15,106 +14,45 @@ import {
fetchHassioSnapshotInfo,
HassioSnapshotDetail,
} from "../../../../src/data/hassio/snapshot";
-import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../../src/dialogs/generic/show-dialog-box";
import { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
-import { PolymerChangedEvent } from "../../../../src/polymer-types";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
+import "../../components/supervisor-snapshot-content";
+import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content";
import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot";
-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) =>
- addons.map((addon) => ({
- slug: addon.slug,
- name: addon.name,
- version: addon.version,
- checked: true,
- }));
-
-interface AddonItem {
- slug: string;
- name: string;
- version: string;
- checked: boolean | null | undefined;
-}
-
-interface FolderItem {
- slug: string;
- name: string;
- checked: boolean | null | undefined;
-}
-
@customElement("dialog-hassio-snapshot")
class HassioSnapshotDialog
extends LitElement
implements HassDialog {
@property({ attribute: false }) public hass!: HomeAssistant;
- @property({ attribute: false }) public supervisor?: Supervisor;
-
@state() private _error?: string;
- @state() private _onboarding = false;
-
@state() private _snapshot?: HassioSnapshotDetail;
- @state() private _folders!: FolderItem[];
-
- @state() private _addons!: AddonItem[];
-
@state() private _dialogParams?: HassioSnapshotDialogParams;
- @state() private _snapshotPassword!: string;
+ @state() private _restoringSnapshot = false;
- @state() private _restoreHass = true;
+ @query("supervisor-snapshot-content")
+ private _snapshotContent!: SupervisorSnapshotContent;
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;
- this._onboarding = params.onboarding ?? false;
- this.supervisor = params.supervisor;
- if (!this._snapshot.homeassistant) {
- this._restoreHass = false;
- }
+ this._restoringSnapshot = false;
}
public closeDialog() {
- this._dialogParams = undefined;
this._snapshot = undefined;
- this._snapshotPassword = "";
- this._folders = [];
- this._addons = [];
+ this._dialogParams = undefined;
+ this._restoringSnapshot = false;
+ this._error = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
@@ -123,121 +61,41 @@ class HassioSnapshotDialog
return html``;
}
return html`
-
-
-
- ${this._computeName}
-
-
-
-
-
-
- ${this._snapshot.type === "full"
- ? "Full snapshot"
- : "Partial snapshot"}
- (${this._computeSize})
- ${formatDateTime(new Date(this._snapshot.date), this.hass.locale)}
-
- ${this._snapshot.homeassistant
- ? html`Home Assistant:
- {
- this._restoreHass = (ev.target as PaperCheckboxElement).checked!;
- }}"
- >
- Home Assistant
- (${this._snapshot.homeassistant})
- `
- : ""}
- ${this._folders.length
- ? html`
- Folders:
-
- ${this._folders.map(
- (item) => html`
-
- this._updateFolders(
- item,
- (ev.target as PaperCheckboxElement).checked
- )}"
- >
- ${item.name}
-
- `
- )}
-
- `
- : ""}
- ${this._addons.length
- ? html`
- Add-on:
-
- ${this._addons.map(
- (item) => html`
-
- this._updateAddons(
- item,
- (ev.target as PaperCheckboxElement).checked
- )}"
- >
- ${item.name}
- (${item.version})
-
- `
- )}
-
- `
- : ""}
- ${this._snapshot.protected
- ? html`
-
- `
- : ""}
- ${this._error ? html` Error: ${this._error}
` : ""}
+
+ ${this._restoringSnapshot
+ ? html` `
+ : html`
+ `}
+ ${this._error ? html`Error: ${this._error}
` : ""}
-
-
-
- Restore Selected
-
- ${!this._onboarding
- ? html`
-
-
-
- Delete Snapshot
-
- `
- : ""}
-
-
- ${this._snapshot.type === "full"
- ? html`
-
-
- Restore Everything
-
- `
- : ""}
- ${!this._onboarding
- ? html`
-
- Download Snapshot
- `
- : ""}
-
+
+ Restore
+
+
+ ev.stopPropagation()}
+ >
+
+
+
+ Download Snapshot
+ Delete Snapshot
+
`;
}
@@ -247,83 +105,47 @@ class HassioSnapshotDialog
haStyle,
haStyleDialog,
css`
- paper-checkbox {
+ ha-svg-icon {
+ color: var(--primary-text-color);
+ }
+ ha-circular-progress {
display: block;
- margin: 4px;
- }
- mwc-button ha-svg-icon {
- margin-right: 4px;
- }
- .button-row {
- display: grid;
- gap: 8px;
- margin-right: 8px;
- }
- .details {
- color: var(--secondary-text-color);
- }
- .warning,
- .error {
- color: var(--error-color);
- }
- .buttons li {
- list-style-type: none;
- }
- .buttons .icon {
- margin-right: 16px;
- }
- .no-margin-top {
- margin-top: 0;
- }
- span.version {
- color: var(--secondary-text-color);
- }
- ha-header-bar {
- --mdc-theme-on-primary: var(--primary-text-color);
- --mdc-theme-primary: var(--mdc-theme-surface);
- flex-shrink: 0;
- }
- /* overrule the ha-style-dialog max-height on small screens */
- @media all and (max-width: 450px), all and (max-height: 500px) {
- ha-header-bar {
- --mdc-theme-primary: var(--app-header-background-color);
- --mdc-theme-on-primary: var(--app-header-text-color, white);
- }
+ text-align: center;
}
`,
];
}
- private _updateFolders(item: FolderItem, value: boolean | null | undefined) {
- this._folders = this._folders.map((folder) => {
- if (folder.slug === item.slug) {
- folder.checked = value;
- }
- return folder;
- });
+ private _handleMenuAction(ev: CustomEvent) {
+ switch (ev.detail.index) {
+ case 0:
+ this._downloadClicked();
+ break;
+ case 1:
+ this._deleteClicked();
+ break;
+ }
}
- private _updateAddons(item: AddonItem, value: boolean | null | undefined) {
- this._addons = this._addons.map((addon) => {
- if (addon.slug === item.slug) {
- addon.checked = value;
- }
- return addon;
- });
+ private async _restoreClicked() {
+ const snapshotDetails = this._snapshotContent.snapshotDetails();
+ this._restoringSnapshot = true;
+ if (this._snapshotContent.snapshotType === "full") {
+ await this._fullRestoreClicked(snapshotDetails);
+ } else {
+ await this._partialRestoreClicked(snapshotDetails);
+ }
+ this._restoringSnapshot = false;
}
- private _passwordInput(ev: PolymerChangedEvent) {
- this._snapshotPassword = ev.detail.value;
- }
-
- private async _partialRestoreClicked() {
+ private async _partialRestoreClicked(snapshotDetails) {
if (
- this.supervisor !== undefined &&
- this.supervisor.info.state !== "running"
+ this._dialogParams?.supervisor !== undefined &&
+ this._dialogParams?.supervisor.info.state !== "running"
) {
await showAlertDialog(this, {
title: "Could not restore snapshot",
- text: `Restoring a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`,
+ text: `Restoring a snapshot is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
});
return;
}
@@ -337,40 +159,16 @@ class HassioSnapshotDialog
return;
}
- const addons = this._addons
- .filter((addon) => addon.checked)
- .map((addon) => addon.slug);
-
- const folders = this._folders
- .filter((folder) => folder.checked)
- .map((folder) => folder.slug);
-
- const data: {
- homeassistant: boolean;
- addons: any;
- folders: any;
- password?: string;
- } = {
- homeassistant: this._restoreHass,
- addons,
- folders,
- };
-
- if (this._snapshot!.protected) {
- data.password = this._snapshotPassword;
- }
-
- if (!this._onboarding) {
+ if (!this._dialogParams?.onboarding) {
this.hass
.callApi(
"POST",
`hassio/snapshots/${this._snapshot!.slug}/restore/partial`,
- data
+ snapshotDetails
)
.then(
() => {
- alert("Snapshot restored!");
this.closeDialog();
},
(error) => {
@@ -381,20 +179,20 @@ class HassioSnapshotDialog
fireEvent(this, "restoring");
fetch(`/api/hassio/snapshots/${this._snapshot!.slug}/restore/partial`, {
method: "POST",
- body: JSON.stringify(data),
+ body: JSON.stringify(snapshotDetails),
});
this.closeDialog();
}
}
- private async _fullRestoreClicked() {
+ private async _fullRestoreClicked(snapshotDetails) {
if (
- this.supervisor !== undefined &&
- this.supervisor.info.state !== "running"
+ this._dialogParams?.supervisor !== undefined &&
+ this._dialogParams?.supervisor.info.state !== "running"
) {
await showAlertDialog(this, {
title: "Could not restore snapshot",
- text: `Restoring a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`,
+ text: `Restoring a snapshot is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
});
return;
}
@@ -409,19 +207,15 @@ class HassioSnapshotDialog
return;
}
- const data = this._snapshot!.protected
- ? { password: this._snapshotPassword }
- : undefined;
- if (!this._onboarding) {
+ if (!this._dialogParams?.onboarding) {
this.hass
.callApi(
"POST",
`hassio/snapshots/${this._snapshot!.slug}/restore/full`,
- data
+ snapshotDetails
)
.then(
() => {
- alert("Snapshot restored!");
this.closeDialog();
},
(error) => {
@@ -432,7 +226,7 @@ class HassioSnapshotDialog
fireEvent(this, "restoring");
fetch(`/api/hassio/snapshots/${this._snapshot!.slug}/restore/full`, {
method: "POST",
- body: JSON.stringify(data),
+ body: JSON.stringify(snapshotDetails),
});
this.closeDialog();
}
@@ -473,7 +267,9 @@ class HassioSnapshotDialog
`/api/hassio/snapshots/${this._snapshot!.slug}/download`
);
} catch (err) {
- alert(`Error: ${extractApiErrorMessage(err)}`);
+ await showAlertDialog(this, {
+ text: extractApiErrorMessage(err),
+ });
return;
}
@@ -504,10 +300,6 @@ class HassioSnapshotDialog
? this._snapshot.name || this._snapshot.slug
: "Unnamed snapshot";
}
-
- private get _computeSize() {
- return Math.ceil(this._snapshot!.size * 10) / 10 + " MB";
- }
}
declare global {
diff --git a/src/components/ha-button-menu.ts b/src/components/ha-button-menu.ts
index 52e27af49e..8223b68d1c 100644
--- a/src/components/ha-button-menu.ts
+++ b/src/components/ha-button-menu.ts
@@ -12,6 +12,8 @@ export class HaButtonMenu extends LitElement {
@property({ type: Boolean }) public disabled = false;
+ @property({ type: Boolean }) public fixed = false;
+
@query("mwc-menu", true) private _menu?: Menu;
public get items() {
@@ -29,6 +31,7 @@ export class HaButtonMenu extends LitElement {
diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts
index 0281f0d9a4..ba34776228 100644
--- a/src/data/hassio/snapshot.ts
+++ b/src/data/hassio/snapshot.ts
@@ -42,11 +42,10 @@ export interface HassioFullSnapshotCreateParams {
name: string;
password?: string;
}
-export interface HassioPartialSnapshotCreateParams {
- name: string;
+export interface HassioPartialSnapshotCreateParams
+ extends HassioFullSnapshotCreateParams {
folders?: string[];
addons?: string[];
- password?: string;
homeassistant?: boolean;
}
diff --git a/src/translations/en.json b/src/translations/en.json
index f25ae07695..79f039cfe5 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -3901,14 +3901,15 @@
"create_snapshot": "Create snapshot",
"create": "Create",
"created": "Created",
- "name": "Name",
- "type": "Type",
+ "name": "Snapshot name",
+ "type": "Snapshot type",
+ "select_type": "Select what to restore",
"security": "Security",
"full_snapshot": "Full snapshot",
"partial_snapshot": "Partial snapshot",
"addons": "Add-ons",
"folders": "Folders",
- "password": "Password",
+ "password": "Snapshot password",
"password_protection": "Password protection",
"password_protected": "password protected",
"enter_password": "Please enter a password.",