mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
Simplify entity combo-box code (#25338)
This commit is contained in:
parent
9629159ef1
commit
90710fedf2
@ -5,7 +5,6 @@ import type { HassEntity } from "home-assistant-js-websocket";
|
|||||||
import type { PropertyValues, TemplateResult } from "lit";
|
import type { PropertyValues, TemplateResult } from "lit";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { computeAreaName } from "../../common/entity/compute_area_name";
|
import { computeAreaName } from "../../common/entity/compute_area_name";
|
||||||
@ -30,28 +29,17 @@ import "../ha-icon-button";
|
|||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
import "./state-badge";
|
import "./state-badge";
|
||||||
|
|
||||||
const FAKE_ENTITY: HassEntity = {
|
interface EntityComboBoxItem {
|
||||||
entity_id: "",
|
|
||||||
state: "",
|
|
||||||
last_changed: "",
|
|
||||||
last_updated: "",
|
|
||||||
context: { id: "", user_id: null, parent_id: null },
|
|
||||||
attributes: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
interface EntityComboBoxItem extends HassEntity {
|
|
||||||
// Force empty label to always display empty value by default in the search field
|
// Force empty label to always display empty value by default in the search field
|
||||||
|
id: string;
|
||||||
label: "";
|
label: "";
|
||||||
primary: string;
|
primary: string;
|
||||||
secondary?: string;
|
secondary?: string;
|
||||||
translated_domain?: string;
|
domain_name?: string;
|
||||||
show_entity_id?: boolean;
|
search_labels?: string[];
|
||||||
entity_name?: string;
|
|
||||||
area_name?: string;
|
|
||||||
device_name?: string;
|
|
||||||
friendly_name?: string;
|
|
||||||
sorting_label?: string;
|
sorting_label?: string;
|
||||||
icon_path?: string;
|
icon_path?: string;
|
||||||
|
stateObj?: HassEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HaEntityComboBoxEntityFilterFunc = (entity: HassEntity) => boolean;
|
export type HaEntityComboBoxEntityFilterFunc = (entity: HassEntity) => boolean;
|
||||||
@ -59,22 +47,6 @@ export type HaEntityComboBoxEntityFilterFunc = (entity: HassEntity) => boolean;
|
|||||||
const CREATE_ID = "___create-new-entity___";
|
const CREATE_ID = "___create-new-entity___";
|
||||||
const NO_ENTITIES_ID = "___no-entities___";
|
const NO_ENTITIES_ID = "___no-entities___";
|
||||||
|
|
||||||
const DOMAIN_STYLE = styleMap({
|
|
||||||
fontSize: "var(--ha-font-size-s)",
|
|
||||||
fontWeight: "var(--ha-font-weight-normal)",
|
|
||||||
lineHeight: "var(--ha-line-height-normal)",
|
|
||||||
alignSelf: "flex-end",
|
|
||||||
maxWidth: "30%",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
overflow: "hidden",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
});
|
|
||||||
|
|
||||||
const ENTITY_ID_STYLE = styleMap({
|
|
||||||
fontFamily: "var(--ha-font-family-code)",
|
|
||||||
fontSize: "var(--ha-font-size-xs)",
|
|
||||||
});
|
|
||||||
|
|
||||||
@customElement("ha-entity-combo-box")
|
@customElement("ha-entity-combo-box")
|
||||||
export class HaEntityComboBox extends LitElement {
|
export class HaEntityComboBox extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -177,33 +149,41 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
private _rowRenderer: ComboBoxLitRenderer<EntityComboBoxItem> = (
|
private _rowRenderer: ComboBoxLitRenderer<EntityComboBoxItem> = (
|
||||||
item,
|
item,
|
||||||
{ index }
|
{ index }
|
||||||
) => html`
|
) => {
|
||||||
<ha-combo-box-item type="button" compact .borderTop=${index !== 0}>
|
const showEntityId = this.hass.userData?.showEntityIdPicker;
|
||||||
${item.icon_path
|
|
||||||
? html`<ha-svg-icon slot="start" .path=${item.icon_path}></ha-svg-icon>`
|
return html`
|
||||||
: html`
|
<ha-combo-box-item type="button" compact .borderTop=${index !== 0}>
|
||||||
<state-badge
|
${item.icon_path
|
||||||
slot="start"
|
? html`
|
||||||
.stateObj=${item}
|
<ha-svg-icon slot="start" .path=${item.icon_path}></ha-svg-icon>
|
||||||
.hass=${this.hass}
|
`
|
||||||
></state-badge>
|
: html`
|
||||||
`}
|
<state-badge
|
||||||
<span slot="headline">${item.primary}</span>
|
slot="start"
|
||||||
${item.secondary
|
.stateObj=${item.stateObj}
|
||||||
? html`<span slot="supporting-text">${item.secondary}</span>`
|
.hass=${this.hass}
|
||||||
: nothing}
|
></state-badge>
|
||||||
${item.entity_id && item.show_entity_id
|
`}
|
||||||
? html`<span slot="supporting-text" style=${ENTITY_ID_STYLE}
|
<span slot="headline">${item.primary}</span>
|
||||||
>${item.entity_id}</span
|
${item.secondary
|
||||||
>`
|
? html`<span slot="supporting-text">${item.secondary}</span>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${item.translated_domain && !item.show_entity_id
|
${item.stateObj && showEntityId
|
||||||
? html`<div slot="trailing-supporting-text" style=${DOMAIN_STYLE}>
|
? html`
|
||||||
${item.translated_domain}
|
<span slot="supporting-text" class="code">
|
||||||
</div>`
|
${item.stateObj.entity_id}
|
||||||
: nothing}
|
</span>
|
||||||
</ha-combo-box-item>
|
`
|
||||||
`;
|
: nothing}
|
||||||
|
${item.domain_name && !showEntityId
|
||||||
|
? html`
|
||||||
|
<div slot="trailing-supporting-text">${item.domain_name}</div>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
</ha-combo-box-item>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
private _getItems = memoizeOne(
|
private _getItems = memoizeOne(
|
||||||
(
|
(
|
||||||
@ -218,7 +198,7 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
excludeEntities: this["excludeEntities"],
|
excludeEntities: this["excludeEntities"],
|
||||||
createDomains: this["createDomains"]
|
createDomains: this["createDomains"]
|
||||||
): EntityComboBoxItem[] => {
|
): EntityComboBoxItem[] => {
|
||||||
let states: EntityComboBoxItem[] = [];
|
let items: EntityComboBoxItem[] = [];
|
||||||
|
|
||||||
let entityIds = Object.keys(hass.states);
|
let entityIds = Object.keys(hass.states);
|
||||||
|
|
||||||
@ -236,9 +216,8 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...FAKE_ENTITY,
|
id: CREATE_ID + domain,
|
||||||
label: "",
|
label: "",
|
||||||
entity_id: CREATE_ID + domain,
|
|
||||||
primary: primary,
|
primary: primary,
|
||||||
secondary: this.hass.localize(
|
secondary: this.hass.localize(
|
||||||
"ui.components.entity.entity-picker.new_entity"
|
"ui.components.entity.entity-picker.new_entity"
|
||||||
@ -251,9 +230,8 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
if (!entityIds.length) {
|
if (!entityIds.length) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
...FAKE_ENTITY,
|
id: NO_ENTITIES_ID,
|
||||||
label: "",
|
label: "",
|
||||||
entity_id: NO_ENTITIES_ID,
|
|
||||||
primary: this.hass!.localize(
|
primary: this.hass!.localize(
|
||||||
"ui.components.entity.entity-picker.no_entities"
|
"ui.components.entity.entity-picker.no_entities"
|
||||||
),
|
),
|
||||||
@ -289,7 +267,7 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
|
|
||||||
const isRTL = computeRTL(this.hass);
|
const isRTL = computeRTL(this.hass);
|
||||||
|
|
||||||
states = entityIds
|
items = entityIds
|
||||||
.map<EntityComboBoxItem>((entityId) => {
|
.map<EntityComboBoxItem>((entityId) => {
|
||||||
const stateObj = hass!.states[entityId];
|
const stateObj = hass!.states[entityId];
|
||||||
|
|
||||||
@ -300,28 +278,32 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
const deviceName = device ? computeDeviceName(device) : undefined;
|
const deviceName = device ? computeDeviceName(device) : undefined;
|
||||||
const areaName = area ? computeAreaName(area) : undefined;
|
const areaName = area ? computeAreaName(area) : undefined;
|
||||||
|
|
||||||
|
const domainName = domainToName(
|
||||||
|
this.hass.localize,
|
||||||
|
computeDomain(entityId)
|
||||||
|
);
|
||||||
|
|
||||||
const primary = entityName || deviceName || entityId;
|
const primary = entityName || deviceName || entityId;
|
||||||
const secondary = [areaName, entityName ? deviceName : undefined]
|
const secondary = [areaName, entityName ? deviceName : undefined]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(isRTL ? " ◂ " : " ▸ ");
|
.join(isRTL ? " ◂ " : " ▸ ");
|
||||||
|
|
||||||
const translatedDomain = domainToName(
|
|
||||||
this.hass.localize,
|
|
||||||
computeDomain(entityId)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...hass!.states[entityId],
|
id: entityId,
|
||||||
label: "",
|
label: "",
|
||||||
primary: primary,
|
primary: primary,
|
||||||
secondary: secondary,
|
secondary: secondary,
|
||||||
translated_domain: translatedDomain,
|
domain_name: domainName,
|
||||||
sorting_label: [deviceName, entityName].filter(Boolean).join("-"),
|
sorting_label: [deviceName, entityName].filter(Boolean).join("_"),
|
||||||
entity_name: entityName || deviceName,
|
search_labels: [
|
||||||
area_name: areaName,
|
entityName,
|
||||||
device_name: deviceName,
|
deviceName,
|
||||||
friendly_name: friendlyName,
|
areaName,
|
||||||
show_entity_id: hass.userData?.showEntityIdPicker,
|
domainName,
|
||||||
|
friendlyName,
|
||||||
|
entityId,
|
||||||
|
].filter(Boolean) as string[],
|
||||||
|
stateObj: stateObj,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.sort((entityA, entityB) =>
|
.sort((entityA, entityB) =>
|
||||||
@ -333,41 +315,43 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (includeDeviceClasses) {
|
if (includeDeviceClasses) {
|
||||||
states = states.filter(
|
items = items.filter(
|
||||||
(stateObj) =>
|
(item) =>
|
||||||
// We always want to include the entity of the current value
|
// We always want to include the entity of the current value
|
||||||
stateObj.entity_id === this.value ||
|
item.id === this.value ||
|
||||||
(stateObj.attributes.device_class &&
|
(item.stateObj?.attributes.device_class &&
|
||||||
includeDeviceClasses.includes(stateObj.attributes.device_class))
|
includeDeviceClasses.includes(
|
||||||
|
item.stateObj.attributes.device_class
|
||||||
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeUnitOfMeasurement) {
|
if (includeUnitOfMeasurement) {
|
||||||
states = states.filter(
|
items = items.filter(
|
||||||
(stateObj) =>
|
(item) =>
|
||||||
// We always want to include the entity of the current value
|
// We always want to include the entity of the current value
|
||||||
stateObj.entity_id === this.value ||
|
item.id === this.value ||
|
||||||
(stateObj.attributes.unit_of_measurement &&
|
(item.stateObj?.attributes.unit_of_measurement &&
|
||||||
includeUnitOfMeasurement.includes(
|
includeUnitOfMeasurement.includes(
|
||||||
stateObj.attributes.unit_of_measurement
|
item.stateObj.attributes.unit_of_measurement
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityFilter) {
|
if (entityFilter) {
|
||||||
states = states.filter(
|
items = items.filter(
|
||||||
(stateObj) =>
|
(item) =>
|
||||||
// We always want to include the entity of the current value
|
// We always want to include the entity of the current value
|
||||||
stateObj.entity_id === this.value || entityFilter!(stateObj)
|
item.id === this.value ||
|
||||||
|
(item.stateObj && entityFilter!(item.stateObj))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!states.length) {
|
if (!items.length) {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
...FAKE_ENTITY,
|
id: NO_ENTITIES_ID,
|
||||||
label: "",
|
label: "",
|
||||||
entity_id: NO_ENTITIES_ID,
|
|
||||||
primary: this.hass!.localize(
|
primary: this.hass!.localize(
|
||||||
"ui.components.entity.entity-picker.no_match"
|
"ui.components.entity.entity-picker.no_match"
|
||||||
),
|
),
|
||||||
@ -378,10 +362,10 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (createItems?.length) {
|
if (createItems?.length) {
|
||||||
states.push(...createItems);
|
items.push(...createItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
return states;
|
return items;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -424,7 +408,7 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-combo-box
|
<ha-combo-box
|
||||||
item-value-path="entity_id"
|
item-value-path="id"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.value=${this._value}
|
.value=${this._value}
|
||||||
.label=${this.label === undefined
|
.label=${this.label === undefined
|
||||||
@ -476,17 +460,7 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _fuseIndex = memoizeOne((states: EntityComboBoxItem[]) =>
|
private _fuseIndex = memoizeOne((states: EntityComboBoxItem[]) =>
|
||||||
Fuse.createIndex(
|
Fuse.createIndex(["search_labels"], states)
|
||||||
[
|
|
||||||
"entity_name",
|
|
||||||
"device_name",
|
|
||||||
"area_name",
|
|
||||||
"translated_domain",
|
|
||||||
"friendly_name", // for backwards compatibility
|
|
||||||
"entity_id", // for technical search
|
|
||||||
],
|
|
||||||
states
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private _filterChanged(ev: CustomEvent): void {
|
private _filterChanged(ev: CustomEvent): void {
|
||||||
@ -503,9 +477,8 @@ export class HaEntityComboBox extends LitElement {
|
|||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
target.filteredItems = [
|
target.filteredItems = [
|
||||||
{
|
{
|
||||||
...FAKE_ENTITY,
|
id: NO_ENTITIES_ID,
|
||||||
label: "",
|
label: "",
|
||||||
entity_id: NO_ENTITIES_ID,
|
|
||||||
primary: this.hass!.localize(
|
primary: this.hass!.localize(
|
||||||
"ui.components.entity.entity-picker.no_match"
|
"ui.components.entity.entity-picker.no_match"
|
||||||
),
|
),
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { mdiChartLine, mdiShape } from "@mdi/js";
|
import { mdiChartLine, mdiHelpCircle, mdiShape } from "@mdi/js";
|
||||||
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import type { PropertyValues, TemplateResult } from "lit";
|
import type { PropertyValues, TemplateResult } from "lit";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../common/array/ensure-array";
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
@ -26,31 +25,27 @@ import type { HaComboBox } from "../ha-combo-box";
|
|||||||
import "../ha-combo-box-item";
|
import "../ha-combo-box-item";
|
||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
import "./state-badge";
|
import "./state-badge";
|
||||||
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
|
|
||||||
type StatisticItemType = "entity" | "external" | "no_state";
|
type StatisticItemType = "entity" | "external" | "no_state";
|
||||||
|
|
||||||
interface StatisticItem {
|
interface StatisticItem {
|
||||||
|
// Force empty label to always display empty value by default in the search field
|
||||||
id: string;
|
id: string;
|
||||||
|
statistic_id?: string;
|
||||||
label: "";
|
label: "";
|
||||||
primary: string;
|
primary: string;
|
||||||
secondary?: string;
|
secondary?: string;
|
||||||
show_entity_id?: boolean;
|
search_labels?: string[];
|
||||||
entity_name?: string;
|
|
||||||
area_name?: string;
|
|
||||||
device_name?: string;
|
|
||||||
friendly_name?: string;
|
|
||||||
sorting_label?: string;
|
sorting_label?: string;
|
||||||
state?: HassEntity;
|
icon_path?: string;
|
||||||
type?: StatisticItemType;
|
type?: StatisticItemType;
|
||||||
iconPath?: string;
|
stateObj?: HassEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TYPE_ORDER = ["entity", "external", "no_state"] as StatisticItemType[];
|
const MISSING_ID = "___missing-entity___";
|
||||||
|
|
||||||
const ENTITY_ID_STYLE = styleMap({
|
const TYPE_ORDER = ["entity", "external", "no_state"] as StatisticItemType[];
|
||||||
fontFamily: "var(--ha-font-family-code)",
|
|
||||||
fontSize: "11px",
|
|
||||||
});
|
|
||||||
|
|
||||||
@customElement("ha-statistic-combo-box")
|
@customElement("ha-statistic-combo-box")
|
||||||
export class HaStatisticComboBox extends LitElement {
|
export class HaStatisticComboBox extends LitElement {
|
||||||
@ -131,37 +126,39 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
private _rowRenderer: ComboBoxLitRenderer<StatisticItem> = (
|
private _rowRenderer: ComboBoxLitRenderer<StatisticItem> = (
|
||||||
item,
|
item,
|
||||||
{ index }
|
{ index }
|
||||||
) => html`
|
) => {
|
||||||
<ha-combo-box-item type="button" compact .borderTop=${index !== 0}>
|
const showEntityId = this.hass.userData?.showEntityIdPicker;
|
||||||
${!item.state
|
return html`
|
||||||
? html`
|
<ha-combo-box-item type="button" compact .borderTop=${index !== 0}>
|
||||||
<ha-svg-icon
|
${item.icon_path
|
||||||
style="margin: 0 4px"
|
? html`
|
||||||
slot="start"
|
<ha-svg-icon
|
||||||
.path=${item.iconPath}
|
style="margin: 0 4px"
|
||||||
></ha-svg-icon>
|
slot="start"
|
||||||
`
|
.path=${item.icon_path}
|
||||||
: html`
|
></ha-svg-icon>
|
||||||
<state-badge
|
`
|
||||||
slot="start"
|
: item.stateObj
|
||||||
.stateObj=${item.state}
|
? html`
|
||||||
.hass=${this.hass}
|
<state-badge
|
||||||
></state-badge>
|
slot="start"
|
||||||
`}
|
.stateObj=${item.stateObj}
|
||||||
|
.hass=${this.hass}
|
||||||
<span slot="headline">${item.primary} </span>
|
></state-badge>
|
||||||
${item.secondary
|
`
|
||||||
? html`<span slot="supporting-text">${item.secondary}</span>`
|
: nothing}
|
||||||
: nothing}
|
<span slot="headline">${item.primary} </span>
|
||||||
${item.id && item.show_entity_id
|
${item.secondary
|
||||||
? html`
|
? html`<span slot="supporting-text">${item.secondary}</span>`
|
||||||
<span slot="supporting-text" style=${ENTITY_ID_STYLE}>
|
: nothing}
|
||||||
${item.id}
|
${item.id && showEntityId
|
||||||
</span>
|
? html`<span slot="supporting-text" class="code">
|
||||||
`
|
${item.statistic_id}
|
||||||
: nothing}
|
</span>`
|
||||||
</ha-combo-box-item>
|
: nothing}
|
||||||
`;
|
</ha-combo-box-item>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
private _getItems = memoizeOne(
|
private _getItems = memoizeOne(
|
||||||
(
|
(
|
||||||
@ -249,19 +246,22 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
label: "",
|
label: "",
|
||||||
type,
|
type,
|
||||||
sorting_label: label,
|
sorting_label: label,
|
||||||
iconPath: mdiShape,
|
search_labels: [label, id],
|
||||||
|
icon_path: mdiShape,
|
||||||
});
|
});
|
||||||
} else if (type === "external") {
|
} else if (type === "external") {
|
||||||
const domain = id.split(":")[0];
|
const domain = id.split(":")[0];
|
||||||
const domainName = domainToName(this.hass.localize, domain);
|
const domainName = domainToName(this.hass.localize, domain);
|
||||||
output.push({
|
output.push({
|
||||||
id,
|
id,
|
||||||
|
statistic_id: id,
|
||||||
primary: label,
|
primary: label,
|
||||||
secondary: domainName,
|
secondary: domainName,
|
||||||
label: "",
|
label: "",
|
||||||
type,
|
type,
|
||||||
sorting_label: label,
|
sorting_label: label,
|
||||||
iconPath: mdiChartLine,
|
search_labels: [label, domainName, id],
|
||||||
|
icon_path: mdiChartLine,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -283,17 +283,20 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
|
|
||||||
output.push({
|
output.push({
|
||||||
id,
|
id,
|
||||||
|
statistic_id: id,
|
||||||
|
label: "",
|
||||||
primary,
|
primary,
|
||||||
secondary,
|
secondary,
|
||||||
label: "",
|
stateObj: stateObj,
|
||||||
state: stateObj,
|
|
||||||
type: "entity",
|
type: "entity",
|
||||||
sorting_label: [deviceName, entityName].join("_"),
|
sorting_label: [deviceName, entityName].join("_"),
|
||||||
entity_name: entityName || deviceName,
|
search_labels: [
|
||||||
area_name: areaName,
|
entityName,
|
||||||
device_name: deviceName,
|
deviceName,
|
||||||
friendly_name: friendlyName,
|
areaName,
|
||||||
show_entity_id: hass.userData?.showEntityIdPicker,
|
friendlyName,
|
||||||
|
id,
|
||||||
|
].filter(Boolean) as string[],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -323,11 +326,12 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output.push({
|
output.push({
|
||||||
id: "__missing",
|
id: MISSING_ID,
|
||||||
primary: this.hass.localize(
|
primary: this.hass.localize(
|
||||||
"ui.components.statistic-picker.missing_entity"
|
"ui.components.statistic-picker.missing_entity"
|
||||||
),
|
),
|
||||||
label: "",
|
label: "",
|
||||||
|
icon_path: mdiHelpCircle,
|
||||||
});
|
});
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
@ -422,8 +426,12 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
private _statisticChanged(ev: ValueChangedEvent<string>) {
|
private _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
let newValue = ev.detail.value;
|
let newValue = ev.detail.value;
|
||||||
if (newValue === "__missing") {
|
if (newValue === MISSING_ID) {
|
||||||
newValue = "";
|
newValue = "";
|
||||||
|
window.open(
|
||||||
|
documentationUrl(this.hass, this.helpMissingEntityUrl),
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newValue !== this._value) {
|
if (newValue !== this._value) {
|
||||||
@ -436,16 +444,7 @@ export class HaStatisticComboBox extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _fuseIndex = memoizeOne((states: StatisticItem[]) =>
|
private _fuseIndex = memoizeOne((states: StatisticItem[]) =>
|
||||||
Fuse.createIndex(
|
Fuse.createIndex(["search_labels"], states)
|
||||||
[
|
|
||||||
"entity_name",
|
|
||||||
"device_name",
|
|
||||||
"area_name",
|
|
||||||
"friendly_name", // for backwards compatibility
|
|
||||||
"id", // for technical search
|
|
||||||
],
|
|
||||||
states
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
private _filterChanged(ev: CustomEvent): void {
|
private _filterChanged(ev: CustomEvent): void {
|
||||||
|
@ -35,6 +35,20 @@ export class HaComboBoxItem extends HaMdListItem {
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
::slotted(.code) {
|
||||||
|
font-family: var(--ha-font-family-code);
|
||||||
|
font-size: var(--ha-font-size-xs);
|
||||||
|
}
|
||||||
|
[slot="trailing-supporting-text"] {
|
||||||
|
font-size: var(--ha-font-size-s);
|
||||||
|
font-weight: var(--ha-font-weight-normal);
|
||||||
|
line-height: var(--ha-line-height-normal);
|
||||||
|
align-self: flex-end;
|
||||||
|
max-width: 30%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -95,22 +95,6 @@ type BaseNavigationCommand = Pick<
|
|||||||
"primaryText" | "path"
|
"primaryText" | "path"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const DOMAIN_STYLE = styleMap({
|
|
||||||
fontSize: "var(--ha-font-size-s)",
|
|
||||||
fontWeight: "var(--ha-font-weight-normal)",
|
|
||||||
lineHeight: "var(--ha-line-height-normal)",
|
|
||||||
alignSelf: "flex-end",
|
|
||||||
maxWidth: "30%",
|
|
||||||
textOverflow: "ellipsis",
|
|
||||||
overflow: "hidden",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
});
|
|
||||||
|
|
||||||
const ENTITY_ID_STYLE = styleMap({
|
|
||||||
fontFamily: "var(--ha-font-family-code)",
|
|
||||||
fontSize: "var(--ha-font-size-xs)",
|
|
||||||
});
|
|
||||||
|
|
||||||
@customElement("ha-quick-bar")
|
@customElement("ha-quick-bar")
|
||||||
export class QuickBar extends LitElement {
|
export class QuickBar extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -397,12 +381,12 @@ export class QuickBar extends LitElement {
|
|||||||
? html` <span slot="supporting-text">${item.altText}</span> `
|
? html` <span slot="supporting-text">${item.altText}</span> `
|
||||||
: nothing}
|
: nothing}
|
||||||
${item.entityId && showEntityId
|
${item.entityId && showEntityId
|
||||||
? html`<span slot="supporting-text" style=${ENTITY_ID_STYLE}
|
? html`
|
||||||
>${item.entityId}</span
|
<span slot="supporting-text" class="code">${item.entityId}</span>
|
||||||
>`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
${item.translatedDomain && !showEntityId
|
${item.translatedDomain && !showEntityId
|
||||||
? html`<div slot="trailing-supporting-text" style=${DOMAIN_STYLE}>
|
? html`<div slot="trailing-supporting-text">
|
||||||
${item.translatedDomain}
|
${item.translatedDomain}
|
||||||
</div>`
|
</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
@ -1038,6 +1022,22 @@ export class QuickBar extends LitElement {
|
|||||||
--md-list-item-bottom-space: 8px;
|
--md-list-item-bottom-space: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha-md-list-item .code {
|
||||||
|
font-family: var(--ha-font-family-code);
|
||||||
|
font-size: var(--ha-font-size-xs);
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-md-list-item [slot="trailing-supporting-text"] {
|
||||||
|
font-size: var(--ha-font-size-s);
|
||||||
|
font-weight: var(--ha-font-weight-normal);
|
||||||
|
line-height: var(--ha-line-height-normal);
|
||||||
|
align-self: flex-end;
|
||||||
|
max-width: 30%;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
ha-tip {
|
ha-tip {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user