Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 365 additions & 0 deletions hassio/src/dialogs/snapshot/dialog-hassio-create-snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,365 @@
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
css,
CSSResult,
customElement,
html,
internalProperty,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
internalProperty,
state,

LitElement,
property,
TemplateResult,
} from "lit-element";
import { formatDate } from "../../../../src/common/datetime/format_date";
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,
haStyleScrollbar,
} from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { HassioCreateSnapshotDialogParams } from "./show-dialog-hassio-create-snapshot";

interface CheckboxItem {
slug: string;
checked: boolean;
name?: string;
version?: string;
}

@customElement("dialog-hassio-create-snapshot")
class HassioCreateSnapshotDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@internalProperty() private _snapshotName = "";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@internalProperty() private _snapshotName = "";
@state() private _snapshotName = "";


@internalProperty() private _snapshotPassword = "";

@internalProperty() private _snapshotHasPassword = false;
Comment thread
ludeeus marked this conversation as resolved.
Outdated

@internalProperty() private _snapshotType: HassioSnapshot["type"] = "full";
Comment thread
ludeeus marked this conversation as resolved.
Outdated

@internalProperty() private _dialogParams?: HassioCreateSnapshotDialogParams;

@internalProperty() private _addonList: CheckboxItem[] = [];

@internalProperty() private _folderList: CheckboxItem[] = [
Comment thread
ludeeus marked this conversation as resolved.
Outdated
{
slug: "homeassistant",
checked: true,
},
{ slug: "ssl", checked: true },
{ slug: "share", checked: true },
{ slug: "media", checked: true },
{ slug: "addons/local", checked: true },
];

@internalProperty() private _error = "";
Comment thread
ludeeus marked this conversation as resolved.
Outdated

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));
}

public closeDialog() {
this._dialogParams = undefined;
Comment thread
ludeeus marked this conversation as resolved.
fireEvent(this, "dialog-closed", { dialog: this.localName });
}

protected render(): TemplateResult {
if (!this._dialogParams) {
return html``;
}
return html`
<ha-dialog
class="ha-scrollbar"
Comment thread
ludeeus marked this conversation as resolved.
Outdated
open
@closing=${this.closeDialog}
.heading=${createCloseHeading(
this.hass,
this._dialogParams.supervisor.localize("snapshot.create_snapshot")
)}
>
<div class="content">
<paper-input
name="snapshotName"
.label=${this._dialogParams.supervisor.localize("snapshot.name")}
.value=${this._snapshotName}
@value-changed=${this._handleTextValueChanged}
>
</paper-input>
<div class="snapshot-types">
<div>
${this._dialogParams.supervisor.localize("snapshot.type")}:
</div>
<ha-formfield
.label=${this._dialogParams.supervisor.localize(
"snapshot.full_snapshot"
)}
>
<ha-radio
@change=${this._handleRadioValueChanged}
value="full"
name="snapshotType"
.checked=${this._snapshotType === "full"}
>
</ha-radio>
</ha-formfield>
<ha-formfield
.label=${this._dialogParams.supervisor.localize(
"snapshot.partial_snapshot"
)}
>
<ha-radio
@change=${this._handleRadioValueChanged}
value="partial"
name="snapshotType"
.checked=${this._snapshotType === "partial"}
>
</ha-radio>
</ha-formfield>
</div>

${this._snapshotType === "full"
? undefined
: html`
${this._dialogParams.supervisor.localize("snapshot.folders")}:
<div class="checkbox-section">
${this._folderList.map(
(folder, idx) => html`
<div class="checkbox-line">
<ha-checkbox
.idx=${idx}
.checked=${folder.checked}
@change=${this._folderChecked}
slot="prefix"
>
</ha-checkbox>
<span>
${this._dialogParams!.supervisor.localize(
`snapshot.folder.${folder.slug}`
)}
</span>
</div>
`
)}
</div>

${this._dialogParams.supervisor.localize("snapshot.addons")}:
<div class="checkbox-section">
${this._addonList.map(
(addon, idx) => html`
<div class="checkbox-line">
<ha-checkbox
.idx=${idx}
.checked=${addon.checked}
@change=${this._addonChecked}
slot="prefix"
>
</ha-checkbox>
<span>
${addon.name}<span class="version">
(${addon.version})
</span>
</span>
</div>
`
)}
</div>
`}
${this._dialogParams.supervisor.localize("snapshot.security")}:
<paper-checkbox
Comment thread
ludeeus marked this conversation as resolved.
Outdated
name="snapshotHasPassword"
.checked=${this._snapshotHasPassword}
@checked-changed=${this._handleCheckboxValueChanged}
>
${this._dialogParams.supervisor.localize(
"snapshot.password_protection"
)}
</paper-checkbox>
${this._snapshotHasPassword
? html`
<paper-input
.label=${this._dialogParams.supervisor.localize(
"snapshot.password"
)}
type="password"
name="snapshotPassword"
.value=${this._snapshotPassword}
@value-changed=${this._handleTextValueChanged}
>
</paper-input>
`
: undefined}
${this._error !== ""
? html` <p class="error">${this._error}</p> `
: undefined}
</div>
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this._dialogParams.supervisor.localize("common.close")}
</mwc-button>
<ha-progress-button slot="primaryAction" @click=${this._createSnapshot}>
${this._dialogParams.supervisor.localize("snapshot.create")}
</ha-progress-button>
</ha-dialog>
`;
}

private _handleTextValueChanged(ev: PolymerChangedEvent<string>) {
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<void> {
if (this._dialogParams!.supervisor.info.state !== "running") {
await showAlertDialog(this, {
title: this._dialogParams!.supervisor.localize(
"snapshot.could_not_create"
),
text: this._dialogParams!.supervisor.localize(
"snapshot.create_blocked_not_running",
"state",
this._dialogParams!.supervisor.info.state
),
});
}
Comment thread
ludeeus marked this conversation as resolved.
const button = ev.currentTarget as any;
button.progress = true;

this._error = "";
if (this._snapshotHasPassword && !this._snapshotPassword.length) {
this._error = this._dialogParams!.supervisor.localize(
"snapshot.enter_password"
);
button.progress = 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);
} 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);
}

this._dialogParams!.onCreate();
this.closeDialog();
} catch (err) {
this._error = extractApiErrorMessage(err);
}
button.progress = false;
}

static get styles(): CSSResult[] {
return [
haStyle,
haStyleDialog,
haStyleScrollbar,
css`
paper-checkbox {
display: block;
margin: 4px;
}
.error {
color: var(--error-color);
}
paper-radio-group {
display: block;
}
paper-radio-button {
padding: 0 0 2px 2px;
}
paper-radio-button,
paper-checkbox,
Comment thread
ludeeus marked this conversation as resolved.
Outdated
paper-input[type="password"] {
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;
}
`,
];
}
}

declare global {
interface HTMLElementTagNameMap {
"dialog-hassio-create-snapshot": HassioCreateSnapshotDialog;
}
}
Loading