Add the ability to archive all activity fom chat (#4922)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-03-11 19:05:15 +04:00 committed by GitHub
parent 65e046905a
commit 809dedd2ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 108 additions and 13 deletions

View File

@ -95,6 +95,9 @@
"NewDirectChat": "New direct chat", "NewDirectChat": "New direct chat",
"AddMembers": "Add members", "AddMembers": "Add members",
"PinnedCount": "{count} pinned", "PinnedCount": "{count} pinned",
"LoadingHistory": "Loading history..." "LoadingHistory": "Loading history...",
"UnpinChannels": "Unpin all channels",
"ArchiveActivityConfirmationTitle": "Archive all activity channels?",
"ArchiveActivityConfirmationMessage": "Are you sure you want to archive all activity channels? This operation cannot be undone."
} }
} }

View File

@ -95,6 +95,9 @@
"NewDirectChat": "Новый личный чат", "NewDirectChat": "Новый личный чат",
"AddMembers": "Добавить участников", "AddMembers": "Добавить участников",
"PinnedCount": "{count} закреплено", "PinnedCount": "{count} закреплено",
"LoadingHistory": "Загрузка истории..." "LoadingHistory": "Загрузка истории...",
"UnpinChannels": "Открепить все каналы",
"ArchiveActivityConfirmationTitle": "Архивировать все каналы активности?",
"ArchiveActivityConfirmationMessage": "Вы уверены, что хотите заархивировать все каналы активности? Эту операцию невозможно отменить."
} }
} }

View File

@ -15,8 +15,8 @@
<script lang="ts"> <script lang="ts">
import { Class, Doc, getCurrentAccount, groupByArray, Ref } from '@hcengineering/core' import { Class, Doc, getCurrentAccount, groupByArray, Ref } from '@hcengineering/core'
import notification, { DocNotifyContext } from '@hcengineering/notification' import notification, { DocNotifyContext } from '@hcengineering/notification'
import { createQuery, getClient, LiveQuery } from '@hcengineering/presentation' import { createQuery, getClient, LiveQuery, MessageBox } from '@hcengineering/presentation'
import { Action, Scroller } from '@hcengineering/ui' import { Action, Scroller, showPopup } from '@hcengineering/ui'
import activity from '@hcengineering/activity' import activity from '@hcengineering/activity'
import view from '@hcengineering/view' import view from '@hcengineering/view'
import { getResource } from '@hcengineering/platform' import { getResource } from '@hcengineering/platform'
@ -25,6 +25,7 @@
import ChatGroupHeader from './ChatGroupHeader.svelte' import ChatGroupHeader from './ChatGroupHeader.svelte'
import chunter from '../../../plugin' import chunter from '../../../plugin'
import { ChatNavGroupModel } from '../types' import { ChatNavGroupModel } from '../types'
import { readActivityChannels, removeActivityChannels } from '../utils'
export let selectedContextId: Ref<DocNotifyContext> | undefined = undefined export let selectedContextId: Ref<DocNotifyContext> | undefined = undefined
export let model: ChatNavGroupModel export let model: ChatNavGroupModel
@ -88,11 +89,47 @@
} }
} }
function getPinnedActions (): Action[] { function archiveActivityChannels (contexts: DocNotifyContext[]): void {
showPopup(
MessageBox,
{
label: chunter.string.ArchiveActivityConfirmationTitle,
message: chunter.string.ArchiveActivityConfirmationMessage
},
'top',
(result?: boolean) => {
if (result === true) {
void removeActivityChannels(contexts)
}
}
)
}
function getActions (contexts: DocNotifyContext[]): Action[] {
if (model.id !== 'activity') return []
return [ return [
{
icon: notification.icon.ReadAll,
label: notification.string.MarkReadAll,
action: () => readActivityChannels(contexts)
},
{
icon: view.icon.Archive,
label: notification.string.ArchiveAll,
action: async () => {
archiveActivityChannels(contexts)
}
}
]
}
function getPinnedActions (pinnedContexts: DocNotifyContext[]): Action[] {
const baseActions = getActions(pinnedContexts)
const actions: Action[] = [
{ {
icon: view.icon.Delete, icon: view.icon.Delete,
label: view.string.Delete, label: chunter.string.UnpinChannels,
action: chunter.actionImpl.UnpinAllChannels action: chunter.actionImpl.UnpinAllChannels
} }
].map(({ icon, label, action }) => ({ ].map(({ icon, label, action }) => ({
@ -103,6 +140,8 @@
await actionFn(pinnedContexts, evt) await actionFn(pinnedContexts, evt)
} }
})) }))
return actions.concat(baseActions)
} }
function sortContexts (contexts: DocNotifyContext[]): DocNotifyContext[] { function sortContexts (contexts: DocNotifyContext[]): DocNotifyContext[] {
@ -133,7 +172,7 @@
<Scroller padding="0 0.5rem"> <Scroller padding="0 0.5rem">
{#if pinnedContexts.length} {#if pinnedContexts.length}
<div class="block"> <div class="block">
<ChatGroupHeader header={chunter.string.Pinned} actions={getPinnedActions()} /> <ChatGroupHeader header={chunter.string.Pinned} actions={getPinnedActions(pinnedContexts)} />
{#each pinnedContexts as context (context._id)} {#each pinnedContexts as context (context._id)}
{@const _class = context.attachedToClass} {@const _class = context.attachedToClass}
{@const object = objectsByClass.get(_class)?.find(({ _id }) => _id === context.attachedTo)} {@const object = objectsByClass.get(_class)?.find(({ _id }) => _id === context.attachedTo)}
@ -148,7 +187,7 @@
{#if contexts.length} {#if contexts.length}
<div class="block"> <div class="block">
<ChatGroupHeader header={model.label} /> <ChatGroupHeader header={model.label} actions={getActions(contexts)} />
{#each contexts as context (context._id)} {#each contexts as context (context._id)}
{@const _class = context.attachedToClass} {@const _class = context.attachedToClass}
{@const object = objectsByClass.get(_class)?.find(({ _id }) => _id === context.attachedTo)} {@const object = objectsByClass.get(_class)?.find(({ _id }) => _id === context.attachedTo)}

View File

@ -56,7 +56,9 @@
}) })
notificationClient.inboxNotificationsByContext.subscribe((res) => { notificationClient.inboxNotificationsByContext.subscribe((res) => {
notifications = res.get(context._id) ?? [] notifications = (res.get(context._id) ?? []).filter(
({ _class }) => _class === notification.class.ActivityInboxNotification
)
}) })
$: isDirect = hierarchy.isDerived(context.attachedToClass, chunter.class.DirectMessage) $: isDirect = hierarchy.isDerived(context.attachedToClass, chunter.class.DirectMessage)

View File

@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
import notification from '@hcengineering/notification' import notification, { type DocNotifyContext } from '@hcengineering/notification'
import { SortingOrder, type WithLookup } from '@hcengineering/core' import { generateId, SortingOrder, type WithLookup } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation' import { createQuery, getClient } from '@hcengineering/presentation'
import { writable } from 'svelte/store' import { get, writable } from 'svelte/store'
import view from '@hcengineering/view' import view from '@hcengineering/view'
import workbench, { type SpecialNavModel } from '@hcengineering/workbench' import workbench, { type SpecialNavModel } from '@hcengineering/workbench'
import attachment, { type SavedAttachments } from '@hcengineering/attachment' import attachment, { type SavedAttachments } from '@hcengineering/attachment'
import activity from '@hcengineering/activity' import activity from '@hcengineering/activity'
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
import { type ChatNavGroupModel } from './types' import { type ChatNavGroupModel } from './types'
import chunter from '../../plugin' import chunter from '../../plugin'
@ -121,3 +122,47 @@ export function loadSavedAttachments (): void {
}, 50) }, 50)
} }
} }
export async function removeActivityChannels (contexts: DocNotifyContext[]): Promise<void> {
const client = InboxNotificationsClientImpl.getClient()
const notificationsByContext = get(client.inboxNotificationsByContext)
const doneOp = await getClient().measure('removeActivityChannels')
const ops = getClient().apply(generateId())
try {
for (const context of contexts) {
const notifications = notificationsByContext.get(context._id) ?? []
await client.deleteNotifications(
ops,
notifications.map(({ _id }) => _id)
)
await ops.remove(context)
}
} finally {
await ops.commit()
await doneOp()
}
}
export async function readActivityChannels (contexts: DocNotifyContext[]): Promise<void> {
const client = InboxNotificationsClientImpl.getClient()
const notificationsByContext = get(client.inboxNotificationsByContext)
const doneOp = await getClient().measure('readActivityChannels')
const ops = getClient().apply(generateId())
try {
for (const context of contexts) {
const notifications = notificationsByContext.get(context._id) ?? []
await client.deleteNotifications(
ops,
notifications
.filter(({ _class }) => _class === notification.class.ActivityInboxNotification)
.map(({ _id }) => _id)
)
await ops.update(context, { lastViewedTimestamp: Date.now() })
}
} finally {
await ops.commit()
await doneOp()
}
}

View File

@ -105,6 +105,9 @@ export default mergeIds(chunterId, chunter, {
Mentioned: '' as IntlString, Mentioned: '' as IntlString,
SentMessage: '' as IntlString, SentMessage: '' as IntlString,
PinnedCount: '' as IntlString, PinnedCount: '' as IntlString,
LoadingHistory: '' as IntlString LoadingHistory: '' as IntlString,
UnpinChannels: '' as IntlString,
ArchiveActivityConfirmationTitle: '' as IntlString,
ArchiveActivityConfirmationMessage: '' as IntlString
} }
}) })