From 949f33380c6c0305d1876001451cf3b825bd6320 Mon Sep 17 00:00:00 2001
From: Andrey Sobolev <haiodo@users.noreply.github.com>
Date: Tue, 6 Aug 2024 17:37:26 +0700
Subject: [PATCH] UBERF-7817: Fix tag element query (#6267)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
---
 .../DocUpdateMessageContent.svelte            | 22 ++++++++++-----
 .../DocUpdateMessageObjectValue.svelte        | 27 ++++++++++---------
 .../DocUpdateMessagePresenter.svelte          | 14 +++++-----
 .../tags-resources/src/components/Tags.svelte |  9 +------
 .../src/components/TagsEditor.svelte          | 19 ++++++++++---
 5 files changed, 55 insertions(+), 36 deletions(-)

diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
index 8ec5e747e0..222306696f 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageContent.svelte
@@ -58,30 +58,40 @@
       {@const removeMessages = valueMessages.filter(({ action }) => action === 'remove')}
       {@const createMessages = valueMessages.filter(({ action }) => action === 'create')}
 
+      {@const createMessagesLen = createMessages.length}
+      {@const removeMessagesLen = removeMessages.length}
+
       {#each createMessages as valueMessage, index}
         <DocUpdateMessageObjectValue
-          message={valueMessage}
+          objectClass={valueMessage.objectClass}
+          objectId={valueMessage.objectId}
+          action={valueMessage.action}
           {viewlet}
           withIcon={index === 0}
-          hasSeparator={createMessages.length > 1 && index !== createMessages.length - 1}
+          hasSeparator={createMessagesLen > 1 && index !== createMessagesLen - 1}
           {preview}
         />
       {/each}
       {#each removeMessages as valueMessage, index}
         <DocUpdateMessageObjectValue
-          message={valueMessage}
+          objectClass={valueMessage.objectClass}
+          objectId={valueMessage.objectId}
+          action={valueMessage.action}
           {viewlet}
           withIcon={index === 0}
-          hasSeparator={removeMessages.length > 1 && index !== removeMessages.length - 1}
+          hasSeparator={removeMessagesLen > 1 && index !== removeMessagesLen - 1}
           {preview}
         />
       {/each}
     {:else}
+      {@const len = valueMessages.length}
       {#each valueMessages as valueMessage, index}
         <DocUpdateMessageObjectValue
-          message={valueMessage}
+          objectClass={valueMessage.objectClass}
+          objectId={valueMessage.objectId}
+          action={valueMessage.action}
           {viewlet}
-          hasSeparator={valueMessages.length > 1 && index !== valueMessages.length - 1}
+          hasSeparator={len > 1 && index !== len - 1}
           {preview}
         />
       {/each}
diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
index 346c23a44f..d2ce1ee29a 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessageObjectValue.svelte
@@ -13,14 +13,16 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import { buildRemovedDoc, checkIsObjectRemoved, DocNavLink, getDocLinkTitle } from '@hcengineering/view-resources'
-  import { Component, Icon, IconAdd, IconDelete } from '@hcengineering/ui'
-  import { createQuery, getClient } from '@hcengineering/presentation'
-  import view from '@hcengineering/view'
-  import { Class, Doc, Ref } from '@hcengineering/core'
   import { DisplayDocUpdateMessage, DocUpdateMessageViewlet } from '@hcengineering/activity'
+  import { Class, Doc, Ref } from '@hcengineering/core'
+  import { createQuery, getClient } from '@hcengineering/presentation'
+  import { Component, Icon, IconAdd, IconDelete } from '@hcengineering/ui'
+  import view from '@hcengineering/view'
+  import { buildRemovedDoc, checkIsObjectRemoved, DocNavLink, getDocLinkTitle } from '@hcengineering/view-resources'
 
-  export let message: DisplayDocUpdateMessage
+  export let objectClass: DisplayDocUpdateMessage['objectClass']
+  export let objectId: DisplayDocUpdateMessage['objectId']
+  export let action: DisplayDocUpdateMessage['action']
   export let viewlet: DocUpdateMessageViewlet | undefined
   export let withIcon: boolean = false
   export let hasSeparator: boolean = false
@@ -32,8 +34,8 @@
 
   let object: Doc | undefined = undefined
 
-  $: objectPanel = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPanel)
-  $: objectPresenter = hierarchy.classHierarchyMixin(message.objectClass, view.mixin.ObjectPresenter)
+  $: objectPanel = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPanel)
+  $: objectPresenter = hierarchy.classHierarchyMixin(objectClass, view.mixin.ObjectPresenter)
 
   async function getValue (object: Doc): Promise<string | undefined> {
     if (viewlet?.valueAttr) {
@@ -48,6 +50,7 @@
 
     if (isRemoved) {
       object = await buildRemovedDoc(client, _id, _class)
+      objectQuery.unsubscribe()
     } else {
       objectQuery.query(_class, { _id }, (res) => {
         object = res[0]
@@ -55,14 +58,14 @@
     }
   }
 
-  $: void loadObject(message.objectId, message.objectClass)
+  $: void loadObject(objectId, objectClass)
 </script>
 
 {#if object}
-  {#if withIcon && message.action === 'create'}
+  {#if withIcon && action === 'create'}
     <Icon icon={IconAdd} size="x-small" />
   {/if}
-  {#if withIcon && message.action === 'remove'}
+  {#if withIcon && action === 'remove'}
     <Icon icon={IconDelete} size="x-small" />
   {/if}
 
@@ -80,7 +83,7 @@
         <DocNavLink
           {object}
           colorInherit
-          disabled={message.action === 'remove'}
+          disabled={action === 'remove'}
           component={objectPanel?.component ?? view.component.EditDoc}
           shrink={0}
         >
diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
index 948ffef6a9..2c7e5b007c 100644
--- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
+++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte
@@ -26,7 +26,7 @@
   import { Account, AttachedDoc, Class, Collection, Doc, Ref, Space } from '@hcengineering/core'
   import { IntlString } from '@hcengineering/platform'
   import { createQuery, getClient } from '@hcengineering/presentation'
-  import { Component, ShowMore, Action } from '@hcengineering/ui'
+  import { Action, Component, ShowMore } from '@hcengineering/ui'
   import { AttributeModel } from '@hcengineering/view'
   import { buildRemovedDoc, checkIsObjectRemoved } from '@hcengineering/view-resources'
 
@@ -144,17 +144,17 @@
   }
 
   async function loadParentObject (
-    message: DocUpdateMessage,
-    parentMessage?: ActivityMessage,
+    message: Pick<DocUpdateMessage, 'attachedTo' | 'attachedToClass' | 'objectId' | 'space'>,
+    parentMessage?: Pick<ActivityMessage, 'attachedTo' | 'space' | 'attachedToClass'>,
     doc?: Doc
   ): Promise<void> {
-    if (!parentMessage && message.objectId === message.attachedTo) {
+    if (parentMessage === undefined && message.objectId === message.attachedTo) {
       return
     }
 
-    const _id = parentMessage ? parentMessage.attachedTo : message.attachedTo
-    const _class = parentMessage ? parentMessage.attachedToClass : message.attachedToClass
-    const space = parentMessage ? parentMessage.space : message.space
+    const _id = parentMessage !== undefined ? parentMessage.attachedTo : message.attachedTo
+    const _class = parentMessage !== undefined ? parentMessage.attachedToClass : message.attachedToClass
+    const space = parentMessage !== undefined ? parentMessage.space : message.space
 
     if (doc !== undefined && doc._id === _id) {
       parentObject = doc
diff --git a/plugins/tags-resources/src/components/Tags.svelte b/plugins/tags-resources/src/components/Tags.svelte
index b9ac7a793a..f33a451bf0 100644
--- a/plugins/tags-resources/src/components/Tags.svelte
+++ b/plugins/tags-resources/src/components/Tags.svelte
@@ -13,7 +13,7 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import { Class, Doc, IdMap, Ref, toIdMap } from '@hcengineering/core'
+  import { Class, Doc, Ref } from '@hcengineering/core'
   import { createQuery, getClient, KeyedAttribute } from '@hcengineering/presentation'
   import { TagElement, TagReference } from '@hcengineering/tags'
   import tags from '../plugin'
@@ -52,16 +52,9 @@
   async function updateWeight (tag: TagReference, weight: TagReference['weight']): Promise<void> {
     await client.update(tag, { weight })
   }
-
-  let elements: IdMap<TagElement> = new Map()
-  const elementQuery = createQuery()
-  $: elementQuery.query(tags.class.TagElement, {}, (result) => {
-    elements = toIdMap(result)
-  })
 </script>
 
 <TagsEditor
-  bind:elements
   {key}
   bind:items
   targetClass={_class}
diff --git a/plugins/tags-resources/src/components/TagsEditor.svelte b/plugins/tags-resources/src/components/TagsEditor.svelte
index 0c1161211e..bd57a8e919 100644
--- a/plugins/tags-resources/src/components/TagsEditor.svelte
+++ b/plugins/tags-resources/src/components/TagsEditor.svelte
@@ -13,9 +13,17 @@
 // limitations under the License.
 -->
 <script lang="ts">
-  import type { AttachedDoc, Class, Collection, Doc, Ref } from '@hcengineering/core'
+  import {
+    toIdMap,
+    type AttachedDoc,
+    type Class,
+    type Collection,
+    type Doc,
+    type IdMap,
+    type Ref
+  } from '@hcengineering/core'
   import { translate } from '@hcengineering/platform'
-  import { KeyedAttribute } from '@hcengineering/presentation'
+  import { createQuery, KeyedAttribute } from '@hcengineering/presentation'
   import { TagElement, TagReference } from '@hcengineering/tags'
   import {
     Button,
@@ -37,9 +45,14 @@
   export let targetClass: Ref<Class<Doc>>
   export let key: KeyedAttribute
   export let showTitle = true
-  export let elements: Map<Ref<TagElement>, TagElement>
   export let schema: '0' | '3' | '9' = key.attr.schema ?? '0'
 
+  let elements: IdMap<TagElement> = new Map()
+  const elementQuery = createQuery()
+  $: elementQuery.query(tags.class.TagElement, { _id: { $in: items.map((it) => it.tag) } }, (result) => {
+    elements = toIdMap(result)
+  })
+
   const dispatch = createEventDispatcher()
 
   let keyLabel: string = ''