From 2e5982f2fe1b6d6dd13a2c8f570bc02ca88029fd Mon Sep 17 00:00:00 2001
From: Alex <41288429+Dvinyanin@users.noreply.github.com>
Date: Wed, 20 Apr 2022 13:07:22 +0700
Subject: [PATCH] Add AttachmentPresenter (#1452)

Signed-off-by: Dvinyanin Alexandr <dvinyanin.alexandr@gmail.com>
---
 plugins/board-assets/lang/en.json             |  6 +-
 plugins/board-assets/lang/ru.json             |  6 +-
 .../components/popups/EditAttachment.svelte   | 44 +++++++++++
 .../components/popups/RemoveAttachment.svelte | 40 ++++++++++
 .../presenters/AttachmentPresenter.svelte     | 73 +++++++++++++++++--
 plugins/board-resources/src/plugin.ts         |  6 +-
 6 files changed, 167 insertions(+), 8 deletions(-)
 create mode 100644 plugins/board-resources/src/components/popups/EditAttachment.svelte
 create mode 100644 plugins/board-resources/src/components/popups/RemoveAttachment.svelte

diff --git a/plugins/board-assets/lang/en.json b/plugins/board-assets/lang/en.json
index c6a96e5882..32595d4a1f 100644
--- a/plugins/board-assets/lang/en.json
+++ b/plugins/board-assets/lang/en.json
@@ -78,6 +78,10 @@
     "Remove": "Remove",
     "NullDate": "M/D/YYYY",
     "ViewProfile": "View profile",
-    "RemoveFromCard": "Remove from card"
+    "RemoveFromCard": "Remove from card",
+    "LinkName": "Link name",
+    "Edit": "Edit",
+    "Update": "Update",
+    "DeleteAttachment": "Deleting an attachment is permanent. There is no undo."
   }
 }
diff --git a/plugins/board-assets/lang/ru.json b/plugins/board-assets/lang/ru.json
index ed11b294c4..71df39afa8 100644
--- a/plugins/board-assets/lang/ru.json
+++ b/plugins/board-assets/lang/ru.json
@@ -78,6 +78,10 @@
     "Remove": "Удалить",
     "NullDate": "М/Д/ГГГГ",
     "ViewProfile": "Перейти в профиль",
-    "RemoveFromCard": "Удалить из карточки"
+    "RemoveFromCard": "Удалить из карточки",
+    "LinkName": "Имя ссылки",
+    "Edit": "Изменить",
+    "Update": "Обновить",
+    "DeleteAttachment": "Удаление вложения необратимо. Отмена невозможна."
   }
 }
diff --git a/plugins/board-resources/src/components/popups/EditAttachment.svelte b/plugins/board-resources/src/components/popups/EditAttachment.svelte
new file mode 100644
index 0000000000..0939d732a2
--- /dev/null
+++ b/plugins/board-resources/src/components/popups/EditAttachment.svelte
@@ -0,0 +1,44 @@
+<script lang="ts">
+  import { createEventDispatcher } from 'svelte'
+  import { Label, Button, ActionIcon, IconClose, EditBox } from '@anticrm/ui'
+  import board from '../../plugin'
+  import { getClient } from '@anticrm/presentation';
+  import { Attachment } from '@anticrm/attachment';
+
+  export let object: Attachment
+
+  let {name} = object
+
+  const client = getClient()
+  const dispatch = createEventDispatcher()
+</script>
+
+<div class="antiPopup antiPopup-withHeader antiPopup-withCategory w-85">
+  <div class="ap-space"/>
+  <div class="flex-row-center header">
+    <div class="flex-center flex-grow">
+      <Label label={board.string.Edit}/>
+    </div>
+    <div class="close-icon">
+      <ActionIcon icon={IconClose} size={'small'} action={() => {dispatch("close")}} />
+    </div>
+  </div>
+  <div class="ap-space bottom-divider"/>
+  <div class="ap-category">
+    <div class="ap-categoryItem">
+      <EditBox bind:value={name} maxWidth="18rem" label={board.string.LinkName} placeholder={board.string.LinkName}/>
+    </div>
+  </div>
+  <div class="ap-footer">
+    <Button
+      size={'small'}
+      label={board.string.Update}
+      kind={'primary'}
+      on:click={() => {
+        if (!name) return
+        client.update(object, {name})
+        dispatch('close')
+      }}
+    />
+  </div>
+</div>
diff --git a/plugins/board-resources/src/components/popups/RemoveAttachment.svelte b/plugins/board-resources/src/components/popups/RemoveAttachment.svelte
new file mode 100644
index 0000000000..09925615fa
--- /dev/null
+++ b/plugins/board-resources/src/components/popups/RemoveAttachment.svelte
@@ -0,0 +1,40 @@
+<script lang="ts">
+  import { createEventDispatcher } from 'svelte'
+  import { Label, Button, ActionIcon, IconClose } from '@anticrm/ui'
+  import board from '../../plugin'
+  import { getClient } from '@anticrm/presentation';
+  import { Attachment } from '@anticrm/attachment';
+
+  export let object: Attachment
+
+  const client = getClient()
+  const dispatch = createEventDispatcher()
+</script>
+
+<div class="antiPopup antiPopup-withHeader antiPopup-withTitle antiPopup-withCategory w-85">
+  <div class="ap-space"/>
+  <div class="flex-row-center header">
+    <div class="flex-center flex-grow">
+      <Label label={board.string.Delete} />
+    </div>
+    <div class="close-icon">
+      <ActionIcon icon={IconClose} size={'small'} action={() => {dispatch("close")}} />
+    </div>
+  </div>
+  <div class="ap-space bottom-divider"/>
+  <div class="ap-box ml-4 mr-4 mt-4">
+    <Label label={board.string.DeleteAttachment}/>
+  </div>
+  <div class="ap-footer">
+    <Button
+      size={'small'}
+      width="100%"
+      label={board.string.Delete}
+      kind={'dangerous'}
+      on:click={() => {
+        client.remove(object)
+        dispatch('close')
+      }}
+    />
+  </div>
+</div>
diff --git a/plugins/board-resources/src/components/presenters/AttachmentPresenter.svelte b/plugins/board-resources/src/components/presenters/AttachmentPresenter.svelte
index 943d4d1301..5ab83e2098 100644
--- a/plugins/board-resources/src/components/presenters/AttachmentPresenter.svelte
+++ b/plugins/board-resources/src/components/presenters/AttachmentPresenter.svelte
@@ -12,14 +12,77 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 -->
+
 <script lang="ts">
-  import { Attachment } from '@anticrm/attachment'
-  import { AttachmentPresenter } from '@anticrm/attachment-resources'
+  import type { Attachment } from '@anticrm/attachment'
+  import { PDFViewer, getFileUrl } from '@anticrm/presentation'
+  import { Button, showPopup, TimeSince, closeTooltip } from '@anticrm/ui'
+  import board from '../../plugin'
+  import EditAttachment from '../popups/EditAttachment.svelte';
+  import RemoveAttachment from '../popups/RemoveAttachment.svelte';
 
   export let value: Attachment
-  // TODO: implement
+
+  const maxLenght: number = 30
+  const trimFilename = (fname: string): string => (fname.length > maxLenght)
+    ? fname.substr(0, (maxLenght - 1) / 2) + '...' + fname.substr(-(maxLenght - 1) / 2)
+    : fname
+
+  function iconLabel (name: string): string {
+    const parts = name.split('.')
+    const ext = parts[parts.length - 1]
+    return ext.substring(0, 4).toUpperCase()
+  }
+
+  function openEmbedded (contentType: string) {
+    return contentType.includes('application/pdf') || contentType.startsWith('image/')
+  }
+
+  const handleClick = openEmbedded(value.type)
+  ? () => {
+    closeTooltip();
+    showPopup(PDFViewer, { file: value.file, name: value.name, contentType: value.type }, 'right')
+  } : undefined
 </script>
 
-<div>
-  <AttachmentPresenter {value} />
+<div class="flex-row-center">
+  {#if openEmbedded(value.type)}
+    <div class="flex-center content mr-2 cursor-pointer" on:click={handleClick}>
+      <img src={getFileUrl(value.file)} alt={value.name} />
+    </div>
+  {:else}
+    <a class="no-line" href={getFileUrl(value.file)} download={value.name}><div class="flex-center icon">{iconLabel(value.name)}</div></a>
+  {/if}
+  <div class="flex-col-centre info">
+    <div class="fs-title">{trimFilename(value.name)}</div>
+    <div class="flex-row-center">
+      <TimeSince value={value.lastModified}/>
+      <Button label={board.string.Edit} on:click={() => {showPopup(EditAttachment, {object: value})}} kind="transparent"/>
+      <Button label={board.string.Delete} on:click={() => {showPopup(RemoveAttachment, {object: value})}} kind="transparent"/>
+    </div>
+  </div>
 </div>
+
+<style lang="scss">
+  .icon {
+    flex-shrink: 0;
+    margin-right: 1rem;
+    width: 8rem;
+    height: 6rem;
+    font-weight: 500;
+    font-size: 1rem;
+    color: var(--primary-button-color);
+    background-color: var(--primary-button-enabled);
+    border: 1px solid rgba(0, 0, 0, .1);
+    border-radius: .5rem;
+  }
+  .content {
+    width: 8rem;
+    max-height: 6rem;
+
+    img {
+      max-width: 8rem;
+      max-height: 6rem;
+    }
+  }
+</style>
diff --git a/plugins/board-resources/src/plugin.ts b/plugins/board-resources/src/plugin.ts
index 38ab9fc2b2..45a959edf3 100644
--- a/plugins/board-resources/src/plugin.ts
+++ b/plugins/board-resources/src/plugin.ts
@@ -99,7 +99,11 @@ export default mergeIds(boardId, board, {
     Remove: '' as IntlString,
     NullDate: '' as IntlString,
     ViewProfile: '' as IntlString,
-    RemoveFromCard: '' as IntlString
+    RemoveFromCard: '' as IntlString,
+    LinkName: '' as IntlString,
+    Edit: '' as IntlString,
+    Update: '' as IntlString,
+    DeleteAttachment: '' as IntlString
   },
   component: {
     Boards: '' as AnyComponent,