forked from platypush/platypush
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.
This commit is contained in:
parent
0fc0a22cd7
commit
68359b88a9
2 changed files with 72 additions and 76 deletions
|
@ -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 @@
|
|||
</div>
|
||||
|
||||
<div class="children fade-in" v-if="hasChildren && !isCollapsed">
|
||||
<div class="child" v-for="entity in computedChildren" :key="entity.id">
|
||||
<div class="child" v-for="entity in children" :key="entity.id">
|
||||
<Entity
|
||||
:value="entity"
|
||||
:parent="value"
|
||||
|
@ -57,19 +57,12 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
computedChildren() {
|
||||
return Object.values(this.children || {}).filter((child) => 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})
|
||||
}
|
||||
)
|
||||
|
|
|
@ -55,8 +55,8 @@
|
|||
|
||||
<div class="body">
|
||||
<div class="entity-frame"
|
||||
v-for="entity in group.entities"
|
||||
:key="entity.id">
|
||||
v-for="entity in Object.values(group.entities).sort((a, b) => a.name.localeCompare(b.name))"
|
||||
:key="entity.id">
|
||||
<Entity
|
||||
:value="entity"
|
||||
:children="childrenByParentId(entity.id)"
|
||||
|
@ -64,6 +64,7 @@
|
|||
@show-modal="onEntityModal($event)"
|
||||
@input="onEntityInput(entity)"
|
||||
:error="!!errorEntities[entity.id]"
|
||||
:key="entity.id"
|
||||
:loading="!!loadingEntities[entity.id]"
|
||||
@loading="loadingEntities[entity.id] = $event"
|
||||
v-if="!entity.parent_id"
|
||||
|
@ -122,6 +123,12 @@ export default {
|
|||
errorEntities: {},
|
||||
entityTimeouts: {},
|
||||
entities: {},
|
||||
entityGroups: {
|
||||
id: {},
|
||||
category: {},
|
||||
plugin: {},
|
||||
type: {},
|
||||
},
|
||||
modalEntityId: null,
|
||||
modalVisible: false,
|
||||
variableModalVisible: false,
|
||||
|
@ -141,10 +148,6 @@ export default {
|
|||
return icons
|
||||
},
|
||||
|
||||
entityTypes() {
|
||||
return this.groupEntities('type')
|
||||
},
|
||||
|
||||
typesByCategory() {
|
||||
return Object.entries(meta).reduce((obj, [type, meta]) => {
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue