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>