mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-22 03:14:40 +03:00
Auto lastview subscribe (#1130)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
e63274efb5
commit
776b657e79
@ -19,6 +19,7 @@ import core from '@anticrm/core'
|
||||
import inventory from '@anticrm/inventory'
|
||||
import view from '@anticrm/view'
|
||||
import serverInventory from '@anticrm/server-inventory'
|
||||
import serverCore from '@anticrm/server-core'
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.HTMLPresenter, {
|
||||
@ -28,4 +29,12 @@ export function createModel (builder: Builder): void {
|
||||
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.TextPresenter, {
|
||||
presenter: serverInventory.function.ProductTextPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverInventory.trigger.OnProductCreate
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverInventory.trigger.OnProductUpdate
|
||||
})
|
||||
}
|
||||
|
@ -24,4 +24,8 @@ export function createModel (builder: Builder): void {
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverNotification.trigger.OnBacklinkCreate
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverNotification.trigger.UpdateLastView
|
||||
})
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import core from '@anticrm/core'
|
||||
import task from '@anticrm/task'
|
||||
import view from '@anticrm/view'
|
||||
import serverTask from '@anticrm/server-task'
|
||||
import serverCore from '@anticrm/server-core'
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.mixin(task.class.Issue, core.class.Class, view.mixin.HTMLPresenter, {
|
||||
@ -28,4 +29,12 @@ export function createModel (builder: Builder): void {
|
||||
builder.mixin(task.class.Issue, core.class.Class, view.mixin.TextPresenter, {
|
||||
presenter: serverTask.function.IssueTextPresenter
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverTask.trigger.OnTaskCreate
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverTask.trigger.OnTaskUpdate
|
||||
})
|
||||
}
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
const notificationClient = NotificationClientImpl.getClient()
|
||||
const lastViews = notificationClient.getLastViews()
|
||||
$: subscribed = $lastViews.has(value._id)
|
||||
|
||||
$: lastView = $lastViews.get(value._id)
|
||||
$: subscribed = lastView !== undefined && lastView !== -1
|
||||
</script>
|
||||
|
||||
{#if !subscribed}
|
||||
|
@ -24,7 +24,7 @@
|
||||
const lastViews = notificationClient.getLastViews()
|
||||
|
||||
$: lastView = $lastViews.get(value._id)
|
||||
$: hasNotification = lastView !== undefined && lastView < value.modifiedOn
|
||||
$: hasNotification = lastView !== undefined && lastView !== -1 && lastView < value.modifiedOn
|
||||
</script>
|
||||
|
||||
{#if hasNotification}
|
||||
|
@ -63,7 +63,7 @@ export class NotificationClientImpl implements NotificationClient {
|
||||
const user = getCurrentAccount()._id
|
||||
const lastView = time ?? new Date().getTime()
|
||||
const current = this.lastViews.get(_id)
|
||||
if (current !== undefined) {
|
||||
if (current !== undefined && current.lastView !== -1) {
|
||||
if (current.lastView < lastView || force) {
|
||||
const u = client.txFactory.createTxUpdateDoc(current._class, current.space, current._id, {
|
||||
lastView: lastView
|
||||
@ -89,7 +89,9 @@ export class NotificationClientImpl implements NotificationClient {
|
||||
const user = getCurrentAccount()._id
|
||||
const current = await client.findOne(notification.class.LastView, { attachedTo: _id, user })
|
||||
if (current !== undefined) {
|
||||
await client.removeDoc(current._class, current.space, current._id)
|
||||
await client.updateDoc(current._class, current.space, current._id, {
|
||||
lastView: -1
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/server-core": "~0.6.0",
|
||||
"@anticrm/server-notification": "~0.6.0",
|
||||
"@anticrm/inventory": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/login": "~0.6.1",
|
||||
|
@ -13,13 +13,73 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { Doc } from '@anticrm/core'
|
||||
import core, { AttachedDoc, Doc, Tx, TxCollectionCUD, TxCreateDoc, TxProcessor, TxUpdateDoc } from '@anticrm/core'
|
||||
import inventory, { Product } from '@anticrm/inventory'
|
||||
import login from '@anticrm/login'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
import { TriggerControl } from '@anticrm/server-core'
|
||||
import { getUpdateLastViewTx } from '@anticrm/server-notification'
|
||||
import view from '@anticrm/view'
|
||||
import workbench from '@anticrm/workbench'
|
||||
|
||||
const extractTx = (tx: Tx): Tx => {
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
const ctx = (tx as TxCollectionCUD<Doc, AttachedDoc>)
|
||||
if (ctx.tx._class === core.class.TxCreateDoc) {
|
||||
const create = ctx.tx as TxCreateDoc<AttachedDoc>
|
||||
create.attributes.attachedTo = ctx.objectId
|
||||
create.attributes.attachedToClass = ctx.objectClass
|
||||
create.attributes.collection = ctx.collection
|
||||
return create
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function OnProductCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const actualTx = extractTx(tx)
|
||||
if (actualTx._class !== core.class.TxCreateDoc) {
|
||||
return []
|
||||
}
|
||||
|
||||
const createTx = actualTx as TxCreateDoc<Product>
|
||||
|
||||
if (!control.hierarchy.isDerived(createTx.objectClass, inventory.class.Product)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const doc = TxProcessor.createDoc2Doc(createTx)
|
||||
|
||||
const lastViewTx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, createTx.modifiedOn, createTx.modifiedBy)
|
||||
|
||||
return lastViewTx !== undefined ? [lastViewTx] : []
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function OnProductUpdate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const actualTx = extractTx(tx)
|
||||
if (actualTx._class !== core.class.TxUpdateDoc) {
|
||||
return []
|
||||
}
|
||||
|
||||
const updateTx = actualTx as TxUpdateDoc<Product>
|
||||
|
||||
if (!control.hierarchy.isDerived(updateTx.objectClass, inventory.class.Product)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const lastViewTx = await getUpdateLastViewTx(control.findAll, updateTx.objectId, updateTx.objectClass, updateTx.modifiedOn, updateTx.modifiedBy)
|
||||
|
||||
return lastViewTx !== undefined ? [lastViewTx] : []
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -39,6 +99,10 @@ export function productTextPresenter (doc: Doc): string {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
OnProductCreate,
|
||||
OnProductUpdate
|
||||
},
|
||||
function: {
|
||||
ProductHTMLPresenter: productHTMLPresenter,
|
||||
ProductTextPresenter: productTextPresenter
|
||||
|
@ -16,6 +16,7 @@
|
||||
import type { Resource, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import { Doc } from '@anticrm/core'
|
||||
import { TriggerFunc } from '@anticrm/server-core'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -26,6 +27,10 @@ export const serverInventoryId = 'server-inventory' as Plugin
|
||||
* @public
|
||||
*/
|
||||
export default plugin(serverInventoryId, {
|
||||
trigger: {
|
||||
OnProductCreate: '' as Resource<TriggerFunc>,
|
||||
OnProductUpdate: '' as Resource<TriggerFunc>
|
||||
},
|
||||
function: {
|
||||
ProductHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
||||
ProductTextPresenter: '' as Resource<(doc: Doc) => string>
|
||||
|
@ -29,6 +29,7 @@
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/server-core": "~0.6.0",
|
||||
"@anticrm/server-notification": "~0.6.0",
|
||||
"@anticrm/notification": "~0.6.0",
|
||||
"@anticrm/chunter": "~0.6.1",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
|
@ -16,12 +16,29 @@
|
||||
|
||||
import chunter, { Backlink } from '@anticrm/chunter'
|
||||
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
||||
import core, { Class, Data, Doc, generateId, Hierarchy, Obj, Ref, Space, Tx, TxCollectionCUD, TxCreateDoc, TxProcessor } from '@anticrm/core'
|
||||
import core, { AttachedDoc, Class, Data, Doc, generateId, Hierarchy, Obj, Ref, Space, Tx, TxCollectionCUD, TxCreateDoc, TxCUD, TxProcessor } from '@anticrm/core'
|
||||
import notification, { EmailNotification, Notification, NotificationStatus } from '@anticrm/notification'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
import type { TriggerControl } from '@anticrm/server-core'
|
||||
import { getUpdateLastViewTx } from '@anticrm/server-notification'
|
||||
import view, { HTMLPresenter, TextPresenter } from '@anticrm/view'
|
||||
|
||||
const extractTx = (tx: Tx): Tx => {
|
||||
if (tx._class === core.class.TxCollectionCUD) {
|
||||
const ctx = (tx as TxCollectionCUD<Doc, AttachedDoc>)
|
||||
if (ctx.tx._class === core.class.TxCreateDoc) {
|
||||
const create = ctx.tx as TxCreateDoc<AttachedDoc>
|
||||
create.attributes.attachedTo = ctx.objectId
|
||||
create.attributes.attachedToClass = ctx.objectClass
|
||||
create.attributes.collection = ctx.collection
|
||||
return create
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -56,6 +73,60 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
const actualTx = extractTx(tx)
|
||||
if (![core.class.TxUpdateDoc, core.class.TxCreateDoc, core.class.TxMixin].includes(actualTx._class)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const result: Tx[] = []
|
||||
|
||||
switch (actualTx._class) {
|
||||
case core.class.TxCreateDoc: {
|
||||
const createTx = actualTx as TxCreateDoc<Doc>
|
||||
if (control.hierarchy.isDerived(createTx.objectClass, core.class.AttachedDoc)) {
|
||||
const doc = TxProcessor.createDoc2Doc(createTx as TxCreateDoc<AttachedDoc>)
|
||||
const attachedTx = await getUpdateLastViewTx(control.findAll, doc.attachedTo, doc.attachedToClass, createTx.modifiedOn, createTx.modifiedBy)
|
||||
if (attachedTx !== undefined) {
|
||||
result.push(attachedTx)
|
||||
}
|
||||
} else {
|
||||
const doc = TxProcessor.createDoc2Doc(createTx)
|
||||
const tx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, createTx.modifiedOn, createTx.modifiedBy)
|
||||
if (tx !== undefined) {
|
||||
result.push(tx)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case core.class.TxUpdateDoc:
|
||||
case core.class.TxMixin: {
|
||||
const tx = actualTx as TxCUD<Doc>
|
||||
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
|
||||
if (control.hierarchy.isDerived(doc._class, core.class.AttachedDoc)) {
|
||||
const attachedDoc = doc as AttachedDoc
|
||||
const attachedTx = await getUpdateLastViewTx(control.findAll, attachedDoc.attachedTo, attachedDoc.attachedToClass, tx.modifiedOn, tx.modifiedBy)
|
||||
if (attachedTx !== undefined) {
|
||||
result.push(attachedTx)
|
||||
}
|
||||
} else {
|
||||
const resTx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, tx.modifiedOn, tx.modifiedBy)
|
||||
if (resTx !== undefined) {
|
||||
result.push(resTx)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async function getPlatformNotificationTx (ptx: TxCollectionCUD<Doc, Backlink>, control: TriggerControl): Promise<TxCollectionCUD<Doc, Notification> | undefined> {
|
||||
const attached = (await control.modelDb.findAll(contact.class.EmployeeAccount, {
|
||||
employee: ptx.objectId as Ref<Employee>
|
||||
@ -191,6 +262,7 @@ function getTextPresenter (_class: Ref<Class<Doc>>, hierarchy: Hierarchy): TextP
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
OnBacklinkCreate
|
||||
OnBacklinkCreate,
|
||||
UpdateLastView
|
||||
}
|
||||
})
|
||||
|
@ -29,6 +29,7 @@
|
||||
"dependencies": {
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/notification": "~0.6.0",
|
||||
"@anticrm/server-core": "~0.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -14,20 +14,55 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { Account, Class, Doc, Ref, TxCreateDoc, TxFactory, TxUpdateDoc } from '@anticrm/core'
|
||||
import type { Resource, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import type { TriggerFunc } from '@anticrm/server-core'
|
||||
import type { TriggerControl, TriggerFunc } from '@anticrm/server-core'
|
||||
import notification, { LastView } from '@anticrm/notification'
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export const serverNotificationId = 'server-notification' as Plugin
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function getUpdateLastViewTx (findAll: TriggerControl['findAll'], attachedTo: Ref<Doc>, attachedToClass: Ref<Class<Doc>>, lastView: number, user: Ref<Account>): Promise<TxUpdateDoc<LastView> | TxCreateDoc<LastView> | undefined> {
|
||||
const current = (await findAll(notification.class.LastView, {
|
||||
attachedTo,
|
||||
attachedToClass,
|
||||
user
|
||||
}, { limit: 1 }))[0]
|
||||
const factory = new TxFactory(user)
|
||||
if (current !== undefined) {
|
||||
if (current.lastView === -1) {
|
||||
return
|
||||
}
|
||||
const u = factory.createTxUpdateDoc(current._class, current.space, current._id, {
|
||||
lastView
|
||||
})
|
||||
u.space = core.space.DerivedTx
|
||||
return u
|
||||
} else {
|
||||
const u = factory.createTxCreateDoc(notification.class.LastView, notification.space.Notifications, {
|
||||
user,
|
||||
lastView,
|
||||
attachedTo,
|
||||
attachedToClass,
|
||||
collection: 'lastViews'
|
||||
})
|
||||
u.space = core.space.DerivedTx
|
||||
return u
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export default plugin(serverNotificationId, {
|
||||
trigger: {
|
||||
OnBacklinkCreate: '' as Resource<TriggerFunc>
|
||||
OnBacklinkCreate: '' as Resource<TriggerFunc>,
|
||||
UpdateLastView: '' as Resource<TriggerFunc>
|
||||
}
|
||||
})
|
||||
|
@ -29,6 +29,7 @@
|
||||
"@anticrm/core": "~0.6.11",
|
||||
"@anticrm/platform": "~0.6.5",
|
||||
"@anticrm/server-core": "~0.6.0",
|
||||
"@anticrm/server-notification": "~0.6.0",
|
||||
"@anticrm/task": "~0.6.0",
|
||||
"@anticrm/view": "~0.6.0",
|
||||
"@anticrm/login": "~0.6.1",
|
||||
|
@ -13,12 +13,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import task, { Issue } from '@anticrm/task'
|
||||
import { Doc } from '@anticrm/core'
|
||||
import core, { Doc, Tx, TxCreateDoc, TxProcessor, TxUpdateDoc } from '@anticrm/core'
|
||||
import login from '@anticrm/login'
|
||||
import { getMetadata } from '@anticrm/platform'
|
||||
import workbench from '@anticrm/workbench'
|
||||
import { TriggerControl } from '@anticrm/server-core'
|
||||
import { getUpdateLastViewTx } from '@anticrm/server-notification'
|
||||
import task, { Issue, Task } from '@anticrm/task'
|
||||
import view from '@anticrm/view'
|
||||
import workbench from '@anticrm/workbench'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -37,8 +39,78 @@ export function issueTextPresenter (doc: Doc): string {
|
||||
return `Task-${issue.number}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function OnTaskCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
if (tx._class !== core.class.TxCreateDoc) {
|
||||
return []
|
||||
}
|
||||
|
||||
const createTx = tx as TxCreateDoc<Task>
|
||||
|
||||
if (!control.hierarchy.isDerived(createTx.objectClass, task.class.Task)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const doc = TxProcessor.createDoc2Doc(createTx)
|
||||
const txes: Tx[] = []
|
||||
|
||||
const mainTx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, createTx.modifiedOn, createTx.modifiedBy)
|
||||
if (mainTx !== undefined) {
|
||||
txes.push(mainTx)
|
||||
}
|
||||
if (doc.assignee != null) {
|
||||
const assignee = (await control.modelDb.findAll(core.class.Account, { emoloyee: doc.assignee }, { limit: 1 }))[0]
|
||||
if (assignee !== undefined) {
|
||||
const assigneeTx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, createTx.modifiedOn, assignee._id)
|
||||
if (assigneeTx !== undefined) {
|
||||
txes.push(assigneeTx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return txes
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function OnTaskUpdate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
||||
if (tx._class !== core.class.TxUpdateDoc) {
|
||||
return []
|
||||
}
|
||||
|
||||
const updateTx = tx as TxUpdateDoc<Task>
|
||||
|
||||
if (!control.hierarchy.isDerived(updateTx.objectClass, task.class.Task)) {
|
||||
return []
|
||||
}
|
||||
const txes: Tx[] = []
|
||||
|
||||
const mainTx = await getUpdateLastViewTx(control.findAll, updateTx.objectId, updateTx.objectClass, updateTx.modifiedOn, updateTx.modifiedBy)
|
||||
if (mainTx !== undefined) {
|
||||
txes.push(mainTx)
|
||||
}
|
||||
if (updateTx.operations.assignee != null) {
|
||||
const assignee = (await control.modelDb.findAll(core.class.Account, { emoloyee: updateTx.operations.assignee }, { limit: 1 }))[0]
|
||||
if (assignee !== undefined) {
|
||||
const assigneeTx = await getUpdateLastViewTx(control.findAll, updateTx.objectId, updateTx.objectClass, updateTx.modifiedOn, assignee._id)
|
||||
if (assigneeTx !== undefined) {
|
||||
txes.push(assigneeTx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return txes
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
trigger: {
|
||||
OnTaskCreate,
|
||||
OnTaskUpdate
|
||||
},
|
||||
function: {
|
||||
IssueHTMLPresenter: issueHTMLPresenter,
|
||||
IssueTextPresenter: issueTextPresenter
|
||||
|
@ -16,6 +16,7 @@
|
||||
import type { Resource, Plugin } from '@anticrm/platform'
|
||||
import { plugin } from '@anticrm/platform'
|
||||
import { Doc } from '@anticrm/core'
|
||||
import { TriggerFunc } from '@anticrm/server-core'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -26,6 +27,10 @@ export const serverTaskId = 'server-task' as Plugin
|
||||
* @public
|
||||
*/
|
||||
export default plugin(serverTaskId, {
|
||||
trigger: {
|
||||
OnTaskCreate: '' as Resource<TriggerFunc>,
|
||||
OnTaskUpdate: '' as Resource<TriggerFunc>
|
||||
},
|
||||
function: {
|
||||
IssueHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
||||
IssueTextPresenter: '' as Resource<(doc: Doc) => string>
|
||||
|
Loading…
Reference in New Issue
Block a user