From 3349031cbd1128f864580fd81bcd5c12512ccdcf Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 20 Sep 2023 12:09:44 +0200 Subject: [PATCH] Simplify data table template (#17825) * Simplify data table template * Fix backup and gallery --- gallery/src/pages/misc/entity-state.ts | 8 +- hassio/src/backups/hassio-backups.ts | 22 +- src/components/data-table/ha-data-table.ts | 4 +- .../ha-config-application-credentials.ts | 9 +- .../config/automation/ha-automation-picker.ts | 45 +-- src/panels/config/backup/ha-config-backup.ts | 20 +- .../config/blueprint/ha-blueprint-overview.ts | 29 +- .../devices/ha-config-devices-dashboard.ts | 278 +++++++++--------- .../config/entities/ha-config-entities.ts | 53 ++-- .../config/helpers/ha-config-helpers.ts | 48 ++- .../zha/zha-clusters-data-table.ts | 4 +- .../zha/zha-device-endpoint-data-table.ts | 20 +- .../zha/zha-groups-dashboard.ts | 10 +- .../zwave_js/zwave_js-provisioned.ts | 18 +- .../ha-config-lovelace-dashboards.ts | 32 +- .../resources/ha-config-lovelace-resources.ts | 8 +- src/panels/config/scene/ha-scene-dashboard.ts | 34 ++- src/panels/config/script/ha-script-picker.ts | 273 +++++++++-------- src/panels/config/tags/ha-config-tags.ts | 155 +++++----- src/panels/config/users/ha-config-users.ts | 28 +- .../ha-config-voice-assistants-expose.ts | 20 +- .../statistics/developer-tools-statistics.ts | 19 +- .../card-editor/hui-entity-picker-table.ts | 10 +- 23 files changed, 597 insertions(+), 550 deletions(-) diff --git a/gallery/src/pages/misc/entity-state.ts b/gallery/src/pages/misc/entity-state.ts index 58c639e6fd93..9e62a6ae91d0 100644 --- a/gallery/src/pages/misc/entity-state.ts +++ b/gallery/src/pages/misc/entity-state.ts @@ -343,7 +343,7 @@ export class DemoEntityState extends LitElement { const columns: DataTableColumnContainer = { icon: { title: "Icon", - template: (_, entry) => html` + template: (entry) => html` + template: (entry) => html`${computeStateDisplay( hass.localize, entry.stateObj, @@ -371,14 +371,14 @@ export class DemoEntityState extends LitElement { }, device_class: { title: "Device class", - template: (dc) => html`${dc ?? "-"}`, + template: (entry) => html`${entry.device_class ?? "-"}`, width: "20%", filterable: true, sortable: true, }, domain: { title: "Domain", - template: (_, entry) => html`${computeDomain(entry.entity_id)}`, + template: (entry) => html`${computeDomain(entry.entity_id)}`, width: "20%", filterable: true, sortable: true, diff --git a/hassio/src/backups/hassio-backups.ts b/hassio/src/backups/hassio-backups.ts index 7dc5c949727e..80282aa7d6ad 100644 --- a/hassio/src/backups/hassio-backups.ts +++ b/hassio/src/backups/hassio-backups.ts @@ -49,6 +49,10 @@ import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hass import { supervisorTabs } from "../hassio-tabs"; import { hassioStyle } from "../resources/hassio-style"; +type BackupItem = HassioBackup & { + secondary: string; +}; + @customElement("hassio-backups") export class HassioBackups extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -117,15 +121,15 @@ export class HassioBackups extends LitElement { } private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => ({ + (narrow: boolean): DataTableColumnContainer => ({ name: { title: this.supervisor.localize("backup.name"), main: true, sortable: true, filterable: true, grows: true, - template: (entry: string, backup: any) => - html`${entry || backup.slug} + template: (backup) => + html`${backup.name || backup.slug}
${backup.secondary}
`, }, size: { @@ -134,7 +138,7 @@ export class HassioBackups extends LitElement { hidden: narrow, filterable: true, sortable: true, - template: (entry: number) => Math.ceil(entry * 10) / 10 + " MB", + template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB", }, location: { title: this.supervisor.localize("backup.location"), @@ -142,8 +146,8 @@ export class HassioBackups extends LitElement { hidden: narrow, filterable: true, sortable: true, - template: (entry: string | null) => - entry || this.supervisor.localize("backup.data_disk"), + template: (backup) => + backup.location || this.supervisor.localize("backup.data_disk"), }, date: { title: this.supervisor.localize("backup.created"), @@ -152,8 +156,8 @@ export class HassioBackups extends LitElement { hidden: narrow, filterable: true, sortable: true, - template: (entry: string) => - relativeTime(new Date(entry), this.hass.locale), + template: (backup) => + relativeTime(new Date(backup.date), this.hass.locale), }, secondary: { title: "", @@ -163,7 +167,7 @@ export class HassioBackups extends LitElement { }) ); - private _backupData = memoizeOne((backups: HassioBackup[]) => + private _backupData = memoizeOne((backups: HassioBackup[]): BackupItem[] => backups.map((backup) => ({ ...backup, secondary: this._computeBackupContent(backup), diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index e88869063924..10293fc761ab 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -74,7 +74,7 @@ export interface DataTableColumnData extends DataTableSortColumnData { title: TemplateResult | string; label?: TemplateResult | string; type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex"; - template?: (data: any, row: T) => TemplateResult | string | typeof nothing; + template?: (row: T) => TemplateResult | string | typeof nothing; width?: string; maxWidth?: string; grows?: boolean; @@ -431,7 +431,7 @@ export class HaDataTable extends LitElement { }) : ""} > - ${column.template ? column.template(row[key], row) : row[key]} + ${column.template ? column.template(row) : row[key]} `; })} diff --git a/src/panels/config/application_credentials/ha-config-application-credentials.ts b/src/panels/config/application_credentials/ha-config-application-credentials.ts index da139623eeeb..ec1b97dba308 100644 --- a/src/panels/config/application_credentials/ha-config-application-credentials.ts +++ b/src/panels/config/application_credentials/ha-config-application-credentials.ts @@ -62,17 +62,16 @@ export class HaConfigApplicationCredentials extends LitElement { ), direction: "asc", grows: true, - template: (_, entry: ApplicationCredential) => html`${entry.name}`, + template: (entry) => html`${entry.name}`, }, - clientId: { + client_id: { title: localize( "ui.panel.config.application_credentials.picker.headers.client_id" ), width: "30%", direction: "asc", hidden: narrow, - template: (_, entry: ApplicationCredential) => - html`${entry.client_id}`, + template: (entry) => html`${entry.client_id}`, }, application: { title: localize( @@ -81,7 +80,7 @@ export class HaConfigApplicationCredentials extends LitElement { sortable: true, width: "30%", direction: "asc", - template: (_, entry) => html`${domainToName(localize, entry.domain)}`, + template: (entry) => html`${domainToName(localize, entry.domain)}`, }, }; diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index a6ae94240b6f..c608b2008655 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -55,6 +55,12 @@ import { findRelated } from "../../../data/search"; import { fetchBlueprints } from "../../../data/blueprint"; import { UNAVAILABLE } from "../../../data/entity"; +type AutomationItem = AutomationEntity & { + name: string; + last_triggered?: string | undefined; + disabled: boolean; +}; + @customElement("ha-automation-picker") class HaAutomationPicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -79,7 +85,7 @@ class HaAutomationPicker extends LitElement { ( automations: AutomationEntity[], filteredAutomations?: string[] | null - ) => { + ): AutomationItem[] => { if (filteredAutomations === null) { return []; } @@ -100,14 +106,14 @@ class HaAutomationPicker extends LitElement { private _columns = memoizeOne( (narrow: boolean, _locale): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { + const columns: DataTableColumnContainer = { icon: { title: "", label: this.hass.localize( "ui.panel.config.automation.picker.headers.state" ), type: "icon", - template: (_, automation) => + template: (automation) => html` { + ? (automation) => { const date = new Date(automation.attributes.last_triggered); const now = new Date(); const dayDifference = differenceInDays(now, date); return html` - ${name} + ${automation.name}
${this.hass.localize("ui.card.automation.last_triggered")}: ${automation.attributes.last_triggered @@ -156,20 +162,17 @@ class HaAutomationPicker extends LitElement { sortable: true, width: "20%", title: this.hass.localize("ui.card.automation.last_triggered"), - template: (last_triggered) => { - const date = new Date(last_triggered); + template: (automation) => { + if (!automation.last_triggered) { + return this.hass.localize("ui.components.relative_time.never"); + } + const date = new Date(automation.last_triggered); const now = new Date(); const dayDifference = differenceInDays(now, date); return html` - ${last_triggered - ? dayDifference > 3 - ? formatShortDateTime( - date, - this.hass.locale, - this.hass.config - ) - : relativeTime(date, this.hass.locale) - : this.hass.localize("ui.components.relative_time.never")} + ${dayDifference > 3 + ? formatShortDateTime(date, this.hass.locale, this.hass.config) + : relativeTime(date, this.hass.locale)} `; }, }; @@ -178,8 +181,8 @@ class HaAutomationPicker extends LitElement { columns.disabled = this.narrow ? { title: "", - template: (disabled: boolean) => - disabled + template: (automation) => + automation.disabled ? html` ${this.hass.localize( @@ -196,8 +199,8 @@ class HaAutomationPicker extends LitElement { : { width: "20%", title: "", - template: (disabled: boolean) => - disabled + template: (automation) => + automation.disabled ? html` ${this.hass.localize( @@ -212,7 +215,7 @@ class HaAutomationPicker extends LitElement { title: "", width: this.narrow ? undefined : "10%", type: "overflow-menu", - template: (_: string, automation: any) => html` + template: (automation) => html` ({ + (narrow, _language): DataTableColumnContainer => ({ name: { title: this.hass.localize("ui.panel.config.backup.name"), main: true, sortable: true, filterable: true, grows: true, - template: (entry: string, backup: BackupContent) => - html`${entry} + template: (backup) => + html`${backup.name}
${backup.path}
`, }, size: { @@ -65,7 +65,7 @@ class HaConfigBackup extends LitElement { hidden: narrow, filterable: true, sortable: true, - template: (entry: number) => Math.ceil(entry * 10) / 10 + " MB", + template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB", }, date: { title: this.hass.localize("ui.panel.config.backup.created"), @@ -74,15 +74,15 @@ class HaConfigBackup extends LitElement { hidden: narrow, filterable: true, sortable: true, - template: (entry: string) => - relativeTime(new Date(entry), this.hass.locale), + template: (backup) => + relativeTime(new Date(backup.date), this.hass.locale), }, actions: { title: "", width: "15%", type: "overflow-menu", - template: (_: string, backup: BackupContent) => + template: (backup) => html` { @@ -86,7 +87,7 @@ class HaBlueprintOverview extends LitElement { >; private _processedBlueprints = memoizeOne( - (blueprints: Record) => { + (blueprints: Record): BlueprintMetaDataPath[] => { const result: any[] = []; Object.entries(blueprints).forEach(([type, typeBlueprints]) => Object.entries(typeBlueprints).forEach(([path, blueprint]) => { @@ -125,9 +126,9 @@ class HaBlueprintOverview extends LitElement { direction: "asc", grows: true, template: narrow - ? (name, entity: any) => html` - ${name}
-
${entity.path}
+ ? (blueprint) => html` + ${blueprint.name}
+
${blueprint.path}
` : undefined, }, @@ -135,9 +136,9 @@ class HaBlueprintOverview extends LitElement { title: this.hass.localize( "ui.panel.config.blueprint.overview.headers.type" ), - template: (type: BlueprintDomain) => + template: (blueprint) => html`${this.hass.localize( - `ui.panel.config.blueprint.overview.types.${type}` + `ui.panel.config.blueprint.overview.types.${blueprint.type}` )}`, sortable: true, filterable: true, @@ -163,7 +164,7 @@ class HaBlueprintOverview extends LitElement { title: "", width: this.narrow ? undefined : "10%", type: "overflow-menu", - template: (_: string, blueprint) => + template: (blueprint) => blueprint.error ? html` this._createNew(blueprint), }, @@ -324,7 +325,7 @@ class HaBlueprintOverview extends LitElement { private _handleRowClicked(ev: HASSDomEvent) { const blueprint = this._processedBlueprints(this.blueprints).find( (b) => b.fullpath === ev.detail.id - ); + )!; if (blueprint.error) { showAlertDialog(this, { title: this.hass.localize("ui.panel.config.blueprint.overview.error", { diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 669712319227..0526d048d11f 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -2,27 +2,26 @@ import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js"; import { - css, CSSResultGroup, - html, LitElement, - nothing, TemplateResult, + css, + html, + nothing, } from "lit"; import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { - protocolIntegrationPicked, PROTOCOL_INTEGRATIONS, + protocolIntegrationPicked, } from "../../../common/integrations/protocolIntegrationPicked"; import { navigate } from "../../../common/navigate"; import { LocalizeFunc } from "../../../common/translations/localize"; import { computeRTL } from "../../../common/util/compute_rtl"; import { DataTableColumnContainer, - DataTableRowData, RowClickedEvent, } from "../../../components/data-table/ha-data-table"; import "../../../components/entity/ha-battery-icon"; @@ -33,9 +32,9 @@ import "../../../components/ha-icon-button"; import { AreaRegistryEntry } from "../../../data/area_registry"; import { ConfigEntry, sortConfigEntries } from "../../../data/config_entries"; import { - computeDeviceName, DeviceEntityLookup, DeviceRegistryEntry, + computeDeviceName, } from "../../../data/device_registry"; import { EntityRegistryEntry, @@ -231,7 +230,7 @@ export class HaConfigDeviceDashboard extends LitElement { outputDevices = outputDevices.filter((device) => !device.disabled_by); } - outputDevices = outputDevices.map((device) => { + const formattedOutputDevices = outputDevices.map((device) => { const deviceEntries = sortConfigEntries( device.config_entries .filter((entId) => entId in entryLookup) @@ -277,156 +276,153 @@ export class HaConfigDeviceDashboard extends LitElement { }; }); - this._numHiddenDevices = startLength - outputDevices.length; + this._numHiddenDevices = startLength - formattedOutputDevices.length; return { - devicesOutput: outputDevices, + devicesOutput: formattedOutputDevices, filteredConfigEntry: filterConfigEntry, filteredDomains, }; } ); - private _columns = memoizeOne( - (narrow: boolean, showDisabled: boolean): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { - icon: { - title: "", - type: "icon", - template: (_icon, device) => - device.domains.length - ? html`` - : "", - }, - }; - - if (narrow) { - columns.name = { - title: this.hass.localize( - "ui.panel.config.devices.data_table.device" - ), - main: true, - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: (name, device: DataTableRowData) => html` - ${name} -
${device.area} | ${device.integration}
- `, - }; - } else { - columns.name = { - title: this.hass.localize( - "ui.panel.config.devices.data_table.device" - ), - main: true, - sortable: true, - filterable: true, - grows: true, - direction: "asc", - }; - } - - columns.manufacturer = { - title: this.hass.localize( - "ui.panel.config.devices.data_table.manufacturer" - ), + private _columns = memoizeOne((narrow: boolean, showDisabled: boolean) => { + type DeviceItem = ReturnType< + typeof this._devicesAndFilterDomains + >["devicesOutput"][number]; + + const columns: DataTableColumnContainer = { + icon: { + title: "", + type: "icon", + template: (device) => + device.domains.length + ? html`` + : "", + }, + }; + + if (narrow) { + columns.name = { + title: this.hass.localize("ui.panel.config.devices.data_table.device"), + main: true, sortable: true, - hidden: narrow, filterable: true, - width: "15%", + direction: "asc", + grows: true, + template: (device) => html` + ${device.name} +
${device.area} | ${device.integration}
+ `, }; - columns.model = { - title: this.hass.localize("ui.panel.config.devices.data_table.model"), + } else { + columns.name = { + title: this.hass.localize("ui.panel.config.devices.data_table.device"), + main: true, sortable: true, - hidden: narrow, filterable: true, - width: "15%", + grows: true, + direction: "asc", }; - columns.area = { - title: this.hass.localize("ui.panel.config.devices.data_table.area"), - sortable: true, - hidden: narrow, - filterable: true, - width: "15%", - }; - columns.integration = { - title: this.hass.localize( - "ui.panel.config.devices.data_table.integration" - ), - sortable: true, - hidden: narrow, - filterable: true, - width: "15%", - }; - columns.battery_entity = { - title: this.hass.localize("ui.panel.config.devices.data_table.battery"), - sortable: true, - filterable: true, - type: "numeric", - width: narrow ? "95px" : "15%", - maxWidth: "95px", - valueColumn: "battery_level", - template: (batteryEntityPair: DeviceRowData["battery_entity"]) => { - const battery = - batteryEntityPair && batteryEntityPair[0] - ? this.hass.states[batteryEntityPair[0]] - : undefined; - const batteryDomain = battery - ? computeStateDomain(battery) + } + + columns.manufacturer = { + title: this.hass.localize( + "ui.panel.config.devices.data_table.manufacturer" + ), + sortable: true, + hidden: narrow, + filterable: true, + width: "15%", + }; + columns.model = { + title: this.hass.localize("ui.panel.config.devices.data_table.model"), + sortable: true, + hidden: narrow, + filterable: true, + width: "15%", + }; + columns.area = { + title: this.hass.localize("ui.panel.config.devices.data_table.area"), + sortable: true, + hidden: narrow, + filterable: true, + width: "15%", + }; + columns.integration = { + title: this.hass.localize( + "ui.panel.config.devices.data_table.integration" + ), + sortable: true, + hidden: narrow, + filterable: true, + width: "15%", + }; + columns.battery_entity = { + title: this.hass.localize("ui.panel.config.devices.data_table.battery"), + sortable: true, + filterable: true, + type: "numeric", + width: narrow ? "95px" : "15%", + maxWidth: "95px", + 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; - 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`—`; - }, + + return battery && + (batteryDomain === "binary_sensor" || !isNaN(battery.state as any)) + ? html` + ${batteryDomain === "sensor" + ? this.hass.formatEntityState(battery) + : nothing} + + ` + : html`—`; + }, + }; + if (showDisabled) { + columns.disabled_by = { + title: "", + label: this.hass.localize( + "ui.panel.config.devices.data_table.disabled_by" + ), + type: "icon", + template: (device) => + device.disabled_by + ? html`
+ + + ${this.hass.localize("ui.panel.config.devices.disabled")} + +
` + : "—", }; - if (showDisabled) { - columns.disabled_by = { - title: "", - label: this.hass.localize( - "ui.panel.config.devices.data_table.disabled_by" - ), - type: "icon", - template: (disabled_by) => - disabled_by - ? html`
- - - ${this.hass.localize("ui.panel.config.devices.disabled")} - -
` - : "—", - }; - } - return columns; } - ); + return columns; + }); public willUpdate(changedProps) { if (changedProps.has("_searchParms")) { diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 9c0815850cf9..8a0dcc6f988a 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -183,7 +183,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { "ui.panel.config.entities.picker.headers.state_icon" ), type: "icon", - template: (_, entry: EntityRow) => html` + template: (entry) => html` html` - ${name}
+ ? (entry) => html` + ${entry.name}
- ${entity.entity_id} | - ${this.hass.localize(`component.${entity.platform}.title`) || - entity.platform} + ${entry.entity_id} | + ${this.hass.localize(`component.${entry.platform}.title`) || + entry.platform}
` : undefined, @@ -228,8 +228,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { sortable: true, filterable: true, width: "20%", - template: (platform) => - this.hass.localize(`component.${platform}.title`) || platform, + template: (entry) => + this.hass.localize(`component.${entry.platform}.title`) || + entry.platform, }, area: { title: this.hass.localize( @@ -248,10 +249,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { hidden: narrow || !showDisabled, filterable: true, width: "15%", - template: (disabled_by: EntityRegistryEntry["disabled_by"]) => - disabled_by === null + template: (entry) => + entry.disabled_by === null ? "—" - : this.hass.localize(`config_entry.disabled_by.${disabled_by}`), + : this.hass.localize( + `config_entry.disabled_by.${entry.disabled_by}` + ), }, status: { title: this.hass.localize( @@ -261,11 +264,11 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { sortable: true, filterable: true, width: "68px", - template: (_status, entity: EntityRow) => - entity.unavailable || - entity.disabled_by || - entity.hidden_by || - entity.readonly + template: (entry) => + entry.unavailable || + entry.disabled_by || + entry.hidden_by || + entry.readonly ? html`
- ${entity.restored + ${entry.restored ? this.hass.localize( "ui.panel.config.entities.picker.status.restored" ) - : entity.unavailable + : entry.unavailable ? this.hass.localize( "ui.panel.config.entities.picker.status.unavailable" ) - : entity.disabled_by + : entry.disabled_by ? this.hass.localize( "ui.panel.config.entities.picker.status.disabled" ) - : entity.hidden_by + : entry.hidden_by ? this.hass.localize( "ui.panel.config.entities.picker.status.hidden" ) diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 1346cfb5df33..8507edad4208 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -6,7 +6,10 @@ import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { navigate } from "../../../common/navigate"; -import { LocalizeFunc } from "../../../common/translations/localize"; +import { + LocalizeFunc, + LocalizeKeys, +} from "../../../common/translations/localize"; import { extractSearchParam } from "../../../common/url/search-params"; import { DataTableColumnContainer, @@ -27,6 +30,7 @@ import { } from "../../../data/entity_registry"; import { domainToName } from "../../../data/integration"; import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow"; +import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow"; import { showAlertDialog, showConfirmationDialog, @@ -38,9 +42,19 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { HomeAssistant, Route } from "../../../types"; import { configSections } from "../ha-panel-config"; import "../integrations/ha-integration-overflow-menu"; -import { HelperDomain, isHelperDomain } from "./const"; +import { isHelperDomain } from "./const"; import { showHelperDetailDialog } from "./show-dialog-helper-detail"; -import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow"; + +type HelperItem = { + id: string; + name: string; + icon?: string; + entity_id: string; + editable?: boolean; + type: string; + configEntry?: ConfigEntry; + entity?: HassEntity; +}; // This groups items by a key but only returns last entry per key. const groupByOne = ( @@ -108,16 +122,16 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { private _columns = memoizeOne( (narrow: boolean, localize: LocalizeFunc): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { + const columns: DataTableColumnContainer = { icon: { title: "", label: localize("ui.panel.config.helpers.picker.headers.icon"), type: "icon", - template: (icon, helper: any) => + template: (helper) => helper.entity ? html`` : html``, }, @@ -128,10 +142,10 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { filterable: true, grows: true, direction: "asc", - template: (name, item: any) => html` - ${name} + template: (helper) => html` + ${helper.name} ${narrow - ? html`
${item.entity_id}
` + ? html`
${helper.entity_id}
` : ""} `, }, @@ -149,11 +163,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { sortable: true, width: "25%", filterable: true, - template: (type: HelperDomain, row) => - row.configEntry - ? domainToName(localize, type) + template: (helper) => + helper.configEntry + ? domainToName(localize, helper.type) : html` - ${localize(`ui.panel.config.helpers.types.${type}`) || type} + ${localize( + `ui.panel.config.helpers.types.${helper.type}` as LocalizeKeys + ) || helper.type} `, }; columns.editable = { @@ -162,8 +178,8 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { "ui.panel.config.helpers.picker.headers.editable" ), type: "icon", - template: (editable) => html` - ${!editable + template: (helper) => html` + ${!helper.editable ? html`
, configEntries: Record - ) => { + ): HelperItem[] => { const configEntriesCopy = { ...configEntries }; const states = stateItems.map((entityState) => { diff --git a/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts index 9cebc071b288..bf45ceecbf19 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts @@ -38,7 +38,7 @@ export class ZHAClustersDataTable extends LitElement { }); private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => + (narrow: boolean): DataTableColumnContainer => narrow ? { name: { @@ -57,7 +57,7 @@ export class ZHAClustersDataTable extends LitElement { }, id: { title: "ID", - template: (id: number) => html` ${formatAsPaddedHex(id)} `, + template: (cluster) => html` ${formatAsPaddedHex(cluster.id)} `, sortable: true, width: "25%", }, diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts index bebc5826a8a6..fbadb2ec0620 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts @@ -67,9 +67,9 @@ export class ZHADeviceEndpointDataTable extends LitElement { filterable: true, direction: "asc", grows: true, - template: (name, device: any) => html` + template: (device) => html` - ${name} + ${device.name} `, }, @@ -86,9 +86,9 @@ export class ZHADeviceEndpointDataTable extends LitElement { filterable: true, direction: "asc", grows: true, - template: (name, device: any) => html` + template: (device) => html` - ${name} + ${device.name} `, }, @@ -102,10 +102,10 @@ export class ZHADeviceEndpointDataTable extends LitElement { sortable: false, filterable: false, width: "50%", - template: (entities) => html` - ${entities.length - ? entities.length > 3 - ? html`${entities + template: (device) => html` + ${device.entities.length + ? device.entities.length > 3 + ? html`${device.entities .slice(0, 2) .map( (entity) => @@ -115,8 +115,8 @@ export class ZHADeviceEndpointDataTable extends LitElement { ${entity.name || entity.original_name}
` )} -
And ${entities.length - 2} more...
` - : entities.map( +
And ${device.entities.length - 2} more...
` + : device.entities.map( (entity) => html`
+ (narrow: boolean): DataTableColumnContainer => narrow ? { name: { @@ -94,16 +94,14 @@ export class ZHAGroupsDashboard extends LitElement { title: this.hass.localize("ui.panel.config.zha.groups.group_id"), type: "numeric", width: "15%", - template: (groupId: number) => html` - ${formatAsPaddedHex(groupId)} - `, + 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: (members: ZHADevice[]) => html` ${members.length} `, + template: (group) => html` ${group.members.length} `, sortable: true, }, } diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-provisioned.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-provisioned.ts index a9a41cdadbc0..e19478cfed31 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-provisioned.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-provisioned.ts @@ -41,15 +41,15 @@ class ZWaveJSProvisioned extends LitElement { } private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => ({ + (narrow: boolean): DataTableColumnContainer => ({ included: { title: this.hass.localize( "ui.panel.config.zwave_js.provisioned.included" ), type: "icon", width: "100px", - template: (_info, provisioningEntry: any) => - provisioningEntry.additional_properties.nodeId + template: (entry) => + entry.additional_properties.nodeId ? html` - securityClasses + template: (entry) => { + const securityClasses = entry.security_classes; + return securityClasses .map((secClass) => this.hass.localize( `ui.panel.config.zwave_js.security_classes.${SecurityClass[secClass]}.title` ) ) - .join(", "), + .join(", "); + }, }, unprovision: { title: this.hass.localize( @@ -96,13 +98,13 @@ class ZWaveJSProvisioned extends LitElement { ), type: "icon-button", width: "100px", - template: (_info, provisioningEntry: any) => html` + template: (entry) => html` `, 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 cfbac3ec2c7d..7ab29c4ae958 100644 --- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts +++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts @@ -68,12 +68,12 @@ export class HaConfigLovelaceDashboards extends LitElement { "ui.panel.config.lovelace.dashboards.picker.headers.icon" ), type: "icon", - template: (icon: DataTableItem["icon"], dashboard) => - icon + template: (dashboard) => + dashboard.icon ? html` { + template: (dashboard) => { const titleTemplate = html` - ${title} + ${dashboard.title} ${dashboard.default ? html` html` + template: (dashboard) => html` ${this.hass.localize( - `ui.panel.config.lovelace.dashboards.conf_mode.${mode}` - ) || mode} + `ui.panel.config.lovelace.dashboards.conf_mode.${dashboard.mode}` + ) || dashboard.mode} `, }; if (dashboards.some((dashboard) => dashboard.filename)) { @@ -155,8 +155,8 @@ export class HaConfigLovelaceDashboards extends LitElement { sortable: true, type: "icon", width: "100px", - template: (requireAdmin: DataTableItem["require_admin"]) => - requireAdmin + template: (dashboard) => + dashboard.require_admin ? html`` : html`—`, }; @@ -166,8 +166,8 @@ export class HaConfigLovelaceDashboards extends LitElement { ), type: "icon", width: "121px", - template: (sidebar: DataTableItem["show_in_sidebar"]) => - sidebar + template: (dashboard) => + dashboard.show_in_sidebar ? html`` : html`—`, }; @@ -180,12 +180,12 @@ export class HaConfigLovelaceDashboards extends LitElement { ), filterable: true, width: "100px", - template: (urlPath) => + template: (dashboard) => narrow ? html` ` : html` - ${this.hass.localize( "ui.panel.config.lovelace.dashboards.picker.open" )} ({ + (_language): DataTableColumnContainer => ({ url: { title: this.hass.localize( "ui.panel.config.lovelace.resources.picker.headers.url" @@ -58,10 +58,10 @@ export class HaConfigLovelaceRescources extends LitElement { sortable: true, filterable: true, width: "30%", - template: (type: LovelaceResource["type"]) => html` + template: (resource) => html` ${this.hass.localize( - `ui.panel.config.lovelace.resources.types.${type}` - ) || type} + `ui.panel.config.lovelace.resources.types.${resource.type}` + ) || resource.type} `, }, }) diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index 3a7a7790b843..5e8fdc13e48f 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -47,6 +47,10 @@ import { formatShortDateTime } from "../../../common/datetime/format_date_time"; import { relativeTime } from "../../../common/datetime/relative_time"; import { isUnavailableState } from "../../../data/entity"; +type SceneItem = SceneEntity & { + name: string; +}; + @customElement("ha-scene-dashboard") class HaSceneDashboard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -66,7 +70,7 @@ class HaSceneDashboard extends LitElement { @state() private _filterValue?; private _scenes = memoizeOne( - (scenes: SceneEntity[], filteredScenes?: string[] | null) => { + (scenes: SceneEntity[], filteredScenes?: string[] | null): SceneItem[] => { if (filteredScenes === null) { return []; } @@ -83,14 +87,14 @@ class HaSceneDashboard extends LitElement { private _columns = memoizeOne( (_language, narrow): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { + const columns: DataTableColumnContainer = { icon: { title: "", label: this.hass.localize( "ui.panel.config.scene.picker.headers.state" ), type: "icon", - template: (_, scene) => html` + template: (scene) => html` `, }, @@ -112,20 +116,18 @@ class HaSceneDashboard extends LitElement { ), sortable: true, width: "30%", - template: (last_activated) => { - const date = new Date(last_activated); + template: (scene) => { + const lastActivated = scene.state; + if (!lastActivated || isUnavailableState(lastActivated)) { + return this.hass.localize("ui.components.relative_time.never"); + } + const date = new Date(scene.state); const now = new Date(); const dayDifference = differenceInDays(now, date); return html` - ${last_activated && !isUnavailableState(last_activated) - ? dayDifference > 3 - ? formatShortDateTime( - date, - this.hass.locale, - this.hass.config - ) - : relativeTime(date, this.hass.locale) - : this.hass.localize("ui.components.relative_time.never")} + ${dayDifference > 3 + ? formatShortDateTime(date, this.hass.locale, this.hass.config) + : relativeTime(date, this.hass.locale)} `; }, }; @@ -133,7 +135,7 @@ class HaSceneDashboard extends LitElement { columns.only_editable = { title: "", width: "56px", - template: (_info, scene: any) => + template: (scene) => !scene.attributes.id ? html` @@ -152,7 +154,7 @@ class HaSceneDashboard extends LitElement { title: "", width: "72px", type: "overflow-menu", - template: (_: string, scene: any) => html` + template: (scene) => html` { + ( + scripts: ScriptEntity[], + filteredScripts?: string[] | null + ): ScriptItem[] => { if (filteredScripts === null) { return []; } @@ -93,126 +100,136 @@ class HaScriptPicker extends LitElement { } ); - private _columns = memoizeOne((narrow, _locale): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { - icon: { - title: "", - label: this.hass.localize( - "ui.panel.config.script.picker.headers.state" - ), - type: "icon", - template: (_icon, script) => - html``, - }, - name: { - title: this.hass.localize("ui.panel.config.script.picker.headers.name"), - main: true, - sortable: true, - filterable: true, - direction: "asc", - grows: true, - template: narrow - ? (name, script: any) => { - const date = new Date(script.attributes.last_triggered); - const now = new Date(); - const dayDifference = differenceInDays(now, date); - return html` - ${name} -
- ${this.hass.localize("ui.card.automation.last_triggered")}: - ${script.attributes.last_triggered - ? dayDifference > 3 - ? formatShortDateTime( - date, - this.hass.locale, - this.hass.config - ) - : relativeTime(date, this.hass.locale) - : this.hass.localize("ui.components.relative_time.never")} -
- `; - } - : undefined, - }, - }; - if (!narrow) { - columns.last_triggered = { - sortable: true, - width: "40%", - title: this.hass.localize("ui.card.automation.last_triggered"), - template: (last_triggered) => { - const date = new Date(last_triggered); - const now = new Date(); - const dayDifference = differenceInDays(now, date); - return html` - ${last_triggered - ? dayDifference > 3 - ? formatShortDateTime(date, this.hass.locale, this.hass.config) - : relativeTime(date, this.hass.locale) - : this.hass.localize("ui.components.relative_time.never")} - `; + private _columns = memoizeOne( + (narrow, _locale): DataTableColumnContainer => { + const columns: DataTableColumnContainer = { + icon: { + title: "", + label: this.hass.localize( + "ui.panel.config.script.picker.headers.state" + ), + type: "icon", + template: (script) => + html``, + }, + name: { + title: this.hass.localize( + "ui.panel.config.script.picker.headers.name" + ), + main: true, + sortable: true, + filterable: true, + direction: "asc", + grows: true, + template: narrow + ? (script) => { + const date = new Date(script.last_triggered); + const now = new Date(); + const dayDifference = differenceInDays(now, date); + return html` + ${script.name} +
+ ${this.hass.localize("ui.card.automation.last_triggered")}: + ${script.last_triggered + ? dayDifference > 3 + ? formatShortDateTime( + date, + this.hass.locale, + this.hass.config + ) + : relativeTime(date, this.hass.locale) + : this.hass.localize("ui.components.relative_time.never")} +
+ `; + } + : undefined, }, }; - } + if (!narrow) { + columns.last_triggered = { + sortable: true, + width: "40%", + title: this.hass.localize("ui.card.automation.last_triggered"), + template: (script) => { + const date = new Date(script.last_triggered); + const now = new Date(); + const dayDifference = differenceInDays(now, date); + return html` + ${script.last_triggered + ? dayDifference > 3 + ? formatShortDateTime( + date, + this.hass.locale, + this.hass.config + ) + : relativeTime(date, this.hass.locale) + : this.hass.localize("ui.components.relative_time.never")} + `; + }, + }; + } - columns.actions = { - title: "", - width: this.narrow ? undefined : "10%", - type: "overflow-menu", - template: (_: string, script: any) => html` - this._showInfo(script), - }, - { - path: mdiPlay, - label: this.hass.localize("ui.panel.config.script.picker.run"), - action: () => this._runScript(script), - }, - { - path: mdiTransitConnection, - label: this.hass.localize( - "ui.panel.config.script.picker.show_trace" - ), - action: () => this._showTrace(script), - }, - { - divider: true, - }, - { - path: mdiContentDuplicate, - label: this.hass.localize( - "ui.panel.config.script.picker.duplicate" - ), - action: () => this._duplicate(script), - }, - { - label: this.hass.localize("ui.panel.config.script.picker.delete"), - path: mdiDelete, - action: () => this._deleteConfirm(script), - warning: true, - }, - ]} - > - - `, - }; + columns.actions = { + title: "", + width: this.narrow ? undefined : "10%", + type: "overflow-menu", + template: (script) => html` + this._showInfo(script), + }, + { + path: mdiPlay, + label: this.hass.localize("ui.panel.config.script.picker.run"), + action: () => this._runScript(script), + }, + { + path: mdiTransitConnection, + label: this.hass.localize( + "ui.panel.config.script.picker.show_trace" + ), + action: () => this._showTrace(script), + }, + { + divider: true, + }, + { + path: mdiContentDuplicate, + label: this.hass.localize( + "ui.panel.config.script.picker.duplicate" + ), + action: () => this._duplicate(script), + }, + { + label: this.hass.localize( + "ui.panel.config.script.picker.delete" + ), + path: mdiDelete, + action: () => this._deleteConfirm(script), + warning: true, + }, + ]} + > + + `, + }; - return columns; - }); + return columns; + } + ); protected render(): TemplateResult { return html` diff --git a/src/panels/config/tags/ha-config-tags.ts b/src/panels/config/tags/ha-config-tags.ts index 61a61c8af735..4ac788eba29c 100644 --- a/src/panels/config/tags/ha-config-tags.ts +++ b/src/panels/config/tags/ha-config-tags.ts @@ -36,6 +36,7 @@ import { showTagDetailDialog } from "./show-dialog-tag-detail"; import "./tag-image"; export interface TagRowData extends Tag { + display_name: string; last_scanned_datetime: Date | null; } @@ -55,94 +56,90 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { return this.hass.auth.external?.config.canWriteTag; } - private _columns = memoizeOne( - (narrow: boolean, _language): DataTableColumnContainer => { - const columns: DataTableColumnContainer = { - icon: { - title: "", - label: this.hass.localize("ui.panel.config.tag.headers.icon"), - type: "icon", - template: (_icon, tag) => html``, - }, - display_name: { - title: this.hass.localize("ui.panel.config.tag.headers.name"), - main: true, - sortable: true, - filterable: true, - grows: true, - template: (name, tag: any) => - html`${name} - ${narrow - ? html`
- ${tag.last_scanned_datetime - ? html`` - : this.hass.localize("ui.panel.config.tag.never_scanned")} -
` - : ""}`, - }, - }; - if (!narrow) { - columns.last_scanned_datetime = { - title: this.hass.localize("ui.panel.config.tag.headers.last_scanned"), - sortable: true, - direction: "desc", - width: "20%", - template: (last_scanned_datetime) => html` - ${last_scanned_datetime - ? html`` - : this.hass.localize("ui.panel.config.tag.never_scanned")} - `, - }; - } - if (this._canWriteTags) { - columns.write = { - title: "", - label: this.hass.localize("ui.panel.config.tag.headers.write"), - type: "icon-button", - template: (_write, tag: any) => - html` `, - }; - } - columns.automation = { + private _columns = memoizeOne((narrow: boolean, _language) => { + const columns: DataTableColumnContainer = { + icon: { title: "", - type: "icon-button", - template: (_automation, tag: any) => - html` `, + label: this.hass.localize("ui.panel.config.tag.headers.icon"), + type: "icon", + template: (tag) => html``, + }, + display_name: { + title: this.hass.localize("ui.panel.config.tag.headers.name"), + main: true, + sortable: true, + filterable: true, + grows: true, + template: (tag) => + html`${tag.name} + ${narrow + ? html`
+ ${tag.last_scanned_datetime + ? html`` + : this.hass.localize("ui.panel.config.tag.never_scanned")} +
` + : ""}`, + }, + }; + if (!narrow) { + columns.last_scanned_datetime = { + title: this.hass.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")} + `, }; - columns.edit = { + } + if (this._canWriteTags) { + columns.write = { title: "", + label: this.hass.localize("ui.panel.config.tag.headers.write"), type: "icon-button", - template: (_settings, tag: any) => + template: (tag) => html` `, }; - return columns; } - ); + columns.automation = { + title: "", + type: "icon-button", + template: (tag) => + html` `, + }; + columns.edit = { + title: "", + type: "icon-button", + template: (tag) => + html` `, + }; + return columns; + }); private _data = memoizeOne((tags: Tag[]): TagRowData[] => tags.map((tag) => ({ diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts index a125ef8b81a1..80d069bdf952 100644 --- a/src/panels/config/users/ha-config-users.ts +++ b/src/panels/config/users/ha-config-users.ts @@ -49,14 +49,14 @@ export class HaConfigUsers extends LitElement { width: "25%", direction: "asc", grows: true, - template: (name, user) => + template: (user) => narrow - ? html` ${name}
+ ? html` ${user.name}
${user.username ? `${user.username} |` : ""} ${localize(`groups.${user.group_ids[0]}`)}
` - : html` ${name || + : html` ${user.name || this.hass!.localize( "ui.panel.config.users.editor.unnamed_user" )}`, @@ -68,7 +68,7 @@ export class HaConfigUsers extends LitElement { width: "20%", direction: "asc", hidden: narrow, - template: (username) => html`${username || "—"}`, + template: (user) => html`${user.name || "—"}`, }, group_ids: { title: localize("ui.panel.config.users.picker.headers.group"), @@ -77,8 +77,8 @@ export class HaConfigUsers extends LitElement { width: "20%", direction: "asc", hidden: narrow, - template: (groupIds: User["group_ids"]) => html` - ${localize(`groups.${groupIds[0]}`)} + template: (user) => html` + ${localize(`groups.${user.group_ids[0]}`)} `, }, is_active: { @@ -90,8 +90,8 @@ export class HaConfigUsers extends LitElement { filterable: true, width: "80px", hidden: narrow, - template: (is_active) => - is_active + template: (user) => + user.is_active ? html`` : "", }, @@ -104,8 +104,8 @@ export class HaConfigUsers extends LitElement { filterable: true, width: "80px", hidden: narrow, - template: (generated) => - generated + template: (user) => + user.system_generated ? html`` : "", }, @@ -118,8 +118,10 @@ export class HaConfigUsers extends LitElement { filterable: true, width: "80px", hidden: narrow, - template: (local) => - local ? html`` : "", + template: (user) => + user.local_only + ? html`` + : "", }, icons: { title: "", @@ -131,7 +133,7 @@ export class HaConfigUsers extends LitElement { filterable: false, width: "104px", hidden: !narrow, - template: (_, user) => { + template: (user) => { const badges = computeUserBadges(this.hass, user, false); return html`${badges.map( ([icon, tooltip]) => 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 e6f171f367d2..abfc59eacfb2 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 @@ -134,7 +134,7 @@ export class VoiceAssistantsExpose extends LitElement { title: "", type: "icon", hidden: narrow, - template: (_, entry) => html` + template: (entry) => html` html` - ${name}
+ template: (entry) => html` + ${entry.name}
${entry.entity_id}
`, }, @@ -172,13 +172,13 @@ export class VoiceAssistantsExpose extends LitElement { filterable: true, width: "160px", type: "flex", - template: (assistants, entry) => + template: (entry) => html`${availableAssistants.map((key) => { const supported = !supportedEntities?.[key] || supportedEntities[key].includes(entry.entity_id); const manual = entry.manAssistants?.includes(key); - return assistants.includes(key) + return entry.assistants.includes(key) ? html` - aliases.length === 0 + template: (entry) => + entry.aliases.length === 0 ? "-" - : aliases.length === 1 - ? aliases[0] + : entry.aliases.length === 1 + ? entry.aliases[0] : this.hass.localize( "ui.panel.config.voice_assistants.expose.aliases", - { count: aliases.length } + { count: entry.aliases.length } ), }, remove: { diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts index 3ed66f9f5bd5..7eb112a63499 100644 --- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts +++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts @@ -80,7 +80,9 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { ); private _columns = memoizeOne( - (localize: LocalizeFunc): DataTableColumnContainer => ({ + ( + localize: LocalizeFunc + ): DataTableColumnContainer => ({ displayName: { title: localize( "ui.panel.developer-tools.tabs.statistics.data_table.name" @@ -123,8 +125,8 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { filterable: true, direction: "asc", width: "30%", - template: (issues_string) => - html`${issues_string ?? + template: (statistic) => + html`${statistic.issues_string ?? localize("ui.panel.developer-tools.tabs.statistics.no_issue")}`, }, fix: { @@ -132,9 +134,12 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { label: this.hass.localize( "ui.panel.developer-tools.tabs.statistics.fix_issue.fix" ), - template: (_, data: any) => - html`${data.issues - ? html` + template: (statistic) => + html`${statistic.issues + ? html` ${localize( "ui.panel.developer-tools.tabs.statistics.fix_issue.fix" )} @@ -146,7 +151,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { title: "", label: localize("ui.panel.developer-tools.tabs.statistics.adjust_sum"), type: "icon-button", - template: (_info, statistic: StatisticsMetaData) => + template: (statistic) => statistic.has_sum ? html` html` + template: (entity) => html` html` + template: (entity: any) => html`
- ${name} + ${entity.name} ${narrow ? html`
${entity.entity_id}
` : ""} @@ -103,10 +103,10 @@ export class HuiEntityPickerTable extends LitElement { sortable: true, width: "15%", hidden: narrow, - template: (lastChanged: string) => html` + template: (entity) => html` `,