From 68359b88a945650b52f50b0fca236a3ce1a68056 Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Tue, 2 May 2023 10:14:03 +0200 Subject: [PATCH] More performance improvements for the entities page. - Don't recalculate entity groups every time. Instead, keep them in sync every time an entity is added or removed. - Removed `computedChildren` from the entity component - no null nodes are guaranteed to be passed now, so there's no need for another iteration on the list of children. - `childrenByParentId` now only looks in the scope of the entity's children instead of searching all the entities. --- .../src/components/panels/Entities/Entity.vue | 39 +++---- .../src/components/panels/Entities/Index.vue | 109 +++++++++--------- 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/Entity.vue b/platypush/backend/http/webapp/src/components/panels/Entities/Entity.vue index b0a8323d8..b0d1220aa 100644 --- a/platypush/backend/http/webapp/src/components/panels/Entities/Entity.vue +++ b/platypush/backend/http/webapp/src/components/panels/Entities/Entity.vue @@ -8,7 +8,7 @@ :is="component" :value="value" :parent="parent" - :children="computedChildren" + :children="children" :loading="loading" ref="instance" :error="error || value?.reachable == false" @@ -25,7 +25,7 @@
-
+
child) - }, - hasChildren() { - return !!this.computedChildren.length + return !!Object.keys(this.children).length }, isCollapsed() { - if (!this.hasChildren) - return true - - return this.collapsed + return !this.hasChildren ? true : this.collapsed }, instance() { @@ -90,16 +83,16 @@ export default { }, childrenByParentId(parentId) { - return Object.values(this.allEntities || {}). - filter( - (entity) => entity - && entity.parent_id === parentId - && !entity.is_configuration - ). - reduce((obj, entity) => { + const parentEntity = this.allEntities?.[parentId] + if (!parentEntity) + return {} + + return (parentEntity.children_ids || []).reduce((obj, entityId) => { + const entity = this.allEntities[entityId] + if (entity && !entity.is_configuration) obj[entity.id] = entity - return obj - }, {}) + return obj + }, {}) }, onClick(event) { @@ -131,7 +124,7 @@ export default { if (!isChildUpdate) return - this.setJustUpdated() + this.notifyUpdate() }, toggleCollapsed() { @@ -141,7 +134,7 @@ export default { this.instance.collapsed = !this.instance.collapsed }, - setJustUpdated() { + notifyUpdate() { this.justUpdated = true const self = this; setTimeout(() => self.justUpdated = false, 1000) @@ -160,7 +153,7 @@ export default { if (this.valuesEqual(oldValue, newValue)) return false - this.setJustUpdated() + this.notifyUpdate() this.$emit('update', {value: newValue}) } ) diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue b/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue index a8025b6d1..d5303c337 100644 --- a/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue +++ b/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue @@ -55,8 +55,8 @@
+ v-for="entity in Object.values(group.entities).sort((a, b) => a.name.localeCompare(b.name))" + :key="entity.id"> { obj[meta.name_plural] = type @@ -152,21 +155,10 @@ export default { }, {}) }, - entityGroups() { - return { - 'id': Object.entries(this.groupEntities('id')).reduce((obj, [id, entities]) => { - obj[id] = entities[0] - return obj - }, {}), - 'category': this.groupEntities('category'), - 'plugin': this.groupEntities('plugin'), - } - }, - displayGroups() { return Object.entries(this.entityGroups[this.selector.grouping]). filter( - (entry) => entry[1].filter( + (entry) => Object.values(entry[1]).filter( (e) => !!this.selector.selectedEntities[e.id] && e.parent_id == null ).length > 0 @@ -175,7 +167,7 @@ export default { ([grouping, entities]) => { return { name: grouping, - entities: entities.filter( + entities: Object.values(entities).filter( (e) => e.id in this.selector.selectedEntities ), } @@ -186,19 +178,32 @@ export default { }, methods: { - groupEntities(attr) { - return Object.values(this.entities). - filter((entity) => entity.parent_id == null). - reduce((obj, entity) => { - const entities = obj[entity[attr]] || {} - entities[entity.id] = entity + addEntity(entity) { + if (entity.parent_id != null) + return // Only group entities that have no parent - obj[entity[attr]] = Object.values(entities).sort((a, b) => { - return a.name.localeCompare(b.name) - }) + this.entities[entity.id] = entity; + ['id', 'type', 'category', 'plugin'].forEach((attr) => { + if (entity[attr] == null) + return - return obj - }, {}) + if (!this.entityGroups[attr][entity[attr]]) + this.entityGroups[attr][entity[attr]] = {} + this.entityGroups[attr][entity[attr]][entity.id] = entity + }) + }, + + removeEntity(entity) { + if (entity.parent_id != null) + return // Only group entities that have no parent + + ['id', 'type', 'category', 'plugin'].forEach((attr) => { + if (this.entityGroups[attr][entity[attr]][entity.id]) + delete this.entityGroups[attr][entity[attr]][entity.id] + }) + + if (this.entities[entity.id]) + delete this.entities[entity.id] }, _shouldSkipLoading(entity) { @@ -236,6 +241,7 @@ export default { if (this.entityTimeouts[id]) clearTimeout(this.entityTimeouts[id]) + this.addEntity(entity) this.entityTimeouts[id] = setTimeout(() => { if (self.loadingEntities[id]) delete self.loadingEntities[id] @@ -266,6 +272,7 @@ export default { } obj[entity.id] = entity + this.addEntity(entity) return obj }, {}) @@ -275,30 +282,26 @@ export default { } }, - childrenByParentId(parentId) { - return Object.values(this.entities). - filter( - (entity) => entity - && entity.parent_id === parentId - && !entity.is_configuration - ). - reduce((obj, entity) => { - obj[entity.id] = entity - return obj - }, {}) + childrenByParentId(parentId, selectConfig) { + const entity = this.entities?.[parentId] + if (!entity?.children_ids?.length) + return {} + + return entity.children_ids.reduce((obj, id) => { + const child = this.entities[id] + if ( + child && ( + (!selectConfig && !child.is_configuration) || + (selectConfig && child.is_configuration) + ) + ) + obj[id] = this.entities[id] + return obj + }, {}) }, configValuesByParentId(parentId) { - return Object.values(this.entities). - filter( - (entity) => entity - && entity.parent_id === parentId - && entity.is_configuration - ). - reduce((obj, entity) => { - obj[entity.id] = entity - return obj - }, {}) + return this.childrenByParentId(parentId, true) }, clearEntityTimeouts(entityId) { @@ -343,7 +346,7 @@ export default { ...(event.entity?.meta || {}), } - this.entities[entityId] = entity + this.addEntity(entity) bus.publishEntity(entity) }, @@ -354,7 +357,7 @@ export default { if (entityId === this.modalEntityId) this.modalEntityId = null if (this.entities[entityId]) - delete this.entities[entityId] + this.removeEntity(this.entities[entityId]) }, onEntityModal(entityId) {