TSK-713: Notifications for DM (#2695)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2023-03-01 14:23:42 +05:00 committed by GitHub
parent 496e0cff38
commit 1d97d0c689
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 154 additions and 9 deletions

View File

@ -194,6 +194,10 @@ export function createModel (builder: Builder, options = { addApplication: true
presenter: chunter.component.DmPresenter
})
builder.mixin(chunter.class.Message, core.class.Class, view.mixin.ObjectPresenter, {
presenter: chunter.component.MessagePresenter
})
builder.mixin(chunter.class.Channel, core.class.Class, view.mixin.ObjectPresenter, {
presenter: chunter.component.ChannelPresenter
})
@ -442,6 +446,22 @@ export function createModel (builder: Builder, options = { addApplication: true
chunter.ids.TxCommentRemove
)
builder.createDoc(
activity.class.TxViewlet,
core.space.Model,
{
objectClass: chunter.class.Message,
icon: chunter.icon.Chunter,
txClass: core.class.TxCreateDoc,
component: chunter.activity.TxMessageCreate,
label: notification.string.DMNotification,
display: 'content',
editable: true,
hideOnRemove: true
},
chunter.ids.TxMessageCreate
)
builder.createDoc(
activity.class.TxViewlet,
core.space.Model,

View File

@ -26,6 +26,7 @@ export default mergeIds(chunterId, chunter, {
component: {
CommentPresenter: '' as AnyComponent,
ChannelPresenter: '' as AnyComponent,
MessagePresenter: '' as AnyComponent,
DmPresenter: '' as AnyComponent,
Threads: '' as AnyComponent,
ThreadView: '' as AnyComponent,
@ -78,12 +79,14 @@ export default mergeIds(chunterId, chunter, {
TxCommentCreate: '' as Ref<TxViewlet>,
TxBacklinkCreate: '' as Ref<TxViewlet>,
TxCommentRemove: '' as Ref<TxViewlet>,
TxBacklinkRemove: '' as Ref<TxViewlet>
TxBacklinkRemove: '' as Ref<TxViewlet>,
TxMessageCreate: '' as Ref<TxViewlet>
},
activity: {
TxCommentCreate: '' as AnyComponent,
TxBacklinkCreate: '' as AnyComponent,
TxBacklinkReference: '' as AnyComponent
TxBacklinkReference: '' as AnyComponent,
TxMessageCreate: '' as AnyComponent
},
space: {
General: '' as Ref<Channel>,

View File

@ -137,6 +137,18 @@ export function createModel (builder: Builder): void {
notification.ids.MentionNotification
)
builder.createDoc(
notification.class.NotificationType,
core.space.Model,
{
label: notification.string.DMNotification,
textTemplate: '{sender} has send you a message: {doc} {data}',
htmlTemplate: '<p><b>{sender}</b> has send you a message {doc}</p> {data}',
subjectTemplate: 'You have new DM message in {doc}'
},
notification.ids.DMNotification
)
builder.createDoc(
notification.class.NotificationProvider,
core.space.Model,

View File

@ -21,6 +21,7 @@ import { AnyComponent } from '@hcengineering/ui'
export default mergeIds(notificationId, notification, {
string: {
LastView: '' as IntlString,
DMNotification: '' as IntlString,
MentionNotification: '' as IntlString,
PlatformNotification: '' as IntlString,
BrowserNotification: '' as IntlString,

View File

@ -42,4 +42,8 @@ export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverChunter.trigger.ChunterTrigger
})
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverChunter.trigger.DMTrigger
})
}

View File

@ -0,0 +1,35 @@
<script lang="ts">
import { DirectMessage, Message } from '@hcengineering/chunter'
import { getCurrentLocation, navigate } from '@hcengineering/ui'
import { createQuery, getClient, MessageViewer } from '@hcengineering/presentation'
import { getDmName, getSpaceLink } from '../utils'
import chunter from '../plugin'
export let value: Message
const client = getClient()
let dm: DirectMessage | undefined
const query = createQuery()
$: query.query(chunter.class.DirectMessage, { _id: value.space }, (result) => {
dm = result[0]
})
$: link = getSpaceLink(value.space)
function goto () {
const loc = getCurrentLocation()
loc.path[1] = 'chunter'
loc.path[2] = value.space
loc.query = undefined
navigate(loc)
}
</script>
{#if dm}
{#await getDmName(client, dm) then name}
<a class="flex-presenter" href={link} on:click={() => goto()}>
<span class="label">{name}</span>
</a>
<div><MessageViewer message={value.content} /></div>
{/await}
{/if}

View File

@ -0,0 +1,10 @@
<script lang="ts">
import { TxCreateDoc } from '@hcengineering/core'
import { Message } from '@hcengineering/chunter'
export let tx: TxCreateDoc<Message>
</script>
<div class="flex">
<span>{tx.attributes.content}</span>
</div>

View File

@ -31,8 +31,10 @@ import { getCurrentLocation, navigate, showPopup } from '@hcengineering/ui'
import TxBacklinkCreate from './components/activity/TxBacklinkCreate.svelte'
import TxBacklinkReference from './components/activity/TxBacklinkReference.svelte'
import TxCommentCreate from './components/activity/TxCommentCreate.svelte'
import TxMessageCreate from './components/activity/TxMessageCreate.svelte'
import ChannelPresenter from './components/ChannelPresenter.svelte'
import DmPresenter from './components/DmPresenter.svelte'
import MessagePresenter from './components/MessagePresenter.svelte'
import ChannelView from './components/ChannelView.svelte'
import ChannelHeader from './components/ChannelHeader.svelte'
import DmHeader from './components/DmHeader.svelte'
@ -229,6 +231,7 @@ export default async (): Promise<Resources> => ({
CommentPresenter,
CommentsPresenter,
ChannelPresenter,
MessagePresenter,
ChunterBrowser,
DmHeader,
DmPresenter,
@ -244,7 +247,8 @@ export default async (): Promise<Resources> => ({
activity: {
TxCommentCreate,
TxBacklinkCreate,
TxBacklinkReference
TxBacklinkReference,
TxMessageCreate
},
actionImpl: {
MarkUnread,

View File

@ -5,6 +5,7 @@
"Notifications": "Notifications",
"NoNotifications": "No notifications",
"MentionNotification": "Mentioned",
"DMNotification": "Sent you a message",
"EmailNotification": "by email",
"PlatformNotification": "in platform",
"Track": "Track",
@ -15,4 +16,4 @@
"MarkAllAsRead": "Mark all notifications as read",
"MarkAsRead": "Mark as read"
}
}
}

View File

@ -5,6 +5,7 @@
"Notifications": "Уведомления",
"NoNotifications": "Нет уведомлений",
"MentionNotification": "Упомянул",
"DMNotification": "Отправил сообщение",
"EmailNotification": "по email",
"PlatformNotification": "в системе",
"Track": "Отслеживать",
@ -15,4 +16,4 @@
"MarkAllAsRead": "Отметить все нотификации как прочитанные",
"MarkAsRead": "Отметить нотификация прочитанной"
}
}
}

View File

@ -156,6 +156,7 @@ const notification = plugin(notificationId, {
},
ids: {
MentionNotification: '' as Ref<NotificationType>,
DMNotification: '' as Ref<NotificationType>,
PlatformNotification: '' as Ref<NotificationProvider>,
BrowserNotification: '' as Ref<NotificationProvider>,
EmailNotification: '' as Ref<NotificationProvider>,

View File

@ -33,6 +33,7 @@
"@hcengineering/chunter": "^0.6.2",
"@hcengineering/view": "^0.6.2",
"@hcengineering/login": "^0.6.1",
"@hcengineering/workbench": "^0.6.2"
"@hcengineering/workbench": "^0.6.2",
"@hcengineering/notification": "^0.6.5"
}
}

View File

@ -13,7 +13,14 @@
// limitations under the License.
//
import chunter, { chunterId, ChunterSpace, Comment, Message, ThreadMessage } from '@hcengineering/chunter'
import chunter, {
chunterId,
ChunterMessage,
ChunterSpace,
Comment,
Message,
ThreadMessage
} from '@hcengineering/chunter'
import { EmployeeAccount } from '@hcengineering/contact'
import core, {
Class,
@ -35,6 +42,9 @@ import login from '@hcengineering/login'
import { getMetadata } from '@hcengineering/platform'
import { TriggerControl } from '@hcengineering/server-core'
import { workbenchId } from '@hcengineering/workbench'
import { getEmployeeAccountById } from '../../notification'
import { createNotificationTxes } from '../../notification-resources'
import notification from '@hcengineering/notification'
/**
* @public
@ -261,10 +271,51 @@ export async function ChunterTrigger (tx: Tx, control: TriggerControl): Promise<
return res.flat()
}
/**
* @public
*/
export async function DMTrigger (tx: Tx, control: TriggerControl): Promise<Tx[]> {
if (tx._class !== core.class.TxCollectionCUD) return []
const hierarchy = control.hierarchy
const ctx = tx as TxCollectionCUD<ChunterSpace, Message>
if (!hierarchy.isDerived(ctx.tx.objectClass, chunter.class.Message)) {
return []
}
const actualTx = TxProcessor.extractTx(tx)
if (actualTx._class !== core.class.TxCreateDoc) {
return []
}
const doc = TxProcessor.createDoc2Doc(actualTx as TxCreateDoc<ChunterMessage>)
const dms = await control.findAll(chunter.class.DirectMessage, { _id: doc.space })
if (dms.total === 0) {
return []
}
const sender = await getEmployeeAccountById(ctx.tx.modifiedBy, control)
if (sender === undefined) return []
const res: Tx[] = []
for (const member of dms[0].members) {
const receiver = await getEmployeeAccountById(member, control)
if (receiver === undefined) continue
if (receiver._id === sender._id) continue
const createNotificationTx = await createNotificationTxes(
control,
ctx,
notification.ids.DMNotification,
doc,
sender,
receiver,
doc.content
)
res.push(...createNotificationTx)
}
return res
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
ChunterTrigger
ChunterTrigger,
DMTrigger
},
function: {
CommentRemove,

View File

@ -29,7 +29,8 @@ export const serverChunterId = 'server-chunter' as Plugin
*/
export default plugin(serverChunterId, {
trigger: {
ChunterTrigger: '' as Resource<TriggerFunc>
ChunterTrigger: '' as Resource<TriggerFunc>,
DMTrigger: '' as Resource<TriggerFunc>
},
function: {
CommentRemove: '' as Resource<