diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts
index fec0e9ddb6..cf1cd313d3 100644
--- a/models/chunter/src/index.ts
+++ b/models/chunter/src/index.ts
@@ -721,7 +721,7 @@ export function createModel (builder: Builder, options = { addApplication: true
},
group: chunter.ids.ChunterNotificationGroup
},
- chunter.ids.ThreadNotification
+ chunter.ids.ChannelNotification
)
builder.createDoc(
@@ -738,7 +738,7 @@ export function createModel (builder: Builder, options = { addApplication: true
},
group: chunter.ids.ChunterNotificationGroup
},
- chunter.ids.ChannelNotification
+ chunter.ids.ThreadNotification
)
createAction(builder, {
diff --git a/models/server-chunter/src/index.ts b/models/server-chunter/src/index.ts
index 7937d578a9..27390bf7d7 100644
--- a/models/server-chunter/src/index.ts
+++ b/models/server-chunter/src/index.ts
@@ -58,10 +58,6 @@ export function createModel (builder: Builder): void {
}
})
- builder.mixin(chunter.ids.DMNotification, notification.class.NotificationType, serverNotification.mixin.TypeMatch, {
- func: serverChunter.function.IsDirectMessage
- })
-
builder.mixin(
chunter.ids.MentionNotification,
notification.class.NotificationType,
@@ -71,6 +67,19 @@ export function createModel (builder: Builder): void {
}
)
+ builder.mixin(chunter.ids.DMNotification, notification.class.NotificationType, serverNotification.mixin.TypeMatch, {
+ func: serverChunter.function.IsDirectMessage
+ })
+
+ builder.mixin(
+ chunter.ids.ThreadNotification,
+ notification.class.NotificationType,
+ serverNotification.mixin.TypeMatch,
+ {
+ func: serverChunter.function.IsThreadMessage
+ }
+ )
+
builder.mixin(
chunter.ids.ChannelNotification,
notification.class.NotificationType,
diff --git a/plugins/chunter-assets/lang/en.json b/plugins/chunter-assets/lang/en.json
index 9510a44b63..477eef243e 100644
--- a/plugins/chunter-assets/lang/en.json
+++ b/plugins/chunter-assets/lang/en.json
@@ -23,6 +23,7 @@
"Comment": "Comment",
"Message": "Message",
"MessageOn": "Message on",
+ "On": "on",
"Reference": "Reference",
"Chat": "Chat",
"In": "In",
diff --git a/plugins/chunter-assets/lang/ru.json b/plugins/chunter-assets/lang/ru.json
index 976ef2292d..53c032ef16 100644
--- a/plugins/chunter-assets/lang/ru.json
+++ b/plugins/chunter-assets/lang/ru.json
@@ -23,6 +23,7 @@
"Comment": "Комментарий",
"Message": "Сообщение",
"MessageOn": "Сообщение в",
+ "On": "в",
"MentionNotification": "Упомянул",
"Reference": "Ссылка",
"Chat": "Чат",
diff --git a/plugins/chunter-resources/src/components/MessagePresenter.svelte b/plugins/chunter-resources/src/components/MessagePresenter.svelte
index c8d25c64a2..ac63fd8ea2 100644
--- a/plugins/chunter-resources/src/components/MessagePresenter.svelte
+++ b/plugins/chunter-resources/src/components/MessagePresenter.svelte
@@ -20,11 +20,14 @@
import { AttributeModel } from '@hcengineering/view'
import { getObjectPresenter } from '@hcengineering/view-resources'
+ import chunterResources from '../plugin'
+
export let value: Message
export let inline: boolean = false
export let disabled = false
const client = getClient()
+ const isThreadMessage = client.getHierarchy().isDerived(value._class, chunter.class.ThreadMessage)
let presenter: AttributeModel | undefined
getObjectPresenter(client, value.attachedToClass, { key: '' }).then((p) => {
@@ -40,14 +43,16 @@
{#if inline}
{#if presenter && doc}
-
-
-
-
-
-
-
-
+
+ {#if isThreadMessage}
+
+
+
+
+
+
+
+ {/if}
{/if}
diff --git a/plugins/chunter-resources/src/components/Replies.svelte b/plugins/chunter-resources/src/components/Replies.svelte
index 0b0e3bf61b..ec31e933a6 100644
--- a/plugins/chunter-resources/src/components/Replies.svelte
+++ b/plugins/chunter-resources/src/components/Replies.svelte
@@ -16,20 +16,33 @@
import { Message } from '@hcengineering/chunter'
import { Person } from '@hcengineering/contact'
import { personByIdStore } from '@hcengineering/contact-resources'
- import { IdMap, Ref } from '@hcengineering/core'
+ import { Doc, IdMap, Ref } from '@hcengineering/core'
import { Avatar } from '@hcengineering/contact-resources'
import { Label, TimeSince } from '@hcengineering/ui'
+ import { NotificationClientImpl } from '@hcengineering/notification-resources'
+ import { DocUpdates } from '@hcengineering/notification'
+
import chunter from '../plugin'
export let message: Message
$: lastReply = message.lastReply ?? new Date().getTime()
$: employees = new Set(message.replies)
+ const notificationClient = NotificationClientImpl.getClient()
+ const docUpdates = notificationClient.docUpdatesStore
+
const shown: number = 4
let showReplies: Person[] = []
+ $: hasNew = checkNewReplies(message, $docUpdates)
$: updateQuery(employees, $personByIdStore)
+ function checkNewReplies (message: Message, docUpdates: Map
[, DocUpdates>): boolean {
+ const docUpdate = docUpdates.get(message._id)
+ if (docUpdate === undefined) return false
+ return docUpdate.txes.filter((tx) => tx.isNew).length > 0
+ }
+
function updateQuery (employees: Set][>, map: IdMap) {
showReplies = []
for (const employee of employees) {
@@ -55,6 +68,9 @@
]
+ {#if hasNew}
+
+ {/if}
{#if (message.replies?.length ?? 0) > 1}
@@ -101,4 +117,12 @@
background-color: var(--theme-bg-color);
}
}
+
+ .marker {
+ margin: 0 0.25rem 0 -0.25rem;
+ width: 0.425rem;
+ height: 0.425rem;
+ border-radius: 50%;
+ background-color: var(--highlight-red);
+ }
diff --git a/plugins/chunter-resources/src/components/ThreadView.svelte b/plugins/chunter-resources/src/components/ThreadView.svelte
index c4f9220e66..cf0adb7db2 100644
--- a/plugins/chunter-resources/src/components/ThreadView.svelte
+++ b/plugins/chunter-resources/src/components/ThreadView.svelte
@@ -156,11 +156,12 @@
function newMessagesStart (comments: ThreadMessage[], docUpdates: Map
[, DocUpdates>): number {
const docUpdate = docUpdates.get(_id)
- const lastView = docUpdate?.txes?.[0]?.modifiedOn
+ const lastView = docUpdate?.txes?.findLast((tx) => !tx.isNew)
+ if (!docUpdate?.txes.some((tx) => tx.isNew)) return -1
if (docUpdate === undefined || lastView === undefined) return -1
for (let index = 0; index < comments.length; index++) {
const comment = comments[index]
- if ((comment.createdOn ?? 0) >= lastView) return index
+ if ((comment.createdOn ?? 0) >= lastView.modifiedOn) return index
}
return -1
}
diff --git a/plugins/chunter-resources/src/plugin.ts b/plugins/chunter-resources/src/plugin.ts
index d60bf7704e..cdd51acb9e 100644
--- a/plugins/chunter-resources/src/plugin.ts
+++ b/plugins/chunter-resources/src/plugin.ts
@@ -90,6 +90,7 @@ export default mergeIds(chunterId, chunter, {
CopyLink: '' as IntlString,
You: '' as IntlString,
YouHaveJoinedTheConversation: '' as IntlString,
- NoMessages: '' as IntlString
+ NoMessages: '' as IntlString,
+ On: '' as IntlString
}
})
diff --git a/plugins/notification-resources/src/components/Inbox.svelte b/plugins/notification-resources/src/components/Inbox.svelte
index baafca071c..4d17a3e42d 100644
--- a/plugins/notification-resources/src/components/Inbox.svelte
+++ b/plugins/notification-resources/src/components/Inbox.svelte
@@ -18,7 +18,17 @@
import { Class, Doc, Ref, getCurrentAccount } from '@hcengineering/core'
import { DocUpdates } from '@hcengineering/notification'
import { getClient } from '@hcengineering/presentation'
- import { AnyComponent, Button, Component, IconAdd, Tabs, eventToHTMLElement, showPopup } from '@hcengineering/ui'
+ import {
+ AnyComponent,
+ Button,
+ Component,
+ IconAdd,
+ Tabs,
+ eventToHTMLElement,
+ getLocation,
+ navigate,
+ showPopup
+ } from '@hcengineering/ui'
import view from '@hcengineering/view'
import contact from '@hcengineering/contact'
import { UsersPopup } from '@hcengineering/contact-resources'
@@ -53,7 +63,6 @@
let _id: Ref | undefined
let _class: Ref> | undefined
let selectedEmployee: Ref | undefined = undefined
- let prevValue: DocUpdates | undefined = undefined
async function select (value: DocUpdates | undefined) {
if (!value) {
@@ -62,19 +71,27 @@
_class = undefined
return
}
- if (prevValue !== undefined) {
- if (prevValue.txes.some((p) => p.isNew)) {
- prevValue.txes.forEach((p) => (p.isNew = false))
- const txes = prevValue.txes
- await client.update(prevValue, { txes })
+
+ const isDmOpened = hierarchy.isDerived(value.attachedToClass, chunter.class.ChunterSpace)
+ if (!isDmOpened && value !== undefined) {
+ // chats messages are marked as read explicitly, but
+ // other notifications should be marked as read upon opening
+ if (value.txes.some((p) => p.isNew)) {
+ value.txes.forEach((p) => (p.isNew = false))
+ const txes = value.txes
+ await client.update(value, { txes })
}
}
- 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
- prevValue = value
+
+ if (hierarchy.isDerived(value.attachedToClass, chunter.class.ChunterSpace)) {
+ openDM(value.attachedTo)
+ } else {
+ 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
+ }
}
function openDM (value: Ref) {
@@ -84,6 +101,9 @@
component = panelComponent.component ?? view.component.EditDoc
_id = value
_class = chunter.class.DirectMessage
+ const loc = getLocation()
+ loc.path[3] = _id
+ navigate(loc)
}
}
diff --git a/plugins/workbench-resources/src/components/Workbench.svelte b/plugins/workbench-resources/src/components/Workbench.svelte
index 87304912a2..7b69eb1bee 100644
--- a/plugins/workbench-resources/src/components/Workbench.svelte
+++ b/plugins/workbench-resources/src/components/Workbench.svelte
@@ -760,7 +760,7 @@
{/if}
]
- {#if asideId}
+ {#if asideId && currentSpace}
{@const asideComponent = navigatorModel?.aside ?? currentApplication?.aside}
{#if asideComponent !== undefined}
diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts
index 5e83731919..fc4ee79ef9 100644
--- a/server-plugins/chunter-resources/src/index.ts
+++ b/server-plugins/chunter-resources/src/index.ts
@@ -13,7 +13,15 @@
// limitations under the License.
//
-import chunter, { Backlink, chunterId, ChunterSpace, Comment, Message, ThreadMessage } from '@hcengineering/chunter'
+import chunter, {
+ Backlink,
+ chunterId,
+ ChunterSpace,
+ Comment,
+ DirectMessage,
+ Message,
+ ThreadMessage
+} from '@hcengineering/chunter'
import contact, { Employee, PersonAccount } from '@hcengineering/contact'
import core, {
Account,
@@ -455,8 +463,8 @@ export async function IsDirectMessage (
type: NotificationType,
control: TriggerControl
): Promise {
- const space = (await control.findAll(chunter.class.DirectMessage, { _id: doc.space }))[0]
- return space !== undefined
+ const dm = (await control.findAll(chunter.class.DirectMessage, { _id: doc._id as Ref }))[0]
+ return dm !== undefined
}
function isBacklink (ptx: TxCollectionCUD, hierarchy: Hierarchy): boolean {
@@ -508,6 +516,20 @@ export async function IsChannelMessage (
return space !== undefined
}
+/**
+ * @public
+ */
+export async function IsThreadMessage (
+ tx: Tx,
+ doc: Doc,
+ user: Ref,
+ type: NotificationType,
+ control: TriggerControl
+): Promise {
+ const space = (await control.findAll(chunter.class.DirectMessage, { _id: doc.space }))[0]
+ return space !== undefined
+}
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
@@ -520,6 +542,7 @@ export default async () => ({
ChannelHTMLPresenter: channelHTMLPresenter,
ChannelTextPresenter: channelTextPresenter,
IsDirectMessage,
+ IsThreadMessage,
IsMeMentioned,
IsChannelMessage
}
diff --git a/server-plugins/chunter/src/index.ts b/server-plugins/chunter/src/index.ts
index ebcca7bdd1..88c64b52bc 100644
--- a/server-plugins/chunter/src/index.ts
+++ b/server-plugins/chunter/src/index.ts
@@ -49,6 +49,7 @@ export default plugin(serverChunterId, {
ChannelTextPresenter: '' as Resource,
IsDirectMessage: '' as TypeMatchFunc,
IsChannelMessage: '' as TypeMatchFunc,
+ IsThreadMessage: '' as TypeMatchFunc,
IsMeMentioned: '' as TypeMatchFunc
}
})