mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-09 18:36:35 +00:00
Multiple backup adjustments (#23361)
* Always show welcome screen during onboarding * Fix content overflow in dialog * Rename copies to backups, drop 7 days * Remove including new and learn more button * Some other fixes * Allow changing default local location from new backup page * Dont show addon version in settings and onboarding * Add margin for ios * Display old encryption key before change * Refactor descriptipn
This commit is contained in:
parent
c66f5e2d8a
commit
fb228dc918
@ -1,5 +1,6 @@
|
||||
import { mdiBackupRestore, mdiFolder, mdiHarddisk, mdiPlayBox } from "@mdi/js";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
@ -173,6 +174,16 @@ class HaMountPicker extends LitElement {
|
||||
fireEvent(this, "change");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
css`
|
||||
ha-select {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -68,7 +68,8 @@ export type Selector =
|
||||
| TTSVoiceSelector
|
||||
| UiActionSelector
|
||||
| UiColorSelector
|
||||
| UiStateContentSelector;
|
||||
| UiStateContentSelector
|
||||
| BackupLocationSelector;
|
||||
|
||||
export interface ActionSelector {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
|
@ -48,6 +48,13 @@ class HaBackupConfigAgents extends LitElement {
|
||||
return this.value ?? DEFAULT_AGENTS;
|
||||
}
|
||||
|
||||
private _description(agentId: string) {
|
||||
if (agentId === CLOUD_AGENT) {
|
||||
return "It stores one backup. The oldest backups are deleted.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
${this._agentIds.length > 0
|
||||
@ -60,6 +67,7 @@ class HaBackupConfigAgents extends LitElement {
|
||||
agentId,
|
||||
this._agentIds
|
||||
);
|
||||
const description = this._description(agentId);
|
||||
return html`
|
||||
<ha-md-list-item>
|
||||
${isLocalAgent(agentId)
|
||||
@ -82,13 +90,8 @@ class HaBackupConfigAgents extends LitElement {
|
||||
/>
|
||||
`}
|
||||
<div slot="headline">${name}</div>
|
||||
${agentId === CLOUD_AGENT
|
||||
? html`
|
||||
<div slot="supporting-text">
|
||||
It stores one backup. The oldest backups are
|
||||
deleted.
|
||||
</div>
|
||||
`
|
||||
${description
|
||||
? html`<div slot="supporting-text">${description}</div>`
|
||||
: nothing}
|
||||
<ha-switch
|
||||
slot="end"
|
||||
|
@ -60,6 +60,9 @@ class HaBackupConfigData extends LitElement {
|
||||
@property({ type: Boolean, attribute: "force-home-assistant" })
|
||||
public forceHomeAssistant = false;
|
||||
|
||||
@property({ attribute: "hide-addon-version", type: Boolean })
|
||||
public hideAddonVersion = false;
|
||||
|
||||
@state() private value?: BackupConfigData;
|
||||
|
||||
@state() private _addons: BackupAddonItem[] = [];
|
||||
@ -156,7 +159,7 @@ class HaBackupConfigData extends LitElement {
|
||||
The bare minimum needed to restore your system.
|
||||
</span>
|
||||
${this.forceHomeAssistant
|
||||
? html`<ha-button slot="end">Learn more</ha-button>`
|
||||
? nothing
|
||||
: html`
|
||||
<ha-switch
|
||||
id="homeassistant"
|
||||
@ -253,7 +256,7 @@ class HaBackupConfigData extends LitElement {
|
||||
.value=${data.addons_mode}
|
||||
>
|
||||
<ha-md-select-option value="all">
|
||||
<div slot="headline">All, including new</div>
|
||||
<div slot="headline">All</div>
|
||||
</ha-md-select-option>
|
||||
<ha-md-select-option value="none">
|
||||
<div slot="headline">None</div>
|
||||
@ -276,6 +279,7 @@ class HaBackupConfigData extends LitElement {
|
||||
.value=${data.addons}
|
||||
@value-changed=${this._addonsChanged}
|
||||
.addons=${this._addons}
|
||||
.hideVersion=${this.hideAddonVersion}
|
||||
></ha-backup-addons-picker>
|
||||
</ha-expansion-panel>
|
||||
`
|
||||
|
@ -23,7 +23,6 @@ const MAX_VALUE = 50;
|
||||
|
||||
enum RetentionPreset {
|
||||
COPIES_3 = "copies_3",
|
||||
DAYS_7 = "days_7",
|
||||
FOREVER = "forever",
|
||||
CUSTOM = "custom",
|
||||
}
|
||||
@ -38,7 +37,6 @@ const RETENTION_PRESETS: Record<
|
||||
RetentionData
|
||||
> = {
|
||||
copies_3: { type: "copies", value: 3 },
|
||||
days_7: { type: "days", value: 7 },
|
||||
forever: { type: "days", value: 0 },
|
||||
};
|
||||
|
||||
@ -176,7 +174,7 @@ class HaBackupConfigSchedule extends LitElement {
|
||||
</ha-md-select>
|
||||
</ha-md-list-item>
|
||||
<ha-md-list-item>
|
||||
<span slot="headline">Maximum copies</span>
|
||||
<span slot="headline">Backups to keep</span>
|
||||
<span slot="supporting-text">
|
||||
The number of backups that are saved
|
||||
</span>
|
||||
@ -186,13 +184,10 @@ class HaBackupConfigSchedule extends LitElement {
|
||||
.value=${this._retentionPreset}
|
||||
>
|
||||
<ha-md-select-option .value=${RetentionPreset.COPIES_3}>
|
||||
<div slot="headline">Latest 3 copies</div>
|
||||
</ha-md-select-option>
|
||||
<ha-md-select-option .value=${RetentionPreset.DAYS_7}>
|
||||
<div slot="headline">Keep 7 days</div>
|
||||
<div slot="headline">3 backups</div>
|
||||
</ha-md-select-option>
|
||||
<ha-md-select-option .value=${RetentionPreset.FOREVER}>
|
||||
<div slot="headline">Keep forever</div>
|
||||
<div slot="headline">All backups</div>
|
||||
</ha-md-select-option>
|
||||
<ha-md-select-option .value=${RetentionPreset.CUSTOM}>
|
||||
<div slot="headline">Custom</div>
|
||||
@ -223,7 +218,7 @@ class HaBackupConfigSchedule extends LitElement {
|
||||
<div slot="headline">days</div>
|
||||
</ha-md-select-option>
|
||||
<ha-md-select-option .value=${"copies"}>
|
||||
<div slot="headline">copies</div>
|
||||
<div slot="headline">backups</div>
|
||||
</ha-md-select-option>
|
||||
</ha-md-select>
|
||||
</ha-md-list-item>
|
||||
|
@ -26,6 +26,9 @@ export class HaBackupAddonsPicker extends LitElement {
|
||||
|
||||
@property({ attribute: false }) public value?: string[];
|
||||
|
||||
@property({ attribute: "hide-version", type: Boolean })
|
||||
public hideVersion = false;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div class="items">
|
||||
@ -35,7 +38,7 @@ export class HaBackupAddonsPicker extends LitElement {
|
||||
<ha-backup-formfield-label
|
||||
slot="label"
|
||||
.label=${item.name}
|
||||
.version=${item.version}
|
||||
.version=${this.hideVersion ? undefined : item.version}
|
||||
.iconPath=${item.iconPath || mdiPuzzle}
|
||||
.imageUrl=${this.addons?.find((a) => a.slug === item.slug)?.icon
|
||||
? `/api/hassio/addons/${item.slug}/icon`
|
||||
|
@ -43,7 +43,7 @@ class SupervisorFormfieldLabel extends LitElement {
|
||||
margin-right: 4px;
|
||||
margin-inline-end: 4px;
|
||||
margin-inline-start: initial;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0.5px;
|
||||
|
@ -102,8 +102,7 @@ class HaBackupOverviewBackups extends LitElement {
|
||||
gap: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 24px;
|
||||
margin-bottom: 72px;
|
||||
margin-bottom: calc(72px + env(safe-area-inset-bottom));
|
||||
}
|
||||
.card-actions {
|
||||
display: flex;
|
||||
|
@ -38,7 +38,7 @@ class HaBackupOverviewBackups extends LitElement {
|
||||
Backups are essential to a reliable smart home. They protect your
|
||||
setup against failures and allows you to quickly have a working
|
||||
system again. It is recommended to create a daily backup and keep
|
||||
copies of the last 3 days on two different locations. And one of
|
||||
backups of the last 3 days on two different locations. And one of
|
||||
them is off-site.
|
||||
</p>
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@ class HaBackupBackupsSummary extends LitElement {
|
||||
|
||||
let copiesText = "and keep all backups";
|
||||
if (copies) {
|
||||
copiesText = `and keep the latest ${copies} copie(s)`;
|
||||
copiesText = `and keep the latest ${copies} backup(s)`;
|
||||
} else if (days) {
|
||||
copiesText = `and keep backups for ${days} day(s)`;
|
||||
}
|
||||
@ -69,7 +69,7 @@ class HaBackupBackupsSummary extends LitElement {
|
||||
|
||||
private _addonsDescription(config: BackupConfig): string {
|
||||
if (config.create_backup.include_all_addons) {
|
||||
return "All add-ons, including new";
|
||||
return "All add-ons";
|
||||
}
|
||||
if (config.create_backup.include_addons?.length) {
|
||||
return `${config.create_backup.include_addons.length} add-ons`;
|
||||
|
@ -82,8 +82,6 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
|
||||
@state() private _step?: Step;
|
||||
|
||||
@state() private _steps: Step[] = [];
|
||||
|
||||
@state() private _params?: BackupOnboardingDialogParams;
|
||||
|
||||
@query("ha-md-dialog") private _dialog!: HaMdDialog;
|
||||
@ -92,8 +90,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
|
||||
public showDialog(params: BackupOnboardingDialogParams): void {
|
||||
this._params = params;
|
||||
this._steps = params.showIntro ? STEPS.concat() : STEPS.slice(1);
|
||||
this._step = this._steps[0];
|
||||
this._step = STEPS[0];
|
||||
this._config = RECOMMENDED_CONFIG;
|
||||
|
||||
const agents: string[] = [];
|
||||
@ -128,7 +125,6 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
}
|
||||
this._opened = false;
|
||||
this._step = undefined;
|
||||
this._steps = [];
|
||||
this._config = undefined;
|
||||
this._params = undefined;
|
||||
}
|
||||
@ -170,19 +166,19 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
}
|
||||
|
||||
private _previousStep() {
|
||||
const index = this._steps.indexOf(this._step!);
|
||||
const index = STEPS.indexOf(this._step!);
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
this._step = this._steps[index - 1];
|
||||
this._step = STEPS[index - 1];
|
||||
}
|
||||
|
||||
private _nextStep() {
|
||||
const index = this._steps.indexOf(this._step!);
|
||||
if (index === this._steps.length - 1) {
|
||||
const index = STEPS.indexOf(this._step!);
|
||||
if (index === STEPS.length - 1) {
|
||||
return;
|
||||
}
|
||||
this._step = this._steps[index + 1];
|
||||
this._step = STEPS[index + 1];
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@ -190,8 +186,8 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const isLastStep = this._step === this._steps[this._steps.length - 1];
|
||||
const isFirstStep = this._step === this._steps[0];
|
||||
const isLastStep = this._step === STEPS[STEPS.length - 1];
|
||||
const isFirstStep = this._step === STEPS[0];
|
||||
|
||||
return html`
|
||||
<ha-md-dialog disable-cancel-action open @closed=${this.closeDialog}>
|
||||
@ -224,7 +220,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
@click=${this._done}
|
||||
.disabled=${!this._isStepValid()}
|
||||
>
|
||||
Save
|
||||
Save and create backup
|
||||
</ha-button>
|
||||
`
|
||||
: html`
|
||||
@ -296,7 +292,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
Backups are essential to a reliable smart home. They protect your
|
||||
setup against failures and allows you to quickly have a working
|
||||
system again. It is recommended to create a daily backup and keep
|
||||
copies of the last 3 days on two different locations. And one of
|
||||
backups of the last 3 days on two different locations. And one of
|
||||
them is off-site.
|
||||
</p>
|
||||
</div>
|
||||
@ -331,7 +327,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
case "setup":
|
||||
return html`
|
||||
<p>
|
||||
It is recommended to create a daily backup and keep copies of the
|
||||
It is recommended to create a daily backup and keep backups of the
|
||||
last 3 days on two different locations. And one of them is off-site.
|
||||
</p>
|
||||
<ha-md-list class="full">
|
||||
@ -355,7 +351,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
return html`
|
||||
<p>
|
||||
Let Home Assistant take care of your backups by creating a scheduled
|
||||
backup that also removes older copies.
|
||||
backup that also removes older backups.
|
||||
</p>
|
||||
<ha-backup-config-schedule
|
||||
.hass=${this.hass}
|
||||
@ -374,6 +370,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
.value=${this._dataConfig(this._config)}
|
||||
@value-changed=${this._dataChanged}
|
||||
force-home-assistant
|
||||
hide-addon-version
|
||||
></ha-backup-config-data>
|
||||
`;
|
||||
case "locations":
|
||||
@ -470,9 +467,7 @@ class DialogBackupOnboarding extends LitElement implements HassDialog {
|
||||
ha-md-dialog {
|
||||
width: 90vw;
|
||||
max-width: 560px;
|
||||
}
|
||||
div[slot="content"] {
|
||||
margin-top: -16px;
|
||||
--dialog-content-padding: 8px 24px;
|
||||
}
|
||||
ha-md-list {
|
||||
background: none;
|
||||
|
@ -141,6 +141,13 @@ class DialogChangeBackupEncryptionKey extends LitElement implements HassDialog {
|
||||
have access to all your current backups. All next backups will use
|
||||
the new encryption key.
|
||||
</p>
|
||||
<div class="encryption-key">
|
||||
<p>${this._params?.currentKey}</p>
|
||||
<ha-icon-button
|
||||
.path=${mdiContentCopy}
|
||||
@click=${this._copyOldKeyToClipboard}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
<ha-md-list>
|
||||
<ha-md-list-item>
|
||||
<span slot="headline">Download old emergency kit</span>
|
||||
@ -202,6 +209,16 @@ class DialogChangeBackupEncryptionKey extends LitElement implements HassDialog {
|
||||
});
|
||||
}
|
||||
|
||||
private _copyOldKeyToClipboard() {
|
||||
if (!this._params?.currentKey) {
|
||||
return;
|
||||
}
|
||||
copyToClipboard(this._params.currentKey);
|
||||
showToast(this, {
|
||||
message: this.hass.localize("ui.common.copied_clipboard"),
|
||||
});
|
||||
}
|
||||
|
||||
private _downloadOld() {
|
||||
if (!this._params?.currentKey) {
|
||||
return;
|
||||
@ -240,9 +257,7 @@ class DialogChangeBackupEncryptionKey extends LitElement implements HassDialog {
|
||||
ha-md-dialog {
|
||||
width: 90vw;
|
||||
max-width: 560px;
|
||||
}
|
||||
div[slot="content"] {
|
||||
margin-top: -16px;
|
||||
--dialog-content-padding: 8px 24px;
|
||||
}
|
||||
ha-md-list {
|
||||
background: none;
|
||||
|
151
src/panels/config/backup/dialogs/dialog-local-backup-location.ts
Normal file
151
src/panels/config/backup/dialogs/dialog-local-backup-location.ts
Normal file
@ -0,0 +1,151 @@
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-button";
|
||||
import { createCloseHeading } from "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-form/ha-form";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
SchemaUnion,
|
||||
} from "../../../../components/ha-form/types";
|
||||
import { extractApiErrorMessage } from "../../../../data/hassio/common";
|
||||
import { changeMountOptions } from "../../../../data/supervisor/mounts";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LocalBackupLocationDialogParams } from "./show-dialog-local-backup-location";
|
||||
|
||||
const SCHEMA = [
|
||||
{
|
||||
name: "default_backup_mount",
|
||||
required: true,
|
||||
selector: { backup_location: {} },
|
||||
},
|
||||
] as const satisfies HaFormSchema[];
|
||||
|
||||
@customElement("dialog-local-backup-location")
|
||||
class LocalBackupLocationDialog extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@state() private _dialogParams?: LocalBackupLocationDialogParams;
|
||||
|
||||
@state() private _data?: { default_backup_mount: string | null };
|
||||
|
||||
@state() private _waiting?: boolean;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
public async showDialog(
|
||||
dialogParams: LocalBackupLocationDialogParams
|
||||
): Promise<void> {
|
||||
this._dialogParams = dialogParams;
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this._data = undefined;
|
||||
this._error = undefined;
|
||||
this._waiting = undefined;
|
||||
this._dialogParams = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._dialogParams) {
|
||||
return nothing;
|
||||
}
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
scrimClickAction
|
||||
escapeKeyAction
|
||||
.heading=${createCloseHeading(
|
||||
this.hass,
|
||||
this.hass.localize(
|
||||
`ui.panel.config.backup.dialogs.local_backup_location.title`
|
||||
)
|
||||
)}
|
||||
@closed=${this.closeDialog}
|
||||
>
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: nothing}
|
||||
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.backup.dialogs.local_backup_location.description`
|
||||
)}
|
||||
</p>
|
||||
<ha-form
|
||||
.hass=${this.hass}
|
||||
.data=${this._data}
|
||||
.schema=${SCHEMA}
|
||||
.computeLabel=${this._computeLabelCallback}
|
||||
@value-changed=${this._valueChanged}
|
||||
dialogInitialFocus
|
||||
></ha-form>
|
||||
<ha-button
|
||||
slot="secondaryAction"
|
||||
@click=${this.closeDialog}
|
||||
dialogInitialFocus
|
||||
>
|
||||
${this.hass.localize("ui.common.cancel")}
|
||||
</ha-button>
|
||||
<ha-button
|
||||
.disabled=${this._waiting || !this._data}
|
||||
slot="primaryAction"
|
||||
@click=${this._changeMount}
|
||||
>
|
||||
${this.hass.localize("ui.common.save")}
|
||||
</ha-button>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
private _computeLabelCallback = (
|
||||
schema: SchemaUnion<typeof SCHEMA>
|
||||
): string =>
|
||||
this.hass.localize(
|
||||
`ui.panel.config.backup.dialogs.local_backup_location.options.${schema.name}.name`
|
||||
) || schema.name;
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
const newLocation = ev.detail.value.default_backup_mount;
|
||||
this._data = {
|
||||
default_backup_mount: newLocation === "/backup" ? null : newLocation,
|
||||
};
|
||||
}
|
||||
|
||||
private async _changeMount() {
|
||||
if (!this._data) {
|
||||
return;
|
||||
}
|
||||
this._error = undefined;
|
||||
this._waiting = true;
|
||||
try {
|
||||
await changeMountOptions(this.hass, this._data);
|
||||
} catch (err: any) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
this._waiting = false;
|
||||
return;
|
||||
}
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
haStyleDialog,
|
||||
css`
|
||||
ha-dialog {
|
||||
--mdc-dialog-max-width: 500px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-local-backup-location": LocalBackupLocationDialog;
|
||||
}
|
||||
}
|
@ -115,9 +115,6 @@ class DialogNewBackup extends LitElement implements HassDialog {
|
||||
--dialog-content-padding: 0;
|
||||
max-width: 500px;
|
||||
}
|
||||
div[slot="content"] {
|
||||
margin-top: -16px;
|
||||
}
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
ha-md-dialog {
|
||||
max-width: none;
|
||||
|
@ -157,7 +157,11 @@ class DialogRestoreBackupEncryptionKey
|
||||
</div>
|
||||
<div slot="actions">
|
||||
<ha-button @click=${this.closeDialog}>Cancel</ha-button>
|
||||
<ha-button @click=${this._submit} .disabled=${!this._getKey()}>
|
||||
<ha-button
|
||||
@click=${this._submit}
|
||||
class="danger"
|
||||
.disabled=${!this._getKey()}
|
||||
>
|
||||
Restore
|
||||
</ha-button>
|
||||
</div>
|
||||
@ -221,10 +225,14 @@ class DialogRestoreBackupEncryptionKey
|
||||
ha-md-dialog {
|
||||
max-width: 500px;
|
||||
width: 100%;
|
||||
--dialog-content-padding: 8px 24px;
|
||||
}
|
||||
.content p {
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
ha-button.danger {
|
||||
--mdc-theme-primary: var(--error-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -193,9 +193,7 @@ class DialogSetBackupEncryptionKey extends LitElement implements HassDialog {
|
||||
ha-md-dialog {
|
||||
width: 90vw;
|
||||
max-width: 500px;
|
||||
}
|
||||
div[slot="content"] {
|
||||
margin-top: -16px;
|
||||
--dialog-content-padding: 8px 24px;
|
||||
}
|
||||
ha-md-list {
|
||||
background: none;
|
||||
|
@ -4,7 +4,6 @@ import type { CloudStatus } from "../../../../data/cloud";
|
||||
export interface BackupOnboardingDialogParams {
|
||||
submit?: (value: boolean) => void;
|
||||
cancel?: () => void;
|
||||
showIntro?: boolean;
|
||||
cloudStatus: CloudStatus;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
|
||||
export interface LocalBackupLocationDialogParams {}
|
||||
|
||||
export const showLocalBackupLocationDialog = (
|
||||
element: HTMLElement,
|
||||
dialogParams: LocalBackupLocationDialogParams
|
||||
): void => {
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-local-backup-location",
|
||||
dialogImport: () => import("./dialog-local-backup-location"),
|
||||
dialogParams,
|
||||
});
|
||||
};
|
@ -119,26 +119,6 @@ class HaConfigBackupDetails extends LitElement {
|
||||
: !this._backup
|
||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||
: html`
|
||||
<ha-card header="Select what to restore">
|
||||
<div class="card-content">
|
||||
<ha-backup-data-picker
|
||||
.hass=${this.hass}
|
||||
.data=${this._backup}
|
||||
.value=${this._selectedBackup}
|
||||
@value-changed=${this._selectedBackupChanged}
|
||||
.addonsInfo=${this._addonsInfo}
|
||||
>
|
||||
</ha-backup-data-picker>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-button
|
||||
@click=${this._restore}
|
||||
.disabled=${this._isRestoreDisabled()}
|
||||
>
|
||||
Restore
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
<ha-card header="Backup">
|
||||
<div class="card-content">
|
||||
<ha-md-list>
|
||||
@ -159,6 +139,27 @@ class HaConfigBackupDetails extends LitElement {
|
||||
</ha-md-list>
|
||||
</div>
|
||||
</ha-card>
|
||||
<ha-card header="Select what to restore">
|
||||
<div class="card-content">
|
||||
<ha-backup-data-picker
|
||||
.hass=${this.hass}
|
||||
.data=${this._backup}
|
||||
.value=${this._selectedBackup}
|
||||
@value-changed=${this._selectedBackupChanged}
|
||||
.addonsInfo=${this._addonsInfo}
|
||||
>
|
||||
</ha-backup-data-picker>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-button
|
||||
@click=${this._restore}
|
||||
.disabled=${this._isRestoreDisabled()}
|
||||
class="danger"
|
||||
>
|
||||
Restore
|
||||
</ha-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
<ha-card header="Locations">
|
||||
<div class="card-content">
|
||||
<ha-md-list>
|
||||
@ -172,6 +173,8 @@ class HaConfigBackupDetails extends LitElement {
|
||||
this._backup!.agent_ids!
|
||||
);
|
||||
|
||||
const isLocal = isLocalAgent(agentId);
|
||||
|
||||
return html`
|
||||
<ha-md-list-item>
|
||||
${isLocalAgent(agentId)
|
||||
@ -204,7 +207,11 @@ class HaConfigBackupDetails extends LitElement {
|
||||
>
|
||||
</span>
|
||||
<span>
|
||||
${success ? "Backup synced" : "Backup failed"}
|
||||
${success
|
||||
? isLocal
|
||||
? "Backup created"
|
||||
: "Backup uploaded"
|
||||
: "Backup failed"}
|
||||
</span>
|
||||
</div>
|
||||
${success
|
||||
@ -390,6 +397,9 @@ class HaConfigBackupDetails extends LitElement {
|
||||
.warning ha-svg-icon {
|
||||
color: var(--error-color);
|
||||
}
|
||||
ha-button.danger {
|
||||
--mdc-theme-primary: var(--error-color);
|
||||
}
|
||||
ha-backup-data-picker {
|
||||
display: block;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { mdiDotsVertical, mdiPlus, mdiUpload } from "@mdi/js";
|
||||
import { mdiDotsVertical, mdiHarddisk, mdiPlus, mdiUpload } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||
import "../../../components/ha-button";
|
||||
@ -34,6 +35,7 @@ import "./components/overview/ha-backup-overview-settings";
|
||||
import "./components/overview/ha-backup-overview-summary";
|
||||
import { showBackupOnboardingDialog } from "./dialogs/show-dialog-backup_onboarding";
|
||||
import { showGenerateBackupDialog } from "./dialogs/show-dialog-generate-backup";
|
||||
import { showLocalBackupLocationDialog } from "./dialogs/show-dialog-local-backup-location";
|
||||
import { showNewBackupDialog } from "./dialogs/show-dialog-new-backup";
|
||||
import { showUploadBackupDialog } from "./dialogs/show-dialog-upload-backup";
|
||||
|
||||
@ -63,15 +65,22 @@ class HaConfigBackupOverview extends LitElement {
|
||||
await showUploadBackupDialog(this, {});
|
||||
}
|
||||
|
||||
private _handleOnboardingButtonClick(ev) {
|
||||
ev.stopPropagation();
|
||||
this._setupAutomaticBackup(false);
|
||||
private async _changeLocalLocation(ev) {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
showLocalBackupLocationDialog(this, {});
|
||||
}
|
||||
|
||||
private async _setupAutomaticBackup(showIntro: boolean) {
|
||||
private _handleOnboardingButtonClick(ev) {
|
||||
ev.stopPropagation();
|
||||
this._setupAutomaticBackup();
|
||||
}
|
||||
|
||||
private async _setupAutomaticBackup() {
|
||||
const success = await showBackupOnboardingDialog(this, {
|
||||
cloudStatus: this.cloudStatus,
|
||||
showIntro: showIntro,
|
||||
});
|
||||
if (!success) {
|
||||
return;
|
||||
@ -84,7 +93,7 @@ class HaConfigBackupOverview extends LitElement {
|
||||
|
||||
private async _newBackup(): Promise<void> {
|
||||
if (this._needsOnboarding) {
|
||||
this._setupAutomaticBackup(true);
|
||||
this._setupAutomaticBackup();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -125,6 +134,8 @@ class HaConfigBackupOverview extends LitElement {
|
||||
const backupInProgress =
|
||||
"state" in this.manager && this.manager.state === "in_progress";
|
||||
|
||||
const isHassio = isComponentLoaded(this.hass, "hassio");
|
||||
|
||||
return html`
|
||||
<hass-subpage
|
||||
back-path="/config/system"
|
||||
@ -139,6 +150,18 @@ class HaConfigBackupOverview extends LitElement {
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
${isHassio
|
||||
? html`<ha-list-item
|
||||
graphic="icon"
|
||||
@request-selected=${this._changeLocalLocation}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiHarddisk}
|
||||
></ha-svg-icon>
|
||||
Change local location
|
||||
</ha-list-item>`
|
||||
: nothing}
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
@request-selected=${this._uploadBackup}
|
||||
|
@ -56,7 +56,7 @@ class HaConfigBackupSettings extends LitElement {
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Let Home Assistant take care of your backups by creating a
|
||||
scheduled backup that also removes older copies.
|
||||
scheduled backup that also removes older backups.
|
||||
</p>
|
||||
<ha-backup-config-schedule
|
||||
.hass=${this.hass}
|
||||
@ -73,6 +73,7 @@ class HaConfigBackupSettings extends LitElement {
|
||||
.value=${this._dataConfig}
|
||||
@value-changed=${this._dataConfigChanged}
|
||||
force-home-assistant
|
||||
hide-addon-version
|
||||
></ha-backup-config-data>
|
||||
</div>
|
||||
</ha-card>
|
||||
|
@ -2209,6 +2209,17 @@
|
||||
},
|
||||
"picker": {
|
||||
"search": "Search backups"
|
||||
},
|
||||
"dialogs": {
|
||||
"local_backup_location": {
|
||||
"title": "Change local backup location",
|
||||
"description": "Change the default location where local backups are stored on your Home Assistant instance.",
|
||||
"options": {
|
||||
"default_backup_mount": {
|
||||
"name": "Default location"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tag": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user