mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 21:17:47 +00:00
Add add-on restore dialog
This commit is contained in:
parent
bdef9fd040
commit
c1df1d41f9
@ -50,6 +50,10 @@ import {
|
||||
fetchHassioStats,
|
||||
HassioStats,
|
||||
} from "../../../../src/data/hassio/common";
|
||||
import {
|
||||
fetchHassioSnapshots,
|
||||
HassioSnapshot,
|
||||
} from "../../../../src/data/hassio/snapshot";
|
||||
import { StoreAddon } from "../../../../src/data/supervisor/store";
|
||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||
import {
|
||||
@ -61,6 +65,7 @@ import { HomeAssistant } from "../../../../src/types";
|
||||
import { bytesToString } from "../../../../src/util/bytes-to-string";
|
||||
import "../../components/hassio-card-content";
|
||||
import "../../components/supervisor-metric";
|
||||
import { showHassioAddonRestoreDialog } from "../../dialogs/addon/show-dialog-hassio-addon-restore";
|
||||
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
|
||||
import { showDialogSupervisorUpdate } from "../../dialogs/update/show-dialog-update";
|
||||
import { hassioStyle } from "../../resources/hassio-style";
|
||||
@ -82,6 +87,8 @@ class HassioAddonInfo extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
||||
|
||||
@property({ attribute: false }) public snapshots?: HassioSnapshot[];
|
||||
|
||||
@state() private _metrics?: HassioStats;
|
||||
|
||||
@state() private _error?: string;
|
||||
@ -626,6 +633,11 @@ class HassioAddonInfo extends LitElement {
|
||||
${this.supervisor.localize("addon.dashboard.install")}
|
||||
</ha-progress-button>
|
||||
`}
|
||||
${this.snapshots?.length
|
||||
? html`<mwc-button @click=${this._restoreClicked}>
|
||||
${this.supervisor.localize("addon.dashboard.restore")}
|
||||
</mwc-button>`
|
||||
: ""}
|
||||
</div>
|
||||
<div>
|
||||
${this.addon.version
|
||||
@ -698,6 +710,11 @@ class HassioAddonInfo extends LitElement {
|
||||
}
|
||||
|
||||
private async _loadData(): Promise<void> {
|
||||
const snapshots = await fetchHassioSnapshots(this.hass);
|
||||
this.snapshots = snapshots.filter((snapshot) =>
|
||||
snapshot.content.addons.includes(this.addon.slug)
|
||||
);
|
||||
|
||||
if (this.addon.state === "started") {
|
||||
this._metrics = await fetchHassioStats(
|
||||
this.hass,
|
||||
@ -1000,6 +1017,22 @@ class HassioAddonInfo extends LitElement {
|
||||
fireEvent(this, "hass-api-called", eventdata);
|
||||
}
|
||||
|
||||
private async _restoreClicked(): Promise<void> {
|
||||
showHassioAddonRestoreDialog(this, {
|
||||
supervisor: this.supervisor,
|
||||
snapshots: this.snapshots || [],
|
||||
addon: this.addon,
|
||||
onRestore: () => {
|
||||
const eventdata = {
|
||||
success: true,
|
||||
response: undefined,
|
||||
path: "update",
|
||||
};
|
||||
fireEvent(this, "hass-api-called", eventdata);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async _startClicked(ev: CustomEvent): Promise<void> {
|
||||
const button = ev.currentTarget as any;
|
||||
button.progress = true;
|
||||
|
190
hassio/src/dialogs/addon/dialog-hassio-addon-restore.ts
Normal file
190
hassio/src/dialogs/addon/dialog-hassio-addon-restore.ts
Normal file
@ -0,0 +1,190 @@
|
||||
import "@material/mwc-button/mwc-button";
|
||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import relativeTime from "../../../../src/common/datetime/relative_time";
|
||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||
import "../../../../src/common/search/search-input";
|
||||
import { compare } from "../../../../src/common/string/compare";
|
||||
import { nextRender } from "../../../../src/common/util/render-status";
|
||||
import "../../../../src/components/ha-circular-progress";
|
||||
import { createCloseHeading } from "../../../../src/components/ha-dialog";
|
||||
import "../../../../src/components/ha-expansion-panel";
|
||||
import "../../../../src/components/ha-settings-row";
|
||||
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
|
||||
import {
|
||||
fetchHassioSnapshotInfo,
|
||||
HassioPartialSnapshotCreateParams,
|
||||
HassioSnapshotDetail,
|
||||
supervisorRestorePartialSnapshot,
|
||||
} from "../../../../src/data/hassio/snapshot";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showPromptDialog,
|
||||
} from "../../../../src/dialogs/generic/show-dialog-box";
|
||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { HassioAddonRestoreDialogParams } from "./show-dialog-hassio-addon-restore";
|
||||
|
||||
@customElement("dialog-hassio-addon-restore")
|
||||
class HassioAddonRestoreDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _dialogParams?: HassioAddonRestoreDialogParams;
|
||||
|
||||
@state() private _snapshots?: HassioSnapshotDetail[];
|
||||
|
||||
@state() private _restoring = false;
|
||||
|
||||
public showDialog(params: HassioAddonRestoreDialogParams) {
|
||||
this._dialogParams = params;
|
||||
this._restoring = false;
|
||||
Promise.all(
|
||||
params.snapshots.map((snapshot) =>
|
||||
fetchHassioSnapshotInfo(this.hass, snapshot.slug)
|
||||
)
|
||||
).then((data) => {
|
||||
this._snapshots = data.sort((a, b) => compare(b.date, a.date));
|
||||
});
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
this._dialogParams = undefined;
|
||||
this._snapshots = undefined;
|
||||
this._restoring = false;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._dialogParams || (!this._snapshots && !this._restoring)) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const snapshotCount = this._snapshots?.length || 0;
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
hideActions
|
||||
@closed=${this.closeDialog}
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this._dialogParams.supervisor.localize("dialog.addon_restore.title", {
|
||||
name: this._dialogParams.addon.name,
|
||||
})
|
||||
)}
|
||||
>
|
||||
${this._restoring
|
||||
? html`<div class="restore">
|
||||
<ha-circular-progress size="large" active></ha-circular-progress>
|
||||
<span
|
||||
>${this._dialogParams.supervisor.localize(
|
||||
"dialog.addon_restore.restore_in_progress"
|
||||
)}
|
||||
</span>
|
||||
</div>`
|
||||
: html`${this._dialogParams.supervisor.localize(
|
||||
"dialog.addon_restore.description",
|
||||
{
|
||||
name: this._dialogParams.addon.name,
|
||||
count: snapshotCount,
|
||||
}
|
||||
)}
|
||||
${this._snapshots?.map(
|
||||
(snapshot) =>
|
||||
html`<ha-settings-row three-lines>
|
||||
<span slot="heading">
|
||||
${snapshot.name || snapshot.slug}
|
||||
</span>
|
||||
<span slot="description">
|
||||
<div>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
"dialog.addon_restore.version",
|
||||
{
|
||||
version:
|
||||
snapshot.addons.find(
|
||||
(addon) =>
|
||||
addon.slug === this._dialogParams?.addon.slug
|
||||
)?.version ||
|
||||
this._dialogParams!.supervisor.localize(
|
||||
"dialog.addon_restore.no_version"
|
||||
),
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
${relativeTime(new Date(snapshot.date), this.hass.localize)}
|
||||
</span>
|
||||
<mwc-button
|
||||
.snapshot=${snapshot}
|
||||
@click=${this._restoreClicked}
|
||||
>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
"dialog.addon_restore.restore"
|
||||
)}
|
||||
</mwc-button>
|
||||
</ha-settings-row>`
|
||||
)}`}
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _restoreClicked(ev: CustomEvent) {
|
||||
let password: string | null = null;
|
||||
const snapshot: HassioSnapshotDetail = (ev.currentTarget as any).snapshot;
|
||||
if (snapshot.protected) {
|
||||
password = await showPromptDialog(this, {
|
||||
text: this._dialogParams?.supervisor.localize(
|
||||
"dialog.addon_restore.protected"
|
||||
),
|
||||
inputLabel: this._dialogParams?.supervisor.localize(
|
||||
"dialog.addon_restore.password"
|
||||
),
|
||||
inputType: "password",
|
||||
});
|
||||
await nextRender();
|
||||
if (!password) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._restoring = true;
|
||||
|
||||
const data: HassioPartialSnapshotCreateParams = {
|
||||
addons: [this._dialogParams!.addon.slug],
|
||||
};
|
||||
if (password) {
|
||||
data.password = password;
|
||||
}
|
||||
|
||||
try {
|
||||
await supervisorRestorePartialSnapshot(this.hass, snapshot.slug, data);
|
||||
} catch (err) {
|
||||
await showAlertDialog(this, {
|
||||
text: extractApiErrorMessage(err),
|
||||
});
|
||||
await nextRender();
|
||||
return;
|
||||
}
|
||||
|
||||
this._dialogParams?.onRestore();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
.restore {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-hassio-addon-restore": HassioAddonRestoreDialog;
|
||||
}
|
||||
}
|
22
hassio/src/dialogs/addon/show-dialog-hassio-addon-restore.ts
Normal file
22
hassio/src/dialogs/addon/show-dialog-hassio-addon-restore.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||
import { HassioAddonDetails } from "../../../../src/data/hassio/addon";
|
||||
import { HassioSnapshot } from "../../../../src/data/hassio/snapshot";
|
||||
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
|
||||
|
||||
export interface HassioAddonRestoreDialogParams {
|
||||
supervisor: Supervisor;
|
||||
snapshots: HassioSnapshot[];
|
||||
addon: HassioAddonDetails;
|
||||
onRestore: () => void;
|
||||
}
|
||||
|
||||
export const showHassioAddonRestoreDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: HassioAddonRestoreDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-hassio-addon-restore",
|
||||
dialogImport: () => import("./dialog-hassio-addon-restore"),
|
||||
dialogParams,
|
||||
});
|
||||
};
|
@ -39,7 +39,7 @@ export interface HassioSnapshotDetail extends HassioSnapshot {
|
||||
}
|
||||
|
||||
export interface HassioFullSnapshotCreateParams {
|
||||
name: string;
|
||||
name?: string;
|
||||
password?: string;
|
||||
}
|
||||
export interface HassioPartialSnapshotCreateParams
|
||||
@ -194,3 +194,26 @@ export const uploadSnapshot = async (
|
||||
}
|
||||
return resp.json();
|
||||
};
|
||||
|
||||
export const supervisorRestorePartialSnapshot = async (
|
||||
hass: HomeAssistant,
|
||||
slug: string,
|
||||
data: HassioPartialSnapshotCreateParams
|
||||
) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/snapshots/${slug}/restore/partial`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/snapshots/${slug}/restore/partial`,
|
||||
data
|
||||
);
|
||||
};
|
||||
|
@ -3630,6 +3630,7 @@
|
||||
"restart": "restart",
|
||||
"start": "start",
|
||||
"stop": "stop",
|
||||
"restore": "restore",
|
||||
"install": "install",
|
||||
"uninstall": "uninstall",
|
||||
"rebuild": "rebuild",
|
||||
@ -3978,6 +3979,16 @@
|
||||
"create_snapshot": "Create a snapshot of {name} before updating",
|
||||
"updating": "Updating {name} to version {version}",
|
||||
"snapshotting": "Creating snapshot of {name}"
|
||||
},
|
||||
"addon_restore": {
|
||||
"title": "Restore {name}",
|
||||
"description": "You have {count, plural,\n one {one snapshot}\n other {{count} snapshots}\n} that includes restore points for {name}",
|
||||
"version": "Version {version}",
|
||||
"no_version": "No version",
|
||||
"restore": "Restore",
|
||||
"password": "Password",
|
||||
"protected": "The snapshot is password protected, please provide the password for it.",
|
||||
"restore_in_progress": "Restore in progress"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user