mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-05 09:17:41 +02:00
250 lines
7.2 KiB
TypeScript
250 lines
7.2 KiB
TypeScript
//
|
|
// Copyright © 2025 Hardcore Engineering Inc.
|
|
//
|
|
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License. You may
|
|
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
//
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
import type { Class, Doc, Ref, WithLookup } from '@hcengineering/core'
|
|
import {
|
|
navigate,
|
|
type Location,
|
|
getCurrentResolvedLocation,
|
|
getLocation,
|
|
locationStorageKeyId,
|
|
getCurrentLocation
|
|
} from '@hcengineering/ui'
|
|
import { inboxId } from '@hcengineering/inbox'
|
|
import { type MessageID, type Notification } from '@hcengineering/communication-types'
|
|
import { decodeObjectURI, encodeObjectURI } from '@hcengineering/view'
|
|
import activity, { type ActivityMessage } from '@hcengineering/activity'
|
|
import {
|
|
type ActivityInboxNotification,
|
|
type DocNotifyContext,
|
|
type InboxNotification
|
|
} from '@hcengineering/notification'
|
|
import { getResource } from '@hcengineering/platform'
|
|
import chunter, { type ThreadMessage } from '@hcengineering/chunter'
|
|
import { isActivityMessageClass, messageInFocus } from '@hcengineering/activity-resources'
|
|
import { getClient } from '@hcengineering/presentation'
|
|
import { isMentionNotification, isReactionNotification } from '@hcengineering/notification-resources'
|
|
import { type NavigationItem } from './type'
|
|
|
|
// Url: /inbox/{_class}&{_id}/{thread}?message={messageId}
|
|
|
|
export function getDocInfoFromLocation (loc: Location): Pick<Doc, '_id' | '_class'> | undefined {
|
|
if (loc.path[2] !== inboxId) {
|
|
return undefined
|
|
}
|
|
|
|
const [_id, _class] = decodeObjectURI(loc.path[3])
|
|
|
|
if (_id == null || _class == null) return undefined
|
|
if (_id === '' || _class === '') return undefined
|
|
|
|
return {
|
|
_id,
|
|
_class
|
|
}
|
|
}
|
|
|
|
export function getMessageInfoFromLocation (loc: Location):
|
|
| {
|
|
id: Ref<ActivityMessage> | MessageID
|
|
date?: Date
|
|
}
|
|
| undefined {
|
|
if (loc.path[2] !== inboxId) return undefined
|
|
if (loc.query?.message == null || loc.query.message === '') return undefined
|
|
|
|
const [id, date] = decodeURIComponent(loc.query.message).split(':')
|
|
|
|
if (id == null || id === '') return undefined
|
|
|
|
return {
|
|
id: id as any,
|
|
date: date != null ? new Date(date) : undefined
|
|
}
|
|
}
|
|
|
|
export function navigateToDoc (
|
|
navItem: NavigationItem,
|
|
doc: Doc,
|
|
notification?: InboxNotification | Notification
|
|
): void {
|
|
if (navItem.type === 'legacy') {
|
|
void selectInboxContext(navItem.context, doc, notification as InboxNotification)
|
|
return
|
|
}
|
|
|
|
const loc = getCurrentResolvedLocation()
|
|
|
|
loc.path[2] = inboxId
|
|
loc.path[3] = encodeObjectURI(navItem._id, navItem._class)
|
|
|
|
loc.path[4] = ''
|
|
loc.path.length = 4
|
|
|
|
delete loc.fragment
|
|
|
|
const nn = notification as Notification | undefined
|
|
if (nn?.message != null) {
|
|
loc.query = {
|
|
...loc.query,
|
|
message: encodeURIComponent(`${nn.messageId}:${nn.message.created.toISOString()}`)
|
|
}
|
|
} else {
|
|
delete loc.query?.message
|
|
}
|
|
|
|
navigate(loc)
|
|
}
|
|
|
|
export function closeDoc (): void {
|
|
const loc = getCurrentResolvedLocation()
|
|
|
|
loc.path[2] = inboxId
|
|
loc.path[3] = ''
|
|
loc.path[4] = ''
|
|
loc.path.length = 3
|
|
|
|
delete loc.query?.message
|
|
delete loc.fragment
|
|
|
|
localStorage.setItem(`${locationStorageKeyId}_${inboxId}`, JSON.stringify(loc))
|
|
|
|
navigate(loc)
|
|
}
|
|
|
|
async function navigateToInboxDoc (
|
|
context: Ref<DocNotifyContext>,
|
|
_id: Ref<Doc>,
|
|
_class: Ref<Class<Doc>>,
|
|
thread?: Ref<ActivityMessage>,
|
|
message?: Ref<ActivityMessage>
|
|
): Promise<void> {
|
|
const loc = getLocation()
|
|
|
|
if (loc.path[2] !== inboxId) {
|
|
return
|
|
}
|
|
|
|
loc.path[3] = encodeObjectURI(_id, _class)
|
|
|
|
if (thread !== undefined) {
|
|
loc.path[4] = thread
|
|
loc.path.length = 5
|
|
const fn = await getResource(chunter.function.OpenThreadInSidebar)
|
|
void fn(thread, undefined, undefined, message, { autofocus: false })
|
|
} else {
|
|
loc.path[4] = ''
|
|
loc.path.length = 4
|
|
}
|
|
|
|
loc.query = { ...loc.query, context, message: message ?? null }
|
|
messageInFocus.set(message)
|
|
navigate(loc)
|
|
}
|
|
|
|
export async function selectInboxContext (
|
|
context: DocNotifyContext,
|
|
doc?: Doc,
|
|
notification?: WithLookup<InboxNotification>
|
|
): Promise<void> {
|
|
const client = getClient()
|
|
const hierarchy = client.getHierarchy()
|
|
const { objectId, objectClass } = context
|
|
const loc = getCurrentLocation()
|
|
|
|
if (isMentionNotification(notification) && isActivityMessageClass(notification.mentionedInClass)) {
|
|
const selectedMsg = notification.mentionedIn as Ref<ActivityMessage>
|
|
|
|
void navigateToInboxDoc(
|
|
context._id,
|
|
objectId,
|
|
objectClass,
|
|
isActivityMessageClass(objectClass) ? (objectId as Ref<ActivityMessage>) : undefined,
|
|
selectedMsg
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
if (isReactionNotification(notification)) {
|
|
const thread = hierarchy.isDerived(context.objectClass, activity.class.ActivityMessage)
|
|
? context.objectId
|
|
: undefined
|
|
const reactedTo = await client.findOne(activity.class.ActivityMessage, { _id: notification.attachedTo })
|
|
const isThread = reactedTo != null && hierarchy.isDerived(reactedTo._class, chunter.class.ThreadMessage)
|
|
const channelId = isThread ? (reactedTo as ThreadMessage)?.objectId : (reactedTo?.attachedTo ?? objectId)
|
|
const channelClass = isThread
|
|
? (reactedTo as ThreadMessage)?.objectClass
|
|
: (reactedTo?.attachedToClass ?? objectClass)
|
|
|
|
void navigateToInboxDoc(
|
|
context._id,
|
|
channelId,
|
|
channelClass,
|
|
thread as Ref<ActivityMessage>,
|
|
notification.attachedTo
|
|
)
|
|
return
|
|
}
|
|
|
|
if (hierarchy.isDerived(objectClass, activity.class.ActivityMessage)) {
|
|
const message = (notification as WithLookup<ActivityInboxNotification>)?.$lookup?.attachedTo
|
|
|
|
if (objectClass === chunter.class.ThreadMessage) {
|
|
const thread =
|
|
doc?._id === objectId
|
|
? (doc as ThreadMessage)
|
|
: await client.findOne(
|
|
chunter.class.ThreadMessage,
|
|
{
|
|
_id: objectId as Ref<ThreadMessage>
|
|
},
|
|
{ projection: { _id: 1, attachedTo: 1 } }
|
|
)
|
|
|
|
void navigateToInboxDoc(
|
|
context._id,
|
|
thread?.objectId ?? objectId,
|
|
thread?.objectClass ?? objectClass,
|
|
thread?.attachedTo,
|
|
thread?._id
|
|
)
|
|
return
|
|
}
|
|
|
|
const selectedMsg = (notification as ActivityInboxNotification)?.attachedTo
|
|
const thread = selectedMsg !== objectId ? objectId : loc.path[4] === objectId ? objectId : undefined
|
|
const channelId = (doc as ActivityMessage)?.attachedTo ?? message?.attachedTo ?? objectId
|
|
const channelClass = (doc as ActivityMessage)?.attachedToClass ?? message?.attachedToClass ?? objectClass
|
|
|
|
void navigateToInboxDoc(
|
|
context._id,
|
|
channelId,
|
|
channelClass,
|
|
thread as Ref<ActivityMessage>,
|
|
selectedMsg ?? (objectId as Ref<ActivityMessage>)
|
|
)
|
|
return
|
|
}
|
|
|
|
void navigateToInboxDoc(
|
|
context._id,
|
|
objectId,
|
|
objectClass,
|
|
undefined,
|
|
(notification as ActivityInboxNotification)?.attachedTo
|
|
)
|
|
}
|