From ffb19b31a52197ba76ca00e52959c5e8db71289f Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 28 Nov 2023 08:28:13 +0100 Subject: [PATCH] Use subscribe for todo items (#18776) --- src/data/todo.ts | 14 ++- .../lovelace/cards/hui-todo-list-card.ts | 89 ++++++++----------- 2 files changed, 47 insertions(+), 56 deletions(-) diff --git a/src/data/todo.ts b/src/data/todo.ts index 209f5ecc7d..15a1397066 100644 --- a/src/data/todo.ts +++ b/src/data/todo.ts @@ -47,15 +47,25 @@ export interface TodoItems { export const fetchItems = async ( hass: HomeAssistant, - entityId: string + entity_id: string ): Promise => { const result = await hass.callWS({ type: "todo/item/list", - entity_id: entityId, + entity_id, }); return result.items; }; +export const subscribeItems = ( + hass: HomeAssistant, + entity_id: string, + callback: (item) => void +) => + hass.connection.subscribeMessage(callback, { + type: "todo/item/subscribe", + entity_id, + }); + export const updateItem = ( hass: HomeAssistant, entity_id: string, diff --git a/src/panels/lovelace/cards/hui-todo-list-card.ts b/src/panels/lovelace/cards/hui-todo-list-card.ts index 071872e877..83a8a8542a 100644 --- a/src/panels/lovelace/cards/hui-todo-list-card.ts +++ b/src/panels/lovelace/cards/hui-todo-list-card.ts @@ -24,36 +24,32 @@ import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_elemen import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-card"; import "../../../components/ha-checkbox"; +import "../../../components/ha-icon-button"; import "../../../components/ha-list-item"; import "../../../components/ha-select"; import "../../../components/ha-svg-icon"; -import "../../../components/ha-icon-button"; import "../../../components/ha-textfield"; import type { HaTextField } from "../../../components/ha-textfield"; +import { isUnavailableState } from "../../../data/entity"; import { TodoItem, TodoItemStatus, TodoListEntityFeature, createItem, deleteItems, - fetchItems, moveItem, + subscribeItems, updateItem, } from "../../../data/todo"; -import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import type { SortableInstance } from "../../../resources/sortable"; import { HomeAssistant } from "../../../types"; import { findEntities } from "../common/find-entities"; import { createEntityNotFoundWarning } from "../components/hui-warning"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { TodoListCardConfig } from "./types"; -import { isUnavailableState } from "../../../data/entity"; @customElement("hui-todo-list-card") -export class HuiTodoListCard - extends SubscribeMixin(LitElement) - implements LovelaceCard -{ +export class HuiTodoListCard extends LitElement implements LovelaceCard { public static async getConfigElement(): Promise { await import("../editor/config-elements/hui-todo-list-editor"); return document.createElement("hui-todo-list-card-editor"); @@ -87,10 +83,24 @@ export class HuiTodoListCard @state() private _reordering = false; + private _unsubItems?: Promise; + private _sortable?: SortableInstance; @query("#unchecked") private _uncheckedContainer?: HTMLElement; + connectedCallback(): void { + super.connectedCallback(); + if (this.hasUpdated) { + this._subscribeItems(); + } + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + this._unsubItems?.then((unsub) => unsub()); + } + public getCardSize(): number { return (this._config ? (this._config.title ? 2 : 0) : 0) + 3; } @@ -132,26 +142,13 @@ export class HuiTodoListCard if (!this._entityId) { this._entityId = this.getEntityId(); } - this._fetchData(); + this._subscribeItems(); } else if (changedProperties.has("_entityId") || !this._items) { this._items = undefined; - this._fetchData(); + this._subscribeItems(); } } - public hassSubscribe(): Promise[] { - return [ - this.hass!.connection.subscribeEvents(() => { - if ( - this._entityId && - this.hass!.entities[this._entityId]?.platform === "shopping_list" - ) { - this._fetchData(); - } - }, "shopping_list_updated"), - ]; - } - protected updated(changedProps: PropertyValues): void { super.updated(changedProps); if (!this._config || !this.hass) { @@ -169,15 +166,6 @@ export class HuiTodoListCard ) { applyThemesOnElement(this, this.hass.themes, this._config.theme); } - - if ( - this._entityId && - oldHass && - oldHass.states[this._entityId] !== this.hass.states[this._entityId] && - this.hass.entities[this._entityId]?.platform !== "shopping_list" - ) { - this._fetchData(); - } } protected render() { @@ -392,14 +380,20 @@ export class HuiTodoListCard return entityStateObj && supportsFeature(entityStateObj, feature); } - private async _fetchData(): Promise { + private async _subscribeItems(): Promise { + if (this._unsubItems) { + this._unsubItems.then((unsub) => unsub()); + this._unsubItems = undefined; + } if (!this.hass || !this._entityId) { return; } if (!(this._entityId in this.hass.states)) { return; } - this._items = await fetchItems(this.hass!, this._entityId!); + this._unsubItems = subscribeItems(this.hass!, this._entityId, (update) => { + this._items = update.items; + }); } private _getItem(itemId: string) { @@ -416,7 +410,7 @@ export class HuiTodoListCard status: ev.target.checked ? TodoItemStatus.Completed : TodoItemStatus.NeedsAction, - }).finally(() => this._fetchData()); + }); } private _saveEdit(ev): void { @@ -429,13 +423,11 @@ export class HuiTodoListCard updateItem(this.hass!, this._entityId!, { ...item, summary: ev.target.value, - }).finally(() => this._fetchData()); + }); } else if ( this.todoListSupportsFeature(TodoListEntityFeature.DELETE_TODO_ITEM) ) { - deleteItems(this.hass!, this._entityId!, [ev.target.itemId]).finally(() => - this._fetchData() - ); + deleteItems(this.hass!, this._entityId!, [ev.target.itemId]); } ev.target.blur(); @@ -447,9 +439,7 @@ export class HuiTodoListCard } const checkedItems = this._getCheckedItems(this._items); const uids = checkedItems.map((item: TodoItem) => item.uid); - deleteItems(this.hass!, this._entityId!, uids).finally(() => - this._fetchData() - ); + deleteItems(this.hass!, this._entityId!, uids); } private get _newItem(): HaTextField { @@ -459,9 +449,7 @@ export class HuiTodoListCard private _addItem(ev): void { const newItem = this._newItem; if (newItem.value!.length > 0) { - createItem(this.hass!, this._entityId!, newItem.value!).finally(() => - this._fetchData() - ); + createItem(this.hass!, this._entityId!, newItem.value!); } newItem.value = ""; @@ -475,9 +463,7 @@ export class HuiTodoListCard if (!item) { return; } - deleteItems(this.hass!, this._entityId!, [item.uid]).finally(() => - this._fetchData() - ); + deleteItems(this.hass!, this._entityId!, [item.uid]); } private _addKeyPress(ev): void { @@ -552,12 +538,7 @@ export class HuiTodoListCard } this._items = [...this._items!]; - await moveItem( - this.hass!, - this._entityId!, - item.uid, - prevItem?.uid - ).finally(() => this._fetchData()); + await moveItem(this.hass!, this._entityId!, item.uid, prevItem?.uid); } static get styles(): CSSResultGroup {