diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index b6d6ca5148..6088367954 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -269,9 +269,10 @@ export function createModel (builder: Builder): void { label: notification.string.Archive, icon: view.icon.Archive, input: 'focus', + keyBinding: ['Backspace'], category: notification.category.Notification, target: notification.class.DocUpdates, - context: { mode: 'context', application: notification.app.Notification, group: 'edit' } + context: { mode: ['context', 'browser'], group: 'edit' } }, notification.action.Hide ) diff --git a/plugins/notification-resources/src/components/Inbox.svelte b/plugins/notification-resources/src/components/Inbox.svelte index e513ef8245..c6a4c396b3 100644 --- a/plugins/notification-resources/src/components/Inbox.svelte +++ b/plugins/notification-resources/src/components/Inbox.svelte @@ -20,6 +20,7 @@ import { createQuery, getClient } from '@hcengineering/presentation' import { AnyComponent, Component, Label, Loading, Scroller } from '@hcengineering/ui' import view from '@hcengineering/view' + import { ActionContext, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources' import NotificationView from './NotificationView.svelte' export let visibileNav: boolean @@ -39,8 +40,11 @@ }, (res) => { docs = res - if (loading && docs.length > 0) { - select(docs[0].attachedTo, docs[0].attachedToClass) + listProvider.update(docs) + if (loading || _id === undefined) { + changeSelected(selected) + } else if (docs.find((p) => p.attachedTo === _id) === undefined) { + changeSelected(selected) } loading = false }, @@ -51,16 +55,32 @@ } ) - function select (objectId: Ref<Doc>, objectClass: Ref<Class<Doc>>) { - const targetClass = hierarchy.getClass(objectClass) - const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel) - component = panelComponent.component ?? view.component.EditDoc - _id = objectId - _class = objectClass + $: changeSelected(selected) + + function changeSelected (index: number) { + if (docs[index] !== undefined) { + select(docs[index]) + } else if (docs.length) { + if (index < docs.length - 1) { + selected++ + } else { + selected-- + } + } else { + selected = 0 + component = undefined + _id = undefined + _class = undefined + } } - function selectHandler (e: CustomEvent) { - select(e.detail._id, e.detail._class) + function select (value: DocUpdates) { + listProvider.updateFocus(value) + const targetClass = hierarchy.getClass(value.attachedToClass) + const panelComponent = hierarchy.as(targetClass, view.mixin.ObjectPanel) + component = panelComponent.component ?? view.component.EditDoc + _id = value.attachedTo + _class = value.attachedToClass } let component: AnyComponent | undefined @@ -69,12 +89,28 @@ let viewlets: Map<ActivityKey, TxViewlet> + const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => { + if (dir === 'vertical') { + const value = selected + offset + if (docs[value] !== undefined) { + selected = value + } + } + }) + const descriptors = createQuery() descriptors.query(activity.class.TxViewlet, {}, (result) => { viewlets = new Map(result.map((r) => [activityKey(r.objectClass, r.txClass), r])) }) + + let selected = 0 </script> +<ActionContext + context={{ + mode: 'browser' + }} +/> <div class="flex h-full"> {#if visibileNav} <div class="antiPanel-component border-right filled indent aside"> @@ -88,8 +124,15 @@ {#if loading} <Loading /> {:else} - {#each docs as doc} - <NotificationView value={doc} selected={doc.attachedTo === _id} {viewlets} on:click={selectHandler} /> + {#each docs as doc, i} + <NotificationView + value={doc} + selected={selected === i} + {viewlets} + on:click={() => { + selected = i + }} + /> {/each} {/if} </Scroller> @@ -99,9 +142,7 @@ {#if component && _id && _class} <Component is={component} props={{ embedded: true, _id, _class }} /> {:else} - <div class="antiPanel-component filled w-full"> - <Loading /> - </div> + <div class="antiPanel-component filled w-full" /> {/if} </div> diff --git a/plugins/notification-resources/src/components/NotificationView.svelte b/plugins/notification-resources/src/components/NotificationView.svelte index 3c5a3d2f55..ea1b9c117d 100644 --- a/plugins/notification-resources/src/components/NotificationView.svelte +++ b/plugins/notification-resources/src/components/NotificationView.svelte @@ -24,7 +24,6 @@ import { AnySvelteComponent, Label, TimeSince, getEventPositionElement, showPopup } from '@hcengineering/ui' import view from '@hcengineering/view' import { Menu } from '@hcengineering/view-resources' - import { createEventDispatcher } from 'svelte' import TxView from './TxView.svelte' export let value: DocUpdates @@ -60,10 +59,10 @@ query.query(contact.class.EmployeeAccount, { _id: tx.modifiedBy as Ref<EmployeeAccount> }, (r) => ([account] = r)) $: employee = account && $employeeByIdStore.get(account.employee) - const dispatch = createEventDispatcher() - const docQuery = createQuery() - $: docQuery.query(value.attachedToClass, { _id: value.attachedTo }, (res) => ([doc] = res)) + $: docQuery.query(value.attachedToClass, { _id: value.attachedTo }, (res) => { + ;[doc] = res + }) $: newTxes = value.txes.length @@ -74,12 +73,7 @@ <!-- svelte-ignore a11y-click-events-have-key-events --> {#if doc} - <div - class="container cursor-pointer bottom-divider" - class:selected - on:contextmenu|preventDefault={showMenu} - on:click={() => dispatch('click', { _id: value.attachedTo, _class: value.attachedToClass })} - > + <div class="container cursor-pointer bottom-divider" class:selected on:contextmenu|preventDefault={showMenu} on:click> <div class="header flex"> <Avatar avatar={employee?.avatar} size="medium" /> <div class="ml-2 w-full clear-mins"> diff --git a/plugins/notification-resources/src/utils.ts b/plugins/notification-resources/src/utils.ts index 0e56e8eca7..5829041425 100644 --- a/plugins/notification-resources/src/utils.ts +++ b/plugins/notification-resources/src/utils.ts @@ -133,11 +133,19 @@ export async function unsubscribe (object: DocUpdates): Promise<void> { /** * @public */ -export async function hide (object: DocUpdates): Promise<void> { +export async function hide (object: DocUpdates | DocUpdates[]): Promise<void> { const client = getClient() - await client.update(object, { - hidden: true - }) + if (Array.isArray(object)) { + for (const value of object) { + await client.update(value, { + hidden: true + }) + } + } else { + await client.update(object, { + hidden: true + }) + } } /** diff --git a/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte b/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte index c1557691bd..9271cea639 100644 --- a/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte +++ b/plugins/tracker-resources/src/components/issues/edit/SubIssueList.svelte @@ -15,7 +15,7 @@ <script lang="ts"> import { Doc, DocumentQuery, Ref } from '@hcengineering/core' import { Issue, Project } from '@hcengineering/tracker' - import { Viewlet, ViewOptions } from '@hcengineering/view' + import { ViewOptions, Viewlet } from '@hcengineering/view' import { ActionContext, List, @@ -23,7 +23,6 @@ SelectDirection, selectionStore } from '@hcengineering/view-resources' - import { onDestroy } from 'svelte' import tracker from '../../../plugin' export let query: DocumentQuery<Issue> | undefined = undefined @@ -43,10 +42,6 @@ list.select(offset, of) } }) - - onDestroy(() => { - ListSelectionProvider.Pop() - }) </script> <ActionContext diff --git a/plugins/view-resources/src/selection.ts b/plugins/view-resources/src/selection.ts index 1b38164c59..077c272c1c 100644 --- a/plugins/view-resources/src/selection.ts +++ b/plugins/view-resources/src/selection.ts @@ -146,13 +146,15 @@ export class ListSelectionProvider implements SelectionFocusProvider { }) if (this._docs.length > 0) { - if (this._current?.focus === undefined) { + if (this._current === undefined) { this.delegate(0, undefined, 'vertical') } else { // Check if we don't have object, we need to select first one. this.delegate(0, this._current?.focus, 'vertical') } - updateFocus({ focus: this._current?.focus, provider: this }) + if (this._current?.focus === undefined) { + updateFocus({ focus: this._current?.focus, provider: this }) + } } } diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts index d75e28abc3..2da4afeb2f 100644 --- a/server-plugins/chunter-resources/src/index.ts +++ b/server-plugins/chunter-resources/src/index.ts @@ -132,7 +132,10 @@ async function CommentCreate (tx: TxCUD<Doc>, control: TriggerControl): Promise< const actualTx = TxProcessor.extractTx(tx) if (actualTx._class !== core.class.TxCreateDoc) return [] const doc = TxProcessor.createDoc2Doc(actualTx as TxCreateDoc<Comment>) - if (!hierarchy.isDerived(doc._class, chunter.class.Comment)) { + if ( + !hierarchy.isDerived(doc._class, chunter.class.Comment) || + hierarchy.isDerived(doc._class, chunter.class.Backlink) + ) { return [] } const res: Tx[] = [] diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts index 6d4efd7ee7..2573afe023 100644 --- a/server-plugins/notification-resources/src/index.ts +++ b/server-plugins/notification-resources/src/index.ts @@ -94,6 +94,16 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis } ) res.push(collabTx) + res = res.concat( + await createCollabDocInfo( + [receiver._id], + tx as TxCUD<Doc>, + doc._id, + doc._class, + control, + tx._id as Ref<TxCUD<Doc>> + ) + ) } } const notifyTx = await createNotificationTxes(