Compare commits

...

2 Commits

Author SHA1 Message Date
Aidan Timson a2c66488f6 Replace hass with lazy context in settings areas 2026-06-03 13:15:22 +01:00
renovate[bot] 033d035b18 Update dependency lint-staged to v17.0.7 (#52389) 2026-06-03 12:03:23 +01:00
8 changed files with 85 additions and 81 deletions
+1 -1
View File
@@ -180,7 +180,7 @@
"jsdom": "29.1.1",
"jszip": "3.10.1",
"license-checker-rseidelsohn": "5.0.1",
"lint-staged": "17.0.6",
"lint-staged": "17.0.7",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.18.1",
+41 -20
View File
@@ -1,17 +1,19 @@
import type { SelectedDetail } from "@material/mwc-list";
import { consume, type ContextType } from "@lit/context";
import { mdiFilterVariantRemove } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { consumeLocalize } from "../common/decorators/consume-context-entry";
import { fireEvent } from "../common/dom/fire_event";
import { stringCompare } from "../common/string/compare";
import type { LocalizeFunc } from "../common/translations/localize";
import { internationalizationContext, manifestsContext } from "../data/context";
import type { IntegrationManifest } from "../data/integration";
import { domainToName, fetchIntegrationManifests } from "../data/integration";
import { domainToName } from "../data/integration";
import { haStyleScrollbar } from "../resources/styles";
import type { HomeAssistant } from "../types";
import "./ha-check-list-item";
import "./ha-domain-icon";
import "./ha-expansion-panel";
@@ -21,15 +23,26 @@ import type { HaInputSearch } from "./input/ha-input-search";
@customElement("ha-filter-integrations")
export class HaFilterIntegrations extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public value?: string[];
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean, reflect: true }) public expanded = false;
@state() private _manifests?: IntegrationManifest[];
@consume({ context: internationalizationContext, subscribe: true })
private _i18n!: ContextType<typeof internationalizationContext>;
@consumeLocalize()
private _localize!: LocalizeFunc;
@consume({ context: manifestsContext, subscribe: true })
@state()
private _manifests?: ContextType<typeof manifestsContext>;
private _manifestList = memoizeOne(
(manifests: ContextType<typeof manifestsContext>) =>
Object.values(manifests)
);
@state() private _shouldRender = false;
@@ -38,6 +51,10 @@ export class HaFilterIntegrations extends LitElement {
@query("ha-list") private _list?: HTMLElement;
protected render() {
const manifests = this._manifests
? this._manifestList(this._manifests)
: undefined;
return html`
<ha-expansion-panel
left-chevron
@@ -46,7 +63,7 @@ export class HaFilterIntegrations extends LitElement {
@expanded-changed=${this._expandedChanged}
>
<div slot="header" class="header">
${this.hass.localize("ui.panel.config.integrations.caption")}
${this._localize("ui.panel.config.integrations.caption")}
${this.value?.length
? html`<div class="badge">${this.value?.length}</div>
<ha-icon-button
@@ -55,7 +72,7 @@ export class HaFilterIntegrations extends LitElement {
></ha-icon-button>`
: nothing}
</div>
${this._manifests && this._shouldRender
${manifests && this._shouldRender
? html`<ha-input-search
appearance="outlined"
.value=${this._filter}
@@ -69,10 +86,11 @@ export class HaFilterIntegrations extends LitElement {
>
${repeat(
this._integrations(
this.hass.localize,
this._manifests,
this._localize,
manifests,
this._filter,
this.value
this.value,
this._i18n.locale.language
),
(i) => i.domain,
(integration) =>
@@ -117,9 +135,8 @@ export class HaFilterIntegrations extends LitElement {
this.expanded = ev.detail.expanded;
}
protected async firstUpdated() {
this._manifests = await fetchIntegrationManifests(this.hass);
this.hass.loadBackendTranslation("title");
protected firstUpdated() {
this._i18n.loadBackendTranslation("title");
}
private _integrations = memoizeOne(
@@ -127,7 +144,8 @@ export class HaFilterIntegrations extends LitElement {
localize: LocalizeFunc,
manifest: IntegrationManifest[],
filter: string | undefined,
_value
_value: string[] | undefined,
language: string
) =>
manifest
.map((mnfst) => ({
@@ -144,17 +162,20 @@ export class HaFilterIntegrations extends LitElement {
mnfst.name.toLowerCase().includes(filter) ||
mnfst.domain.toLowerCase().includes(filter))
)
.sort((a, b) =>
stringCompare(a.name, b.name, this.hass.locale.language)
)
.sort((a, b) => stringCompare(a.name, b.name, language))
);
private _itemSelected(ev: CustomEvent<SelectedDetail<Set<number>>>) {
if (!this._manifests) {
return;
}
const integrations = this._integrations(
this.hass.localize,
this._manifests!,
this._localize,
this._manifestList(this._manifests),
this._filter,
this.value
this.value,
this._i18n.locale.language
);
const visibleDomains = new Set(integrations.map((i) => i.domain));
@@ -232,7 +232,6 @@ class HaConfigSectionUpdates extends LitElement {
: nothing}
</div>
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${group.entities}
showAll
@@ -256,7 +255,6 @@ class HaConfigSectionUpdates extends LitElement {
</div>
</div>
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${skippedUpdates}
showAll
@@ -280,7 +278,6 @@ class HaConfigSectionUpdates extends LitElement {
</div>
</div>
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${notInstallableUpdates}
showAll
@@ -326,7 +326,6 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
</a>
</div>
<ha-config-updates
.hass=${this.hass}
.narrow=${this.narrow}
.updateEntities=${canInstallUpdates}
></ha-config-updates>
@@ -1,9 +1,9 @@
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import { consume, type ContextType } from "@lit/context";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one";
import { consumeLocalize } from "../../../common/decorators/consume-context-entry";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
import { getDeviceArea } from "../../../common/entity/context/get_device_context";
@@ -14,62 +14,51 @@ import "../../../components/ha-spinner";
import "../../../components/item/ha-list-item-button";
import "../../../components/list/ha-list-base";
import "../../../components/progress/ha-progress-ring";
import type { DeviceRegistryEntry } from "../../../data/device/device_registry";
import { subscribeDeviceRegistry } from "../../../data/device/device_registry";
import type { EntityRegistryEntry } from "../../../data/entity/entity_registry";
import { subscribeEntityRegistry } from "../../../data/entity/entity_registry";
import {
areasContext,
devicesContext,
fullEntitiesContext,
statesContext,
} from "../../../data/context";
import { entityRegistryByEntityId } from "../../../data/entity/entity_registry";
import type { UpdateEntity } from "../../../data/update";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import type { HomeAssistant } from "../../../types";
import type { LocalizeFunc } from "../../../common/translations/localize";
@customElement("ha-config-updates")
class HaConfigUpdates extends SubscribeMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
class HaConfigUpdates extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public updateEntities?: UpdateEntity[];
@state() private _devices?: DeviceRegistryEntry[];
@consumeLocalize()
private _localize!: LocalizeFunc;
@state() private _entities?: EntityRegistryEntry[];
@consume({ context: statesContext, subscribe: true })
private _states!: ContextType<typeof statesContext>;
public hassSubscribe(): UnsubscribeFunc[] {
return [
subscribeDeviceRegistry(this.hass.connection, (entries) => {
this._devices = entries;
}),
subscribeEntityRegistry(this.hass.connection!, (entities) => {
this._entities = entities.filter((entity) => entity.device_id !== null);
}),
];
}
@consume({ context: devicesContext, subscribe: true })
private _devices!: ContextType<typeof devicesContext>;
private getDeviceEntry = memoizeOne(
(deviceId: string): DeviceRegistryEntry | undefined =>
this._devices?.find((device) => device.id === deviceId)
);
@consume({ context: areasContext, subscribe: true })
private _areas!: ContextType<typeof areasContext>;
private getEntityEntry = memoizeOne(
(entityId: string): EntityRegistryEntry | undefined =>
this._entities?.find((entity) => entity.entity_id === entityId)
);
@state()
@consume({ context: fullEntitiesContext, subscribe: true })
private _entities: ContextType<typeof fullEntitiesContext> = [];
private _renderUpdateProgress(entity: UpdateEntity) {
if (entity.attributes.update_percentage != null) {
return html`<ha-progress-ring
size="small"
.value=${entity.attributes.update_percentage}
.label=${this.hass.localize(
"ui.panel.config.updates.update_in_progress"
)}
.label=${this._localize("ui.panel.config.updates.update_in_progress")}
></ha-progress-ring>`;
}
if (entity.attributes.in_progress) {
return html`<ha-spinner
size="small"
.ariaLabel=${this.hass.localize(
.ariaLabel=${this._localize(
"ui.panel.config.updates.update_in_progress"
)}
></ha-spinner>`;
@@ -84,22 +73,23 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
}
const updates = this.updateEntities;
const entities = entityRegistryByEntityId(this._entities);
return html`
<ha-list-base
aria-label=${this.hass.localize("ui.panel.config.updates.caption")}
aria-label=${this._localize("ui.panel.config.updates.caption")}
>
${updates.map((entity) => {
const entityEntry = this.getEntityEntry(entity.entity_id);
const entityEntry = entities[entity.entity_id];
const deviceEntry =
entityEntry && entityEntry.device_id
? this.getDeviceEntry(entityEntry.device_id)
? this._devices[entityEntry.device_id]
: undefined;
const areaName =
deviceEntry && deviceEntry.entry_type !== "service"
? getDeviceArea(deviceEntry, this.hass.areas)?.name ||
this.hass.localize("ui.panel.config.updates.no_area")
? getDeviceArea(deviceEntry, this._areas)?.name ||
this._localize("ui.panel.config.updates.no_area")
: undefined;
return html`
@@ -112,7 +102,6 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
<state-badge
.title=${entity.attributes.title ||
entity.attributes.friendly_name}
.hass=${this.hass}
.stateObj=${entity}
class=${ifDefined(
this.narrow && entity.attributes.in_progress
@@ -130,8 +119,8 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
>${deviceEntry
? computeDeviceNameDisplay(
deviceEntry,
this.hass.localize,
this.hass.states
this._localize,
this._states
)
: entity.attributes.friendly_name}</span
>
@@ -139,7 +128,7 @@ class HaConfigUpdates extends SubscribeMixin(LitElement) {
${areaName ? html`${areaName}` : nothing}
${entity.attributes.title} ${entity.attributes.latest_version}
${entity.attributes.skipped_version
? `(${this.hass.localize("ui.panel.config.updates.skipped")})`
? `(${this._localize("ui.panel.config.updates.skipped")})`
: nothing}
</span>
${!this.narrow
@@ -846,7 +846,6 @@ export class HaConfigDeviceDashboard extends LitElement {
@expanded-changed=${this._filterExpanded}
></ha-filter-floor-areas>
<ha-filter-integrations
.hass=${this.hass}
.value=${this._filters["ha-filter-integrations"]?.value}
@data-table-filter-changed=${this._filterChanged}
slot="filter-pane"
@@ -1014,7 +1014,6 @@ export class HaConfigEntities extends LitElement {
@expanded-changed=${this._filterExpanded}
></ha-filter-domains>
<ha-filter-integrations
.hass=${this.hass}
.value=${this._filters["ha-filter-integrations"]}
@data-table-filter-changed=${this._filterChanged}
slot="filter-pane"
+10 -10
View File
@@ -8557,7 +8557,7 @@ __metadata:
leaflet-draw: "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
leaflet.markercluster: "npm:1.5.3"
license-checker-rseidelsohn: "npm:5.0.1"
lint-staged: "npm:17.0.6"
lint-staged: "npm:17.0.7"
lit: "npm:3.3.3"
lit-analyzer: "npm:2.0.3"
lit-html: "npm:3.3.3"
@@ -9936,21 +9936,21 @@ __metadata:
languageName: node
linkType: hard
"lint-staged@npm:17.0.6":
version: 17.0.6
resolution: "lint-staged@npm:17.0.6"
"lint-staged@npm:17.0.7":
version: 17.0.7
resolution: "lint-staged@npm:17.0.7"
dependencies:
listr2: "npm:^10.2.1"
picomatch: "npm:^4.0.4"
string-argv: "npm:^0.3.2"
tinyexec: "npm:1.2.2"
tinyexec: "npm:^1.2.4"
yaml: "npm:^2.9.0"
dependenciesMeta:
yaml:
optional: true
bin:
lint-staged: bin/lint-staged.js
checksum: 10/371918cfb293ed0ca5d16fc2a1de304b5a95d21b87dc1ea7f3751567c8f8a07971a40349fac8edb5fce3c6ea6713f70922ea90184b142fd432a5bb4db6c316b0
checksum: 10/4ed3cd01caa78ff5cc5da7ec69f77f091c43a0d5cbb1e084f7ffd3872a9e599675fb8b5f11fd5911faee0d330952889dd0e14378a26620d8f529eae401ce49b4
languageName: node
linkType: hard
@@ -13172,10 +13172,10 @@ __metadata:
languageName: node
linkType: hard
"tinyexec@npm:1.2.2, tinyexec@npm:^1.0.2":
version: 1.2.2
resolution: "tinyexec@npm:1.2.2"
checksum: 10/e6f3cabafc33a46063868b4e9c0ab76722e21cb46f0177f7bef5a9656e09ea6fa37115d3e47f776aff11aab9ab696b0c840c8e0099fab574b1e37767c4371aec
"tinyexec@npm:^1.0.2, tinyexec@npm:^1.2.4":
version: 1.2.4
resolution: "tinyexec@npm:1.2.4"
checksum: 10/f20b3e6f56f24c3ebe0129d0b6e657e561d225df2cf93c1a10362996232dd6ad4b8af8c9e81d258a64d09020e723772baf6fe0be26512dba7c61bb366d67b1f9
languageName: node
linkType: hard