TSK-1341 Remove last view (#3115)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2023-04-29 22:46:13 +07:00
committed by GitHub
parent 9b04d366e3
commit ae8fcf8d62
41 changed files with 204 additions and 645 deletions
@@ -22,9 +22,8 @@
export let size: IconSize = 'small'
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
$: lastView = $lastViews[object._id]
$: subscribed = lastView !== undefined && lastView !== -1
const store = notificationClient.docUpdatesStore
$: subscribed = $store.get(object._id) !== undefined
</script>
{#if subscribed}
@@ -15,8 +15,8 @@
<script lang="ts">
import attachment, { Attachment } from '@hcengineering/attachment'
import type { ChunterMessage, Message } from '@hcengineering/chunter'
import core, { Ref, Space, Timestamp, WithLookup } from '@hcengineering/core'
import { LastView } from '@hcengineering/notification'
import core, { Doc, Ref, Space, Timestamp, WithLookup } from '@hcengineering/core'
import { DocUpdates } from '@hcengineering/notification'
import { NotificationClientImpl } from '@hcengineering/notification-resources'
import { createQuery } from '@hcengineering/presentation'
import { location as locationStore } from '@hcengineering/ui'
@@ -69,11 +69,11 @@
}
})
let messages: WithLookup<Message>[] | undefined
let messages: WithLookup<Message>[] = []
const query = createQuery()
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
const docUpdates = notificationClient.docUpdatesStore
$: updateQuery(space)
@@ -90,8 +90,8 @@
},
(res) => {
messages = res
newMessagesPos = newMessagesStart(messages)
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
newMessagesPos = newMessagesStart(messages, $docUpdates)
notificationClient.read(space)
},
{
lookup: {
@@ -102,22 +102,22 @@
)
}
function newMessagesStart (messages: Message[]): number {
function newMessagesStart (messages: Message[], docUpdates: Map<Ref<Doc>, DocUpdates>): number {
if (space === undefined) return -1
const lastView = ($lastViews as any)[space]
if (lastView === undefined || lastView === -1) return -1
const docUpdate = docUpdates.get(space)
const lastView = docUpdate?.txes?.[0]?.[1]
if (docUpdate === undefined || lastView === undefined) return -1
for (let index = 0; index < messages.length; index++) {
const message = messages[index]
if (message.createOn > lastView) return index
if (message.createOn >= lastView) return index
}
return -1
}
$: markUnread($lastViews)
function markUnread (lastViews: LastView) {
if (messages === undefined) return
const newPos = newMessagesStart(messages)
if (newPos !== -1 || newMessagesPos === -1) {
$: markUnread(messages, $docUpdates)
function markUnread (messages: Message[], docUpdates: Map<Ref<Doc>, DocUpdates>) {
const newPos = newMessagesStart(messages, docUpdates)
if (newPos !== -1) {
newMessagesPos = newPos
}
}
@@ -165,7 +165,7 @@
}
let showFixed: boolean | undefined
let selectedDate: Timestamp | undefined = messages ? getDay(messages[0].createOn) : undefined
let selectedDate: Timestamp | undefined = undefined
function handleScroll () {
const upperVisible = getFirstVisible()
if (upperVisible) {
@@ -18,15 +18,7 @@
import type { ChunterSpace, Message, ThreadMessage } from '@hcengineering/chunter'
import contact, { Employee, EmployeeAccount, getName } from '@hcengineering/contact'
import { employeeByIdStore } from '@hcengineering/contact-resources'
import core, {
FindOptions,
generateId,
getCurrentAccount,
IdMap,
Ref,
SortingOrder,
TxFactory
} from '@hcengineering/core'
import core, { FindOptions, IdMap, Ref, SortingOrder, generateId, getCurrentAccount } from '@hcengineering/core'
import { NotificationClientImpl } from '@hcengineering/notification-resources'
import { createQuery, getClient } from '@hcengineering/presentation'
import { Label } from '@hcengineering/ui'
@@ -97,7 +89,7 @@
} else {
comments = res.reverse()
}
notificationClient.updateLastView(id, chunter.class.Message)
notificationClient.read(id)
},
options
)
@@ -130,8 +122,7 @@
if (parent === undefined) return
const { message, attachments } = event.detail
const me = getCurrentAccount()._id
const txFactory = new TxFactory(me)
const tx = txFactory.createTxCreateDoc<ThreadMessage>(
await client.createDoc(
chunter.class.ThreadMessage,
parent.space,
{
@@ -145,9 +136,6 @@
},
commentId
)
tx.attributes.createOn = tx.modifiedOn
await notificationClient.updateLastView(_id, chunter.class.Message, tx.modifiedOn, true)
await client.tx(tx)
// Create an backlink to document
await createBacklinks(client, parent._id, parent._class, commentId, message)
@@ -16,8 +16,8 @@
import attachment, { Attachment } from '@hcengineering/attachment'
import { AttachmentRefInput } from '@hcengineering/attachment-resources'
import type { ChunterMessage, Message, ThreadMessage } from '@hcengineering/chunter'
import core, { Ref, Space, generateId, getCurrentAccount } from '@hcengineering/core'
import { LastView } from '@hcengineering/notification'
import core, { Doc, Ref, Space, generateId, getCurrentAccount } from '@hcengineering/core'
import { DocUpdates } from '@hcengineering/notification'
import { NotificationClientImpl } from '@hcengineering/notification-resources'
import { createQuery, getClient } from '@hcengineering/presentation'
import { IconClose, Label, getCurrentResolvedLocation, navigate } from '@hcengineering/ui'
@@ -59,7 +59,7 @@
})
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
const docUpdates = notificationClient.docUpdatesStore
const lookup = {
_id: { attachments: attachment.class.Attachment, reactions: chunter.class.Reaction },
@@ -101,8 +101,8 @@
},
(res) => {
comments = res
newMessagesPos = newMessagesStart(comments, $lastViews)
notificationClient.updateLastView(id, chunter.class.Message)
newMessagesPos = newMessagesStart(comments, $docUpdates)
notificationClient.read(id)
},
{
lookup
@@ -159,23 +159,25 @@
}
let comments: ThreadMessage[] = []
function newMessagesStart (comments: ThreadMessage[], lastViews: LastView): number {
const lastView = (lastViews as any)[_id]
if (lastView === undefined || lastView === -1) return -1
function newMessagesStart (comments: ThreadMessage[], docUpdates: Map<Ref<Doc>, DocUpdates>): number {
const docUpdate = docUpdates.get(_id)
const lastView = docUpdate?.txes?.[0]?.[1]
if (docUpdate === undefined || lastView === undefined) return -1
for (let index = 0; index < comments.length; index++) {
const comment = comments[index]
if (comment.createOn > lastView) return index
if (comment.createOn >= lastView) return index
}
return -1
}
$: markUnread($lastViews)
function markUnread (lastViews: LastView) {
const newPos = newMessagesStart(comments, lastViews)
if (newPos !== -1 || newMessagesPos === -1) {
$: markUnread(comments, $docUpdates)
function markUnread (comments: ThreadMessage[], docUpdates: Map<Ref<Doc>, DocUpdates>) {
const newPos = newMessagesStart(comments, docUpdates)
if (newPos !== -1) {
newMessagesPos = newPos
}
}
let newMessagesPos: number = -1
let loading = false
</script>
+10 -4
View File
@@ -67,12 +67,12 @@ export { CommentPopup, CommentsPresenter }
async function MarkUnread (object: Message): Promise<void> {
const client = NotificationClientImpl.getClient()
await client.updateLastView(object.space, chunter.class.ChunterSpace, object.createOn - 1, true)
await client.forceRead(object.space, chunter.class.ChunterSpace)
}
async function MarkCommentUnread (object: ThreadMessage): Promise<void> {
const client = NotificationClientImpl.getClient()
await client.updateLastView(object.attachedTo, object.attachedToClass, object.createOn - 1, true)
await client.forceRead(object.attachedTo, object.attachedToClass)
}
async function SubscribeMessage (object: Message): Promise<void> {
@@ -117,14 +117,20 @@ async function UnsubscribeMessage (object: ChunterMessage): Promise<void> {
}
}
)
await notificationClient.unsubscribe(object.attachedTo)
const docUpdate = notificationClient.docUpdatesMap.get(object.attachedTo)
if (docUpdate !== undefined) {
await client.remove(docUpdate)
}
} else {
await client.updateMixin(object._id, object._class, object.space, notification.mixin.Collaborators, {
$pull: {
collaborators: acc._id
}
})
await notificationClient.unsubscribe(object._id)
const docUpdate = notificationClient.docUpdatesMap.get(object._id)
if (docUpdate !== undefined) {
await client.remove(docUpdate)
}
}
}
@@ -17,7 +17,7 @@
import type { Channel, ChannelProvider } from '@hcengineering/contact'
import contact from '@hcengineering/contact'
import type { AttachedData, Doc, Ref } from '@hcengineering/core'
import notification, { LastView } from '@hcengineering/notification'
import notification, { DocUpdates } from '@hcengineering/notification'
import { Asset, IntlString, getResource } from '@hcengineering/platform'
import presentation from '@hcengineering/presentation'
import {
@@ -50,8 +50,8 @@
export let focusIndex = -1
export let restricted: Ref<ChannelProvider>[] = []
let lastViews: Writable<LastView | undefined> = writable()
getResource(notification.function.GetNotificationClient).then((res) => (lastViews = res().getLastViews()))
let docUpdates: Writable<Map<Ref<Doc>, DocUpdates>> = writable(new Map())
getResource(notification.function.GetNotificationClient).then((res) => (docUpdates = res().docUpdatesStore))
const dispatch = createEventDispatcher()
interface Item {
@@ -70,11 +70,11 @@
function getProvider (
item: AttachedData<Channel>,
map: Map<Ref<ChannelProvider>, ChannelProvider>,
lastViews: LastView | undefined
docUpdates: Map<Ref<Doc>, DocUpdates>
): Item | undefined {
const provider = map.get(item.provider)
if (provider) {
const notification = (item as Channel)._id !== undefined ? isNew(item as Channel, lastViews) : false
const notification = (item as Channel)._id !== undefined ? isNew(item as Channel, docUpdates) : false
return {
label: provider.label,
icon: provider.icon as Asset,
@@ -92,16 +92,14 @@
}
}
function isNew (item: Channel, lastViews: LastView | undefined): boolean {
if (item.lastMessage === undefined) return false
const lastView =
(item as Channel)._id !== undefined && lastViews !== undefined ? lastViews[(item as Channel)._id] : undefined
return lastView ? lastView < item.lastMessage : (item.items ?? 0) > 0
function isNew (item: Channel, docUpdates: Map<Ref<Doc>, DocUpdates>): boolean {
const docUpdate = docUpdates.get(item._id)
return docUpdate ? docUpdate.txes.length > 0 : (item.items ?? 0) > 0
}
async function update (
value: AttachedData<Channel>[] | Channel | null,
lastViews: LastView | undefined,
docUpdates: Map<Ref<Doc>, DocUpdates>,
channelProviders: ChannelProvider[]
) {
if (value == null) {
@@ -112,13 +110,13 @@
const map = getChannelProviders(channelProviders)
if (Array.isArray(value)) {
for (const item of value) {
const provider = getProvider(item, map, lastViews)
const provider = getProvider(item, map, docUpdates)
if (provider !== undefined) {
result.push(provider)
}
}
} else {
const provider = getProvider(value, map, lastViews)
const provider = getProvider(value, map, docUpdates)
if (provider !== undefined) {
result.push(provider)
}
@@ -127,7 +125,7 @@
updateMenu(displayItems, channelProviders)
}
$: if (value) update(value, $lastViews, $channelProviders)
$: if (value) update(value, $docUpdates, $channelProviders)
let displayItems: Item[] = []
let actions: Action[] = []
@@ -148,7 +146,7 @@
icon: pr.icon ?? contact.icon.SocialEdit,
label: pr.label,
action: async () => {
const provider = getProvider({ provider: pr._id, value: '' }, getChannelProviders(providers), $lastViews)
const provider = getProvider({ provider: pr._id, value: '' }, getChannelProviders(providers), $docUpdates)
if (provider !== undefined) {
if (_displayItems.filter((it) => it.provider === pr._id).length === 0) {
displayItems = [..._displayItems, provider]
@@ -16,8 +16,8 @@
<script lang="ts">
import type { Channel, ChannelProvider } from '@hcengineering/contact'
import type { AttachedData, Doc, Ref } from '@hcengineering/core'
import notification, { LastView } from '@hcengineering/notification'
import { Asset, getResource, IntlString } from '@hcengineering/platform'
import notification, { DocUpdates } from '@hcengineering/notification'
import { Asset, IntlString, getResource } from '@hcengineering/platform'
import type { AnyComponent } from '@hcengineering/ui'
import { Button } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
@@ -31,8 +31,8 @@
export let reverse: boolean = false
export let integrations: Set<Ref<Doc>> = new Set<Ref<Doc>>()
let lastViews: Writable<LastView | undefined> = writable()
getResource(notification.function.GetNotificationClient).then((res) => (lastViews = res().getLastViews()))
let docUpdates: Writable<Map<Ref<Doc>, DocUpdates>> = writable(new Map())
getResource(notification.function.GetNotificationClient).then((res) => (docUpdates = res().docUpdatesStore))
interface Item {
label: IntlString
@@ -48,11 +48,11 @@
function getProvider (
item: AttachedData<Channel>,
map: Map<Ref<ChannelProvider>, ChannelProvider>,
lastViews: LastView | undefined
docUpdates: Map<Ref<Doc>, DocUpdates>
): any | undefined {
const provider = map.get(item.provider)
if (provider) {
const notification = (item as Channel)._id !== undefined ? isNew(item as Channel, lastViews) : false
const notification = (item as Channel)._id !== undefined ? isNew(item as Channel, docUpdates) : false
return {
label: provider.label,
icon: provider.icon as Asset,
@@ -66,16 +66,14 @@
}
}
function isNew (item: Channel, lastViews: LastView | undefined): boolean {
if (item.lastMessage === undefined) return false
const lastView =
(item as Channel)._id !== undefined && lastViews !== undefined ? lastViews[(item as Channel)._id] : undefined
return lastView ? lastView < item.lastMessage : (item.items ?? 0) > 0
function isNew (item: Channel, docUpdates: Map<Ref<Doc>, DocUpdates>): boolean {
const docUpdate = docUpdates.get(item._id)
return docUpdate ? docUpdate.txes.length > 0 : (item.items ?? 0) > 0
}
async function update (
value: AttachedData<Channel>[] | Channel | null,
lastViews: LastView | undefined,
docUpdates: Map<Ref<Doc>, DocUpdates>,
channels: ChannelProvider[]
) {
if (value === null) {
@@ -86,13 +84,13 @@
const map = getChannelProviders(channels)
if (Array.isArray(value)) {
for (const item of value) {
const provider = getProvider(item, map, lastViews)
const provider = getProvider(item, map, docUpdates)
if (provider !== undefined) {
result.push(provider)
}
}
} else {
const provider = getProvider(value, map, lastViews)
const provider = getProvider(value, map, docUpdates)
if (provider !== undefined) {
result.push(provider)
}
@@ -100,7 +98,7 @@
displayItems = result
}
$: if (value) update(value, $lastViews, $channelProviders)
$: if (value) update(value, $docUpdates, $channelProviders)
let displayItems: Item[] = []
let divHTML: HTMLElement
@@ -60,7 +60,6 @@
export let embedded = false
let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class
const query = createQuery()
@@ -79,17 +78,15 @@
function read (_id: Ref<Doc>) {
if (lastId !== _id) {
const prev = lastId
const prevClass = lastClass
lastId = _id
lastClass = _class
notificationClient.then((client) => client.updateLastView(prev, prevClass))
notificationClient.then((client) => client.read(prev))
}
}
const currentUser = getCurrentAccount() as EmployeeAccount
onDestroy(async () => {
notificationClient.then((client) => client.updateLastView(_id, _class))
notificationClient.then((client) => client.read(_id))
})
let requests: DocumentRequest[] = []
@@ -46,7 +46,7 @@
{ attachedTo: channelId },
(res) => {
messages = res
notificationClient.updateLastView(channelId, channel._class, undefined, true)
notificationClient.read(channelId)
},
{ sort: { sendOn: SortingOrder.Descending } }
)
@@ -68,7 +68,7 @@
messages: convertMessages(object, channel, selectedMessages, $employeeAccountByIdStore, $employeeByIdStore)
}
)
await notificationClient.updateLastView(channel._id, channel._class, undefined, true)
await notificationClient.read(channel._id)
clear()
}
@@ -78,7 +78,7 @@
async function selectHandler (e: CustomEvent): Promise<void> {
currentMessage = e.detail
if (channel !== undefined) {
await notificationClient.updateLastView(channel._id, channel._class, undefined, true)
await notificationClient.read(channel._id)
}
}
@@ -73,7 +73,7 @@
},
objectId
)
await notificationClient.updateLastView(channel._id, channel._class, undefined, true)
await notificationClient.read(channel._id)
objectId = generateId()
dispatch('close')
}
@@ -92,7 +92,7 @@
.map((m) => m.trim())
.filter((m) => m.length)
})
await notificationClient.updateLastView(channel._id, channel._class, undefined, true)
await notificationClient.read(channel._id)
for (const attachment of attachments) {
await client.addCollection(
attachmentP.class.Attachment,
-1
View File
@@ -1,6 +1,5 @@
{
"string": {
"LastView": "Last View",
"Notification": "Notification",
"Notifications": "Notifications",
"NoNotifications": "No notifications",
-1
View File
@@ -1,6 +1,5 @@
{
"string": {
"LastView": "Последний просмотр",
"Notification": "Увдомление",
"Notifications": "Уведомления",
"NoNotifications": "Нет уведомлений",
@@ -13,8 +13,8 @@
// limitations under the License.
-->
<script lang="ts">
import contact, { EmployeeAccount } from '@hcengineering/contact'
import { Doc, getCurrentAccount, Ref } from '@hcengineering/core'
import { EmployeeAccount } from '@hcengineering/contact'
import { getCurrentAccount, Ref } from '@hcengineering/core'
import {
NotificationProvider,
NotificationSetting,
@@ -26,14 +26,10 @@
import { getCurrentLocation, showPanel } from '@hcengineering/ui'
import view from '@hcengineering/view'
import notification from '../plugin'
import { NotificationClientImpl } from '../utils'
const query = createQuery()
const settingQuery = createQuery()
const providersQuery = createQuery()
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
const lastViewId: Ref<Doc> = ((getCurrentAccount() as EmployeeAccount).employee + 'notification') as Ref<Doc>
let settingsReceived = false
let settings: Map<Ref<NotificationType>, NotificationSetting> = new Map<Ref<NotificationType>, NotificationSetting>()
@@ -129,16 +125,6 @@
alreadyShown.clear()
}, 5000)
const lastView = ($lastViews as any)[lastViewId]
if ((lastView ?? notifyInstance.modifiedOn) > 0) {
await notificationClient.updateLastView(
lastViewId,
contact.class.Employee,
notifyInstance.modifiedOn,
lastView === undefined
)
}
// eslint-disable-next-line
const notification = new Notification(getCurrentLocation().path[1], {
tag: notifyInstance._id,
@@ -24,7 +24,7 @@
const store = notificationClient.docUpdatesStore
$: docUpdate = $store.get(value._id)
$: hasNotification = (docUpdate?.txes?.length ?? 0) > 0
$: hasNotification = (docUpdate?.txes?.length ?? 0) > 0 && docUpdate?.hidden !== true
</script>
{#if hasNotification}
+46 -52
View File
@@ -14,44 +14,35 @@
// limitations under the License.
//
import core, { Account, Class, Doc, getCurrentAccount, Ref, Timestamp } from '@hcengineering/core'
import notification, { DocUpdates, LastView, NotificationClient } from '@hcengineering/notification'
import { Account, Class, Doc, getCurrentAccount, Ref } from '@hcengineering/core'
import notification, { Collaborators, DocUpdates, NotificationClient } from '@hcengineering/notification'
import { createQuery, getClient } from '@hcengineering/presentation'
import { get, writable, Writable } from 'svelte/store'
import { writable } from 'svelte/store'
/**
* @public
*/
export class NotificationClientImpl implements NotificationClient {
protected static _instance: NotificationClientImpl | undefined = undefined
private readonly lastViewsStore = writable<LastView>()
readonly docUpdatesStore = writable<Map<Ref<Doc>, DocUpdates>>(new Map())
docUpdatesMap: Map<Ref<Doc>, DocUpdates> = new Map()
readonly docUpdates = writable<DocUpdates[]>([])
private readonly docUpdatesQuery = createQuery(true)
private readonly lastViewQuery = createQuery()
private readonly user: Ref<Account>
private constructor () {
this.user = getCurrentAccount()._id
this.lastViewQuery.query(notification.class.LastView, { user: this.user }, (result) => {
this.lastViewsStore.set(result[0])
if (result[0] === undefined) {
const client = getClient()
const u = client.txFactory.createTxCreateDoc(notification.class.LastView, notification.space.Notifications, {
user: this.user
})
u.space = core.space.DerivedTx
void client.tx(u)
}
})
this.docUpdatesQuery.query(
notification.class.DocUpdates,
{
user: this.user
},
(result) => {
this.docUpdatesStore.set(new Map(result.map((p) => [p.attachedTo, p])))
this.docUpdates.set(result)
this.docUpdatesMap = new Map(result.map((p) => [p.attachedTo, p]))
this.docUpdatesStore.set(this.docUpdatesMap)
}
)
}
@@ -67,46 +58,49 @@ export class NotificationClientImpl implements NotificationClient {
return NotificationClientImpl._instance
}
getLastViews (): Writable<LastView> {
return this.lastViewsStore
}
async updateLastView (
_id: Ref<Doc>,
_class: Ref<Class<Doc>>,
time?: Timestamp,
force: boolean = false
): Promise<void> {
async read (_id: Ref<Doc>): Promise<void> {
const client = getClient()
const hierarchy = client.getHierarchy()
const mixin = hierarchy.classHierarchyMixin(_class, notification.mixin.TrackedDoc)
if (mixin === undefined) return
const lastView = time ?? new Date().getTime()
const obj = get(this.lastViewsStore)
if (obj !== undefined) {
const current = obj[_id] as Timestamp | undefined
if (current !== undefined || force) {
if (current === -1 && !force) return
if (force || (current ?? 0) < lastView) {
const u = client.txFactory.createTxUpdateDoc(obj._class, obj.space, obj._id, {
[_id]: lastView
})
u.space = core.space.DerivedTx
await client.tx(u)
}
}
const docUpdate = this.docUpdatesMap.get(_id)
if (docUpdate !== undefined) {
await client.update(docUpdate, { txes: [] })
}
}
async unsubscribe (_id: Ref<Doc>): Promise<void> {
async forceRead (_id: Ref<Doc>, _class: Ref<Class<Doc>>): Promise<void> {
const client = getClient()
const obj = get(this.lastViewsStore)
if (obj !== undefined) {
const u = client.txFactory.createTxUpdateDoc(obj._class, obj.space, obj._id, {
[_id]: -1
})
u.space = core.space.DerivedTx
await client.tx(u)
const docUpdate = this.docUpdatesMap.get(_id)
if (docUpdate !== undefined) {
await client.update(docUpdate, { txes: [] })
} else {
const doc = await client.findOne(_class, { _id })
if (doc !== undefined) {
const hiearachy = client.getHierarchy()
const collab = hiearachy.as<Doc, Collaborators>(doc, notification.mixin.Collaborators)
if (collab.collaborators === undefined) {
await client.createMixin<Doc, Collaborators>(
collab._id,
collab._class,
collab.space,
notification.mixin.Collaborators,
{
collaborators: [this.user]
}
)
} else if (!collab.collaborators.includes(this.user)) {
await client.updateMixin(collab._id, collab._class, collab.space, notification.mixin.Collaborators, {
$push: {
collaborators: this.user
}
})
}
await client.createDoc(notification.class.DocUpdates, doc.space, {
attachedTo: _id,
attachedToClass: _class,
user: this.user,
hidden: true,
txes: []
})
}
}
}
}
+5 -36
View File
@@ -34,14 +34,6 @@ import { Writable } from './types'
import { Preference } from '@hcengineering/preference'
export * from './types'
/**
* @public
*/
export interface LastView extends Doc {
user: Ref<Account>
[key: string]: any
}
/**
* @public
*/
@@ -135,20 +127,6 @@ export interface NotificationSetting extends Preference {
enabled: boolean
}
/**
* @public
*/
export interface SpaceLastEdit extends Class<Doc> {
lastEditField: string
}
/**
* @public
*/
export interface AnotherUserNotifications extends Class<Doc> {
fields: string[]
}
/**
* @public
*/
@@ -156,11 +134,6 @@ export interface ClassCollaborators extends Class<Doc> {
fields: string[] // Ref<Account> | Ref<Employee> | Ref<Account>[] | Ref<Employee>[]
}
/**
* @public
*/
export interface TrackedDoc extends Class<Doc> {}
/**
* @public
*/
@@ -183,8 +156,8 @@ export interface DocUpdates extends Doc {
attachedTo: Ref<Doc>
attachedToClass: Ref<Class<Doc>>
hidden: boolean
lastTx: Ref<TxCUD<Doc>>
lastTxTime: Timestamp
lastTx?: Ref<TxCUD<Doc>>
lastTxTime?: Timestamp
txes: [Ref<TxCUD<Doc>>, Timestamp][]
}
@@ -198,9 +171,9 @@ export const notificationId = 'notification' as Plugin
*/
export interface NotificationClient {
docUpdatesStore: Writable<Map<Ref<Doc>, DocUpdates>>
getLastViews: () => Writable<LastView>
updateLastView: (_id: Ref<Doc>, _class: Ref<Class<Doc>>, time?: Timestamp, force?: boolean) => Promise<void>
unsubscribe: (_id: Ref<Doc>) => Promise<void>
docUpdates: Writable<DocUpdates[]>
read: (_id: Ref<Doc>) => Promise<void>
forceRead: (_id: Ref<Doc>, _class: Ref<Class<Doc>>, space: Ref<Space>) => Promise<void>
}
/**
@@ -213,15 +186,11 @@ export type NotificationClientFactoy = () => NotificationClient
*/
const notification = plugin(notificationId, {
mixin: {
SpaceLastEdit: '' as Ref<Mixin<SpaceLastEdit>>,
AnotherUserNotifications: '' as Ref<Mixin<AnotherUserNotifications>>,
ClassCollaborators: '' as Ref<Mixin<ClassCollaborators>>,
Collaborators: '' as Ref<Mixin<Collaborators>>,
TrackedDoc: '' as Ref<Mixin<TrackedDoc>>,
NotificationObjectPresenter: '' as Ref<Mixin<NotificationObjectPresenter>>
},
class: {
LastView: '' as Ref<Class<LastView>>,
Notification: '' as Ref<Class<Notification>>,
EmailNotification: '' as Ref<Class<EmailNotification>>,
NotificationType: '' as Ref<Class<NotificationType>>,
@@ -44,7 +44,7 @@
const notificationClient = getResource(notification.function.GetNotificationClient).then((res) => res())
onDestroy(async () => {
notificationClient.then((client) => client.updateLastView(_id, recruit.class.Vacancy))
notificationClient.then((client) => client.read(_id))
})
const client = getClient()
@@ -57,7 +57,7 @@
const prev = lastId
lastId = _id
if (prev) {
notificationClient.then((client) => client.updateLastView(prev, recruit.class.Vacancy))
notificationClient.then((client) => client.read(prev))
}
query.query(recruit.class.Vacancy, { _id }, (result) => {
object = result[0] as Required<Vacancy>
@@ -110,7 +110,7 @@
(res) => {
messages = res.reverse()
if (channel !== undefined) {
notificationClient.updateLastView(channel._id, channel._class, undefined, true)
notificationClient.read(channel._id)
}
},
{
@@ -171,7 +171,7 @@
}
)
if (channel !== undefined) {
await notificationClient.updateLastView(channel._id, channel._class, channel.modifiedOn, true)
await notificationClient.read(channel._id)
}
clear()
}
@@ -47,7 +47,6 @@
export let embedded = false
let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class
const queryClient = createQuery()
const dispatch = createEventDispatcher()
const client = getClient()
@@ -66,15 +65,13 @@
function read (_id: Ref<Doc>) {
if (lastId !== _id) {
const prev = lastId
const prevClass = lastClass
lastId = _id
lastClass = _class
notificationClient.then((client) => client.updateLastView(prev, prevClass))
notificationClient.then((client) => client.read(prev))
}
}
onDestroy(async () => {
notificationClient.then((client) => client.updateLastView(_id, _class))
notificationClient.then((client) => client.read(_id))
})
$: _id &&
@@ -46,7 +46,6 @@
export let _class: Ref<Class<IssueTemplate>>
let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class
const query = createQuery()
const dispatch = createEventDispatcher()
const client = getClient()
@@ -65,15 +64,13 @@
function read (_id: Ref<Doc>) {
if (lastId !== _id) {
const prev = lastId
const prevClass = lastClass
lastId = _id
lastClass = _class
notificationClient.then((client) => client.updateLastView(prev, prevClass))
notificationClient.then((client) => client.read(prev))
}
}
onDestroy(async () => {
notificationClient.then((client) => client.updateLastView(_id, _class))
notificationClient.then((client) => client.read(_id))
})
$: _id &&
@@ -44,7 +44,6 @@
let realObjectClass: Ref<Class<Doc>> = _class
let lastId: Ref<Doc> = _id
let lastClass: Ref<Class<Doc>> = _class
let object: Doc
const client = getClient()
@@ -55,15 +54,13 @@
function read (_id: Ref<Doc>) {
if (lastId !== _id) {
const prev = lastId
const prevClass = lastClass
lastId = _id
lastClass = _class
notificationClient.then((client) => client.updateLastView(prev, prevClass))
notificationClient.then((client) => client.read(prev))
}
}
onDestroy(async () => {
notificationClient.then((client) => client.updateLastView(_id, _class))
notificationClient.then((client) => client.read(_id))
})
const query = createQuery()
@@ -15,7 +15,7 @@
<script lang="ts">
import type { Class, Doc, Ref, Space } from '@hcengineering/core'
import core from '@hcengineering/core'
import notification, { LastView } from '@hcengineering/notification'
import { DocUpdates } from '@hcengineering/notification'
import { NotificationClientImpl } from '@hcengineering/notification-resources'
import { getResource } from '@hcengineering/platform'
import preference from '@hcengineering/preference'
@@ -98,20 +98,13 @@
}
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
const docUpdates = notificationClient.docUpdatesStore
const hierarchy = client.getHierarchy()
$: clazz = hierarchy.getClass(model.spaceClass)
$: lastEditMixin = hierarchy.as(clazz, notification.mixin.SpaceLastEdit)
function isChanged (space: Space, lastViews: LastView): boolean {
const field = lastEditMixin?.lastEditField
const lastView = lastViews[space._id]
if (lastView === undefined || lastView === -1) return false
if (field === undefined) return false
const value = (space as any)[field]
if (isNaN(value)) return false
return lastView < value
function isChanged (space: Space, docUpdates: Map<Ref<Doc>, DocUpdates>): boolean {
const update = docUpdates.get(space._id)
if (update === undefined) return false
return update.txes.length > 0 && update.hidden !== true
}
function getParentActions (): Action[] {
@@ -147,7 +140,7 @@
icon={classIcon(client, space._class)}
selected={deselect ? false : currentSpace === space._id}
actions={() => getActions(space)}
bold={isChanged(space, $lastViews)}
bold={isChanged(space, $docUpdates)}
/>
{/await}
</NavLink>
@@ -15,7 +15,7 @@
<script lang="ts">
import type { Doc, Ref, Space } from '@hcengineering/core'
import core from '@hcengineering/core'
import notification, { LastView } from '@hcengineering/notification'
import { DocUpdates } from '@hcengineering/notification'
import { NotificationClientImpl } from '@hcengineering/notification-resources'
import { IntlString, getResource } from '@hcengineering/platform'
import preference from '@hcengineering/preference'
@@ -74,20 +74,12 @@
}
const notificationClient = NotificationClientImpl.getClient()
const lastViews = notificationClient.getLastViews()
const hierarchy = client.getHierarchy()
const docUpdates = notificationClient.docUpdatesStore
function isChanged (space: Space, lastViews: LastView): boolean {
const clazz = hierarchy.getClass(space._class)
const lastEditMixin = hierarchy.as(clazz, notification.mixin.SpaceLastEdit)
const field = lastEditMixin?.lastEditField
const lastView = lastViews[space._id]
if (lastView === undefined || lastView === -1) return false
if (field === undefined) return false
const value = (space as any)[field]
if (isNaN(value)) return false
return lastView < value
function isChanged (space: Space, docUpdates: Map<Ref<Doc>, DocUpdates>): boolean {
const update = docUpdates.get(space._id)
if (update === undefined) return false
return update.txes.length > 0 && update.hidden !== true
}
</script>
@@ -102,7 +94,7 @@
icon={classIcon(client, space._class)}
selected={currentSpace === space._id}
actions={() => getActions(space)}
bold={isChanged(space, $lastViews)}
bold={isChanged(space, $docUpdates)}
/>
</NavLink>
{/await}