mirror of
https://github.com/home-assistant/frontend.git
synced 2026-06-03 23:11:52 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a2c66488f6 | |||
| 033d035b18 |
+1
-1
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user