Compare commits

...

3 Commits

Author SHA1 Message Date
Bram Kragten
063adac9cc fix: use value imports for LitElement, html, nothing from lit 2026-04-28 09:59:19 +01:00
Bram Kragten
f67286108d fix race in pickers that add items from the picker 2026-04-28 09:34:55 +01:00
Bram Kragten
c6a31324c2 Check for unknown value every render if value is unknown 2026-04-28 09:10:51 +01:00
6 changed files with 124 additions and 17 deletions

View File

@@ -1,7 +1,7 @@
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import { mdiPlus, mdiShape } from "@mdi/js";
import { html, LitElement, nothing, type PropertyValues } from "lit";
import { customElement, property, query } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import { computeEntityPickerDisplay } from "../../common/entity/compute_entity_name_display";
@@ -129,6 +129,20 @@ export class HaEntityPicker extends LitElement {
@query("ha-generic-picker") private _picker?: HaGenericPicker;
@state() private _pendingEntityId?: string;
protected willUpdate(changedProperties: PropertyValues<this>) {
if (
this._pendingEntityId &&
changedProperties.has("hass") &&
this.hass.states !== changedProperties.get("hass")?.states &&
this.hass.states[this._pendingEntityId]
) {
this._setValue(this._pendingEntityId);
this._pendingEntityId = undefined;
}
}
protected firstUpdated(changedProperties: PropertyValues<this>): void {
super.firstUpdated(changedProperties);
// Load title translations so it is available when the combo-box opens
@@ -399,7 +413,13 @@ export class HaEntityPicker extends LitElement {
showHelperDetailDialog(this, {
domain,
dialogClosedCallback: (item) => {
if (item.entityId) this._setValue(item.entityId);
if (item.entityId) {
if (this.hass.states[item.entityId]) {
this._setValue(item.entityId);
} else {
this._pendingEntityId = item.entityId;
}
}
},
});
return;

View File

@@ -1,8 +1,8 @@
import { mdiPlus, mdiTextureBox } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import type { TemplateResult, PropertyValues } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeAreaName } from "../common/entity/compute_area_name";
@@ -85,6 +85,20 @@ export class HaAreaPicker extends LitElement {
@query("ha-generic-picker") private _picker?: HaGenericPicker;
@state() private _pendingAreaId?: string;
protected willUpdate(changedProperties: PropertyValues<this>) {
if (
this._pendingAreaId &&
changedProperties.has("hass") &&
this.hass.areas !== changedProperties.get("hass")?.areas &&
this.hass.areas[this._pendingAreaId]
) {
this._setValue(this._pendingAreaId);
this._pendingAreaId = undefined;
}
}
public async open() {
await this.updateComplete;
await this._picker?.open();
@@ -243,7 +257,11 @@ export class HaAreaPicker extends LitElement {
createEntry: async (values) => {
try {
const area = await createAreaRegistryEntry(this.hass, values);
this._setValue(area.area_id);
if (this.hass.areas[area.area_id]) {
this._setValue(area.area_id);
} else {
this._pendingAreaId = area.area_id;
}
} catch (err: any) {
showAlertDialog(this, {
title: this.hass.localize(

View File

@@ -1,9 +1,9 @@
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import { mdiPlus, mdiTextureBox } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, html } from "lit";
import { customElement, property, query } from "lit/decorators";
import type { TemplateResult, PropertyValues } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeDomain } from "../common/entity/compute_domain";
@@ -104,6 +104,20 @@ export class HaFloorPicker extends LitElement {
@query("ha-generic-picker") private _picker?: HaGenericPicker;
@state() private _pendingFloorId?: string;
protected willUpdate(changedProperties: PropertyValues<this>) {
if (
this._pendingFloorId &&
changedProperties.has("hass") &&
this.hass.floors !== changedProperties.get("hass")?.floors &&
this.hass.floors[this._pendingFloorId]
) {
this._setValue(this._pendingFloorId);
this._pendingFloorId = undefined;
}
}
public async open() {
await this.updateComplete;
await this._picker?.open();
@@ -436,7 +450,11 @@ export class HaFloorPicker extends LitElement {
floor_id: floor.floor_id,
});
});
this._setValue(floor.floor_id);
if (this.hass.floors[floor.floor_id]) {
this._setValue(floor.floor_id);
} else {
this._pendingFloorId = floor.floor_id;
}
} catch (err: any) {
showAlertDialog(this, {
title: this.hass.localize(

View File

@@ -2,8 +2,8 @@ import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import { consume } from "@lit/context";
import { mdiPlus } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { LitElement, html, nothing } from "lit";
import type { TemplateResult, PropertyValues } from "lit";
import {
customElement,
property,
@@ -117,6 +117,19 @@ export class HaLabelPicker extends LitElement {
@query("ha-generic-picker") private _picker?: HaGenericPicker;
@state() private _pendingLabelId?: string;
protected willUpdate(changedProperties: PropertyValues) {
if (
this._pendingLabelId &&
changedProperties.has("_labels") &&
this._labels?.some((l) => l.label_id === this._pendingLabelId)
) {
this._setValue(this._pendingLabelId);
this._pendingLabelId = undefined;
}
}
public async open() {
await this.updateComplete;
await this._picker?.open();
@@ -248,7 +261,11 @@ export class HaLabelPicker extends LitElement {
createEntry: async (values) => {
try {
const label = await createLabelRegistryEntry(this.hass, values);
this._setValue(label.label_id);
if (this._labels?.some((l) => l.label_id === label.label_id)) {
this._setValue(label.label_id);
} else {
this._pendingLabelId = label.label_id;
}
} catch (err: any) {
showAlertDialog(this, {
title: this.hass.localize(

View File

@@ -157,12 +157,24 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
),
};
@state() private _pendingEntityId?: string;
public willUpdate(changedProps: PropertyValues<this>) {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._loadConfigEntries();
}
if (
this._pendingEntityId &&
changedProps.has("hass") &&
this.hass.states !== changedProps.get("hass")?.states &&
this.hass.states[this._pendingEntityId]
) {
this._addTarget(this._pendingEntityId, "entity");
this._pendingEntityId = undefined;
}
}
private _createFuseIndex = (states, keys: FuseWeightedKey[]) =>
@@ -532,10 +544,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
domain,
dialogClosedCallback: (item) => {
if (item.entityId) {
// prevent error that new entity_id isn't in hass object
requestAnimationFrame(() => {
this._addTarget(item.entityId!, "entity");
});
if (this.hass.states[item.entityId]) {
this._addTarget(item.entityId, "entity");
} else {
this._pendingEntityId = item.entityId;
}
}
},
});

View File

@@ -1,7 +1,7 @@
import { mdiPlus, mdiTag } from "@mdi/js";
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { LitElement, html } from "lit";
import type { TemplateResult, PropertyValues } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
@@ -46,6 +46,19 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
@query("ha-generic-picker") private _picker?: HaGenericPicker;
@state() private _pendingCategoryId?: string;
protected willUpdate(changedProperties: PropertyValues) {
if (
this._pendingCategoryId &&
changedProperties.has("_categories") &&
this._categories?.some((c) => c.category_id === this._pendingCategoryId)
) {
this._setValue(this._pendingCategoryId);
this._pendingCategoryId = undefined;
}
}
protected hassSubscribeRequiredHostProps = ["scope"];
public async open() {
@@ -222,7 +235,15 @@ export class HaCategoryPicker extends SubscribeMixin(LitElement) {
this.scope!,
values
);
this._setValue(category.category_id);
if (
this._categories?.some(
(c) => c.category_id === category.category_id
)
) {
this._setValue(category.category_id);
} else {
this._pendingCategoryId = category.category_id;
}
return category;
},
});