extends DataTableSortColumnData {
| "overflow-menu"
| "flex";
template?: (row: T) => TemplateResult | string | typeof nothing;
+ extraTemplate?: (row: T) => TemplateResult | string | typeof nothing;
width?: string;
maxWidth?: string;
grows?: boolean;
@@ -105,6 +110,8 @@ const UNDEFINED_GROUP_KEY = "zzzzz_undefined";
export class HaDataTable extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
+ @property({ type: Boolean }) public narrow = false;
+
@property({ type: Object }) public columns: DataTableColumnContainer = {};
@property({ type: Array }) public data: DataTableRowData[] = [];
@@ -145,6 +152,10 @@ export class HaDataTable extends LitElement {
@property({ attribute: false }) public initialCollapsedGroups?: string[];
+ @property({ attribute: false }) public hiddenColumns?: string[];
+
+ @property({ attribute: false }) public columnOrder?: string[];
+
@state() private _filterable = false;
@state() private _filter = "";
@@ -235,6 +246,7 @@ export class HaDataTable extends LitElement {
(column: ClonedDataTableColumnData) => {
delete column.title;
delete column.template;
+ delete column.extraTemplate;
}
);
@@ -272,12 +284,44 @@ export class HaDataTable extends LitElement {
this._sortFilterData();
}
- if (properties.has("selectable")) {
+ if (properties.has("selectable") || properties.has("hiddenColumns")) {
this._items = [...this._items];
}
}
+ private _sortedColumns = memoizeOne(
+ (columns: DataTableColumnContainer, columnOrder?: string[]) => {
+ if (!columnOrder || !columnOrder.length) {
+ return columns;
+ }
+
+ return Object.keys(columns)
+ .sort((a, b) => {
+ const orderA = columnOrder!.indexOf(a);
+ const orderB = columnOrder!.indexOf(b);
+ if (orderA !== orderB) {
+ if (orderA === -1) {
+ return 1;
+ }
+ if (orderB === -1) {
+ return -1;
+ }
+ }
+ return orderA - orderB;
+ })
+ .reduce((obj, key) => {
+ obj[key] = columns[key];
+ return obj;
+ }, {}) as DataTableColumnContainer;
+ }
+ );
+
protected render() {
+ const columns = this._sortedColumns(this.columns, this.columnOrder);
+
+ const renderRow = (row: DataTableRowData, index: number) =>
+ this._renderRow(columns, this.narrow, row, index);
+
return html`
@@ -326,9 +370,14 @@ export class HaDataTable extends LitElement {
`
: ""}
- ${Object.entries(this.columns).map(([key, column]) => {
- if (column.hidden) {
- return "";
+ ${Object.entries(columns).map(([key, column]) => {
+ if (
+ column.hidden ||
+ (this.columnOrder && this.columnOrder.includes(key)
+ ? this.hiddenColumns?.includes(key) ?? column.defaultHidden
+ : column.defaultHidden)
+ ) {
+ return nothing;
}
const sorted = key === this.sortColumn;
const classes = {
@@ -399,7 +448,7 @@ export class HaDataTable extends LitElement {
@scroll=${this._saveScrollPos}
.items=${this._items}
.keyFunction=${this._keyFunction}
- .renderItem=${this._renderRow}
+ .renderItem=${renderRow}
>
`}
@@ -409,7 +458,12 @@ export class HaDataTable extends LitElement {
private _keyFunction = (row: DataTableRowData) => row?.[this.id] || row;
- private _renderRow = (row: DataTableRowData, index: number) => {
+ private _renderRow = (
+ columns: DataTableColumnContainer,
+ narrow: boolean,
+ row: DataTableRowData,
+ index: number
+ ) => {
// not sure how this happens...
if (!row) {
return nothing;
@@ -454,8 +508,14 @@ export class HaDataTable extends LitElement {
`
: ""}
- ${Object.entries(this.columns).map(([key, column]) => {
- if (column.hidden) {
+ ${Object.entries(columns).map(([key, column]) => {
+ if (
+ (narrow && !column.main && !column.showNarrow) ||
+ column.hidden ||
+ (this.columnOrder && this.columnOrder.includes(key)
+ ? this.hiddenColumns?.includes(key) ?? column.defaultHidden
+ : column.defaultHidden)
+ ) {
return nothing;
}
return html`
@@ -482,7 +542,38 @@ export class HaDataTable extends LitElement {
})
: ""}
>
- ${column.template ? column.template(row) : row[key]}
+ ${column.template
+ ? column.template(row)
+ : narrow && column.main
+ ? html`${row[key]}
+
+ ${Object.entries(columns)
+ .filter(
+ ([key2, column2]) =>
+ !column2.hidden &&
+ !column2.main &&
+ !column2.showNarrow &&
+ !(this.columnOrder &&
+ this.columnOrder.includes(key2)
+ ? this.hiddenColumns?.includes(key2) ??
+ column2.defaultHidden
+ : column2.defaultHidden)
+ )
+ .map(
+ ([key2, column2], i) =>
+ html`${i !== 0
+ ? " ⸱ "
+ : nothing}${column2.template
+ ? column2.template(row)
+ : row[key2]}`
+ )}
+
+ ${column.extraTemplate
+ ? column.extraTemplate(row)
+ : nothing}`
+ : html`${row[key]}${column.extraTemplate
+ ? column.extraTemplate(row)
+ : nothing}`}
`;
})}
@@ -861,6 +952,7 @@ export class HaDataTable extends LitElement {
width: 100%;
border: 0;
white-space: nowrap;
+ position: relative;
}
.mdc-data-table__cell {
diff --git a/src/components/data-table/show-dialog-data-table-settings.ts b/src/components/data-table/show-dialog-data-table-settings.ts
new file mode 100644
index 0000000000..b31e801acb
--- /dev/null
+++ b/src/components/data-table/show-dialog-data-table-settings.ts
@@ -0,0 +1,26 @@
+import { fireEvent } from "../../common/dom/fire_event";
+import { DataTableColumnContainer } from "./ha-data-table";
+
+export interface DataTableSettingsDialogParams {
+ columns: DataTableColumnContainer;
+ onUpdate: (
+ columnOrder: string[] | undefined,
+ hiddenColumns: string[] | undefined
+ ) => void;
+ hiddenColumns?: string[];
+ columnOrder?: string[];
+}
+
+export const loadDataTableSettingsDialog = () =>
+ import("./dialog-data-table-settings");
+
+export const showDataTableSettingsDialog = (
+ element: HTMLElement,
+ dialogParams: DataTableSettingsDialogParams
+): void => {
+ fireEvent(element, "show-dialog", {
+ dialogTag: "dialog-data-table-settings",
+ dialogImport: loadDataTableSettingsDialog,
+ dialogParams,
+ });
+};
diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts
index f59c569c8c..4f062182a2 100644
--- a/src/layouts/hass-tabs-subpage-data-table.ts
+++ b/src/layouts/hass-tabs-subpage-data-table.ts
@@ -6,6 +6,7 @@ import {
mdiArrowDown,
mdiArrowUp,
mdiClose,
+ mdiCog,
mdiFilterVariant,
mdiFilterVariantRemove,
mdiFormatListChecks,
@@ -42,6 +43,7 @@ import "../components/search-input-outlined";
import type { HomeAssistant, Route } from "../types";
import "./hass-tabs-subpage";
import type { PageNavigation } from "./hass-tabs-subpage";
+import { showDataTableSettingsDialog } from "../components/data-table/show-dialog-data-table-settings";
@customElement("hass-tabs-subpage-data-table")
export class HaTabsSubpageDataTable extends LitElement {
@@ -171,6 +173,10 @@ export class HaTabsSubpageDataTable extends LitElement {
@property({ attribute: false }) public groupOrder?: string[];
+ @property({ attribute: false }) public columnOrder?: string[];
+
+ @property({ attribute: false }) public hiddenColumns?: string[];
+
@state() private _sortColumn?: string;
@state() private _sortDirection: SortingDirection = null;
@@ -290,6 +296,14 @@ export class HaTabsSubpageDataTable extends LitElement {
`
: nothing;
+ const settingsButton = html`
+
+ `;
+
return html`
${!this.narrow
? html`
@@ -438,7 +455,7 @@ export class HaTabsSubpageDataTable extends LitElement {
@@ -448,7 +465,7 @@ export class HaTabsSubpageDataTable extends LitElement {
${this.hasFilters && !this.showFilters
? html`${filterButton}`
: nothing}
- ${selectModeBtn}${groupByMenu}${sortByMenu}
+ ${selectModeBtn}${groupByMenu}${sortByMenu}${settingsButton}
`}
`}
@@ -608,6 +625,22 @@ export class HaTabsSubpageDataTable extends LitElement {
fireEvent(this, "grouping-changed", { value: columnId });
}
+ private _openSettings() {
+ showDataTableSettingsDialog(this, {
+ columns: this.columns,
+ hiddenColumns: this.hiddenColumns,
+ columnOrder: this.columnOrder,
+ onUpdate: (
+ columnOrder: string[] | undefined,
+ hiddenColumns: string[] | undefined
+ ) => {
+ this.columnOrder = columnOrder;
+ this.hiddenColumns = hiddenColumns;
+ fireEvent(this, "columns-changed", { columnOrder, hiddenColumns });
+ },
+ });
+ }
+
private _collapseAllGroups() {
this._dataTable.collapseAllGroups();
}
@@ -874,6 +907,10 @@ declare global {
interface HASSDomEvents {
"search-changed": { value: string };
"grouping-changed": { value: string };
+ "columns-changed": {
+ columnOrder: string[] | undefined;
+ hiddenColumns: string[] | undefined;
+ };
"clear-filter": undefined;
}
}
diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts
index 0418f9b701..67da2d580d 100644
--- a/src/panels/config/automation/ha-automation-picker.ts
+++ b/src/panels/config/automation/ha-automation-picker.ts
@@ -192,6 +192,20 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
})
private _activeCollapsed?: string;
+ @storage({
+ key: "automation-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "automation-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
@query("#overflow-menu") private _overflowMenu!: HaMenu;
private _sizeController = new ResizeController(this, {
@@ -253,6 +267,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
title: "",
label: localize("ui.panel.config.automation.picker.headers.state"),
type: "icon",
+ moveable: false,
+ showNarrow: true,
template: (automation) =>
html` {
- const date = new Date(automation.attributes.last_triggered);
- const now = new Date();
- const dayDifference = differenceInDays(now, date);
- return html`
- ${automation.name}
- ${narrow
- ? html`
- ${this.hass.localize("ui.card.automation.last_triggered")}:
- ${automation.attributes.last_triggered
- ? dayDifference > 3
- ? formatShortDateTime(date, locale, this.hass.config)
- : relativeTime(date, locale)
- : localize("ui.components.relative_time.never")}
-
`
- : nothing}
- ${automation.labels.length
- ? html``
- : nothing}
- `;
- },
+ extraTemplate: (automation) =>
+ automation.labels.length
+ ? html``
+ : nothing,
},
area: {
title: localize("ui.panel.config.automation.picker.headers.area"),
@@ -322,7 +321,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
sortable: true,
width: "130px",
title: localize("ui.card.automation.last_triggered"),
- hidden: narrow,
template: (automation) => {
if (!automation.last_triggered) {
return this.hass.localize("ui.components.relative_time.never");
@@ -341,9 +339,9 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
width: "82px",
sortable: true,
groupable: true,
+ hidden: narrow,
title: "",
type: "overflow",
- hidden: narrow,
label: this.hass.localize("ui.panel.config.automation.picker.state"),
template: (automation) => html`
html`
- html`${backup.name}
- ${backup.path}
`,
+ template: narrow
+ ? undefined
+ : (backup) =>
+ html`${backup.name}
+ ${backup.path}
`,
+ },
+ path: {
+ title: localize("ui.panel.config.backup.path"),
+ hidden: !narrow,
},
size: {
title: localize("ui.panel.config.backup.size"),
width: "15%",
- hidden: narrow,
filterable: true,
sortable: true,
template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB",
@@ -76,7 +81,6 @@ class HaConfigBackup extends LitElement {
title: localize("ui.panel.config.backup.created"),
width: "15%",
direction: "desc",
- hidden: narrow,
filterable: true,
sortable: true,
template: (backup) =>
@@ -87,6 +91,9 @@ class HaConfigBackup extends LitElement {
title: "",
width: "15%",
type: "overflow-menu",
+ showNarrow: true,
+ hideable: false,
+ moveable: false,
template: (backup) =>
html` => ({
name: {
@@ -165,19 +177,12 @@ class HaBlueprintOverview extends LitElement {
filterable: true,
direction: "asc",
grows: true,
- template: narrow
- ? (blueprint) => html`
- ${blueprint.name}
- ${blueprint.path}
- `
- : undefined,
},
translated_type: {
title: localize("ui.panel.config.blueprint.overview.headers.type"),
sortable: true,
filterable: true,
groupable: true,
- hidden: narrow,
direction: "asc",
width: "10%",
},
@@ -185,7 +190,6 @@ class HaBlueprintOverview extends LitElement {
title: localize("ui.panel.config.blueprint.overview.headers.file_name"),
sortable: true,
filterable: true,
- hidden: narrow,
direction: "asc",
width: "25%",
},
@@ -197,6 +201,9 @@ class HaBlueprintOverview extends LitElement {
title: "",
width: this.narrow ? undefined : "10%",
type: "overflow-menu",
+ showNarrow: true,
+ moveable: false,
+ hideable: false,
template: (blueprint) =>
blueprint.error
? html` entries[0]?.contentRect.width,
});
@@ -434,10 +448,13 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
typeof this._devicesAndFilterDomains
>["devicesOutput"][number];
- const columns: DataTableColumnContainer = {
+ return {
icon: {
title: "",
+ label: localize("ui.panel.config.devices.data_table.icon"),
type: "icon",
+ moveable: false,
+ showNarrow: true,
template: (device) =>
device.domains.length
? html`
`
: "",
},
- };
-
- if (narrow) {
- columns.name = {
+ name: {
title: localize("ui.panel.config.devices.data_table.device"),
main: true,
sortable: true,
filterable: true,
direction: "asc",
grows: true,
- template: (device) => html`
- ${device.name}
- ${device.area} | ${device.integration}
+ extraTemplate: (device) => html`
${device.label_entries.length
? html`
html`
- ${device.name}
- ${device.label_entries.length
- ? html`
-
- `
- : nothing}
- `,
- };
- }
-
- columns.manufacturer = {
- title: localize("ui.panel.config.devices.data_table.manufacturer"),
- sortable: true,
- hidden: narrow,
- filterable: true,
- groupable: true,
- width: "15%",
- };
- columns.model = {
- title: localize("ui.panel.config.devices.data_table.model"),
- sortable: true,
- hidden: narrow,
- filterable: true,
- width: "15%",
- };
- columns.area = {
- title: localize("ui.panel.config.devices.data_table.area"),
- sortable: true,
- hidden: narrow,
- filterable: true,
- groupable: true,
- width: "15%",
- };
- columns.integration = {
- title: localize("ui.panel.config.devices.data_table.integration"),
- sortable: true,
- hidden: narrow,
- filterable: true,
- groupable: true,
- width: "15%",
- };
- columns.battery_entity = {
- title: localize("ui.panel.config.devices.data_table.battery"),
- sortable: true,
- filterable: true,
- type: "numeric",
- width: narrow ? "105px" : "15%",
- maxWidth: "105px",
- valueColumn: "battery_level",
- template: (device) => {
- const batteryEntityPair = device.battery_entity;
- const battery =
- batteryEntityPair && batteryEntityPair[0]
- ? this.hass.states[batteryEntityPair[0]]
- : undefined;
- const batteryDomain = battery ? computeStateDomain(battery) : undefined;
- const batteryCharging =
- batteryEntityPair && batteryEntityPair[1]
- ? this.hass.states[batteryEntityPair[1]]
- : undefined;
-
- return battery &&
- (batteryDomain === "binary_sensor" || !isNaN(battery.state as any))
- ? html`
- ${batteryDomain === "sensor"
- ? this.hass.formatEntityState(battery)
- : nothing}
-
- `
- : html`—`;
},
- };
- columns.disabled_by = {
- title: "",
- label: localize("ui.panel.config.devices.data_table.disabled_by"),
- hidden: true,
- template: (device) =>
- device.disabled_by
- ? this.hass.localize("ui.panel.config.devices.disabled")
- : "",
- };
- columns.labels = {
- title: "",
- hidden: true,
- filterable: true,
- template: (device) =>
- device.label_entries.map((lbl) => lbl.name).join(" "),
- };
+ manufacturer: {
+ title: localize("ui.panel.config.devices.data_table.manufacturer"),
+ sortable: true,
+ filterable: true,
+ groupable: true,
+ width: "15%",
+ },
+ model: {
+ title: localize("ui.panel.config.devices.data_table.model"),
+ sortable: true,
+ filterable: true,
+ width: "15%",
+ },
+ area: {
+ title: localize("ui.panel.config.devices.data_table.area"),
+ sortable: true,
+ filterable: true,
+ groupable: true,
+ width: "15%",
+ },
+ integration: {
+ title: localize("ui.panel.config.devices.data_table.integration"),
+ sortable: true,
+ filterable: true,
+ groupable: true,
+ width: "15%",
+ },
+ battery_entity: {
+ title: localize("ui.panel.config.devices.data_table.battery"),
+ showNarrow: true,
+ sortable: true,
+ filterable: true,
+ type: "numeric",
+ width: narrow ? "105px" : "15%",
+ maxWidth: "105px",
+ valueColumn: "battery_level",
+ template: (device) => {
+ const batteryEntityPair = device.battery_entity;
+ const battery =
+ batteryEntityPair && batteryEntityPair[0]
+ ? this.hass.states[batteryEntityPair[0]]
+ : undefined;
+ const batteryDomain = battery
+ ? computeStateDomain(battery)
+ : undefined;
+ const batteryCharging =
+ batteryEntityPair && batteryEntityPair[1]
+ ? this.hass.states[batteryEntityPair[1]]
+ : undefined;
- return columns;
+ return battery &&
+ (batteryDomain === "binary_sensor" || !isNaN(battery.state as any))
+ ? html`
+ ${batteryDomain === "sensor"
+ ? this.hass.formatEntityState(battery)
+ : nothing}
+
+ `
+ : html`—`;
+ },
+ },
+ disabled_by: {
+ title: "",
+ label: localize("ui.panel.config.devices.data_table.disabled_by"),
+ hidden: true,
+ template: (device) =>
+ device.disabled_by
+ ? this.hass.localize("ui.panel.config.devices.disabled")
+ : "",
+ },
+ labels: {
+ title: "",
+ hidden: true,
+ filterable: true,
+ template: (device) =>
+ device.label_entries.map((lbl) => lbl.name).join(" "),
+ },
+ } as DataTableColumnContainer;
});
protected hassSubscribe(): (UnsubscribeFunc | Promise)[] {
@@ -704,6 +693,9 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
.initialGroupColumn=${this._activeGrouping}
.initialCollapsedGroups=${this._activeCollapsed}
.initialSorting=${this._activeSorting}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@clear-filter=${this._clearFilter}
@search-changed=${this._handleSearchChange}
@sorting-changed=${this._handleSortingChanged}
@@ -1043,6 +1035,11 @@ ${rejected
this._activeCollapsed = ev.detail.value;
}
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
+
static get styles(): CSSResultGroup {
return [
css`
diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts
index 0eeeac1a51..971f810533 100644
--- a/src/panels/config/entities/ha-config-entities.ts
+++ b/src/panels/config/entities/ha-config-entities.ts
@@ -186,6 +186,20 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
})
private _activeCollapsed?: string;
+ @storage({
+ key: "entities-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "entities-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
@query("hass-tabs-subpage-data-table", true)
private _dataTable!: HaTabsSubpageDataTable;
@@ -251,15 +265,13 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
]);
private _columns = memoize(
- (
- localize: LocalizeFunc,
- narrow,
- _language
- ): DataTableColumnContainer => ({
+ (localize: LocalizeFunc): DataTableColumnContainer => ({
icon: {
title: "",
label: localize("ui.panel.config.entities.picker.headers.state_icon"),
type: "icon",
+ showNarrow: true,
+ moveable: false,
template: (entry) =>
entry.icon
? html``
@@ -283,32 +295,23 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
filterable: true,
direction: "asc",
grows: true,
- template: (entry) => html`
- ${entry.name}
- ${narrow
- ? html`
- ${entry.entity_id} | ${entry.localized_platform}
-
`
- : nothing}
- ${entry.label_entries.length
+ extraTemplate: (entry) =>
+ entry.label_entries.length
? html`
`
- : nothing}
- `,
+ : nothing,
},
entity_id: {
title: localize("ui.panel.config.entities.picker.headers.entity_id"),
- hidden: narrow,
sortable: true,
filterable: true,
width: "25%",
},
localized_platform: {
title: localize("ui.panel.config.entities.picker.headers.integration"),
- hidden: narrow,
sortable: true,
groupable: true,
filterable: true,
@@ -324,7 +327,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
area: {
title: localize("ui.panel.config.entities.picker.headers.area"),
sortable: true,
- hidden: narrow,
filterable: true,
groupable: true,
width: "15%",
@@ -343,6 +345,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
status: {
title: localize("ui.panel.config.entities.picker.headers.status"),
type: "icon",
+ showNarrow: true,
sortable: true,
filterable: true,
width: "68px",
@@ -688,11 +691,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
}
.route=${this.route}
.tabs=${configSections.devices}
- .columns=${this._columns(
- this.hass.localize,
- this.narrow,
- this.hass.language
- )}
+ .columns=${this._columns(this.hass.localize)}
.data=${filteredEntities}
.searchLabel=${this.hass.localize(
"ui.panel.config.entities.picker.search",
@@ -714,6 +713,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
.initialGroupColumn=${this._activeGrouping}
.initialCollapsedGroups=${this._activeCollapsed}
.initialSorting=${this._activeSorting}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@sorting-changed=${this._handleSortingChanged}
@grouping-changed=${this._handleGroupingChanged}
@collapsed-changed=${this._handleCollapseChanged}
@@ -1335,6 +1337,11 @@ ${rejected
this._activeCollapsed = ev.detail.value;
}
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
+
static get styles(): CSSResultGroup {
return [
haStyle,
diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts
index 032eb362f6..1046866244 100644
--- a/src/panels/config/helpers/ha-config-helpers.ts
+++ b/src/panels/config/helpers/ha-config-helpers.ts
@@ -167,6 +167,20 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
})
private _filter = "";
+ @storage({
+ key: "helpers-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "helpers-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
@state() private _stateItems: HassEntity[] = [];
@state() private _entityEntries?: Record;
@@ -243,14 +257,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
}
private _columns = memoizeOne(
- (
- narrow: boolean,
- localize: LocalizeFunc
- ): DataTableColumnContainer => ({
+ (localize: LocalizeFunc): DataTableColumnContainer => ({
icon: {
title: "",
label: localize("ui.panel.config.helpers.picker.headers.icon"),
type: "icon",
+ showNarrow: true,
+ moveable: false,
template: (helper) =>
helper.entity
? html` html`
- ${helper.name}
- ${narrow
- ? html`${helper.entity_id}
`
- : nothing}
- ${helper.label_entries.length
+ extraTemplate: (helper) =>
+ helper.label_entries.length
? html`
`
- : nothing}
- `,
+ : nothing,
},
entity_id: {
title: localize("ui.panel.config.helpers.picker.headers.entity_id"),
- hidden: this.narrow,
sortable: true,
filterable: true,
width: "25%",
@@ -313,10 +320,9 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
},
editable: {
title: "",
- label: this.hass.localize(
- "ui.panel.config.helpers.picker.headers.editable"
- ),
+ label: localize("ui.panel.config.helpers.picker.headers.editable"),
type: "icon",
+ showNarrow: true,
template: (helper) => html`
${!helper.editable
? html`
@@ -337,8 +343,12 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
},
actions: {
title: "",
+ label: "Actions",
width: "64px",
type: "overflow-menu",
+ hideable: false,
+ moveable: false,
+ showNarrow: true,
template: (helper) => html`
{
const columns: DataTableColumnContainer = {
icon: {
title: "",
+ moveable: false,
+ showNarrow: true,
label: localize("ui.panel.config.labels.headers.icon"),
type: "icon",
template: (label) =>
@@ -77,6 +93,7 @@ export class HaConfigLabels extends LitElement {
},
color: {
title: "",
+ showNarrow: true,
label: localize("ui.panel.config.labels.headers.color"),
type: "icon",
template: (label) =>
@@ -105,6 +122,9 @@ export class HaConfigLabels extends LitElement {
},
actions: {
title: "",
+ showNarrow: true,
+ moveable: false,
+ hideable: false,
width: "64px",
type: "overflow-menu",
template: (label) => html`
@@ -167,6 +187,9 @@ export class HaConfigLabels extends LitElement {
.noDataText=${this.hass.localize("ui.panel.config.labels.no_labels")}
hasFab
.initialSorting=${this._activeSorting}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@@ -297,6 +320,11 @@ export class HaConfigLabels extends LitElement {
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
+
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
}
declare global {
diff --git a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts
index 15df18b002..9952ba17a9 100644
--- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts
+++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts
@@ -85,6 +85,20 @@ export class HaConfigLovelaceDashboards extends LitElement {
})
private _activeSorting?: SortingChangedEvent;
+ @storage({
+ key: "lovelace-dashboards-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "lovelace-dashboards-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
public willUpdate() {
if (!this.hasUpdated) {
this.hass.loadFragmentTranslation("lovelace");
@@ -101,6 +115,8 @@ export class HaConfigLovelaceDashboards extends LitElement {
const columns: DataTableColumnContainer = {
icon: {
title: "",
+ moveable: false,
+ showNarrow: true,
label: localize(
"ui.panel.config.lovelace.dashboards.picker.headers.icon"
),
@@ -128,87 +144,75 @@ export class HaConfigLovelaceDashboards extends LitElement {
sortable: true,
filterable: true,
grows: true,
- template: (dashboard) => {
- const titleTemplate = html`
- ${dashboard.title}
- ${dashboard.default
- ? html`
-
-
- ${this.hass.localize(
- `ui.panel.config.lovelace.dashboards.default_dashboard`
- )}
-
- `
- : ""}
- `;
- return narrow
- ? html`
- ${titleTemplate}
-
- ${this.hass.localize(
- `ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}`
- )}${dashboard.filename
- ? html` – ${dashboard.filename} `
- : ""}
-
- `
- : titleTemplate;
- },
+ template: narrow
+ ? undefined
+ : (dashboard) => html`
+ ${dashboard.title}
+ ${dashboard.default
+ ? html`
+
+
+ ${this.hass.localize(
+ `ui.panel.config.lovelace.dashboards.default_dashboard`
+ )}
+
+ `
+ : ""}
+ `,
},
};
- if (!narrow) {
- columns.mode = {
+ columns.mode = {
+ title: localize(
+ "ui.panel.config.lovelace.dashboards.picker.headers.conf_mode"
+ ),
+ sortable: true,
+ filterable: true,
+ width: "20%",
+ template: (dashboard) => html`
+ ${this.hass.localize(
+ `ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}`
+ ) || dashboard.mode}
+ `,
+ };
+ if (dashboards.some((dashboard) => dashboard.filename)) {
+ columns.filename = {
title: localize(
- "ui.panel.config.lovelace.dashboards.picker.headers.conf_mode"
+ "ui.panel.config.lovelace.dashboards.picker.headers.filename"
),
+ width: "15%",
sortable: true,
filterable: true,
- width: "20%",
- template: (dashboard) => html`
- ${this.hass.localize(
- `ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}`
- ) || dashboard.mode}
- `,
- };
- if (dashboards.some((dashboard) => dashboard.filename)) {
- columns.filename = {
- title: localize(
- "ui.panel.config.lovelace.dashboards.picker.headers.filename"
- ),
- width: "15%",
- sortable: true,
- filterable: true,
- };
- }
- columns.require_admin = {
- title: localize(
- "ui.panel.config.lovelace.dashboards.picker.headers.require_admin"
- ),
- sortable: true,
- type: "icon",
- width: "100px",
- template: (dashboard) =>
- dashboard.require_admin
- ? html``
- : html`—`,
- };
- columns.show_in_sidebar = {
- title: localize(
- "ui.panel.config.lovelace.dashboards.picker.headers.sidebar"
- ),
- type: "icon",
- width: "121px",
- template: (dashboard) =>
- dashboard.show_in_sidebar
- ? html``
- : html`—`,
};
}
+ columns.require_admin = {
+ title: localize(
+ "ui.panel.config.lovelace.dashboards.picker.headers.require_admin"
+ ),
+ sortable: true,
+ type: "icon",
+ hidden: narrow,
+ width: "100px",
+ template: (dashboard) =>
+ dashboard.require_admin
+ ? html``
+ : html`—`,
+ };
+ columns.show_in_sidebar = {
+ title: localize(
+ "ui.panel.config.lovelace.dashboards.picker.headers.sidebar"
+ ),
+ type: "icon",
+ hidden: narrow,
+ width: "121px",
+ template: (dashboard) =>
+ dashboard.show_in_sidebar
+ ? html``
+ : html`—`,
+ };
columns.url_path = {
title: "",
@@ -216,6 +220,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
"ui.panel.config.lovelace.dashboards.picker.headers.url"
),
filterable: true,
+ showNarrow: true,
width: "100px",
template: (dashboard) =>
narrow
@@ -311,6 +316,9 @@ export class HaConfigLovelaceDashboards extends LitElement {
)}
.data=${this._getItems(this._dashboards)}
.initialSorting=${this._activeSorting}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@@ -467,6 +475,11 @@ export class HaConfigLovelaceDashboards extends LitElement {
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
+
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
}
declare global {
diff --git a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts
index ab87058e69..2c91a30a88 100644
--- a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts
+++ b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts
@@ -67,12 +67,27 @@ export class HaConfigLovelaceRescources extends LitElement {
})
private _activeSorting?: SortingChangedEvent;
+ @storage({
+ key: "lovelace-resources-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "lovelace-resources-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
private _columns = memoize(
(
_language,
localize: LocalizeFunc
): DataTableColumnContainer => ({
url: {
+ main: true,
title: localize(
"ui.panel.config.lovelace.resources.picker.headers.url"
),
@@ -145,6 +160,9 @@ export class HaConfigLovelaceRescources extends LitElement {
"ui.panel.config.lovelace.resources.picker.no_resources"
)}
.initialSorting=${this._activeSorting}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@sorting-changed=${this._handleSortingChanged}
.filter=${this._filter}
@search-changed=${this._handleSearchChange}
@@ -266,6 +284,11 @@ export class HaConfigLovelaceRescources extends LitElement {
this._filter = ev.detail.value;
}
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
+
static get styles(): CSSResultGroup {
return [
haStyle,
diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts
index 4f2fca1c96..0f47b0644c 100644
--- a/src/panels/config/scene/ha-scene-dashboard.ts
+++ b/src/panels/config/scene/ha-scene-dashboard.ts
@@ -180,6 +180,20 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
})
private _activeCollapsed?: string;
+ @storage({
+ key: "scene-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "scene-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
private _sizeController = new ResizeController(this, {
callback: (entries) => entries[0]?.contentRect.width,
});
@@ -225,11 +239,13 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
);
private _columns = memoizeOne(
- (narrow, localize: LocalizeFunc): DataTableColumnContainer => {
+ (localize: LocalizeFunc): DataTableColumnContainer => {
const columns: DataTableColumnContainer = {
icon: {
title: "",
label: localize("ui.panel.config.scene.picker.headers.state"),
+ moveable: false,
+ showNarrow: true,
type: "icon",
template: (scene) => html`
html`
- ${scene.name}
- ${scene.labels.length
+ extraTemplate: (scene) =>
+ scene.labels.length
? html``
- : nothing}
- `,
+ : nothing,
},
area: {
title: localize("ui.panel.config.scene.picker.headers.area"),
@@ -281,7 +295,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
),
sortable: true,
width: "30%",
- hidden: narrow,
template: (scene) => {
const lastActivated = scene.state;
if (!lastActivated || isUnavailableState(lastActivated)) {
@@ -300,6 +313,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
only_editable: {
title: "",
width: "56px",
+ showNarrow: true,
template: (scene) =>
!scene.attributes.id
? html`
@@ -319,6 +333,9 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
title: "",
width: "64px",
type: "overflow-menu",
+ showNarrow: true,
+ moveable: false,
+ hideable: false,
template: (scene) => html`
entries[0]?.contentRect.width,
});
@@ -232,14 +246,12 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
);
private _columns = memoizeOne(
- (
- narrow,
- localize: LocalizeFunc,
- locale: HomeAssistant["locale"]
- ): DataTableColumnContainer => {
+ (localize: LocalizeFunc): DataTableColumnContainer => {
const columns: DataTableColumnContainer = {
icon: {
title: "",
+ showNarrow: true,
+ moveable: false,
label: localize("ui.panel.config.script.picker.headers.state"),
type: "icon",
template: (script) =>
@@ -259,30 +271,13 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
filterable: true,
direction: "asc",
grows: true,
- template: (script) => {
- const date = new Date(script.last_triggered);
- const now = new Date();
- const dayDifference = differenceInDays(now, date);
- return html`
- ${script.name}
- ${narrow
- ? html`
- ${this.hass.localize("ui.card.automation.last_triggered")}:
- ${script.attributes.last_triggered
- ? dayDifference > 3
- ? formatShortDateTime(date, locale, this.hass.config)
- : relativeTime(date, locale)
- : localize("ui.components.relative_time.never")}
-
`
- : nothing}
- ${script.labels.length
- ? html``
- : nothing}
- `;
- },
+ extraTemplate: (script) =>
+ script.labels.length
+ ? html``
+ : nothing,
},
area: {
title: localize("ui.panel.config.script.picker.headers.area"),
@@ -305,7 +300,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
template: (script) => script.labels.map((lbl) => lbl.name).join(" "),
},
last_triggered: {
- hidden: narrow,
sortable: true,
width: "40%",
title: localize("ui.card.automation.last_triggered"),
@@ -330,6 +324,9 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
title: "",
width: "64px",
type: "overflow-menu",
+ showNarrow: true,
+ moveable: false,
+ hideable: false,
template: (script) => html`
{
- const columns: DataTableColumnContainer = {
- icon: {
- title: "",
- label: localize("ui.panel.config.tag.headers.icon"),
- type: "icon",
- template: (tag) => html``,
- },
- display_name: {
- title: localize("ui.panel.config.tag.headers.name"),
- main: true,
- sortable: true,
- filterable: true,
- grows: true,
- template: (tag) =>
- html`${tag.display_name}
- ${narrow
- ? html`
- ${tag.last_scanned_datetime
- ? html``
- : this.hass.localize("ui.panel.config.tag.never_scanned")}
-
`
- : ""}`,
- },
- last_scanned_datetime: {
- title: localize("ui.panel.config.tag.headers.last_scanned"),
- sortable: true,
- hidden: narrow,
- direction: "desc",
- width: "20%",
- template: (tag) => html`
- ${tag.last_scanned_datetime
- ? html``
- : this.hass.localize("ui.panel.config.tag.never_scanned")}
- `,
- },
- };
- if (this._canWriteTags) {
- columns.write = {
- title: "",
- label: localize("ui.panel.config.tag.headers.write"),
- type: "icon-button",
- template: (tag) =>
- html` `,
- };
- }
- columns.automation = {
+ private _columns = memoizeOne((localize: LocalizeFunc) => {
+ const columns: DataTableColumnContainer = {
+ icon: {
title: "",
+ moveable: false,
+ showNarrow: true,
+ label: localize("ui.panel.config.tag.headers.icon"),
+ type: "icon",
+ template: (tag) => html``,
+ },
+ display_name: {
+ title: localize("ui.panel.config.tag.headers.name"),
+ main: true,
+ sortable: true,
+ filterable: true,
+ grows: true,
+ },
+ last_scanned_datetime: {
+ title: localize("ui.panel.config.tag.headers.last_scanned"),
+ sortable: true,
+ direction: "desc",
+ width: "20%",
+ template: (tag) => html`
+ ${tag.last_scanned_datetime
+ ? html``
+ : this.hass.localize("ui.panel.config.tag.never_scanned")}
+ `,
+ },
+ };
+ if (this._canWriteTags) {
+ columns.write = {
+ title: "",
+ label: localize("ui.panel.config.tag.headers.write"),
type: "icon-button",
+ showNarrow: true,
template: (tag) =>
- html` `,
};
- columns.edit = {
- title: "",
- type: "icon-button",
- template: (tag) =>
- html` `,
- };
- return columns;
}
- );
+ columns.automation = {
+ title: "",
+ type: "icon-button",
+ showNarrow: true,
+ template: (tag) =>
+ html``,
+ };
+ columns.edit = {
+ title: "",
+ type: "icon-button",
+ showNarrow: true,
+ hideable: false,
+ moveable: false,
+ template: (tag) =>
+ html``,
+ };
+ return columns;
+ });
private _data = memoizeOne((tags: Tag[]): TagRowData[] =>
tags.map((tag) => ({
@@ -191,11 +180,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
back-path="/config"
.route=${this.route}
.tabs=${configSections.tags}
- .columns=${this._columns(
- this.narrow,
- this.hass.language,
- this.hass.localize
- )}
+ .columns=${this._columns(this.hass.localize)}
.data=${this._data(this._tags)}
.noDataText=${this.hass.localize("ui.panel.config.tag.no_tags")}
.filter=${this._filter}
diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts
index 89bdea4bf7..553d3f1a02 100644
--- a/src/panels/config/users/ha-config-users.ts
+++ b/src/panels/config/users/ha-config-users.ts
@@ -46,6 +46,20 @@ export class HaConfigUsers extends LitElement {
@storage({ key: "users-table-grouping", state: false, subscribe: false })
private _activeGrouping?: string;
+ @storage({
+ key: "users-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "users-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
@storage({
storage: "sessionStorage",
key: "users-table-search",
@@ -72,17 +86,6 @@ export class HaConfigUsers extends LitElement {
width: "25%",
direction: "asc",
grows: true,
- template: (user) =>
- narrow
- ? html` ${user.name}
-
- ${user.username ? `${user.username} |` : ""}
- ${localize(`groups.${user.group_ids[0]}`)}
-
`
- : html` ${user.name ||
- this.hass!.localize(
- "ui.panel.config.users.editor.unnamed_user"
- )}`,
},
username: {
title: localize("ui.panel.config.users.picker.headers.username"),
@@ -90,7 +93,6 @@ export class HaConfigUsers extends LitElement {
filterable: true,
width: "20%",
direction: "asc",
- hidden: narrow,
template: (user) => html`${user.username || "—"}`,
},
group: {
@@ -100,7 +102,6 @@ export class HaConfigUsers extends LitElement {
groupable: true,
width: "20%",
direction: "asc",
- hidden: narrow,
},
is_active: {
title: this.hass.localize(
@@ -154,6 +155,7 @@ export class HaConfigUsers extends LitElement {
filterable: false,
width: "104px",
hidden: !narrow,
+ showNarrow: true,
template: (user) => {
const badges = computeUserBadges(this.hass, user, false);
return html`${badges.map(
@@ -186,6 +188,9 @@ export class HaConfigUsers extends LitElement {
.tabs=${configSections.persons}
.columns=${this._columns(this.narrow, this.hass.localize)}
.data=${this._userData(this._users, this.hass.localize)}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
.initialGroupColumn=${this._activeGrouping}
.initialCollapsedGroups=${this._activeCollapsed}
.initialSorting=${this._activeSorting}
@@ -213,6 +218,7 @@ export class HaConfigUsers extends LitElement {
private _userData = memoizeOne((users: User[], localize: LocalizeFunc) =>
users.map((user) => ({
...user,
+ name: user.name || localize("ui.panel.config.users.editor.unnamed_user"),
group: localize(`groups.${user.group_ids[0]}`),
}))
);
@@ -302,6 +308,11 @@ export class HaConfigUsers extends LitElement {
private _handleSearchChange(ev: CustomEvent) {
this._filter = ev.detail.value;
}
+
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
}
declare global {
diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
index ff901348e6..7a2b5e9c49 100644
--- a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
+++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts
@@ -118,6 +118,20 @@ export class VoiceAssistantsExpose extends LitElement {
})
private _activeCollapsed?: string;
+ @storage({
+ key: "voice-expose-table-column-order",
+ state: false,
+ subscribe: false,
+ })
+ private _activeColumnOrder?: string[];
+
+ @storage({
+ key: "voice-expose-table-hidden-columns",
+ state: false,
+ subscribe: false,
+ })
+ private _activeHiddenColumns?: string[];
+
@query("hass-tabs-subpage-data-table", true)
private _dataTable!: HaTabsSubpageDataTable;
@@ -137,6 +151,7 @@ export class VoiceAssistantsExpose extends LitElement {
icon: {
title: "",
type: "icon",
+ moveable: false,
hidden: narrow,
template: (entry) => html`
html`
- ${entry.name}
- ${entry.entity_id}
- `,
+ template: narrow
+ ? undefined
+ : (entry) => html`
+ ${entry.name}
+ ${entry.entity_id}
+ `,
+ },
+ // For search & narrow
+ entity_id: {
+ title: localize(
+ "ui.panel.config.voice_assistants.expose.headers.entity_id"
+ ),
+ hidden: !narrow,
+ filterable: true,
},
domain: {
title: localize(
@@ -171,7 +196,6 @@ export class VoiceAssistantsExpose extends LitElement {
title: localize("ui.panel.config.voice_assistants.expose.headers.area"),
sortable: true,
groupable: true,
- hidden: narrow,
filterable: true,
width: "15%",
},
@@ -179,6 +203,7 @@ export class VoiceAssistantsExpose extends LitElement {
title: localize(
"ui.panel.config.voice_assistants.expose.headers.assistants"
),
+ showNarrow: true,
sortable: true,
filterable: true,
width: "160px",
@@ -208,7 +233,6 @@ export class VoiceAssistantsExpose extends LitElement {
),
sortable: true,
filterable: true,
- hidden: narrow,
width: "15%",
template: (entry) =>
entry.aliases.length === 0
@@ -230,12 +254,6 @@ export class VoiceAssistantsExpose extends LitElement {
.path=${mdiCloseCircleOutline}
>`,
},
- // For search
- entity_id: {
- title: "",
- hidden: true,
- filterable: true,
- },
})
);
@@ -552,6 +570,9 @@ export class VoiceAssistantsExpose extends LitElement {
.initialSorting=${this._activeSorting}
.initialGroupColumn=${this._activeGrouping}
.initialCollapsedGroups=${this._activeCollapsed}
+ .columnOrder=${this._activeColumnOrder}
+ .hiddenColumns=${this._activeHiddenColumns}
+ @columns-changed=${this._handleColumnsChanged}
@sorting-changed=${this._handleSortingChanged}
@selection-changed=${this._handleSelectionChanged}
@grouping-changed=${this._handleGroupingChanged}
@@ -757,6 +778,11 @@ export class VoiceAssistantsExpose extends LitElement {
this._activeCollapsed = ev.detail.value;
}
+ private _handleColumnsChanged(ev: CustomEvent) {
+ this._activeColumnOrder = ev.detail.columnOrder;
+ this._activeHiddenColumns = ev.detail.hiddenColumns;
+ }
+
static get styles(): CSSResultGroup {
return [
haStyle,
diff --git a/src/translations/en.json b/src/translations/en.json
index f813a386f1..822152b221 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -530,7 +530,8 @@
"selected": "Selected {selected}",
"close_select_mode": "Close selection mode",
"select_all": "Select all",
- "select_none": "Select none"
+ "select_none": "Select none",
+ "settings": "Customize table"
},
"config-entry-picker": {
"config_entry": "Integration"
@@ -799,7 +800,14 @@
"filtering_by": "Filtering by",
"hidden": "{number} hidden",
"clear": "Clear",
- "ungrouped": "Ungrouped"
+ "ungrouped": "Ungrouped",
+ "settings": {
+ "header": "Customize",
+ "hide": "Hide column {title}",
+ "show": "Show column {title}",
+ "done": "Done",
+ "restore": "Restore defaults"
+ }
},
"media-browser": {
"tts": {
@@ -2071,6 +2079,7 @@
"download_backup": "[%key:supervisor::backup::download_backup%]",
"remove_backup": "[%key:supervisor::backup::delete_backup_title%]",
"name": "[%key:supervisor::backup::name%]",
+ "path": "Path",
"size": "[%key:supervisor::backup::size%]",
"created": "[%key:supervisor::backup::created%]",
"no_backups": "[%key:supervisor::backup::no_backups%]",
@@ -2665,6 +2674,7 @@
"caption": "Expose",
"headers": {
"name": "Name",
+ "entity_id": "Entity ID",
"area": "Area",
"domain": "Domain",
"assistants": "Assistants",
@@ -4040,6 +4050,7 @@
"update_device_error": "Updating the device failed",
"disabled": "Disabled",
"data_table": {
+ "icon": "Icon",
"device": "Device",
"manufacturer": "Manufacturer",
"model": "Model",