From ab479a93a0472e6f85564d436cfe6b032fc50e8d Mon Sep 17 00:00:00 2001
From: Denis Bykhov <bykhov.denis@gmail.com>
Date: Fri, 21 Apr 2023 08:52:37 +0600
Subject: [PATCH] Remove status (#3031)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
---
 plugins/tracker-assets/lang/en.json           |   3 +-
 plugins/tracker-assets/lang/ru.json           |   3 +-
 .../components/workflow/RemoveStatus.svelte   | 130 ++++++++++++++++++
 .../workflow/StatusPresenter.svelte           |   2 +-
 .../src/components/workflow/Statuses.svelte   |  16 +--
 plugins/tracker-resources/src/plugin.ts       |   1 -
 6 files changed, 139 insertions(+), 16 deletions(-)
 create mode 100644 plugins/tracker-resources/src/components/workflow/RemoveStatus.svelte

diff --git a/plugins/tracker-assets/lang/en.json b/plugins/tracker-assets/lang/en.json
index e3d36b0fd2..07b3ae3bd5 100644
--- a/plugins/tracker-assets/lang/en.json
+++ b/plugins/tracker-assets/lang/en.json
@@ -188,8 +188,7 @@
     "EditWorkflowStatus": "Edit issue status",
     "DeleteWorkflowStatus": "Delete issue status",
     "DeleteWorkflowStatusConfirm": "Do you want to delete the \"{status}\" status?",
-    "DeleteWorkflowStatusError": "Can't delete the issue status",
-    "DeleteWorkflowStatusErrorDescription": "The \"{status}\" status has {count, plural, =1 {1 issue} other {# issues}} assigned. Please archive or move {count, plural, =1 {it} other {them}} before deleting this status.",
+    "DeleteWorkflowStatusErrorDescription": "The \"{status}\" status has {count, plural, =1 {1 issue} other {# issues}} assigned. Please select a status to move",
 
     "Save": "Save",
     "IncludeItemsThatMatch": "Include items that match",
diff --git a/plugins/tracker-assets/lang/ru.json b/plugins/tracker-assets/lang/ru.json
index a4ff6ed4a8..d6366ee1c2 100644
--- a/plugins/tracker-assets/lang/ru.json
+++ b/plugins/tracker-assets/lang/ru.json
@@ -188,8 +188,7 @@
     "EditWorkflowStatus": "Редактировать статус задачи",
     "DeleteWorkflowStatus": "Удалить статус задачи",
     "DeleteWorkflowStatusConfirm": "Вы действительно хотите удалить \"{status}\" статус?",
-    "DeleteWorkflowStatusError": "Невозможно удалить статус задачи",
-    "DeleteWorkflowStatusErrorDescription": "Статус \"{status}\" {count, plural, =1 {имеет 1 задача} other {имеют # задачи}}. Пожалуйста, архивируйте или переместите {count, plural, =1 {ее} other {их}} перед удалением этого статуса.",
+    "DeleteWorkflowStatusErrorDescription": "Статус \"{status}\" {count, plural, =1 {имеет 1 задача} other {имеют # задачи}}. Пожалуйста, выберите статус для перемещения.",
 
     "Save": "Сохранить",
     "IncludeItemsThatMatch": "Включить элементы, которые соответствуют",
diff --git a/plugins/tracker-resources/src/components/workflow/RemoveStatus.svelte b/plugins/tracker-resources/src/components/workflow/RemoveStatus.svelte
new file mode 100644
index 0000000000..827d69269f
--- /dev/null
+++ b/plugins/tracker-resources/src/components/workflow/RemoveStatus.svelte
@@ -0,0 +1,130 @@
+<script lang="ts">
+  import { Ref } from '@hcengineering/core'
+  import { Issue, IssueStatus, Project } from '@hcengineering/tracker'
+  import { Button, Label, SelectPopup, eventToHTMLElement, showPopup } from '@hcengineering/ui'
+  import presentation, { getClient, statusStore } from '@hcengineering/presentation'
+  import tracker from '../../plugin'
+  import { createEventDispatcher } from 'svelte'
+  import IssueStatusIcon from '../issues/IssueStatusIcon.svelte'
+  import { StatusPresenter } from '@hcengineering/view-resources'
+
+  export let projectId: Ref<Project>
+  export let issues: Issue[]
+  export let status: IssueStatus
+
+  let processing = false
+
+  const client = getClient()
+
+  let newStatus: IssueStatus =
+    $statusStore.statuses.find(
+      (s) => s._id !== status._id && s.category === status.category && s.space === projectId
+    ) ??
+    $statusStore.statuses.find((s) => s._id !== status._id && s.space === projectId) ??
+    status
+
+  async function remove () {
+    processing = true
+    await Promise.all(
+      issues.map(async (p) => {
+        await client.update(p, {
+          status: newStatus._id
+        })
+      })
+    )
+    await client.remove(status)
+    processing = false
+    dispatch('close')
+  }
+
+  $: statuses = $statusStore.filter((it) => it.space === projectId && it._id !== status._id)
+  $: statusesInfo = statuses?.map((s) => {
+    return {
+      id: s._id,
+      component: StatusPresenter,
+      props: { value: s, size: 'small' },
+      isSelected: newStatus._id === s._id ?? false
+    }
+  })
+
+  const dispatch = createEventDispatcher()
+
+  const handleStatusEditorOpened = (event: MouseEvent) => {
+    showPopup(
+      SelectPopup,
+      { value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
+      eventToHTMLElement(event),
+      (val) => (newStatus = $statusStore.byId.get(val) ?? newStatus)
+    )
+  }
+</script>
+
+<div class="msgbox-container">
+  <div class="overflow-label fs-title mb-4"><Label label={tracker.string.DeleteWorkflowStatus} /></div>
+  <div class="message">
+    <Label label={tracker.string.DeleteWorkflowStatusConfirm} params={{ status: status.name }} />
+    <Label
+      label={tracker.string.DeleteWorkflowStatusErrorDescription}
+      params={{ status: status.name, count: issues.length }}
+    />
+  </div>
+  <div class="mt-2 mb-2">
+    <Button kind={'link'} justify={'left'} width={'10rem'} on:click={handleStatusEditorOpened}>
+      <span slot="content" class="flex-row-center pointer-events-none">
+        {#if newStatus}
+          <IssueStatusIcon value={newStatus} size="inline" />
+        {/if}
+        {#if newStatus}
+          <span class="overflow-label disabled ml-1">
+            {newStatus.name}
+          </span>
+        {/if}
+      </span>
+    </Button>
+  </div>
+  <div class="footer">
+    <Button
+      focus
+      label={presentation.string.Ok}
+      size={'small'}
+      kind={'primary'}
+      loading={processing}
+      on:click={remove}
+    />
+    <Button
+      label={presentation.string.Cancel}
+      size={'small'}
+      on:click={() => {
+        dispatch('close', false)
+      }}
+    />
+  </div>
+</div>
+
+<style lang="scss">
+  .msgbox-container {
+    display: flex;
+    flex-direction: column;
+    padding: 2rem 1.75rem 1.75rem;
+    width: 30rem;
+    max-width: 40rem;
+    background: var(--popup-bg-color);
+    border-radius: 1.25rem;
+    user-select: none;
+    box-shadow: var(--popup-shadow);
+
+    .message {
+      margin-bottom: 1.75rem;
+      color: var(--accent-color);
+    }
+    .footer {
+      flex-shrink: 0;
+      display: grid;
+      grid-auto-flow: column;
+      direction: rtl;
+      justify-content: flex-start;
+      align-items: center;
+      column-gap: 0.5rem;
+    }
+  }
+</style>
diff --git a/plugins/tracker-resources/src/components/workflow/StatusPresenter.svelte b/plugins/tracker-resources/src/components/workflow/StatusPresenter.svelte
index 80871fca40..f590e6acfb 100644
--- a/plugins/tracker-resources/src/components/workflow/StatusPresenter.svelte
+++ b/plugins/tracker-resources/src/components/workflow/StatusPresenter.svelte
@@ -60,7 +60,7 @@
     >
       <Icon icon={IconEdit} size="small" />
     </div>
-    {#if !isSingle}
+    {#if !isDefault}
       <!-- svelte-ignore a11y-click-events-have-key-events -->
       <div
         class="btn"
diff --git a/plugins/tracker-resources/src/components/workflow/Statuses.svelte b/plugins/tracker-resources/src/components/workflow/Statuses.svelte
index 62340f7403..d8b87c87ab 100644
--- a/plugins/tracker-resources/src/components/workflow/Statuses.svelte
+++ b/plugins/tracker-resources/src/components/workflow/Statuses.svelte
@@ -34,6 +34,7 @@
   import tracker from '../../plugin'
   import StatusEditor from './StatusEditor.svelte'
   import StatusPresenter from './StatusPresenter.svelte'
+  import RemoveStatus from './RemoveStatus.svelte'
 
   export let projectId: Ref<Project>
   export let projectClass: Ref<Class<Project>>
@@ -128,18 +129,13 @@
     closeTooltip()
 
     const { detail: status } = event
-    const issuesWithDeletingStatus = await client.findAll(
-      tracker.class.Issue,
-      { status: status._id },
-      { projection: { _id: 1 } }
-    )
+    const issuesWithDeletingStatus = await client.findAll(tracker.class.Issue, { status: status._id })
 
     if (issuesWithDeletingStatus.length > 0) {
-      showPopup(MessageBox, {
-        label: tracker.string.DeleteWorkflowStatusError,
-        message: tracker.string.DeleteWorkflowStatusErrorDescription,
-        params: { status: status.name, count: issuesWithDeletingStatus.length },
-        canSubmit: false
+      showPopup(RemoveStatus, {
+        issues: issuesWithDeletingStatus,
+        projectId,
+        status
       })
     } else {
       showPopup(
diff --git a/plugins/tracker-resources/src/plugin.ts b/plugins/tracker-resources/src/plugin.ts
index b50b32cbf8..92bcba9840 100644
--- a/plugins/tracker-resources/src/plugin.ts
+++ b/plugins/tracker-resources/src/plugin.ts
@@ -106,7 +106,6 @@ export default mergeIds(trackerId, tracker, {
     EditWorkflowStatus: '' as IntlString,
     DeleteWorkflowStatus: '' as IntlString,
     DeleteWorkflowStatusConfirm: '' as IntlString,
-    DeleteWorkflowStatusError: '' as IntlString,
     DeleteWorkflowStatusErrorDescription: '' as IntlString,
     Name: '' as IntlString,
     StatusCategory: '' as IntlString,