From 4f98524258cd993e017bb15609bb9644dd1d87a2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 5 Mar 2020 09:09:29 -0800 Subject: [PATCH] =?UTF-8?q?Optimise=20config=20entities=20panel=20+=20clar?= =?UTF-8?q?ify=20not=20being=20able=20to=20dele=E2=80=A6=20(#5079)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/entities/ha-config-entities.ts | 116 ++++++++++++------ src/translations/en.json | 5 +- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 9d31792024..4e61cdde59 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -3,7 +3,7 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-tooltip/paper-tooltip"; -import { UnsubscribeFunc, HassEntities } from "home-assistant-js-websocket"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, CSSResult, @@ -58,6 +58,7 @@ export interface StateEntity extends EntityRegistryEntry { export interface EntityRow extends StateEntity { icon: string; unavailable: boolean; + restored: boolean; status: string; } @@ -68,6 +69,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { @property() public narrow!: boolean; @property() public route!: Route; @property() private _entities?: EntityRegistryEntry[]; + @property() private _stateEntities: StateEntity[] = []; @property() private _showDisabled = false; @property() private _showUnavailable = true; @property() private _showReadOnly = true; @@ -115,14 +117,20 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { style=${styleMap({ color: entity.unavailable ? "var(--google-red-500)" : "", })} - .icon=${entity.unavailable + .icon=${entity.restored + ? "hass:restore-alert" + : entity.unavailable ? "hass:alert-circle" : entity.disabled_by ? "hass:cancel" : "hass:pencil-off"} > - ${entity.unavailable + ${entity.restored + ? this.hass.localize( + "ui.panel.config.entities.picker.status.restored" + ) + : entity.unavailable ? this.hass.localize( "ui.panel.config.entities.picker.status.unavailable" ) @@ -177,40 +185,23 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { private _filteredEntities = memoize( ( entities: EntityRegistryEntry[], - states: HassEntities, + stateEntities: StateEntity[], showDisabled: boolean, showUnavailable: boolean, showReadOnly: boolean ): EntityRow[] => { - const stateEntities: StateEntity[] = []; - if (showReadOnly) { - const regEntityIds = new Set( - entities.map((entity) => entity.entity_id) - ); - for (const entityId of Object.keys(states)) { - if (regEntityIds.has(entityId)) { - continue; - } - stateEntities.push({ - name: computeStateName(states[entityId]), - entity_id: entityId, - platform: computeDomain(entityId), - disabled_by: null, - readonly: true, - selectable: false, - }); - } - } - if (!showDisabled) { entities = entities.filter((entity) => !Boolean(entity.disabled_by)); } const result: EntityRow[] = []; - for (const entry of entities.concat(stateEntities)) { - const state = states[entry.entity_id]; - const unavailable = state?.state === "unavailable"; + for (const entry of showReadOnly + ? entities.concat(stateEntities) + : entities) { + const entity = this.hass.states[entry.entity_id]; + const unavailable = entity?.state === "unavailable"; + const restored = entity?.attributes.restored; if (!showUnavailable && unavailable) { continue; @@ -218,14 +209,19 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { result.push({ ...entry, - icon: state - ? stateIcon(state) + icon: entity + ? stateIcon(entity) : domainIcon(computeDomain(entry.entity_id)), name: computeEntityRegistryName(this.hass!, entry) || this.hass.localize("state.default.unavailable"), unavailable, - status: unavailable + restored, + status: restored + ? this.hass.localize( + "ui.panel.config.entities.picker.status.restored" + ) + : unavailable ? this.hass.localize( "ui.panel.config.entities.picker.status.unavailable" ) @@ -389,7 +385,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { .columns=${this._columns(this.narrow, this.hass.language)} .data=${this._filteredEntities( this._entities, - this.hass.states, + this._stateEntities, this._showDisabled, this._showUnavailable, this._showReadOnly @@ -418,6 +414,43 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { loadEntityEditorDialog(); } + protected updated(changedProps): void { + super.updated(changedProps); + const oldHass = changedProps.get("hass"); + let changed = false; + if (!this.hass || !this._entities) { + return; + } + if (changedProps.has("hass") || changedProps.has("_entities")) { + const stateEntities: StateEntity[] = []; + const regEntityIds = new Set( + this._entities.map((entity) => entity.entity_id) + ); + for (const entityId of Object.keys(this.hass.states)) { + if (regEntityIds.has(entityId)) { + continue; + } + if ( + !oldHass || + this.hass.states[entityId] !== oldHass.states[entityId] + ) { + changed = true; + } + stateEntities.push({ + name: computeStateName(this.hass.states[entityId]), + entity_id: entityId, + platform: computeDomain(entityId), + disabled_by: null, + readonly: true, + selectable: false, + }); + } + if (changed) { + this._stateEntities = stateEntities; + } + } + } + private _showDisabledChanged() { this._showDisabled = !this._showDisabled; } @@ -499,13 +532,26 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { }); showConfirmationDialog(this, { title: this.hass.localize( - "ui.panel.config.entities.picker.remove_selected.confirm_title", + `ui.panel.config.entities.picker.remove_selected.confirm_${ + removeableEntities.length !== this._selectedEntities.length + ? "partly_" + : "" + }title`, "number", removeableEntities.length ), - text: this.hass.localize( - "ui.panel.config.entities.picker.remove_selected.confirm_text" - ), + text: + removeableEntities.length === this._selectedEntities.length + ? this.hass.localize( + "ui.panel.config.entities.picker.remove_selected.confirm_text" + ) + : this.hass.localize( + "ui.panel.config.entities.picker.remove_selected.confirm_partly_text", + "removable", + removeableEntities.length, + "selected", + this._selectedEntities.length + ), confirmText: this.hass.localize("ui.common.yes"), dismissText: this.hass.localize("ui.common.no"), confirm: () => { diff --git a/src/translations/en.json b/src/translations/en.json index a07b13243f..d2d2f5dbae 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1488,6 +1488,7 @@ "show_readonly": "Show read-only entities" }, "status": { + "restored": "Restored", "unavailable": "Unavailable", "disabled": "Disabled", "readonly": "Read-only", @@ -1513,7 +1514,9 @@ "remove_selected": { "button": "Remove selected", "confirm_title": "Do you want to remove {number} entities?", - "confirm_text": "Entities can only be removed when the integration is no longer providing the entities." + "confirm_partly_title": "Only {number} selected entities can be removed.", + "confirm_text": "You should remove them from your Lovelace config and automations if they contain these entities.", + "confirm_partly_text": "You can only remove {removable} of the selected {selected} entities. Entities can only be removed when the integration is no longer providing the entities. Sometimes you have to restart Home Assistant before you can remove the entities of a removed integration. Are you sure you want to remove the removable entities?" } } },