Add created/modified to registry tables (#21494)

pull/21501/head
Bram Kragten 2024-07-30 11:18:50 +02:00 committed by GitHub
parent a85dda3365
commit 4ade39543d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 320 additions and 151 deletions

View File

@ -82,6 +82,8 @@ export class HaDemo extends HomeAssistantAppEl {
has_entity_name: false,
unique_id: "co2_intensity",
options: null,
created_at: 0,
modified_at: 0,
},
{
config_entry_id: "co2signal",
@ -100,6 +102,8 @@ export class HaDemo extends HomeAssistantAppEl {
has_entity_name: false,
unique_id: "grid_fossil_fuel_percentage",
options: null,
created_at: 0,
modified_at: 0,
},
]);

View File

@ -15,6 +15,7 @@ import { getEntity } from "../../../../src/fake_data/entity";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { DeviceRegistryEntry } from "../../../../src/data/device_registry";
const ENTITIES = [
getEntity("alarm_control_panel", "alarm", "disarmed", {
@ -41,7 +42,7 @@ const ENTITIES = [
}),
];
const DEVICES = [
const DEVICES: DeviceRegistryEntry[] = [
{
area_id: "bedroom",
configuration_url: null,
@ -61,6 +62,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "backyard",
@ -81,6 +84,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: null,
@ -101,6 +106,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
];
@ -113,6 +120,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "bedroom",
@ -122,6 +131,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "livingroom",
@ -131,6 +142,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
];

View File

@ -21,6 +21,7 @@ import { FloorRegistryEntry } from "../../../../src/data/floor_registry";
import { LabelRegistryEntry } from "../../../../src/data/label_registry";
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
import { DeviceRegistryEntry } from "../../../../src/data/device_registry";
const ENTITIES = [
getEntity("alarm_control_panel", "alarm", "disarmed", {
@ -41,7 +42,7 @@ const ENTITIES = [
}),
];
const DEVICES = [
const DEVICES: DeviceRegistryEntry[] = [
{
area_id: "bedroom",
configuration_url: null,
@ -61,6 +62,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "backyard",
@ -81,6 +84,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: null,
@ -101,6 +106,8 @@ const DEVICES = [
via_device_id: null,
serial_number: null,
labels: [],
created_at: 0,
modified_at: 0,
},
];
@ -113,6 +120,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "bedroom",
@ -122,6 +131,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
{
area_id: "livingroom",
@ -131,6 +142,8 @@ const AREAS: AreaRegistryEntry[] = [
picture: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
];
@ -141,6 +154,8 @@ const FLOORS: FloorRegistryEntry[] = [
level: 0,
icon: null,
aliases: [],
created_at: 0,
modified_at: 0,
},
{
floor_id: "first",
@ -148,6 +163,8 @@ const FLOORS: FloorRegistryEntry[] = [
level: 1,
icon: "mdi:numeric-1",
aliases: [],
created_at: 0,
modified_at: 0,
},
{
floor_id: "second",
@ -155,6 +172,8 @@ const FLOORS: FloorRegistryEntry[] = [
level: 2,
icon: "mdi:numeric-2",
aliases: [],
created_at: 0,
modified_at: 0,
},
];
@ -165,6 +184,8 @@ const LABELS: LabelRegistryEntry[] = [
icon: null,
color: "yellow",
description: null,
created_at: 0,
modified_at: 0,
},
{
label_id: "entertainment",
@ -172,6 +193,8 @@ const LABELS: LabelRegistryEntry[] = [
icon: "mdi:popcorn",
color: "blue",
description: null,
created_at: 0,
modified_at: 0,
},
];

View File

@ -358,13 +358,11 @@ export class DemoEntityState extends LitElement {
},
entity_id: {
title: "Entity ID",
width: "30%",
filterable: true,
sortable: true,
},
state: {
title: "State",
width: "20%",
sortable: true,
template: (entry) =>
html`${computeStateDisplay(
@ -379,14 +377,12 @@ export class DemoEntityState extends LitElement {
device_class: {
title: "Device class",
template: (entry) => html`${entry.device_class ?? "-"}`,
width: "20%",
filterable: true,
sortable: true,
},
domain: {
title: "Domain",
template: (entry) => html`${computeDomain(entry.entity_id)}`,
width: "20%",
filterable: true,
sortable: true,
},

View File

@ -203,6 +203,8 @@ const createEntityRegistryEntries = (
options: null,
labels: [],
categories: {},
created_at: 0,
modified_at: 0,
},
];
@ -228,6 +230,8 @@ const createDeviceRegistryEntries = (
disabled_by: null,
configuration_url: null,
labels: [],
created_at: 0,
modified_at: 0,
},
];

View File

@ -127,14 +127,13 @@ export class HassioBackups extends LitElement {
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
template: (backup) =>
html`${backup.name || backup.slug}
<div class="secondary">${backup.secondary}</div>`,
},
size: {
title: this.supervisor.localize("backup.size"),
width: "15%",
hidden: narrow,
filterable: true,
sortable: true,
@ -142,7 +141,6 @@ export class HassioBackups extends LitElement {
},
location: {
title: this.supervisor.localize("backup.location"),
width: "15%",
hidden: narrow,
filterable: true,
sortable: true,
@ -151,7 +149,6 @@ export class HassioBackups extends LitElement {
},
date: {
title: this.supervisor.localize("backup.created"),
width: "15%",
direction: "desc",
hidden: narrow,
filterable: true,

View File

@ -85,9 +85,9 @@ export interface DataTableColumnData<T = any> extends DataTableSortColumnData {
| "flex";
template?: (row: T) => TemplateResult | string | typeof nothing;
extraTemplate?: (row: T) => TemplateResult | string | typeof nothing;
width?: string;
minWidth?: string;
maxWidth?: string;
grows?: boolean;
flex?: number;
forceLTR?: boolean;
hidden?: boolean;
}
@ -216,6 +216,18 @@ export class HaDataTable extends LitElement {
this.updateComplete.then(() => this._calcTableHeight());
}
protected updated() {
const header = this.renderRoot.querySelector(".mdc-data-table__header-row");
if (!header) {
return;
}
if (header.scrollWidth > header.clientWidth) {
this.style.setProperty("--table-row-width", `${header.scrollWidth}px`);
} else {
this.style.removeProperty("--table-row-width");
}
}
public willUpdate(properties: PropertyValues) {
super.willUpdate(properties);
@ -355,7 +367,12 @@ export class HaDataTable extends LitElement {
: `calc(100% - ${this._headerHeight}px)`,
})}
>
<div class="mdc-data-table__header-row" role="row" aria-rowindex="1">
<div
class="mdc-data-table__header-row"
role="row"
aria-rowindex="1"
@scroll=${this._scrollContent}
>
<slot name="header-row">
${this.selectable
? html`
@ -398,18 +415,16 @@ export class HaDataTable extends LitElement {
column.type === "overflow",
sortable: Boolean(column.sortable),
"not-sorted": Boolean(column.sortable && !sorted),
grows: Boolean(column.grows),
};
return html`
<div
aria-label=${ifDefined(column.label)}
class="mdc-data-table__header-cell ${classMap(classes)}"
style=${column.width
? styleMap({
[column.grows ? "minWidth" : "width"]: column.width,
maxWidth: column.maxWidth || "",
})
: ""}
style=${styleMap({
minWidth: column.minWidth,
maxWidth: column.maxWidth,
flex: column.flex || 1,
})}
role="columnheader"
aria-sort=${ifDefined(
sorted
@ -538,15 +553,13 @@ export class HaDataTable extends LitElement {
"mdc-data-table__cell--overflow-menu":
column.type === "overflow-menu",
"mdc-data-table__cell--overflow": column.type === "overflow",
grows: Boolean(column.grows),
forceLTR: Boolean(column.forceLTR),
})}"
style=${column.width
? styleMap({
[column.grows ? "minWidth" : "width"]: column.width,
maxWidth: column.maxWidth ? column.maxWidth : "",
})
: ""}
style=${styleMap({
minWidth: column.minWidth,
maxWidth: column.maxWidth,
flex: column.flex || 1,
})}
>
${column.template
? column.template(row)
@ -815,6 +828,17 @@ export class HaDataTable extends LitElement {
@eventOptions({ passive: true })
private _saveScrollPos(e: Event) {
this._savedScrollPos = (e.target as HTMLDivElement).scrollTop;
this.renderRoot.querySelector(".mdc-data-table__header-row")!.scrollLeft = (
e.target as HTMLDivElement
).scrollLeft;
}
@eventOptions({ passive: true })
private _scrollContent(e: Event) {
this.renderRoot.querySelector("lit-virtualizer")!.scrollLeft = (
e.target as HTMLDivElement
).scrollLeft;
}
private _collapseGroup = (ev: Event) => {
@ -889,8 +913,8 @@ export class HaDataTable extends LitElement {
.mdc-data-table__row {
display: flex;
width: 100%;
height: var(--data-table-row-height, 52px);
width: var(--table-row-width, 100%);
}
.mdc-data-table__row ~ .mdc-data-table__row {
@ -914,18 +938,26 @@ export class HaDataTable extends LitElement {
.mdc-data-table__header-row {
height: 56px;
display: flex;
width: 100%;
border-bottom: 1px solid var(--divider-color);
overflow: auto;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.mdc-data-table__header-row::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.mdc-data-table__header-row {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.mdc-data-table__cell,
.mdc-data-table__header-cell {
padding-right: 16px;
padding-left: 16px;
min-width: 150px;
align-self: center;
overflow: hidden;
text-overflow: ellipsis;
@ -973,6 +1005,8 @@ export class HaDataTable extends LitElement {
letter-spacing: 0.0178571429em;
text-decoration: inherit;
text-transform: inherit;
flex-grow: 0;
flex-shrink: 0;
}
.mdc-data-table__cell a {
@ -991,7 +1025,8 @@ export class HaDataTable extends LitElement {
.mdc-data-table__header-cell--icon,
.mdc-data-table__cell--icon {
width: 54px;
min-width: 64px;
flex: 0 0 64px !important;
}
.mdc-data-table__cell--icon img {
@ -1031,11 +1066,14 @@ export class HaDataTable extends LitElement {
.mdc-data-table__header-cell--overflow-menu,
.mdc-data-table__header-cell--icon-button,
.mdc-data-table__cell--icon-button {
min-width: 64px;
flex: 0 0 64px !important;
padding: 8px;
}
.mdc-data-table__header-cell--icon-button,
.mdc-data-table__cell--icon-button {
min-width: 56px;
width: 56px;
}

View File

@ -279,6 +279,8 @@ export class HaAreaPicker extends LitElement {
icon: null,
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
];
}
@ -295,6 +297,8 @@ export class HaAreaPicker extends LitElement {
icon: "mdi:plus",
aliases: [],
labels: [],
created_at: 0,
modified_at: 0,
},
];
}
@ -377,6 +381,8 @@ export class HaAreaPicker extends LitElement {
picture: null,
labels: [],
aliases: [],
created_at: 0,
modified_at: 0,
},
] as AreaRegistryEntry[];
} else {
@ -393,6 +399,8 @@ export class HaAreaPicker extends LitElement {
picture: null,
labels: [],
aliases: [],
created_at: 0,
modified_at: 0,
},
] as AreaRegistryEntry[];
}

View File

@ -295,6 +295,8 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
icon: null,
level: null,
aliases: [],
created_at: 0,
modified_at: 0,
},
];
}
@ -309,6 +311,8 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
icon: "mdi:plus",
level: null,
aliases: [],
created_at: 0,
modified_at: 0,
},
];
}
@ -391,6 +395,8 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
icon: null,
level: null,
aliases: [],
created_at: 0,
modified_at: 0,
},
] as FloorRegistryEntry[];
} else {
@ -405,6 +411,8 @@ export class HaFloorPicker extends SubscribeMixin(LitElement) {
icon: "mdi:plus",
level: null,
aliases: [],
created_at: 0,
modified_at: 0,
},
] as FloorRegistryEntry[];
}

View File

@ -303,6 +303,8 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) {
icon: null,
color: null,
description: null,
created_at: 0,
modified_at: 0,
},
];
}
@ -317,6 +319,8 @@ export class HaLabelPicker extends SubscribeMixin(LitElement) {
icon: "mdi:plus",
color: null,
description: null,
created_at: 0,
modified_at: 0,
},
];
}

View File

@ -2,10 +2,11 @@ import { stringCompare } from "../common/string/compare";
import { HomeAssistant } from "../types";
import { DeviceRegistryEntry } from "./device_registry";
import { EntityRegistryEntry } from "./entity_registry";
import { RegistryEntry } from "./registry";
export { subscribeAreaRegistry } from "./ws-area_registry";
export interface AreaRegistryEntry {
export interface AreaRegistryEntry extends RegistryEntry {
area_id: string;
floor_id: string | null;
name: string;

View File

@ -1,19 +1,20 @@
import { computeStateName } from "../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../common/string/compare";
import type { HomeAssistant } from "../types";
import { ConfigEntry } from "./config_entries";
import type {
EntityRegistryDisplayEntry,
EntityRegistryEntry,
} from "./entity_registry";
import { ConfigEntry } from "./config_entries";
import type { EntitySources } from "./entity_sources";
import { RegistryEntry } from "./registry";
export {
fetchDeviceRegistry,
subscribeDeviceRegistry,
} from "./ws-device_registry";
export interface DeviceRegistryEntry {
export interface DeviceRegistryEntry extends RegistryEntry {
id: string;
config_entries: string[];
connections: Array<[string, string]>;

View File

@ -7,6 +7,7 @@ import { debounce } from "../common/util/debounce";
import { HomeAssistant } from "../types";
import { LightColor } from "./light";
import { computeDomain } from "../common/entity/compute_domain";
import { RegistryEntry } from "./registry";
export { subscribeEntityRegistryDisplay } from "./ws-entity_registry_display";
@ -43,7 +44,7 @@ export interface EntityRegistryDisplayEntryResponse {
entity_categories: Record<number, EntityCategory>;
}
export interface EntityRegistryEntry {
export interface EntityRegistryEntry extends RegistryEntry {
id: string;
entity_id: string;
name: string | null;

View File

@ -4,10 +4,11 @@ import { stringCompare } from "../common/string/compare";
import { debounce } from "../common/util/debounce";
import { HomeAssistant } from "../types";
import { AreaRegistryEntry } from "./area_registry";
import { RegistryEntry } from "./registry";
export { subscribeAreaRegistry } from "./ws-area_registry";
export interface FloorRegistryEntry {
export interface FloorRegistryEntry extends RegistryEntry {
floor_id: string;
name: string;
level: number | null;

View File

@ -1,10 +1,11 @@
import { Connection, createCollection } from "home-assistant-js-websocket";
import { Store } from "home-assistant-js-websocket/dist/store";
import { stringCompare } from "../common/string/compare";
import { HomeAssistant } from "../types";
import { debounce } from "../common/util/debounce";
import { HomeAssistant } from "../types";
import { RegistryEntry } from "./registry";
export interface LabelRegistryEntry {
export interface LabelRegistryEntry extends RegistryEntry {
label_id: string;
name: string;
icon: string | null;

4
src/data/registry.ts Normal file
View File

@ -0,0 +1,4 @@
export interface RegistryEntry {
created_at: number;
modified_at: number;
}

View File

@ -87,14 +87,13 @@ export class HaConfigApplicationCredentials extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
client_id: {
title: localize(
"ui.panel.config.application_credentials.picker.headers.client_id"
),
filterable: true,
width: "30%",
},
localizedDomain: {
title: localize(
@ -102,12 +101,10 @@ export class HaConfigApplicationCredentials extends LitElement {
),
sortable: true,
filterable: true,
width: "30%",
direction: "asc",
},
actions: {
title: "",
width: "64px",
type: "overflow-menu",
showNarrow: true,
hideable: false,

View File

@ -288,7 +288,7 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
extraTemplate: (automation) =>
automation.labels.length
? html`<ha-data-table-labels
@ -320,7 +320,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
},
last_triggered: {
sortable: true,
width: "130px",
title: localize("ui.card.automation.last_triggered"),
template: (automation) => {
if (!automation.last_triggered) {
@ -337,7 +336,8 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
},
},
formatted_state: {
width: "82px",
minWidth: "82px",
maxWidth: "82px",
sortable: true,
groupable: true,
hidden: narrow,
@ -353,7 +353,6 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
},
actions: {
title: "",
width: "64px",
type: "icon-button",
showNarrow: true,
moveable: false,

View File

@ -59,7 +59,7 @@ class HaConfigBackup extends LitElement {
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
template: narrow
? undefined
: (backup) =>
@ -72,14 +72,12 @@ class HaConfigBackup extends LitElement {
},
size: {
title: localize("ui.panel.config.backup.size"),
width: "15%",
filterable: true,
sortable: true,
template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB",
},
date: {
title: localize("ui.panel.config.backup.created"),
width: "15%",
direction: "desc",
filterable: true,
sortable: true,
@ -89,7 +87,6 @@ class HaConfigBackup extends LitElement {
actions: {
title: "",
width: "15%",
type: "overflow-menu",
showNarrow: true,
hideable: false,

View File

@ -176,7 +176,7 @@ class HaBlueprintOverview extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
translated_type: {
title: localize("ui.panel.config.blueprint.overview.headers.type"),
@ -184,14 +184,13 @@ class HaBlueprintOverview extends LitElement {
filterable: true,
groupable: true,
direction: "asc",
width: "10%",
},
path: {
title: localize("ui.panel.config.blueprint.overview.headers.file_name"),
sortable: true,
filterable: true,
direction: "asc",
width: "25%",
flex: 2,
},
fullpath: {
title: "fullpath",
@ -199,7 +198,6 @@ class HaBlueprintOverview extends LitElement {
},
actions: {
title: "",
width: this.narrow ? undefined : "10%",
type: "overflow-menu",
showNarrow: true,
moveable: false,

View File

@ -22,6 +22,7 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../../../common/color/compute-color";
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
import { storage } from "../../../common/decorators/storage";
import { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
@ -58,6 +59,11 @@ import "../../../components/ha-sub-menu";
import { createAreaRegistryEntry } from "../../../data/area_registry";
import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries";
import { fullEntitiesContext } from "../../../data/context";
import {
DataTableFilters,
deserializeFilters,
serializeFilters,
} from "../../../data/data_table_filters";
import {
DeviceEntityLookup,
DeviceRegistryEntry,
@ -75,6 +81,7 @@ import {
createLabelRegistryEntry,
subscribeLabelRegistry,
} from "../../../data/label_registry";
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/hass-tabs-subpage-data-table";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles";
@ -85,12 +92,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 { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import {
serializeFilters,
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
interface DeviceRowData extends DeviceRegistryEntry {
device?: DeviceRowData;
@ -443,7 +444,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
}
);
private _columns = memoizeOne((localize: LocalizeFunc, narrow: boolean) => {
private _columns = memoizeOne((localize: LocalizeFunc) => {
type DeviceItem = ReturnType<
typeof this._devicesAndFilterDomains
>["devicesOutput"][number];
@ -476,6 +477,8 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
filterable: true,
direction: "asc",
grows: true,
flex: 2,
minWidth: "150px",
extraTemplate: (device) => html`
${device.label_entries.length
? html`
@ -491,27 +494,27 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
groupable: true,
width: "15%",
minWidth: "120px",
},
model: {
title: localize("ui.panel.config.devices.data_table.model"),
sortable: true,
filterable: true,
width: "15%",
minWidth: "120px",
},
area: {
title: localize("ui.panel.config.devices.data_table.area"),
sortable: true,
filterable: true,
groupable: true,
width: "15%",
minWidth: "120px",
},
integration: {
title: localize("ui.panel.config.devices.data_table.integration"),
sortable: true,
filterable: true,
groupable: true,
width: "15%",
minWidth: "120px",
},
battery_entity: {
title: localize("ui.panel.config.devices.data_table.battery"),
@ -519,8 +522,8 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
type: "numeric",
width: narrow ? "105px" : "15%",
maxWidth: "105px",
maxWidth: "101px",
minWidth: "101px",
valueColumn: "battery_level",
template: (device) => {
const batteryEntityPair = device.battery_entity;
@ -548,9 +551,39 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
.batteryChargingStateObj=${batteryCharging}
></ha-battery-icon>
`
: html``;
: "—";
},
},
created_at: {
title: localize("ui.panel.config.generic.headers.created_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (entry) =>
entry.created_at
? formatShortDateTime(
new Date(entry.created_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
modified_at: {
title: localize("ui.panel.config.generic.headers.modified_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (entry) =>
entry.modified_at
? formatShortDateTime(
new Date(entry.modified_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
disabled_by: {
title: "",
label: localize("ui.panel.config.devices.data_table.disabled_by"),
@ -675,7 +708,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
"ui.panel.config.devices.picker.search",
{ number: devicesOutput.length }
)}
.columns=${this._columns(this.hass.localize, this.narrow)}
.columns=${this._columns(this.hass.localize)}
.data=${devicesOutput}
selectable
.selected=${this._selected.length}

View File

@ -103,6 +103,7 @@ import {
deserializeFilters,
DataTableFilters,
} from "../../../data/data_table_filters";
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
export interface StateEntity
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
@ -294,7 +295,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
extraTemplate: (entry) =>
entry.label_entries.length
? html`
@ -308,14 +309,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
title: localize("ui.panel.config.entities.picker.headers.entity_id"),
sortable: true,
filterable: true,
width: "25%",
},
localized_platform: {
title: localize("ui.panel.config.entities.picker.headers.integration"),
sortable: true,
groupable: true,
filterable: true,
width: "20%",
},
domain: {
title: localize("ui.panel.config.entities.picker.headers.domain"),
@ -329,7 +328,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
groupable: true,
width: "15%",
},
disabled_by: {
title: localize("ui.panel.config.entities.picker.headers.disabled_by"),
@ -348,7 +346,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
showNarrow: true,
sortable: true,
filterable: true,
width: "68px",
template: (entry) =>
entry.unavailable ||
entry.disabled_by ||
@ -398,6 +395,36 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
`
: "—",
},
created_at: {
title: localize("ui.panel.config.generic.headers.created_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (entry) =>
entry.created_at
? formatShortDateTime(
new Date(entry.created_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
modified_at: {
title: localize("ui.panel.config.generic.headers.modified_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (entry) =>
entry.modified_at
? formatShortDateTime(
new Date(entry.modified_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
available: {
title: localize("ui.panel.config.entities.picker.headers.availability"),
sortable: true,
@ -1081,6 +1108,8 @@ ${
options: null,
labels: [],
categories: {},
created_at: 0,
modified_at: 0,
});
}
if (changed) {

View File

@ -280,7 +280,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
direction: "asc",
extraTemplate: (helper) =>
helper.label_entries.length
@ -295,7 +295,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
title: localize("ui.panel.config.helpers.picker.headers.entity_id"),
sortable: true,
filterable: true,
width: "25%",
},
category: {
title: localize("ui.panel.config.helpers.picker.headers.category"),
@ -314,7 +313,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
localized_type: {
title: localize("ui.panel.config.helpers.picker.headers.type"),
sortable: true,
width: "25%",
filterable: true,
groupable: true,
},
@ -344,7 +342,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
actions: {
title: "",
label: "Actions",
width: "64px",
type: "overflow-menu",
hideable: false,
moveable: false,

View File

@ -44,7 +44,7 @@ export class ZHAClustersDataTable extends LitElement {
title: "Name",
sortable: true,
direction: "asc",
grows: true,
flex: 2,
},
}
: {
@ -52,18 +52,16 @@ export class ZHAClustersDataTable extends LitElement {
title: "Name",
sortable: true,
direction: "asc",
grows: true,
flex: 2,
},
id: {
title: "ID",
template: (cluster) => html` ${formatAsPaddedHex(cluster.id)} `,
sortable: true,
width: "25%",
},
endpoint_id: {
title: "Endpoint ID",
sortable: true,
width: "15%",
},
}
);

View File

@ -65,7 +65,7 @@ export class ZHADeviceEndpointDataTable extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
template: (device) => html`
<a href=${`/config/devices/device/${device.dev_id}`}>
${device.name}
@ -84,7 +84,7 @@ export class ZHADeviceEndpointDataTable extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
template: (device) => html`
<a href=${`/config/devices/device/${device.dev_id}`}>
${device.name}
@ -100,7 +100,7 @@ export class ZHADeviceEndpointDataTable extends LitElement {
title: "Associated Entities",
sortable: false,
filterable: false,
width: "50%",
flex: 2,
template: (device) => html`
${device.entities.length
? device.entities.length > 3

View File

@ -69,14 +69,13 @@ class ZHADeviceNeighbors extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
lqi: {
title: this.hass.localize("ui.panel.config.zha.neighbors.lqi"),
sortable: true,
filterable: true,
type: "numeric",
width: "75px",
},
}
: {
@ -85,14 +84,13 @@ class ZHADeviceNeighbors extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
lqi: {
title: this.hass.localize("ui.panel.config.zha.neighbors.lqi"),
sortable: true,
filterable: true,
type: "numeric",
width: "75px",
},
relationship: {
title: this.hass.localize(
@ -100,14 +98,12 @@ class ZHADeviceNeighbors extends LitElement {
),
sortable: true,
filterable: true,
width: "150px",
},
depth: {
title: this.hass.localize("ui.panel.config.zha.neighbors.depth"),
sortable: true,
filterable: true,
type: "numeric",
width: "75px",
},
}
);

View File

@ -79,7 +79,7 @@ export class ZHAGroupsDashboard extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
}
: {
@ -88,19 +88,17 @@ export class ZHAGroupsDashboard extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
},
group_id: {
title: this.hass.localize("ui.panel.config.zha.groups.group_id"),
type: "numeric",
width: "15%",
template: (group) => html` ${formatAsPaddedHex(group.group_id)} `,
sortable: true,
},
members: {
title: this.hass.localize("ui.panel.config.zha.groups.members"),
type: "numeric",
width: "15%",
template: (group) => html` ${group.members.length} `,
sortable: true,
},

View File

@ -47,7 +47,6 @@ class ZWaveJSProvisioned extends LitElement {
"ui.panel.config.zwave_js.provisioned.included"
),
type: "icon",
width: "100px",
template: (entry) =>
entry.nodeId
? html`
@ -71,13 +70,12 @@ class ZWaveJSProvisioned extends LitElement {
title: this.hass.localize("ui.panel.config.zwave_js.provisioned.dsk"),
sortable: true,
filterable: true,
grows: true,
flex: 2,
},
security_classes: {
title: this.hass.localize(
"ui.panel.config.zwave_js.provisioned.security_classes"
),
width: "30%",
hidden: narrow,
filterable: true,
sortable: true,
@ -97,7 +95,6 @@ class ZWaveJSProvisioned extends LitElement {
"ui.panel.config.zwave_js.provisioned.unprovison"
),
type: "icon-button",
width: "100px",
template: (entry) => html`
<ha-icon-button
.label=${this.hass.localize(

View File

@ -10,6 +10,8 @@ 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 { formatShortDateTime } from "../../../common/datetime/format_date_time";
import { storage } from "../../../common/decorators/storage";
import { navigate } from "../../../common/navigate";
import { LocalizeFunc } from "../../../common/translations/localize";
import {
@ -37,7 +39,6 @@ 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 { storage } from "../../../common/decorators/storage";
@customElement("ha-config-labels")
export class HaConfigLabels extends LitElement {
@ -80,7 +81,7 @@ export class HaConfigLabels extends LitElement {
})
private _activeHiddenColumns?: string[];
private _columns = memoizeOne((localize: LocalizeFunc) => {
private _columns = memoizeOne((localize: LocalizeFunc, narrow: boolean) => {
const columns: DataTableColumnContainer<LabelRegistryEntry> = {
icon: {
title: "",
@ -110,22 +111,60 @@ export class HaConfigLabels extends LitElement {
name: {
title: localize("ui.panel.config.labels.headers.name"),
main: true,
flex: 2,
sortable: true,
filterable: true,
grows: true,
template: (label) => html`
<div>${label.name}</div>
${label.description
? html`<div class="secondary">${label.description}</div>`
: nothing}
`,
template: narrow
? undefined
: (label) => html`
<div>${label.name}</div>
${label.description
? html`<div class="secondary">${label.description}</div>`
: nothing}
`,
},
description: {
title: localize("ui.panel.config.labels.headers.description"),
hidden: !narrow,
filterable: true,
hideable: true,
},
created_at: {
title: localize("ui.panel.config.generic.headers.created_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (label) =>
label.created_at
? formatShortDateTime(
new Date(label.created_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
modified_at: {
title: localize("ui.panel.config.generic.headers.modified_at"),
defaultHidden: true,
sortable: true,
filterable: true,
minWidth: "128px",
template: (label) =>
label.modified_at
? formatShortDateTime(
new Date(label.modified_at * 1000),
this.hass.locale,
this.hass.config
)
: "—",
},
actions: {
title: "",
label: localize("ui.panel.config.generic.headers.actions"),
showNarrow: true,
moveable: false,
hideable: false,
width: "64px",
type: "overflow-menu",
template: (label) => html`
<ha-icon-overflow-menu
@ -182,7 +221,7 @@ export class HaConfigLabels extends LitElement {
back-path="/config"
.route=${this.route}
.tabs=${configSections.areas}
.columns=${this._columns(this.hass.localize)}
.columns=${this._columns(this.hass.localize, this.narrow)}
.data=${this._data(this._labels)}
.noDataText=${this.hass.localize("ui.panel.config.labels.no_labels")}
hasFab

View File

@ -143,7 +143,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
template: narrow
? undefined
: (dashboard) => html`
@ -171,7 +171,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
),
sortable: true,
filterable: true,
width: "20%",
template: (dashboard) => html`
${this.hass.localize(
`ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}`
@ -183,7 +182,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
title: localize(
"ui.panel.config.lovelace.dashboards.picker.headers.filename"
),
width: "15%",
sortable: true,
filterable: true,
};
@ -195,7 +193,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
sortable: true,
type: "icon",
hidden: narrow,
width: "100px",
template: (dashboard) =>
dashboard.require_admin
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
@ -207,7 +204,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
),
type: "icon",
hidden: narrow,
width: "121px",
template: (dashboard) =>
dashboard.show_in_sidebar
? html`<ha-svg-icon .path=${mdiCheck}></ha-svg-icon>`
@ -221,7 +217,6 @@ export class HaConfigLovelaceDashboards extends LitElement {
),
filterable: true,
showNarrow: true,
width: "100px",
template: (dashboard) =>
narrow
? html`

View File

@ -94,7 +94,7 @@ export class HaConfigLovelaceRescources extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
forceLTR: true,
},
type: {
@ -103,7 +103,6 @@ export class HaConfigLovelaceRescources extends LitElement {
),
sortable: true,
filterable: true,
width: "30%",
template: (resource) => html`
${this.hass.localize(
`ui.panel.config.lovelace.resources.types.${resource.type}`

View File

@ -260,7 +260,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
extraTemplate: (scene) =>
scene.labels.length
? html`<ha-data-table-labels
@ -294,7 +294,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
"ui.panel.config.scene.picker.headers.last_activated"
),
sortable: true,
width: "30%",
template: (scene) => {
const lastActivated = scene.state;
if (!lastActivated || isUnavailableState(lastActivated)) {
@ -312,7 +311,7 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
},
only_editable: {
title: "",
width: "56px",
type: "icon",
showNarrow: true,
template: (scene) =>
!scene.attributes.id
@ -331,7 +330,6 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
},
actions: {
title: "",
width: "64px",
type: "overflow-menu",
showNarrow: true,
moveable: false,

View File

@ -270,7 +270,7 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
extraTemplate: (script) =>
script.labels.length
? html`<ha-data-table-labels
@ -301,7 +301,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
},
last_triggered: {
sortable: true,
width: "40%",
title: localize("ui.card.automation.last_triggered"),
template: (script) => {
const date = new Date(script.last_triggered);
@ -322,7 +321,6 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
},
actions: {
title: "",
width: "64px",
type: "overflow-menu",
showNarrow: true,
moveable: false,

View File

@ -81,13 +81,12 @@ export class HaConfigTags extends SubscribeMixin(LitElement) {
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
},
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`<ha-relative-time

View File

@ -83,15 +83,13 @@ export class HaConfigUsers extends LitElement {
main: true,
sortable: true,
filterable: true,
width: "25%",
direction: "asc",
grows: true,
flex: 2,
},
username: {
title: localize("ui.panel.config.users.picker.headers.username"),
sortable: true,
filterable: true,
width: "20%",
direction: "asc",
template: (user) => html`${user.username || "—"}`,
},
@ -100,7 +98,6 @@ export class HaConfigUsers extends LitElement {
sortable: true,
filterable: true,
groupable: true,
width: "20%",
direction: "asc",
},
is_active: {
@ -110,7 +107,6 @@ export class HaConfigUsers extends LitElement {
type: "icon",
sortable: true,
filterable: true,
width: "80px",
hidden: narrow,
template: (user) =>
user.is_active
@ -124,7 +120,6 @@ export class HaConfigUsers extends LitElement {
type: "icon",
sortable: true,
filterable: true,
width: "80px",
hidden: narrow,
template: (user) =>
user.system_generated
@ -138,7 +133,6 @@ export class HaConfigUsers extends LitElement {
type: "icon",
sortable: true,
filterable: true,
width: "80px",
hidden: narrow,
template: (user) =>
user.local_only
@ -153,7 +147,7 @@ export class HaConfigUsers extends LitElement {
type: "icon",
sortable: false,
filterable: false,
width: "104px",
minWidth: "104px",
hidden: !narrow,
showNarrow: true,
template: (user) => {

View File

@ -42,13 +42,12 @@ class AssistDevicesPage extends LitElement {
),
filterable: true,
sortable: true,
grows: true,
flex: 2,
},
pipeline: {
title: localize(
"ui.panel.config.voice_assistants.assistants.pipeline.devices.pipeline"
),
width: "30%",
filterable: true,
sortable: true,
},
@ -58,7 +57,6 @@ class AssistDevicesPage extends LitElement {
),
filterable: true,
sortable: true,
width: "30%",
},
};

View File

@ -167,7 +167,7 @@ export class VoiceAssistantsExpose extends LitElement {
sortable: true,
filterable: true,
direction: "asc",
grows: true,
flex: 2,
template: narrow
? undefined
: (entry) => html`
@ -197,7 +197,6 @@ export class VoiceAssistantsExpose extends LitElement {
sortable: true,
groupable: true,
filterable: true,
width: "15%",
},
assistants: {
title: localize(
@ -206,7 +205,8 @@ export class VoiceAssistantsExpose extends LitElement {
showNarrow: true,
sortable: true,
filterable: true,
width: "160px",
minWidth: "160px",
maxWidth: "160px",
type: "flex",
template: (entry) =>
html`${availableAssistants.map((key) => {
@ -233,7 +233,6 @@ export class VoiceAssistantsExpose extends LitElement {
),
sortable: true,
filterable: true,
width: "15%",
template: (entry) =>
entry.aliases.length === 0
? "-"

View File

@ -89,9 +89,10 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
title: localize(
"ui.panel.developer-tools.tabs.statistics.data_table.name"
),
main: true,
sortable: true,
filterable: true,
grows: true,
flex: 2,
},
statistic_id: {
title: localize(
@ -100,7 +101,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
hidden: this.narrow,
width: "20%",
},
statistics_unit_of_measurement: {
title: localize(
@ -108,7 +108,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
),
sortable: true,
filterable: true,
width: "10%",
forceLTR: true,
},
source: {
@ -117,7 +116,6 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
),
sortable: true,
filterable: true,
width: "10%",
},
issues_string: {
title: localize(
@ -126,7 +124,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
sortable: true,
filterable: true,
direction: "asc",
width: "30%",
flex: 2,
template: (statistic) =>
html`${statistic.issues_string ??
localize("ui.panel.developer-tools.tabs.statistics.no_issue")}`,
@ -147,12 +145,15 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
)}
</mwc-button>`
: "—"}`,
width: "113px",
minWidth: "113px",
maxWidth: "113px",
showNarrow: true,
},
actions: {
title: "",
label: localize("ui.panel.developer-tools.tabs.statistics.adjust_sum"),
type: "icon-button",
showNarrow: true,
template: (statistic) =>
statistic.has_sum
? html`
@ -179,6 +180,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) {
.noDataText=${this.hass.localize(
"ui.panel.developer-tools.tabs.statistics.data_table.no_statistics"
)}
.narrow=${this.narrow}
id="statistic_id"
clickable
@row-click=${this._rowClicked}

View File

@ -64,7 +64,8 @@ export class HuiEntityPickerTable extends LitElement {
title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity"),
sortable: true,
filterable: true,
grows: true,
flex: 2,
main: true,
direction: "asc",
template: (entity: any) => html`
<div @click=${this._handleEntityClicked} style="cursor: pointer;">
@ -81,7 +82,6 @@ export class HuiEntityPickerTable extends LitElement {
title: this.hass!.localize("ui.panel.lovelace.unused_entities.entity_id"),
sortable: true,
filterable: true,
width: "30%",
hidden: narrow,
};
@ -89,7 +89,6 @@ export class HuiEntityPickerTable extends LitElement {
title: this.hass!.localize("ui.panel.lovelace.unused_entities.domain"),
sortable: true,
filterable: true,
width: "15%",
hidden: narrow,
};
@ -99,7 +98,6 @@ export class HuiEntityPickerTable extends LitElement {
),
type: "numeric",
sortable: true,
width: "15%",
hidden: narrow,
template: (entity) => html`
<ha-relative-time

View File

@ -1843,6 +1843,13 @@
"error": "An unknown error occurred"
},
"config": {
"generic": {
"headers": {
"modified_at": "Modified",
"created_at": "Created",
"actions": "Actions"
}
},
"header": "Configure Home Assistant",
"dashboard": {
"devices": {