Compare commits

...
Author SHA1 Message Date
Petar Petrov b07a0b5a37 Drop hass from the label pickers
The label registry helpers take callWS, so ha-label-picker, ha-labels-picker and ha-selector-label read their data from contexts.
2026-10-26 17:54:36 +02:00
16 changed files with 82 additions and 53 deletions

No files matched your search

+45 -19
View File
@@ -1,3 +1,4 @@
import type { ContextType } from "@lit/context";
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
import { mdiPlus } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
@@ -15,7 +16,13 @@ import memoizeOne from "memoize-one";
import { consume } from "../common/decorators/consume";
import { computeCssColor } from "../common/color/compute-color";
import { fireEvent } from "../common/dom/fire_event";
import { labelsContext } from "../data/context";
import {
apiContext,
internationalizationContext,
labelsContext,
registriesContext,
statesContext,
} from "../data/context";
import {
getLabels,
labelComboBoxKeys,
@@ -27,7 +34,7 @@ import {
} from "../data/label/label_registry";
import { showAlertDialog } from "../dialogs/generic/show-dialog-box";
import { showLabelDetailDialog } from "../panels/config/labels/show-dialog-label-detail";
import type { HomeAssistant, ValueChangedEvent } from "../types";
import type { ValueChangedEvent } from "../types";
import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
import "./ha-generic-picker";
import type { HaGenericPicker } from "./ha-generic-picker";
@@ -53,8 +60,6 @@ export const renderLabelColorBadge = (color: string | undefined) =>
@customElement("ha-label-picker")
export class HaLabelPicker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public label?: string;
@property() public value?: string;
@@ -112,6 +117,19 @@ export class HaLabelPicker extends LitElement {
@state()
private _labels?: LabelRegistryEntry[];
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
@consume({ context: statesContext, subscribe: true })
private _states?: ContextType<typeof statesContext>;
@consume({ context: registriesContext, subscribe: true })
private _registries?: ContextType<typeof registriesContext>;
@consume({ context: apiContext, subscribe: true })
private _api!: ContextType<typeof apiContext>;
@queryAssignedElements({ flatten: true })
private _slotNodes?: NodeListOf<HTMLElement>;
@@ -149,12 +167,16 @@ export class HaLabelPicker extends LitElement {
private _getLabelsMemoized = memoizeOne(getLabels);
private _getItems = () =>
this._getLabelsMemoized(
this.hass.states,
this.hass.areas,
this.hass.devices,
this.hass.entities,
private _getItems = () => {
const { areas, devices, entities } = this._registries ?? {};
if (!this._states || !areas || !devices || !entities) {
return [];
}
return this._getLabelsMemoized(
this._states,
areas,
devices,
entities,
this._labels,
this.includeDomains,
this.excludeDomains,
@@ -163,6 +185,7 @@ export class HaLabelPicker extends LitElement {
this.entityFilter,
this.excludeLabels
);
};
private _allLabelNames = memoizeOne((labels?: LabelRegistryEntry[]) => {
if (!labels) {
@@ -190,7 +213,7 @@ export class HaLabelPicker extends LitElement {
return [
{
id: ADD_NEW_ID + searchString,
primary: this.hass.localize(
primary: this._i18n.localize(
"ui.components.label-picker.add_new_suggestion",
{
name: searchString,
@@ -204,7 +227,7 @@ export class HaLabelPicker extends LitElement {
return [
{
id: ADD_NEW_ID,
primary: this.hass.localize("ui.components.label-picker.add_new"),
primary: this._i18n.localize("ui.components.label-picker.add_new"),
icon_path: mdiPlus,
},
];
@@ -213,7 +236,7 @@ export class HaLabelPicker extends LitElement {
protected render(): TemplateResult {
const placeholder =
this.placeholder ??
this.hass.localize("ui.components.label-picker.label");
this._i18n.localize("ui.components.label-picker.label");
return html`
<ha-generic-picker
@@ -222,10 +245,10 @@ export class HaLabelPicker extends LitElement {
.label=${this.label}
.helper=${this.helper}
.notFoundLabel=${this._notFoundLabel}
.emptyLabel=${this.hass.localize(
.emptyLabel=${this._i18n.localize(
"ui.components.label-picker.no_labels"
)}
.addButtonLabel=${this.hass.localize("ui.components.label-picker.add")}
.addButtonLabel=${this._i18n.localize("ui.components.label-picker.add")}
.placeholder=${placeholder}
.value=${this.value}
.getItems=${this._getItems}
@@ -253,7 +276,7 @@ export class HaLabelPicker extends LitElement {
}
if (value.startsWith(ADD_NEW_ID)) {
this.hass.loadFragmentTranslation("config");
this._i18n.loadFragmentTranslation("config");
const suggestedName = value.substring(ADD_NEW_ID.length);
@@ -261,7 +284,10 @@ export class HaLabelPicker extends LitElement {
suggestedName: suggestedName,
createEntry: async (values) => {
try {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(
this._api.callWS,
values
);
if (this._labels?.some((l) => l.label_id === label.label_id)) {
this._setValue(label.label_id);
} else {
@@ -269,7 +295,7 @@ export class HaLabelPicker extends LitElement {
}
} catch (err: any) {
showAlertDialog(this, {
title: this.hass.localize(
title: this._i18n.localize(
"ui.components.label-picker.failed_create_label"
),
text: err.message,
@@ -292,7 +318,7 @@ export class HaLabelPicker extends LitElement {
}
private _notFoundLabel = (search: string) =>
this.hass.localize("ui.components.label-picker.no_match", {
this._i18n.localize("ui.components.label-picker.no_match", {
term: html`<b>‘${search}’</b>`,
});
+21 -8
View File
@@ -1,3 +1,4 @@
import type { ContextType } from "@lit/context";
import { mdiPlaylistPlus } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
@@ -8,11 +9,15 @@ import memoizeOne from "memoize-one";
import { consume } from "../common/decorators/consume";
import { fireEvent } from "../common/dom/fire_event";
import { stringCompare } from "../common/string/compare";
import { labelsContext } from "../data/context";
import {
apiContext,
internationalizationContext,
labelsContext,
} from "../data/context";
import type { LabelRegistryEntry } from "../data/label/label_registry";
import { updateLabelRegistryEntry } from "../data/label/label_registry";
import { showLabelDetailDialog } from "../panels/config/labels/show-dialog-label-detail";
import type { HomeAssistant, ValueChangedEvent } from "../types";
import type { ValueChangedEvent } from "../types";
import "./chips/ha-chip-set";
import "./chips/ha-input-chip";
import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
@@ -23,8 +28,6 @@ import "./ha-tooltip";
@customElement("ha-labels-picker")
export class HaLabelsPicker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public label?: string;
@property({ attribute: false }) public value?: string[];
@@ -82,6 +85,13 @@ export class HaLabelsPicker extends LitElement {
@state()
private _labels?: LabelRegistryEntry[];
@state()
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
@consume({ context: apiContext, subscribe: true })
private _api!: ContextType<typeof apiContext>;
@query("ha-label-picker", true) public labelPicker!: HaLabelPicker;
public async open() {
@@ -114,12 +124,11 @@ export class HaLabelsPicker extends LitElement {
const labels = this._sortedLabels(
this.value,
this._labels,
this.hass.locale.language
this._i18n.locale.language
);
return html`
${this.label ? html`<label>${this.label}</label>` : nothing}
<ha-label-picker
.hass=${this.hass}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
@@ -175,7 +184,7 @@ export class HaLabelsPicker extends LitElement {
.disabled=${this.disabled}
>
<ha-svg-icon .path=${mdiPlaylistPlus} slot="start"></ha-svg-icon>
${this.hass.localize("ui.components.label-picker.add")}
${this._i18n.localize("ui.components.label-picker.add")}
</ha-button>
</ha-chip-set>
</ha-label-picker>
@@ -196,7 +205,11 @@ export class HaLabelsPicker extends LitElement {
showLabelDetailDialog(this, {
entry: label,
updateEntry: async (values) => {
await updateLabelRegistryEntry(this.hass, label.label_id, values);
await updateLabelRegistryEntry(
this._api.callWS,
label.label_id,
values
);
},
});
}
@@ -3,13 +3,10 @@ import { customElement, property } from "lit/decorators";
import { ensureArray } from "../../common/array/ensure-array";
import { fireEvent } from "../../common/dom/fire_event";
import type { LabelSelector } from "../../data/selector";
import type { HomeAssistant } from "../../types";
import "../ha-labels-picker";
@customElement("ha-selector-label")
export class HaLabelSelector extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public value?: string | string[];
@property() public name?: string;
@@ -31,7 +28,6 @@ export class HaLabelSelector extends LitElement {
return html`
<ha-labels-picker
no-add
.hass=${this.hass}
.value=${ensureArray(this.value ?? [])}
.required=${this.required}
.disabled=${this.disabled}
@@ -45,7 +41,6 @@ export class HaLabelSelector extends LitElement {
return html`
<ha-label-picker
no-add
.hass=${this.hass}
.value=${this.value}
.required=${this.required}
.disabled=${this.disabled}
+6 -6
View File
@@ -61,30 +61,30 @@ export const subscribeLabelRegistry = (
);
export const createLabelRegistryEntry = (
hass: HomeAssistant,
callWS: HomeAssistant["callWS"],
values: LabelRegistryEntryMutableParams
) =>
hass.callWS<LabelRegistryEntry>({
callWS<LabelRegistryEntry>({
type: "config/label_registry/create",
...values,
});
export const updateLabelRegistryEntry = (
hass: HomeAssistant,
callWS: HomeAssistant["callWS"],
labelId: string,
updates: Partial<LabelRegistryEntryMutableParams>
) =>
hass.callWS<LabelRegistryEntry>({
callWS<LabelRegistryEntry>({
type: "config/label_registry/update",
label_id: labelId,
...updates,
});
export const deleteLabelRegistryEntry = (
hass: HomeAssistant,
callWS: HomeAssistant["callWS"],
labelId: string
) =>
hass.callWS({
callWS({
type: "config/label_registry/delete",
label_id: labelId,
});
@@ -204,7 +204,6 @@ class DialogAreaDetail
<ha-labels-picker
.label=${this.hass.localize("ui.components.label-picker.labels")}
.hass=${this.hass}
.value=${this._labels}
@value-changed=${this._labelsChanged}
.placeholder=${this.hass.localize(
@@ -218,7 +218,6 @@ class DialogAutomationSave
this._visibleOptionals.includes("labels")
? html` <ha-labels-picker
id="labels"
.hass=${this.hass}
.value=${this._entryUpdates.labels}
@value-changed=${this._registryEntryChanged}
></ha-labels-picker>`
@@ -1416,7 +1416,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});
@@ -114,7 +114,6 @@ class DialogDeviceRegistryDetail extends DirtyStateProviderMixin<DeviceFormState
@value-changed=${this._areaPicked}
></ha-area-picker>
<ha-labels-picker
.hass=${this.hass}
.value=${this._labels}
@value-changed=${this._labelsChanged}
></ha-labels-picker>
@@ -1247,7 +1247,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});
@@ -990,7 +990,6 @@ export class EntityRegistrySettingsEditor extends LitElement {
: nothing
}
<ha-labels-picker
.hass=${this.hass}
.value=${this._labels}
.disabled=${!!this.disabled}
@value-changed=${this._labelsChanged}
@@ -1447,7 +1447,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});
@@ -1563,7 +1563,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});
+4 -4
View File
@@ -358,7 +358,7 @@ export class HaConfigLabels extends LitElement {
private async _createLabel(
values: LabelRegistryEntryMutableParams
): Promise<LabelRegistryEntry> {
const newTag = await createLabelRegistryEntry(this.hass, values);
const newTag = await createLabelRegistryEntry(this.hass.callWS, values);
this._labels = [...this._labels, newTag];
return newTag;
}
@@ -368,7 +368,7 @@ export class HaConfigLabels extends LitElement {
values: Partial<LabelRegistryEntryMutableParams>
): Promise<LabelRegistryEntry> {
const updated = await updateLabelRegistryEntry(
this.hass,
this.hass.callWS,
selectedLabel.label_id,
values
);
@@ -399,7 +399,7 @@ export class HaConfigLabels extends LitElement {
return false;
}
try {
await deleteLabelRegistryEntry(this.hass, selectedLabel.label_id);
await deleteLabelRegistryEntry(this.hass.callWS, selectedLabel.label_id);
this._labels = this._labels.filter(
(label) => label.label_id !== selectedLabel.label_id
);
@@ -431,7 +431,7 @@ export class HaConfigLabels extends LitElement {
action: async () => {
const results = await Promise.allSettled(
this._selected.map((labelId) =>
deleteLabelRegistryEntry(this.hass, labelId)
deleteLabelRegistryEntry(this.hass.callWS, labelId)
)
);
const deletedIds = new Set(
@@ -1158,7 +1158,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});
@@ -175,7 +175,6 @@ class DialogSceneSave extends DirtyStateProviderMixin<SceneSaveState>()(
this._visibleOptionals.includes("labels")
? html` <ha-labels-picker
id="labels"
.hass=${this.hass}
.value=${this._entryUpdates.labels}
@value-changed=${this._registryEntryChanged}
></ha-labels-picker>`
+1 -1
View File
@@ -1136,7 +1136,7 @@ ${rejected
private _bulkCreateLabel = () => {
showLabelDetailDialog(this, {
createEntry: async (values) => {
const label = await createLabelRegistryEntry(this.hass, values);
const label = await createLabelRegistryEntry(this.hass.callWS, values);
this._bulkLabel(label.label_id, "add");
},
});