mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
[UBER-783, UBERF-61] Messsage thread notification fixes (#3640)
Signed-off-by: Oleg Solodkov <oleg.solodkov@xored.com>
This commit is contained in:
parent
93fd82a797
commit
af73876255
@ -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, {
|
||||
|
@ -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,
|
||||
|
@ -23,6 +23,7 @@
|
||||
"Comment": "Comment",
|
||||
"Message": "Message",
|
||||
"MessageOn": "Message on",
|
||||
"On": "on",
|
||||
"Reference": "Reference",
|
||||
"Chat": "Chat",
|
||||
"In": "In",
|
||||
|
@ -23,6 +23,7 @@
|
||||
"Comment": "Комментарий",
|
||||
"Message": "Сообщение",
|
||||
"MessageOn": "Сообщение в",
|
||||
"On": "в",
|
||||
"MentionNotification": "Упомянул",
|
||||
"Reference": "Ссылка",
|
||||
"Chat": "Чат",
|
||||
|
@ -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}
|
||||
<div class="flex-presenter inline-presenter">
|
||||
<div class="icon">
|
||||
<Icon icon={chunter.icon.Thread} size={'small'} />
|
||||
</div>
|
||||
<span class="labels-row" style:text-transform={'lowercase'}>
|
||||
<Label label={chunter.string.MessageOn} />
|
||||
</span>
|
||||
|
||||
<div class="flex-presenter">
|
||||
{#if isThreadMessage}
|
||||
<div class="icon">
|
||||
<Icon icon={chunter.icon.Thread} size="small" />
|
||||
</div>
|
||||
<span class="labels-row" style:text-transform="lowercase">
|
||||
<Label label={chunterResources.string.On} />
|
||||
</span>
|
||||
|
||||
{/if}
|
||||
<svelte:component this={presenter.presenter} value={doc} inline {disabled} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -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<Ref<Doc>, 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<Ref<Person>>, map: IdMap<Person>) {
|
||||
showReplies = []
|
||||
for (const employee of employees) {
|
||||
@ -55,6 +68,9 @@
|
||||
<div class="whitespace-nowrap ml-2 mr-2 over-underline">
|
||||
<Label label={chunter.string.RepliesCount} params={{ replies: message.replies?.length ?? 0 }} />
|
||||
</div>
|
||||
{#if hasNew}
|
||||
<div class="marker" />
|
||||
{/if}
|
||||
{#if (message.replies?.length ?? 0) > 1}
|
||||
<div class="mr-1">
|
||||
<Label label={chunter.string.LastReply} />
|
||||
@ -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);
|
||||
}
|
||||
</style>
|
||||
|
@ -156,11 +156,12 @@
|
||||
|
||||
function newMessagesStart (comments: ThreadMessage[], docUpdates: Map<Ref<Doc>, 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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
})
|
||||
|
@ -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<Doc> | undefined
|
||||
let _class: Ref<Class<Doc>> | undefined
|
||||
let selectedEmployee: Ref<PersonAccount> | 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<Doc>) {
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,7 +760,7 @@
|
||||
<SpaceView {currentSpace} {currentView} {createItemDialog} {createItemLabel} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if asideId}
|
||||
{#if asideId && currentSpace}
|
||||
{@const asideComponent = navigatorModel?.aside ?? currentApplication?.aside}
|
||||
{#if asideComponent !== undefined}
|
||||
<div class="splitter" class:hovered={isResizing} on:mousedown={startResize} />
|
||||
|
@ -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<boolean> {
|
||||
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<DirectMessage> }))[0]
|
||||
return dm !== undefined
|
||||
}
|
||||
|
||||
function isBacklink (ptx: TxCollectionCUD<Doc, Backlink>, 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<Account>,
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
): Promise<boolean> {
|
||||
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
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ export default plugin(serverChunterId, {
|
||||
ChannelTextPresenter: '' as Resource<Presenter>,
|
||||
IsDirectMessage: '' as TypeMatchFunc,
|
||||
IsChannelMessage: '' as TypeMatchFunc,
|
||||
IsThreadMessage: '' as TypeMatchFunc,
|
||||
IsMeMentioned: '' as TypeMatchFunc
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user