From 85c285741adc180c525524f01bb9b9383bbc520c Mon Sep 17 00:00:00 2001
From: Alexander Onnikov <Alexander.Onnikov@xored.com>
Date: Wed, 18 Sep 2024 17:49:17 +0700
Subject: [PATCH] UBERF-8164 Display activity in wiki document sidebar (#6620)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
---
 .../src/components/ActivityFilter.svelte      | 49 +++++-----
 plugins/activity-resources/src/index.ts       |  1 +
 .../src/components/EditDoc.svelte             | 14 ++-
 .../src/components/sidebar/Activity.svelte    | 97 +++++++++++++++++++
 4 files changed, 133 insertions(+), 28 deletions(-)
 create mode 100644 plugins/document-resources/src/components/sidebar/Activity.svelte

diff --git a/plugins/activity-resources/src/components/ActivityFilter.svelte b/plugins/activity-resources/src/components/ActivityFilter.svelte
index 725dc27249..acc77ac91a 100644
--- a/plugins/activity-resources/src/components/ActivityFilter.svelte
+++ b/plugins/activity-resources/src/components/ActivityFilter.svelte
@@ -29,6 +29,7 @@
   export let messages: ActivityMessage[]
   export let object: Doc
   export let isNewestFirst = false
+  export let showFilter = true
 
   const allId = activity.ids.AllFilter
   const client = getClient()
@@ -117,30 +118,32 @@
   )
 </script>
 
-<div class="w-4 min-w-4 max-w-4" />
-{#if selectedFiltersRefs === 'All'}
-  <div class="antiSection-header__tag highlight">
-    <Label label={activity.string.All} />
-  </div>
-{:else}
-  {#each selectedFilters as filter}
-    <div class="antiSection-header__tag overflow-label">
-      <Label label={filter.label} />
-      <!-- svelte-ignore a11y-click-events-have-key-events -->
-      <!-- svelte-ignore a11y-no-static-element-interactions -->
-      <div
-        class="tag-icon"
-        on:click={() => {
-          if (selectedFiltersRefs !== allId && Array.isArray(selectedFiltersRefs)) {
-            const ids = selectedFiltersRefs.filter((it) => it !== filter._id)
-            selectedFiltersRefs = ids.length > 0 ? ids : allId
-          }
-        }}
-      >
-        <Icon icon={IconClose} size={'small'} />
-      </div>
+{#if showFilter}
+  <div class="w-4 min-w-4 max-w-4" />
+  {#if selectedFiltersRefs === allId}
+    <div class="antiSection-header__tag highlight">
+      <Label label={activity.string.All} />
     </div>
-  {/each}
+  {:else}
+    {#each selectedFilters as filter}
+      <div class="antiSection-header__tag overflow-label">
+        <Label label={filter.label} />
+        <!-- svelte-ignore a11y-click-events-have-key-events -->
+        <!-- svelte-ignore a11y-no-static-element-interactions -->
+        <div
+          class="tag-icon"
+          on:click={() => {
+            if (selectedFiltersRefs !== allId && Array.isArray(selectedFiltersRefs)) {
+              const ids = selectedFiltersRefs.filter((it) => it !== filter._id)
+              selectedFiltersRefs = ids.length > 0 ? ids : allId
+            }
+          }}
+        >
+          <Icon icon={IconClose} size={'small'} />
+        </div>
+      </div>
+    {/each}
+  {/if}
 {/if}
 <div class="w-4 min-w-4 max-w-4" />
 <ActionIcon icon={IconFilter} size={'medium'} action={handleOptions} />
diff --git a/plugins/activity-resources/src/index.ts b/plugins/activity-resources/src/index.ts
index c250756771..31885dc2ca 100644
--- a/plugins/activity-resources/src/index.ts
+++ b/plugins/activity-resources/src/index.ts
@@ -52,6 +52,7 @@ export { default as ActivityMessagePresenter } from './components/activity-messa
 export { default as ActivityExtension } from './components/ActivityExtension.svelte'
 export { default as ActivityDocLink } from './components/ActivityDocLink.svelte'
 export { default as ReactionPresenter } from './components/reactions/ReactionPresenter.svelte'
+export { default as ActivityFilter } from './components/ActivityFilter.svelte'
 export { default as ActivityMessageNotificationLabel } from './components/activity-message/ActivityMessageNotificationLabel.svelte'
 export { default as ActivityMessageHeader } from './components/activity-message/ActivityMessageHeader.svelte'
 export { default as ActivityMessageAction } from './components/ActivityMessageAction.svelte'
diff --git a/plugins/document-resources/src/components/EditDoc.svelte b/plugins/document-resources/src/components/EditDoc.svelte
index 69ae0146e1..5c42e468a2 100644
--- a/plugins/document-resources/src/components/EditDoc.svelte
+++ b/plugins/document-resources/src/components/EditDoc.svelte
@@ -15,6 +15,7 @@
 //
 -->
 <script lang="ts">
+  import activity from '@hcengineering/activity'
   import attachment, { Attachment } from '@hcengineering/attachment'
   import core, { Doc, Ref, WithLookup, generateId, type Blob } from '@hcengineering/core'
   import { Document, DocumentEvents } from '@hcengineering/document'
@@ -58,8 +59,9 @@
   import DocumentEditor from './DocumentEditor.svelte'
   import DocumentPresenter from './DocumentPresenter.svelte'
   import DocumentTitle from './DocumentTitle.svelte'
-  import References from './sidebar/References.svelte'
+  import Activity from './sidebar/Activity.svelte'
   import History from './sidebar/History.svelte'
+  import References from './sidebar/References.svelte'
 
   export let _id: Ref<Document>
   export let readonly: boolean = false
@@ -185,11 +187,11 @@
     {
       id: 'references',
       icon: document.icon.References
+    },
+    {
+      id: 'activity',
+      icon: activity.icon.Activity
     }
-    // {
-    //   id: 'history',
-    //   icon: document.icon.History
-    // }
   ]
   let selectedAside: string | boolean = false
 
@@ -372,6 +374,8 @@
     <svelte:fragment slot="aside">
       {#if selectedAside === 'references'}
         <References doc={doc._id} />
+      {:else if selectedAside === 'activity'}
+        <Activity value={doc} />
       {:else if selectedAside === 'history'}
         <History value={doc} {readonly} />
       {/if}
diff --git a/plugins/document-resources/src/components/sidebar/Activity.svelte b/plugins/document-resources/src/components/sidebar/Activity.svelte
new file mode 100644
index 0000000000..2a55727b35
--- /dev/null
+++ b/plugins/document-resources/src/components/sidebar/Activity.svelte
@@ -0,0 +1,97 @@
+<!--
+//
+// Copyright © 2024 Hardcore Engineering Inc.
+//
+// Licensed under the Eclipse Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License. You may
+// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+-->
+<script lang="ts">
+  import activity, { ActivityMessage } from '@hcengineering/activity'
+  import { ActivityFilter, ActivityMessagePresenter, canGroupMessages } from '@hcengineering/activity-resources'
+  import { SortingOrder } from '@hcengineering/core'
+  import { Document } from '@hcengineering/document'
+  import { createQuery } from '@hcengineering/presentation'
+  import { Label, Lazy, Scroller } from '@hcengineering/ui'
+
+  export let value: Document
+
+  const query = createQuery()
+
+  let messages: ActivityMessage[] = []
+  let filteredMessages: ActivityMessage[] = []
+
+  $: query.query(
+    activity.class.ActivityMessage,
+    { attachedTo: value._id, space: value.space },
+    (res) => {
+      messages = res
+    },
+    {
+      sort: {
+        createdOn: SortingOrder.Ascending
+      }
+    }
+  )
+</script>
+
+{#key value._id}
+  <div class="h-full flex-col clear-mins">
+    <div class="header">
+      <div class="title"><Label label={activity.string.Activity} /></div>
+      <ActivityFilter
+        {messages}
+        object={value}
+        showFilter={false}
+        on:update={(e) => {
+          filteredMessages = e.detail
+        }}
+      />
+    </div>
+
+    <div class="divider" />
+
+    {#if filteredMessages.length > 0}
+      <Scroller padding="0.75rem 0.25rem">
+        {#each filteredMessages as message, index}
+          {@const canGroup = canGroupMessages(message, filteredMessages[index - 1])}
+          <Lazy>
+            <ActivityMessagePresenter
+              value={message}
+              doc={value}
+              hideLink={true}
+              type={canGroup ? 'short' : 'default'}
+            />
+          </Lazy>
+        {/each}
+      </Scroller>
+    {/if}
+  </div>
+{/key}
+
+<style lang="scss">
+  .header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 0 1.25rem;
+    height: 3rem;
+    min-height: 3rem;
+    border-bottom: 1px solid var(--theme-divider-color);
+
+    .title {
+      flex-grow: 1;
+      font-weight: 500;
+      color: var(--caption-color);
+      user-select: none;
+    }
+  }
+</style>