From ff3b12f2824883f53a23ff36bbfefde1a2f1fdb2 Mon Sep 17 00:00:00 2001
From: Sergey Semenov <lvfx@ya.ru>
Date: Tue, 26 Apr 2022 14:30:46 +0700
Subject: [PATCH] Board: Handle labels when move card to another board (#1538)

Signed-off-by: Sergey Semenov <lvfx@ya.ru>
---
 .../src/components/popups/CopyCard.svelte     |  8 +++-
 .../src/components/popups/MoveCard.svelte     | 10 ++++-
 .../board-resources/src/utils/BoardUtils.ts   | 44 +++++++++++++++++--
 3 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/plugins/board-resources/src/components/popups/CopyCard.svelte b/plugins/board-resources/src/components/popups/CopyCard.svelte
index 31513707dc..d76e3aa74f 100644
--- a/plugins/board-resources/src/components/popups/CopyCard.svelte
+++ b/plugins/board-resources/src/components/popups/CopyCard.svelte
@@ -12,6 +12,7 @@
   import type { TxOperations } from '@anticrm/core'
   import { generateId, AttachedData } from '@anticrm/core'
   import task from '@anticrm/task'
+  import { createMissingLabels } from '../../utils/BoardUtils';
 
   export let object: Card
   export let client: TxOperations
@@ -38,6 +39,10 @@
 
     const incResult = await client.update(sequence, { $inc: { sequence: 1 } }, true)
 
+    const labels = object.space !== selected.space
+      ? await createMissingLabels(client, object, selected.space)
+      : object.labels
+
     const value: AttachedData<Card> = {
       state: selected.state,
       doneState: null,
@@ -47,7 +52,8 @@
       assignee: null,
       description: '',
       members: [],
-      location: ''
+      location: '',
+      labels
     }
 
     await client.addCollection(
diff --git a/plugins/board-resources/src/components/popups/MoveCard.svelte b/plugins/board-resources/src/components/popups/MoveCard.svelte
index b4c1159124..738e823fd0 100644
--- a/plugins/board-resources/src/components/popups/MoveCard.svelte
+++ b/plugins/board-resources/src/components/popups/MoveCard.svelte
@@ -10,6 +10,7 @@
   import SpaceSelect from '../selectors/SpaceSelect.svelte'
   import StateSelect from '../selectors/StateSelect.svelte'
   import RankSelect from '../selectors/RankSelect.svelte'
+  import { createMissingLabels } from '../../utils/BoardUtils'
 
   export let object: Card
 
@@ -23,9 +24,14 @@
     rank: object.rank
   }
 
-  function move () {
+  async function move(): Promise<void> {
     const update: DocumentUpdate<Card> = {}
-    if (selected.space !== object.space) update.space = selected.space
+
+    if (selected.space !== object.space) {
+      update.labels = await createMissingLabels(client, object, selected.space)
+      update.space = selected.space
+    }
+
     if (selected.state !== object.state) update.state = selected.state
     if (selected.rank !== object.rank) update.rank = selected.rank
     client.update(object, update)
diff --git a/plugins/board-resources/src/utils/BoardUtils.ts b/plugins/board-resources/src/utils/BoardUtils.ts
index 39372d666a..146bcb2b87 100644
--- a/plugins/board-resources/src/utils/BoardUtils.ts
+++ b/plugins/board-resources/src/utils/BoardUtils.ts
@@ -1,5 +1,5 @@
-import board, { Board, CardLabel } from '@anticrm/board'
-import core, { Ref, TxOperations } from '@anticrm/core'
+import board, { Board, CardLabel, Card } from '@anticrm/board'
+import core, { Ref, TxOperations, Space } from '@anticrm/core'
 import type { KanbanTemplate } from '@anticrm/task'
 import { createKanban } from '@anticrm/task'
 import {
@@ -16,7 +16,7 @@ import {
   SeagullColor
 } from '@anticrm/ui'
 
-export async function createBoard (
+export async function createBoard(
   client: TxOperations,
   name: string,
   description: string,
@@ -79,3 +79,41 @@ export async function createCardLabel (
     isHidden: isHidden ?? false
   })
 }
+
+const isEqualLabel = (l1: CardLabel, l2: CardLabel): boolean =>
+  l1.title === l2.title && l1.color === l2.color && (l1.isHidden ?? false) === (l2.isHidden ?? false)
+
+export async function createMissingLabels (
+  client: TxOperations,
+  object: Card,
+  targetBoard: Ref<Space>
+): Promise<Array<Ref<CardLabel>> | undefined> {
+  const sourceBoardLabels = await getBoardLabels(client, object.space)
+  const targetBoardLabels = await getBoardLabels(client, targetBoard)
+
+  const missingLabels = sourceBoardLabels.filter((srcLabel) => {
+    if (object.labels?.includes(srcLabel._id) === false) return false
+
+    return targetBoardLabels.findIndex((targetLabel) => isEqualLabel(targetLabel, srcLabel)) === -1
+  })
+
+  await Promise.all(missingLabels.map((l) => createCardLabel(client, targetBoard, l.color, l.title, l.isHidden)))
+
+  const updatedTargetBoardLabels = await getBoardLabels(client, targetBoard)
+
+  const labelsUpdate = object.labels
+    ?.map((srcLabelId) => {
+      const srcLabel = sourceBoardLabels.find((l) => l._id === srcLabelId)
+
+      if (srcLabel === undefined) return null
+
+      const targetLabel = updatedTargetBoardLabels.find((l) => isEqualLabel(l, srcLabel))
+
+      if (targetLabel === undefined) return null
+
+      return targetLabel._id
+    })
+    .filter((l) => l !== null) as Array<Ref<CardLabel>> | undefined
+
+  return labelsUpdate
+}