mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 07:16:39 +00:00
Update entity naming in entities config page (#24966)
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
This commit is contained in:
parent
e3122e8e4d
commit
a6c9702ab2
@ -1,3 +1,4 @@
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
||||
import type {
|
||||
EntityRegistryDisplayEntry,
|
||||
@ -5,6 +6,7 @@ import type {
|
||||
} from "../../data/entity_registry";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { computeStateName } from "./compute_state_name";
|
||||
import { getDuplicates } from "../string/get_duplicates";
|
||||
|
||||
export const computeDeviceName = (
|
||||
device: DeviceRegistryEntry
|
||||
@ -36,3 +38,13 @@ export const fallbackDeviceName = (
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getDuplicatedDeviceNames = memoizeOne(
|
||||
(devices: HomeAssistant["devices"]): Set<string> => {
|
||||
const names = Object.values(devices)
|
||||
.map((device) => computeDeviceName(device))
|
||||
.filter((name): name is string => name !== undefined);
|
||||
|
||||
return getDuplicates(names);
|
||||
}
|
||||
);
|
||||
|
14
src/common/string/get_duplicates.ts
Normal file
14
src/common/string/get_duplicates.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export function getDuplicates(array: string[]): Set<string> {
|
||||
const duplicates = new Set<string>();
|
||||
const seen = new Set<string>();
|
||||
|
||||
for (const item of array) {
|
||||
if (seen.has(item)) {
|
||||
duplicates.add(item);
|
||||
} else {
|
||||
seen.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return duplicates;
|
||||
}
|
@ -497,7 +497,7 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
: "",
|
||||
},
|
||||
name: {
|
||||
title: localize("ui.panel.config.devices.data_table.name"),
|
||||
title: localize("ui.panel.config.devices.data_table.device"),
|
||||
main: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
|
@ -25,15 +25,18 @@ import { computeCssColor } from "../../../common/color/compute-color";
|
||||
import { formatShortDateTimeWithConditionalYear } from "../../../common/datetime/format_date_time";
|
||||
import { storage } from "../../../common/decorators/storage";
|
||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeAreaName } from "../../../common/entity/compute_area_name";
|
||||
import {
|
||||
isDeletableEntity,
|
||||
deleteEntity,
|
||||
} from "../../../common/entity/delete_entity";
|
||||
import type { Helper } from "../helpers/const";
|
||||
import { isHelperDomain } from "../helpers/const";
|
||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
||||
computeDeviceName,
|
||||
getDuplicatedDeviceNames,
|
||||
} from "../../../common/entity/compute_device_name";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeEntityEntryName } from "../../../common/entity/compute_entity_name";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import {
|
||||
deleteEntity,
|
||||
isDeletableEntity,
|
||||
} from "../../../common/entity/delete_entity";
|
||||
import {
|
||||
PROTOCOL_INTEGRATIONS,
|
||||
protocolIntegrationPicked,
|
||||
@ -53,7 +56,6 @@ import "../../../components/data-table/ha-data-table-labels";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-check-list-item";
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-filter-devices";
|
||||
import "../../../components/ha-filter-domains";
|
||||
import "../../../components/ha-filter-floor-areas";
|
||||
@ -62,6 +64,7 @@ import "../../../components/ha-filter-labels";
|
||||
import "../../../components/ha-filter-states";
|
||||
import "../../../components/ha-icon";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-md-divider";
|
||||
import "../../../components/ha-md-menu-item";
|
||||
import "../../../components/ha-sub-menu";
|
||||
import "../../../components/ha-svg-icon";
|
||||
@ -78,17 +81,15 @@ import type {
|
||||
EntityRegistryEntry,
|
||||
UpdateEntityRegistryEntryResult,
|
||||
} from "../../../data/entity_registry";
|
||||
import {
|
||||
computeEntityRegistryName,
|
||||
updateEntityRegistryEntry,
|
||||
} from "../../../data/entity_registry";
|
||||
import type { IntegrationManifest } from "../../../data/integration";
|
||||
import {
|
||||
fetchIntegrationManifests,
|
||||
domainToName,
|
||||
} from "../../../data/integration";
|
||||
import { updateEntityRegistryEntry } from "../../../data/entity_registry";
|
||||
import type { EntitySources } from "../../../data/entity_sources";
|
||||
import { fetchEntitySourcesWithCache } from "../../../data/entity_sources";
|
||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
||||
import type { IntegrationManifest } from "../../../data/integration";
|
||||
import {
|
||||
domainToName,
|
||||
fetchIntegrationManifests,
|
||||
} from "../../../data/integration";
|
||||
import type { LabelRegistryEntry } from "../../../data/label_registry";
|
||||
import {
|
||||
createLabelRegistryEntry,
|
||||
@ -106,6 +107,8 @@ import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import type { Helper } from "../helpers/const";
|
||||
import { isHelperDomain } from "../helpers/const";
|
||||
import "../integrations/ha-integration-overflow-menu";
|
||||
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
@ -124,6 +127,8 @@ export interface EntityRow extends StateEntity {
|
||||
restored: boolean;
|
||||
status: string | undefined;
|
||||
area?: string;
|
||||
device?: string;
|
||||
device_full?: string;
|
||||
localized_platform: string;
|
||||
domain: string;
|
||||
label_entries: LabelRegistryEntry[];
|
||||
@ -304,11 +309,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
},
|
||||
name: {
|
||||
main: true,
|
||||
title: localize("ui.panel.config.entities.picker.headers.name"),
|
||||
title: localize("ui.panel.config.entities.picker.headers.entity"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
flex: 2,
|
||||
extraTemplate: (entry) =>
|
||||
entry.label_entries.length
|
||||
? html`
|
||||
@ -318,10 +322,29 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
`
|
||||
: nothing,
|
||||
},
|
||||
device: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.device"),
|
||||
sortable: true,
|
||||
template: (entry) => entry.device || "—",
|
||||
},
|
||||
device_full: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.device"),
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
hidden: true,
|
||||
},
|
||||
area: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.area"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
template: (entry) => entry.area || "—",
|
||||
},
|
||||
entity_id: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.entity_id"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
defaultHidden: true,
|
||||
},
|
||||
localized_platform: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.integration"),
|
||||
@ -336,12 +359,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
},
|
||||
area: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.area"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
},
|
||||
disabled_by: {
|
||||
title: localize("ui.panel.config.entities.picker.headers.disabled_by"),
|
||||
hidden: true,
|
||||
@ -620,12 +637,16 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
});
|
||||
|
||||
const duplicatedDevicesNames = getDuplicatedDeviceNames(devices);
|
||||
|
||||
for (const entry of filteredEntities) {
|
||||
const entity = this.hass.states[entry.entity_id];
|
||||
const unavailable = entity?.state === UNAVAILABLE;
|
||||
const restored = entity?.attributes.restored === true;
|
||||
const areaId = entry.area_id ?? devices[entry.device_id!]?.area_id;
|
||||
const deviceId = entry.device_id;
|
||||
const areaId = entry.area_id || devices[deviceId!]?.area_id;
|
||||
const area = areaId ? areas[areaId] : undefined;
|
||||
const device = deviceId ? devices[deviceId] : undefined;
|
||||
const hidden = !!entry.hidden_by;
|
||||
const disabled = !!entry.disabled_by;
|
||||
const readonly = entry.readonly;
|
||||
@ -651,17 +672,30 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
(lbl) => labelReg!.find((label) => label.label_id === lbl)!
|
||||
);
|
||||
|
||||
const entityName = computeEntityEntryName(
|
||||
entry as EntityRegistryEntry,
|
||||
this.hass
|
||||
);
|
||||
|
||||
const deviceName = device ? computeDeviceName(device) : undefined;
|
||||
const areaName = area ? computeAreaName(area) : undefined;
|
||||
|
||||
const deviceFullName = deviceName
|
||||
? duplicatedDevicesNames.has(deviceName) && areaName
|
||||
? `${deviceName} (${areaName})`
|
||||
: deviceName
|
||||
: undefined;
|
||||
|
||||
result.push({
|
||||
...entry,
|
||||
entity,
|
||||
name: computeEntityRegistryName(
|
||||
this.hass!,
|
||||
entry as EntityRegistryEntry
|
||||
),
|
||||
name: entityName || deviceName || entry.entity_id,
|
||||
device: deviceName,
|
||||
area: areaName,
|
||||
device_full: deviceFullName,
|
||||
unavailable,
|
||||
restored,
|
||||
localized_platform: domainToName(localize, entry.platform),
|
||||
area: area ? area.name : "—",
|
||||
domain: domainToName(localize, computeDomain(entry.entity_id)),
|
||||
status: restored
|
||||
? localize("ui.panel.config.entities.picker.status.not_provided")
|
||||
@ -792,7 +826,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
selectable
|
||||
.selected=${this._selected.length}
|
||||
.initialGroupColumn=${this._activeGrouping}
|
||||
.initialGroupColumn=${this._activeGrouping ?? "device_full"}
|
||||
.initialCollapsedGroups=${this._activeCollapsed}
|
||||
.initialSorting=${this._activeSorting}
|
||||
.columnOrder=${this._activeColumnOrder}
|
||||
|
@ -4970,7 +4970,7 @@
|
||||
"disabled": "Disabled",
|
||||
"data_table": {
|
||||
"icon": "Icon",
|
||||
"name": "Name",
|
||||
"device": "Device",
|
||||
"manufacturer": "Manufacturer",
|
||||
"model": "Model",
|
||||
"area": "Area",
|
||||
@ -5017,8 +5017,9 @@
|
||||
},
|
||||
"headers": {
|
||||
"state_icon": "State icon",
|
||||
"name": "Name",
|
||||
"entity": "Entity",
|
||||
"entity_id": "Entity ID",
|
||||
"device": "Device",
|
||||
"integration": "Integration",
|
||||
"area": "Area",
|
||||
"disabled_by": "Disabled by",
|
||||
|
Loading…
x
Reference in New Issue
Block a user