mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 15:26:36 +00:00
Filter backups by type (#23366)
* filter backups by type * Add filter pane * Make sure we show all when you click show all
This commit is contained in:
parent
33df805168
commit
b3b0006ba3
@ -1,9 +1,9 @@
|
||||
import "@material/mwc-list/mwc-list";
|
||||
import type { SelectedDetail } from "@material/mwc-list";
|
||||
import type { List, SelectedDetail } from "@material/mwc-list";
|
||||
import { mdiFilterVariantRemove } from "@mdi/js";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { haStyleScrollbar } from "../resources/styles";
|
||||
import type { HomeAssistant } from "../types";
|
||||
@ -32,6 +32,8 @@ export class HaFilterStates extends LitElement {
|
||||
|
||||
@state() private _shouldRender = false;
|
||||
|
||||
@query("mwc-list") private _list!: List;
|
||||
|
||||
protected render() {
|
||||
if (!this.states) {
|
||||
return nothing;
|
||||
@ -84,12 +86,21 @@ export class HaFilterStates extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
protected updated(changed) {
|
||||
protected willUpdate(changed) {
|
||||
if (changed.has("expanded") && this.expanded) {
|
||||
setTimeout(() => {
|
||||
this._shouldRender = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changed) {
|
||||
if ((changed.has("expanded") || changed.has("states")) && this.expanded) {
|
||||
setTimeout(async () => {
|
||||
if (!this.expanded) return;
|
||||
this.renderRoot.querySelector("mwc-list")!.style.height =
|
||||
`${this.clientHeight - 49}px`;
|
||||
const list = this._list;
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
list.style.height = `${this.clientHeight - 49}px`;
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,10 @@ class HaBackupOverviewBackups extends LitElement {
|
||||
<div class="card-header">My backups</div>
|
||||
<div class="card-content">
|
||||
<ha-md-list>
|
||||
<ha-md-list-item type="link" href="/config/backup/backups">
|
||||
<ha-md-list-item
|
||||
type="link"
|
||||
href="/config/backup/backups?type=automatic"
|
||||
>
|
||||
<ha-svg-icon slot="start" .path=${mdiCalendarSync}></ha-svg-icon>
|
||||
<div slot="headline">
|
||||
${automaticStats.count} automatic backups
|
||||
@ -72,7 +75,10 @@ class HaBackupOverviewBackups extends LitElement {
|
||||
</div>
|
||||
<ha-icon-next slot="end"></ha-icon-next>
|
||||
</ha-md-list-item>
|
||||
<ha-md-list-item type="link" href="/config/backup/backups">
|
||||
<ha-md-list-item
|
||||
type="link"
|
||||
href="/config/backup/backups?type=manual"
|
||||
>
|
||||
<ha-svg-icon slot="start" .path=${mdiGestureTap}></ha-svg-icon>
|
||||
<div slot="headline">${manualStats.count} manual backups</div>
|
||||
<div slot="supporting-text">
|
||||
@ -83,7 +89,10 @@ class HaBackupOverviewBackups extends LitElement {
|
||||
</ha-md-list>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-button href="/config/backup/backups" @click=${this._showAll}>
|
||||
<ha-button
|
||||
href="/config/backup/backups?type=all"
|
||||
@click=${this._showAll}
|
||||
>
|
||||
Show all backups
|
||||
</ha-button>
|
||||
</div>
|
||||
|
@ -28,6 +28,7 @@ import type {
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-filter-states";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
@ -46,6 +47,7 @@ import {
|
||||
} from "../../../data/backup";
|
||||
import type { ManagerStateEvent } from "../../../data/backup_manager";
|
||||
import type { CloudStatus } from "../../../data/cloud";
|
||||
import type { DataTableFiltersValues } from "../../../data/data_table_filters";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import {
|
||||
showAlertDialog,
|
||||
@ -89,6 +91,14 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _selected: string[] = [];
|
||||
|
||||
@storage({
|
||||
storage: "sessionStorage",
|
||||
key: "backups-table-filters",
|
||||
state: true,
|
||||
subscribe: false,
|
||||
})
|
||||
private _filters: DataTableFiltersValues = {};
|
||||
|
||||
@storage({ key: "backups-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string = "formatted_type";
|
||||
|
||||
@ -102,6 +112,27 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
@query("hass-tabs-subpage-data-table", true)
|
||||
private _dataTable!: HaTabsSubpageDataTable;
|
||||
|
||||
public connectedCallback() {
|
||||
super.connectedCallback();
|
||||
window.addEventListener("location-changed", this._locationChanged);
|
||||
window.addEventListener("popstate", this._popState);
|
||||
this._setFiltersFromUrl();
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
window.removeEventListener("location-changed", this._locationChanged);
|
||||
window.removeEventListener("popstate", this._popState);
|
||||
}
|
||||
|
||||
private _locationChanged = () => {
|
||||
this._setFiltersFromUrl();
|
||||
};
|
||||
|
||||
private _popState = () => {
|
||||
this._setFiltersFromUrl();
|
||||
};
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(localize: LocalizeFunc): DataTableColumnContainer<BackupRow> => ({
|
||||
name: {
|
||||
@ -230,13 +261,28 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
return capitalizeFirstLetter(type);
|
||||
}
|
||||
|
||||
private _data = memoizeOne((backups: BackupContent[]): BackupRow[] =>
|
||||
backups.map((backup) => ({
|
||||
...backup,
|
||||
formatted_type: this._formatBackupType(
|
||||
backup.with_automatic_settings ? "automatic" : "manual"
|
||||
),
|
||||
}))
|
||||
private _data = memoizeOne(
|
||||
(
|
||||
backups: BackupContent[],
|
||||
filters: DataTableFiltersValues
|
||||
): BackupRow[] => {
|
||||
const typeFilter = filters["ha-filter-states"] as string[] | undefined;
|
||||
let filteredBackups = backups;
|
||||
if (typeFilter?.length) {
|
||||
filteredBackups = filteredBackups.filter(
|
||||
(backup) =>
|
||||
(backup.with_automatic_settings &&
|
||||
typeFilter.includes("automatic")) ||
|
||||
(!backup.with_automatic_settings && typeFilter.includes("manual"))
|
||||
);
|
||||
}
|
||||
return filteredBackups.map((backup) => ({
|
||||
...backup,
|
||||
formatted_type: this._formatBackupType(
|
||||
backup.with_automatic_settings ? "automatic" : "manual"
|
||||
),
|
||||
}));
|
||||
}
|
||||
);
|
||||
|
||||
protected render(): TemplateResult {
|
||||
@ -257,6 +303,15 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
back-path="/config/backup/overview"
|
||||
clickable
|
||||
id="backup_id"
|
||||
has-filters
|
||||
.filters=${Object.values(this._filters).filter((filter) =>
|
||||
Array.isArray(filter)
|
||||
? filter.length
|
||||
: filter &&
|
||||
Object.values(filter).some((val) =>
|
||||
Array.isArray(val) ? val.length : val
|
||||
)
|
||||
).length}
|
||||
selectable
|
||||
.selected=${this._selected.length}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
@ -268,7 +323,7 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
.route=${this.route}
|
||||
@row-click=${this._showBackupDetails}
|
||||
.columns=${this._columns(this.hass.localize)}
|
||||
.data=${this._data(this.backups)}
|
||||
.data=${this._data(this.backups, this._filters)}
|
||||
.noDataText=${this.hass.localize("ui.panel.config.backup.no_backups")}
|
||||
.searchLabel=${this.hass.localize(
|
||||
"ui.panel.config.backup.picker.search"
|
||||
@ -324,6 +379,16 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
</div>
|
||||
</div> `
|
||||
: nothing}
|
||||
<ha-filter-states
|
||||
.hass=${this.hass}
|
||||
label="Type"
|
||||
.value=${this._filters["ha-filter-states"]}
|
||||
.states=${this._states(this.hass.localize)}
|
||||
@data-table-filter-changed=${this._filterChanged}
|
||||
slot="filter-pane"
|
||||
expanded
|
||||
.narrow=${this.narrow}
|
||||
></ha-filter-states>
|
||||
${!this._needsOnboarding
|
||||
? html`
|
||||
<ha-fab
|
||||
@ -341,6 +406,35 @@ class HaConfigBackupBackups extends SubscribeMixin(LitElement) {
|
||||
`;
|
||||
}
|
||||
|
||||
private _states = memoizeOne((_localize: LocalizeFunc) => [
|
||||
{
|
||||
value: "automatic",
|
||||
label: "Automatic",
|
||||
},
|
||||
{
|
||||
value: "manual",
|
||||
label: "Manual",
|
||||
},
|
||||
]);
|
||||
|
||||
private _filterChanged(ev) {
|
||||
const type = ev.target.localName;
|
||||
this._filters = { ...this._filters, [type]: ev.detail.value };
|
||||
}
|
||||
|
||||
private _setFiltersFromUrl() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const type = searchParams.get("type");
|
||||
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._filters = {
|
||||
"ha-filter-states": type === "all" ? [] : [type],
|
||||
};
|
||||
}
|
||||
|
||||
private get _needsOnboarding() {
|
||||
return !this.config?.create_backup.password;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user