mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 21:47:46 +00:00
Add delete backup action to datatable (#22867)
This commit is contained in:
parent
99bde50c01
commit
be6ecefb9e
@ -34,7 +34,7 @@ class HaBackupSummaryCard extends LitElement {
|
||||
public hasAction = false;
|
||||
|
||||
@property()
|
||||
private status: SummaryStatus = "info";
|
||||
public status: SummaryStatus = "info";
|
||||
|
||||
render() {
|
||||
return html`
|
||||
|
@ -1,28 +1,36 @@
|
||||
import { mdiPlus } from "@mdi/js";
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { mdiDelete, mdiPlus } from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import type { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import {
|
||||
fetchBackupInfo,
|
||||
generateBackup,
|
||||
removeBackup,
|
||||
type BackupContent,
|
||||
} from "../../../data/backup";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import "../../../layouts/hass-tabs-subpage-data-table";
|
||||
import type { HaTabsSubpageDataTable } from "../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import { brandsUrl } from "../../../util/brands-url";
|
||||
import {
|
||||
@ -43,6 +51,11 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _backups: BackupContent[] = [];
|
||||
|
||||
@state() private _selected: string[] = [];
|
||||
|
||||
@query("hass-tabs-subpage-data-table", true)
|
||||
private _dataTable!: HaTabsSubpageDataTable;
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(localize: LocalizeFunc): DataTableColumnContainer<BackupContent> => ({
|
||||
name: {
|
||||
@ -90,9 +103,38 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
`;
|
||||
})}`,
|
||||
},
|
||||
actions: {
|
||||
title: "",
|
||||
label: localize("ui.panel.config.generic.headers.actions"),
|
||||
showNarrow: true,
|
||||
moveable: false,
|
||||
hideable: false,
|
||||
type: "overflow-menu",
|
||||
template: (backup) => html`
|
||||
<ha-icon-overflow-menu
|
||||
.hass=${this.hass}
|
||||
narrow
|
||||
.items=${[
|
||||
{
|
||||
label: this.hass.localize("ui.common.delete"),
|
||||
path: mdiDelete,
|
||||
action: () => this._deleteBackup(backup),
|
||||
warning: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
</ha-icon-overflow-menu>
|
||||
`,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
private _handleSelectionChanged(
|
||||
ev: HASSDomEvent<SelectionChangedEvent>
|
||||
): void {
|
||||
this._selected = ev.detail.value;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<hass-tabs-subpage-data-table
|
||||
@ -108,6 +150,9 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
back-path="/config/system"
|
||||
clickable
|
||||
id="backup_id"
|
||||
selectable
|
||||
.selected=${this._selected.length}
|
||||
@selection-changed=${this._handleSelectionChanged}
|
||||
.route=${this.route}
|
||||
@row-click=${this._showBackupDetails}
|
||||
.columns=${this._columns(this.hass.localize)}
|
||||
@ -139,6 +184,41 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
</ha-button>
|
||||
</ha-backup-summary-card>
|
||||
</div>
|
||||
|
||||
${this._selected.length
|
||||
? html`<div
|
||||
class=${classMap({
|
||||
"header-toolbar": this.narrow,
|
||||
"table-header": !this.narrow,
|
||||
})}
|
||||
slot="header"
|
||||
>
|
||||
<p class="selected-txt">
|
||||
${this._selected.length} backups selected
|
||||
</p>
|
||||
<div class="header-btns">
|
||||
${!this.narrow
|
||||
? html`
|
||||
<ha-button @click=${this._deleteSelected} class="warning">
|
||||
Delete selected
|
||||
</ha-button>
|
||||
`
|
||||
: html`
|
||||
<ha-icon-button
|
||||
.label=${"Delete selected"}
|
||||
.path=${mdiDelete}
|
||||
id="delete-btn"
|
||||
class="warning"
|
||||
@click=${this._deleteSelected}
|
||||
></ha-icon-button>
|
||||
<simple-tooltip animation-delay="0" for="delete-btn">
|
||||
Delete selected
|
||||
</simple-tooltip>
|
||||
`}
|
||||
</div>
|
||||
</div> `
|
||||
: nothing}
|
||||
|
||||
<ha-fab
|
||||
slot="fab"
|
||||
?disabled=${this._backingUp}
|
||||
@ -197,6 +277,49 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
navigate(`/config/backup/details/${id}`);
|
||||
}
|
||||
|
||||
private async _deleteBackup(backup: BackupContent): Promise<void> {
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
title: "Delete backup",
|
||||
text: "This backup will be permanently deleted.",
|
||||
confirmText: this.hass.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
await removeBackup(this.hass, backup.backup_id);
|
||||
this._fetchBackupInfo();
|
||||
}
|
||||
|
||||
private async _deleteSelected() {
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
title: "Delete selected backups",
|
||||
text: "These backups will be permanently deleted.",
|
||||
confirmText: this.hass.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
if (!confirm) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await Promise.all(
|
||||
this._selected.map((slug) => removeBackup(this.hass, slug))
|
||||
);
|
||||
} catch (err: any) {
|
||||
showAlertDialog(this, {
|
||||
title: "Failed to delete backups",
|
||||
text: extractApiErrorMessage(err),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this._fetchBackupInfo();
|
||||
this._dataTable.clearSelection();
|
||||
}
|
||||
|
||||
private _configureAutomaticBackup() {
|
||||
navigate("/config/backup/automatic-config");
|
||||
}
|
||||
@ -205,28 +328,71 @@ class HaConfigBackupDashboard extends SubscribeMixin(LitElement) {
|
||||
navigate("/config/backup/locations");
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.header {
|
||||
padding: 16px 16px 0 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
background-color: var(--primary-background-color);
|
||||
}
|
||||
@media (max-width: 1000px) {
|
||||
.header {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.header > * {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.header {
|
||||
padding: 16px 16px 0 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
background-color: var(--primary-background-color);
|
||||
}
|
||||
@media (max-width: 1000px) {
|
||||
.header {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.header > * {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
ha-fab[disabled] {
|
||||
--mdc-theme-secondary: var(--disabled-text-color) !important;
|
||||
}
|
||||
`;
|
||||
ha-fab[disabled] {
|
||||
--mdc-theme-secondary: var(--disabled-text-color) !important;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: var(--header-height);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.header-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: var(--secondary-text-color);
|
||||
position: relative;
|
||||
top: -4px;
|
||||
}
|
||||
.selected-txt {
|
||||
font-weight: bold;
|
||||
padding-left: 16px;
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: initial;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.table-header .selected-txt {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.header-toolbar .selected-txt {
|
||||
font-size: 16px;
|
||||
}
|
||||
.header-toolbar .header-btns {
|
||||
margin-right: -12px;
|
||||
margin-inline-end: -12px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
.header-btns > ha-button,
|
||||
.header-btns > ha-icon-button {
|
||||
margin: 8px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
Loading…
x
Reference in New Issue
Block a user