mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
Implement storing sorting and grouping for all tables (#20594)
This commit is contained in:
parent
d9b71e754d
commit
62de16bb8e
@ -529,11 +529,7 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
|
||||
if (this.appendRow || this.hasFab || this.groupColumn) {
|
||||
const items = [...data];
|
||||
|
||||
if (this.appendRow) {
|
||||
items.push({ append: true, content: this.appendRow });
|
||||
}
|
||||
let items = [...data];
|
||||
|
||||
if (this.groupColumn) {
|
||||
const grouped = groupBy(items, (item) => item[this.groupColumn!]);
|
||||
@ -599,14 +595,18 @@ export class HaDataTable extends LitElement {
|
||||
}
|
||||
});
|
||||
|
||||
this._items = groupedItems;
|
||||
} else {
|
||||
this._items = items;
|
||||
items = groupedItems;
|
||||
}
|
||||
|
||||
if (this.appendRow) {
|
||||
items.push({ append: true, content: this.appendRow });
|
||||
}
|
||||
|
||||
if (this.hasFab) {
|
||||
this._items = [...this._items, { empty: true }];
|
||||
items.push({ empty: true });
|
||||
}
|
||||
|
||||
this._items = items;
|
||||
} else {
|
||||
this._items = data;
|
||||
}
|
||||
|
@ -37,15 +37,21 @@ import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
import "../../../components/chips/ha-assist-chip";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/entity/ha-entity-toggle";
|
||||
@ -105,10 +111,6 @@ import { showCategoryRegistryDetailDialog } from "../category/show-dialog-catego
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { showNewAutomationDialog } from "./show-dialog-new-automation";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
|
||||
type AutomationItem = AutomationEntity & {
|
||||
name: string;
|
||||
@ -156,6 +158,19 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _overflowAutomation?: AutomationItem;
|
||||
|
||||
@storage({ key: "automation-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "automation-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "automation-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
@query("#overflow-menu") private _overflowMenu!: HaMenu;
|
||||
|
||||
private _sizeController = new ResizeController(this, {
|
||||
@ -470,7 +485,12 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
|
||||
this.hass.localize,
|
||||
this.hass.locale
|
||||
)}
|
||||
initialGroupColumn="category"
|
||||
.initialGroupColumn=${this._activeGrouping || "category"}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
.data=${automations}
|
||||
.empty=${!this.automations.length}
|
||||
@row-click=${this._handleRowClicked}
|
||||
@ -1238,6 +1258,18 @@ ${rejected
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -24,6 +24,7 @@ import { extractSearchParam } from "../../../common/url/search-params";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/entity/ha-entity-toggle";
|
||||
import "../../../components/ha-button";
|
||||
@ -54,6 +55,7 @@ import { documentationUrl } from "../../../util/documentation-url";
|
||||
import { showToast } from "../../../util/toast";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showAddBlueprintDialog } from "./show-dialog-import-blueprint";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
|
||||
type BlueprintMetaDataPath = BlueprintMetaData & {
|
||||
path: string;
|
||||
@ -92,8 +94,24 @@ class HaBlueprintOverview extends LitElement {
|
||||
Blueprints
|
||||
>;
|
||||
|
||||
@storage({ key: "blueprint-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "blueprint-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "blueprint-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
private _processedBlueprints = memoizeOne(
|
||||
(blueprints: Record<string, Blueprints>): BlueprintMetaDataPath[] => {
|
||||
(
|
||||
blueprints: Record<string, Blueprints>,
|
||||
localize: LocalizeFunc
|
||||
): BlueprintMetaDataPath[] => {
|
||||
const result: any[] = [];
|
||||
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
||||
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
||||
@ -101,6 +119,9 @@ class HaBlueprintOverview extends LitElement {
|
||||
result.push({
|
||||
name: blueprint.error,
|
||||
type,
|
||||
translated_type: localize(
|
||||
`ui.panel.config.blueprint.overview.types.${type as "automation" | "script"}`
|
||||
),
|
||||
error: true,
|
||||
path,
|
||||
fullpath: `${type}/${path}`,
|
||||
@ -109,6 +130,9 @@ class HaBlueprintOverview extends LitElement {
|
||||
result.push({
|
||||
...blueprint.metadata,
|
||||
type,
|
||||
translated_type: localize(
|
||||
`ui.panel.config.blueprint.overview.types.${type as "automation" | "script"}`
|
||||
),
|
||||
error: false,
|
||||
path,
|
||||
fullpath: `${type}/${path}`,
|
||||
@ -140,14 +164,11 @@ class HaBlueprintOverview extends LitElement {
|
||||
`
|
||||
: undefined,
|
||||
},
|
||||
type: {
|
||||
translated_type: {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.type"),
|
||||
template: (blueprint) =>
|
||||
html`${this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.types.${blueprint.type}`
|
||||
)}`,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
hidden: narrow,
|
||||
direction: "asc",
|
||||
width: "10%",
|
||||
@ -256,7 +277,7 @@ class HaBlueprintOverview extends LitElement {
|
||||
this.hass.language,
|
||||
this.hass.localize
|
||||
)}
|
||||
.data=${this._processedBlueprints(this.blueprints)}
|
||||
.data=${this._processedBlueprints(this.blueprints, this.hass.localize)}
|
||||
id="fullpath"
|
||||
.noDataText=${this.hass.localize(
|
||||
"ui.panel.config.blueprint.overview.no_blueprints"
|
||||
@ -281,6 +302,12 @@ class HaBlueprintOverview extends LitElement {
|
||||
>
|
||||
</a>
|
||||
</div>`}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="toolbar-icon"
|
||||
@ -341,9 +368,10 @@ class HaBlueprintOverview extends LitElement {
|
||||
}
|
||||
|
||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||
const blueprint = this._processedBlueprints(this.blueprints).find(
|
||||
(b) => b.fullpath === ev.detail.id
|
||||
)!;
|
||||
const blueprint = this._processedBlueprints(
|
||||
this.blueprints,
|
||||
this.hass.localize
|
||||
).find((b) => b.fullpath === ev.detail.id)!;
|
||||
if (blueprint.error) {
|
||||
showAlertDialog(this, {
|
||||
title: this.hass.localize("ui.panel.config.blueprint.overview.error", {
|
||||
@ -502,6 +530,18 @@ class HaBlueprintOverview extends LitElement {
|
||||
fireEvent(this, "reload-blueprints");
|
||||
};
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return haStyle;
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import { ifDefined } from "lit/directives/if-defined";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import memoize from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
@ -37,10 +38,15 @@ import {
|
||||
protocolIntegrationPicked,
|
||||
} from "../../../common/integrations/protocolIntegrationPicked";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-alert";
|
||||
@ -66,6 +72,11 @@ import {
|
||||
removeEntityRegistryEntry,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import {
|
||||
EntitySources,
|
||||
fetchEntitySourcesWithCache,
|
||||
} from "../../../data/entity_sources";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
import {
|
||||
LabelRegistryEntry,
|
||||
createLabelRegistryEntry,
|
||||
@ -86,15 +97,6 @@ import { configSections } from "../ha-panel-config";
|
||||
import "../integrations/ha-integration-overflow-menu";
|
||||
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import {
|
||||
EntitySources,
|
||||
fetchEntitySourcesWithCache,
|
||||
} from "../../../data/entity_sources";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
import { domainToName } from "../../../data/integration";
|
||||
|
||||
export interface StateEntity
|
||||
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
|
||||
@ -151,6 +153,19 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
|
||||
@state() private _entitySources?: EntitySources;
|
||||
|
||||
@storage({ key: "entities-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "entities-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "entities-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
@query("hass-tabs-subpage-data-table", true)
|
||||
private _dataTable!: HaTabsSubpageDataTable;
|
||||
|
||||
@ -265,7 +280,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
},
|
||||
domain: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.domain"),
|
||||
sortable: true,
|
||||
sortable: false,
|
||||
hidden: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
@ -603,6 +618,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
.filter=${this._filter}
|
||||
selectable
|
||||
.selected=${this._selected.length}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
@selection-changed=${this._handleSelectionChanged}
|
||||
clickable
|
||||
@clear-filter=${this._clearFilter}
|
||||
@ -1205,6 +1226,18 @@ ${rejected
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
@ -40,6 +41,7 @@ import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-fab";
|
||||
@ -139,6 +141,19 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@storage({ key: "helpers-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "helpers-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "helpers-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
@state() private _stateItems: HassEntity[] = [];
|
||||
|
||||
@state() private _entityEntries?: Record<string, EntityRegistryEntry>;
|
||||
@ -525,7 +540,12 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
).length}
|
||||
.columns=${this._columns(this.narrow, this.hass.localize)}
|
||||
.data=${helpers}
|
||||
initialGroupColumn="category"
|
||||
.initialGroupColumn=${this._activeGrouping || "category"}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
.activeFilters=${this._activeFilters}
|
||||
@clear-filter=${this._clearFilter}
|
||||
@row-click=${this._openEditDialog}
|
||||
@ -1020,6 +1040,18 @@ ${rejected
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -10,15 +10,17 @@ import { LitElement, PropertyValues, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-fab";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-relative-time";
|
||||
import "../../../components/ha-icon-overflow-menu";
|
||||
import "../../../components/ha-relative-time";
|
||||
import {
|
||||
LabelRegistryEntry,
|
||||
LabelRegistryEntryMutableParams,
|
||||
@ -35,7 +37,7 @@ import "../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { HomeAssistant, Route } from "../../../types";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "./show-dialog-label-detail";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
|
||||
@customElement("ha-config-labels")
|
||||
export class HaConfigLabels extends LitElement {
|
||||
@ -49,6 +51,13 @@ export class HaConfigLabels extends LitElement {
|
||||
|
||||
@state() private _labels: LabelRegistryEntry[] = [];
|
||||
|
||||
@storage({
|
||||
key: "labels-table-sort",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
private _columns = memoizeOne((localize: LocalizeFunc) => {
|
||||
const columns: DataTableColumnContainer<LabelRegistryEntry> = {
|
||||
icon: {
|
||||
@ -149,6 +158,8 @@ export class HaConfigLabels extends LitElement {
|
||||
.data=${this._data(this._labels)}
|
||||
.noDataText=${this.hass.localize("ui.panel.config.labels.no_labels")}
|
||||
hasFab
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@row-click=${this._editLabel}
|
||||
clickable
|
||||
id="label_id"
|
||||
@ -268,6 +279,10 @@ export class HaConfigLabels extends LitElement {
|
||||
`/config/automation/dashboard?historyBack=1&label=${label.label_id}`
|
||||
);
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -16,6 +16,7 @@ import { stringCompare } from "../../../../common/string/compare";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../../components/data-table/ha-data-table";
|
||||
import "../../../../components/ha-clickable-list-item";
|
||||
import "../../../../components/ha-fab";
|
||||
@ -46,6 +47,7 @@ import { showNewDashboardDialog } from "../../dashboard/show-dialog-new-dashboar
|
||||
import { lovelaceTabs } from "../ha-config-lovelace";
|
||||
import { showDashboardConfigureStrategyDialog } from "./show-dialog-lovelace-dashboard-configure-strategy";
|
||||
import { showDashboardDetailDialog } from "./show-dialog-lovelace-dashboard-detail";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
|
||||
type DataTableItem = Pick<
|
||||
LovelaceDashboard,
|
||||
@ -68,6 +70,13 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
|
||||
@state() private _dashboards: LovelaceDashboard[] = [];
|
||||
|
||||
@storage({
|
||||
key: "lovelace-dashboards-table-sort",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
public willUpdate() {
|
||||
if (!this.hasUpdated) {
|
||||
this.hass.loadFragmentTranslation("lovelace");
|
||||
@ -293,6 +302,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
this.hass.localize
|
||||
)}
|
||||
.data=${this._getItems(this._dashboards)}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@row-click=${this._editDashboard}
|
||||
id="url_path"
|
||||
hasFab
|
||||
@ -440,6 +451,10 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -10,9 +10,11 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoize from "memoize-one";
|
||||
import { stringCompare } from "../../../../common/string/compare";
|
||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../../components/data-table/ha-data-table";
|
||||
import "../../../../components/ha-card";
|
||||
import "../../../../components/ha-fab";
|
||||
@ -33,10 +35,10 @@ import "../../../../layouts/hass-subpage";
|
||||
import "../../../../layouts/hass-tabs-subpage-data-table";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import { HomeAssistant, Route } from "../../../../types";
|
||||
import { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import { loadLovelaceResources } from "../../../lovelace/common/load-resources";
|
||||
import { lovelaceResourcesTabs } from "../ha-config-lovelace";
|
||||
import { showResourceDetailDialog } from "./show-dialog-lovelace-resource-detail";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
|
||||
@customElement("ha-config-lovelace-resources")
|
||||
export class HaConfigLovelaceRescources extends LitElement {
|
||||
@ -50,6 +52,13 @@ export class HaConfigLovelaceRescources extends LitElement {
|
||||
|
||||
@state() private _resources: LovelaceResource[] = [];
|
||||
|
||||
@storage({
|
||||
key: "lovelace-resources-table-sort",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
private _columns = memoize(
|
||||
(
|
||||
_language,
|
||||
@ -127,6 +136,8 @@ export class HaConfigLovelaceRescources extends LitElement {
|
||||
.noDataText=${this.hass.localize(
|
||||
"ui.panel.config.lovelace.resources.picker.no_resources"
|
||||
)}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@row-click=${this._editResource}
|
||||
hasFab
|
||||
clickable
|
||||
@ -237,6 +248,10 @@ export class HaConfigLovelaceRescources extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -32,14 +32,20 @@ import memoizeOne from "memoize-one";
|
||||
import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-button";
|
||||
@ -95,10 +101,6 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
|
||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
|
||||
type SceneItem = SceneEntity & {
|
||||
name: string;
|
||||
@ -144,6 +146,19 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
@storage({ key: "scene-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "scene-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "scene-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
private _sizeController = new ResizeController(this, {
|
||||
callback: (entries) => entries[0]?.contentRect.width,
|
||||
});
|
||||
@ -463,7 +478,12 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
).length}
|
||||
.columns=${this._columns(this.narrow, this.hass.localize)}
|
||||
id="entity_id"
|
||||
initialGroupColumn="category"
|
||||
.initialGroupColumn=${this._activeGrouping || "category"}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
.data=${scenes}
|
||||
.empty=${!this.scenes.length}
|
||||
.activeFilters=${this._activeFilters}
|
||||
@ -975,6 +995,18 @@ ${rejected
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -33,14 +33,20 @@ import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
|
||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import { HASSDomEvent, fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-fab";
|
||||
@ -97,10 +103,6 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
|
||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import {
|
||||
hasRejectedItems,
|
||||
rejectedItems,
|
||||
} from "../../../common/util/promise-all-settled-results";
|
||||
|
||||
type ScriptItem = ScriptEntity & {
|
||||
name: string;
|
||||
@ -148,6 +150,19 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
@storage({ key: "script-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "script-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "script-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
private _sizeController = new ResizeController(this, {
|
||||
callback: (entries) => entries[0]?.contentRect.width,
|
||||
});
|
||||
@ -462,7 +477,12 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
|
||||
{ number: scripts.length }
|
||||
)}
|
||||
hasFilters
|
||||
initialGroupColumn="category"
|
||||
.initialGroupColumn=${this._activeGrouping || "category"}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
selectable
|
||||
.selected=${this._selected.length}
|
||||
@selection-changed=${this._handleSelectionChanged}
|
||||
@ -1091,6 +1111,18 @@ ${rejected
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
@ -7,6 +7,7 @@ import { LocalizeFunc } from "../../../common/translations/localize";
|
||||
import {
|
||||
DataTableColumnContainer,
|
||||
RowClickedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/data-table/ha-data-table-icon";
|
||||
import "../../../components/ha-fab";
|
||||
@ -25,6 +26,7 @@ import { HomeAssistant, Route } from "../../../types";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showAddUserDialog } from "./show-dialog-add-user";
|
||||
import { showUserDetailDialog } from "./show-dialog-user-detail";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
|
||||
@customElement("ha-config-users")
|
||||
export class HaConfigUsers extends LitElement {
|
||||
@ -38,6 +40,19 @@ export class HaConfigUsers extends LitElement {
|
||||
|
||||
@state() private _users: User[] = [];
|
||||
|
||||
@storage({ key: "users-table-sort", state: false, subscribe: false })
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@storage({ key: "users-table-grouping", state: false, subscribe: false })
|
||||
private _activeGrouping?: string;
|
||||
|
||||
@storage({
|
||||
key: "users-table-collapsed",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeCollapsed?: string;
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(narrow: boolean, localize: LocalizeFunc): DataTableColumnContainer => {
|
||||
const columns: DataTableColumnContainer<User> = {
|
||||
@ -70,16 +85,14 @@ export class HaConfigUsers extends LitElement {
|
||||
hidden: narrow,
|
||||
template: (user) => html`${user.username || "—"}`,
|
||||
},
|
||||
group_ids: {
|
||||
group: {
|
||||
title: localize("ui.panel.config.users.picker.headers.group"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
width: "20%",
|
||||
direction: "asc",
|
||||
hidden: narrow,
|
||||
template: (user) => html`
|
||||
${localize(`groups.${user.group_ids[0]}`)}
|
||||
`,
|
||||
},
|
||||
is_active: {
|
||||
title: this.hass.localize(
|
||||
@ -164,7 +177,13 @@ export class HaConfigUsers extends LitElement {
|
||||
backPath="/config"
|
||||
.tabs=${configSections.persons}
|
||||
.columns=${this._columns(this.narrow, this.hass.localize)}
|
||||
.data=${this._users}
|
||||
.data=${this._userData(this._users, this.hass.localize)}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@grouping-changed=${this._handleGroupingChanged}
|
||||
@collapsed-changed=${this._handleCollapseChanged}
|
||||
@row-click=${this._editUser}
|
||||
hasFab
|
||||
clickable
|
||||
@ -181,6 +200,13 @@ export class HaConfigUsers extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _userData = memoizeOne((users: User[], localize: LocalizeFunc) =>
|
||||
users.map((user) => ({
|
||||
...user,
|
||||
group: localize(`groups.${user.group_ids[0]}`),
|
||||
}))
|
||||
);
|
||||
|
||||
private async _fetchUsers() {
|
||||
this._users = await fetchUsers(this.hass);
|
||||
|
||||
@ -245,6 +271,18 @@ export class HaConfigUsers extends LitElement {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
private _handleGroupingChanged(ev: CustomEvent) {
|
||||
this._activeGrouping = ev.detail.value;
|
||||
}
|
||||
|
||||
private _handleCollapseChanged(ev: CustomEvent) {
|
||||
this._activeCollapsed = ev.detail.value;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -23,6 +23,7 @@ import {
|
||||
DataTableRowData,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
SortingChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
import "../../../components/ha-fab";
|
||||
import { AlexaEntity, fetchCloudAlexaEntities } from "../../../data/alexa";
|
||||
@ -52,6 +53,7 @@ import "./expose/expose-assistant-icon";
|
||||
import { voiceAssistantTabs } from "./ha-config-voice-assistants";
|
||||
import { showExposeEntityDialog } from "./show-dialog-expose-entity";
|
||||
import { showVoiceSettingsDialog } from "./show-dialog-voice-settings";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
|
||||
@customElement("ha-config-voice-assistants-expose")
|
||||
export class VoiceAssistantsExpose extends LitElement {
|
||||
@ -87,6 +89,13 @@ export class VoiceAssistantsExpose extends LitElement {
|
||||
string[] | undefined
|
||||
>;
|
||||
|
||||
@storage({
|
||||
key: "voice-expose-table-sort",
|
||||
state: false,
|
||||
subscribe: false,
|
||||
})
|
||||
private _activeSorting?: SortingChangedEvent;
|
||||
|
||||
@query("hass-tabs-subpage-data-table", true)
|
||||
private _dataTable!: HaTabsSubpageDataTable;
|
||||
|
||||
@ -505,6 +514,8 @@ export class VoiceAssistantsExpose extends LitElement {
|
||||
selectable
|
||||
.selected=${this._selectedEntities.length}
|
||||
clickable
|
||||
.initialSorting=${this._activeSorting}
|
||||
@sorting-changed=${this._handleSortingChanged}
|
||||
@selection-changed=${this._handleSelectionChanged}
|
||||
@clear-filter=${this._clearFilter}
|
||||
@search-changed=${this._handleSearchChange}
|
||||
@ -696,6 +707,10 @@ export class VoiceAssistantsExpose extends LitElement {
|
||||
navigate(window.location.pathname, { replace: true });
|
||||
}
|
||||
|
||||
private _handleSortingChanged(ev: CustomEvent) {
|
||||
this._activeSorting = ev.detail;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
|
Loading…
x
Reference in New Issue
Block a user