mirror of
https://github.com/hcengineering/platform.git
synced 2025-01-05 02:12:26 +03:00
Tracker notification (#2057)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
b471284c53
commit
476558421b
@ -5,6 +5,7 @@
|
|||||||
Tracker:
|
Tracker:
|
||||||
|
|
||||||
- Issue preview
|
- Issue preview
|
||||||
|
- Enabled issue notifications
|
||||||
|
|
||||||
## 0.6.25
|
## 0.6.25
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
"@anticrm/model-core": "~0.6.0",
|
"@anticrm/model-core": "~0.6.0",
|
||||||
"@anticrm/ui": "~0.6.0",
|
"@anticrm/ui": "~0.6.0",
|
||||||
"@anticrm/platform": "~0.6.6",
|
"@anticrm/platform": "~0.6.6",
|
||||||
|
"@anticrm/notification": "~0.6.0",
|
||||||
"@anticrm/inventory": "~0.6.0",
|
"@anticrm/inventory": "~0.6.0",
|
||||||
"@anticrm/inventory-resources": "~0.6.0",
|
"@anticrm/inventory-resources": "~0.6.0",
|
||||||
"@anticrm/view": "~0.6.0",
|
"@anticrm/view": "~0.6.0",
|
||||||
|
@ -20,9 +20,10 @@ import attachment from '@anticrm/model-attachment'
|
|||||||
import core, { TAttachedDoc } from '@anticrm/model-core'
|
import core, { TAttachedDoc } from '@anticrm/model-core'
|
||||||
import { createAction } from '@anticrm/model-view'
|
import { createAction } from '@anticrm/model-view'
|
||||||
import workbench from '@anticrm/model-workbench'
|
import workbench from '@anticrm/model-workbench'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
|
import setting from '@anticrm/setting'
|
||||||
import type {} from '@anticrm/view'
|
import type {} from '@anticrm/view'
|
||||||
import view from '@anticrm/view'
|
import view from '@anticrm/view'
|
||||||
import setting from '@anticrm/setting'
|
|
||||||
import inventory from './plugin'
|
import inventory from './plugin'
|
||||||
|
|
||||||
export const DOMAIN_INVENTORY = 'inventory' as Domain
|
export const DOMAIN_INVENTORY = 'inventory' as Domain
|
||||||
@ -149,6 +150,8 @@ export function createModel (builder: Builder): void {
|
|||||||
inventory.category.Inventory
|
inventory.category.Inventory
|
||||||
)
|
)
|
||||||
|
|
||||||
|
builder.mixin(inventory.class.Product, core.class.Class, notification.mixin.LastViewAttached, {})
|
||||||
|
|
||||||
createAction(builder, {
|
createAction(builder, {
|
||||||
label: inventory.string.CreateSubcategory,
|
label: inventory.string.CreateSubcategory,
|
||||||
icon: inventory.icon.Categories,
|
icon: inventory.icon.Categories,
|
||||||
|
@ -18,18 +18,20 @@ import { Account, Doc, Domain, DOMAIN_MODEL, Ref, Timestamp, TxCUD } from '@anti
|
|||||||
import { ArrOf, Builder, Mixin, Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
|
import { ArrOf, Builder, Mixin, Model, Prop, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model'
|
||||||
import core, { TAttachedDoc, TClass, TDoc } from '@anticrm/model-core'
|
import core, { TAttachedDoc, TClass, TDoc } from '@anticrm/model-core'
|
||||||
import type {
|
import type {
|
||||||
|
AnotherUserNotifications,
|
||||||
EmailNotification,
|
EmailNotification,
|
||||||
LastView,
|
LastView,
|
||||||
NotificationType,
|
LastViewAttached,
|
||||||
|
Notification,
|
||||||
NotificationProvider,
|
NotificationProvider,
|
||||||
NotificationSetting,
|
NotificationSetting,
|
||||||
Notification,
|
|
||||||
NotificationStatus,
|
NotificationStatus,
|
||||||
|
NotificationType,
|
||||||
SpaceLastEdit
|
SpaceLastEdit
|
||||||
} from '@anticrm/notification'
|
} from '@anticrm/notification'
|
||||||
import type { IntlString } from '@anticrm/platform'
|
import type { IntlString } from '@anticrm/platform'
|
||||||
import notification from './plugin'
|
|
||||||
import setting from '@anticrm/setting'
|
import setting from '@anticrm/setting'
|
||||||
|
import notification from './plugin'
|
||||||
|
|
||||||
export const DOMAIN_NOTIFICATION = 'notification' as Domain
|
export const DOMAIN_NOTIFICATION = 'notification' as Domain
|
||||||
|
|
||||||
@ -95,6 +97,14 @@ export class TSpaceLastEdit extends TClass implements SpaceLastEdit {
|
|||||||
lastEditField!: string
|
lastEditField!: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mixin(notification.mixin.AnotherUserNotifications, core.class.Class)
|
||||||
|
export class TAnotherUserNotifications extends TClass implements AnotherUserNotifications {
|
||||||
|
fields!: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mixin(notification.mixin.LastViewAttached, core.class.Class)
|
||||||
|
export class TLastViewAttached extends TClass implements LastViewAttached {}
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.createModel(
|
builder.createModel(
|
||||||
TLastView,
|
TLastView,
|
||||||
@ -103,7 +113,9 @@ export function createModel (builder: Builder): void {
|
|||||||
TNotificationType,
|
TNotificationType,
|
||||||
TNotificationProvider,
|
TNotificationProvider,
|
||||||
TNotificationSetting,
|
TNotificationSetting,
|
||||||
TSpaceLastEdit
|
TSpaceLastEdit,
|
||||||
|
TAnotherUserNotifications,
|
||||||
|
TLastViewAttached
|
||||||
)
|
)
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
|
@ -17,9 +17,8 @@ import { Builder } from '@anticrm/model'
|
|||||||
|
|
||||||
import core from '@anticrm/core'
|
import core from '@anticrm/core'
|
||||||
import inventory from '@anticrm/inventory'
|
import inventory from '@anticrm/inventory'
|
||||||
import view from '@anticrm/view'
|
|
||||||
import serverInventory from '@anticrm/server-inventory'
|
import serverInventory from '@anticrm/server-inventory'
|
||||||
import serverCore from '@anticrm/server-core'
|
import view from '@anticrm/view'
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.HTMLPresenter, {
|
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.HTMLPresenter, {
|
||||||
@ -29,12 +28,4 @@ export function createModel (builder: Builder): void {
|
|||||||
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.TextPresenter, {
|
builder.mixin(inventory.class.Product, core.class.Class, view.mixin.TextPresenter, {
|
||||||
presenter: serverInventory.function.ProductTextPresenter
|
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
import { Builder } from '@anticrm/model'
|
import { Builder } from '@anticrm/model'
|
||||||
|
|
||||||
import core from '@anticrm/core'
|
import core from '@anticrm/core'
|
||||||
|
import serverTask from '@anticrm/server-task'
|
||||||
import task from '@anticrm/task'
|
import task from '@anticrm/task'
|
||||||
import view from '@anticrm/view'
|
import view from '@anticrm/view'
|
||||||
import serverTask from '@anticrm/server-task'
|
|
||||||
import serverCore from '@anticrm/server-core'
|
|
||||||
|
|
||||||
export function createModel (builder: Builder): void {
|
export function createModel (builder: Builder): void {
|
||||||
builder.mixin(task.class.Issue, core.class.Class, view.mixin.HTMLPresenter, {
|
builder.mixin(task.class.Issue, core.class.Class, view.mixin.HTMLPresenter, {
|
||||||
@ -29,12 +28,4 @@ export function createModel (builder: Builder): void {
|
|||||||
builder.mixin(task.class.Issue, core.class.Class, view.mixin.TextPresenter, {
|
builder.mixin(task.class.Issue, core.class.Class, view.mixin.TextPresenter, {
|
||||||
presenter: serverTask.function.IssueTextPresenter
|
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"@anticrm/model-workbench": "~0.6.1",
|
"@anticrm/model-workbench": "~0.6.1",
|
||||||
"@anticrm/model-contact": "~0.6.1",
|
"@anticrm/model-contact": "~0.6.1",
|
||||||
"@anticrm/model-attachment": "~0.6.0",
|
"@anticrm/model-attachment": "~0.6.0",
|
||||||
|
"@anticrm/notification": "~0.6.0",
|
||||||
"@anticrm/task": "~0.6.0",
|
"@anticrm/task": "~0.6.0",
|
||||||
"@anticrm/task-resources": "~0.6.0",
|
"@anticrm/task-resources": "~0.6.0",
|
||||||
"@anticrm/model-chunter": "~0.6.0",
|
"@anticrm/model-chunter": "~0.6.0",
|
||||||
|
@ -36,6 +36,7 @@ import attachment from '@anticrm/model-attachment'
|
|||||||
import chunter from '@anticrm/model-chunter'
|
import chunter from '@anticrm/model-chunter'
|
||||||
import core, { TAttachedDoc, TClass, TDoc, TSpace } from '@anticrm/model-core'
|
import core, { TAttachedDoc, TClass, TDoc, TSpace } from '@anticrm/model-core'
|
||||||
import view, { actionTemplates as viewTemplates, createAction, template } from '@anticrm/model-view'
|
import view, { actionTemplates as viewTemplates, createAction, template } from '@anticrm/model-view'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
import { IntlString } from '@anticrm/platform'
|
import { IntlString } from '@anticrm/platform'
|
||||||
import tags from '@anticrm/tags'
|
import tags from '@anticrm/tags'
|
||||||
import {
|
import {
|
||||||
@ -375,6 +376,11 @@ export function createModel (builder: Builder): void {
|
|||||||
editor: task.component.TaskHeader
|
editor: task.component.TaskHeader
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(task.class.Task, core.class.Class, notification.mixin.LastViewAttached, {})
|
||||||
|
builder.mixin(task.class.Task, core.class.Class, notification.mixin.AnotherUserNotifications, {
|
||||||
|
fields: ['assignee']
|
||||||
|
})
|
||||||
|
|
||||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||||
attachTo: task.class.Issue,
|
attachTo: task.class.Issue,
|
||||||
descriptor: task.viewlet.Kanban,
|
descriptor: task.viewlet.Kanban,
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"@anticrm/model-workbench": "~0.6.1",
|
"@anticrm/model-workbench": "~0.6.1",
|
||||||
"@anticrm/model-contact": "~0.6.1",
|
"@anticrm/model-contact": "~0.6.1",
|
||||||
"@anticrm/model-attachment": "~0.6.0",
|
"@anticrm/model-attachment": "~0.6.0",
|
||||||
|
"@anticrm/notification": "~0.6.0",
|
||||||
"@anticrm/tracker": "~0.6.0",
|
"@anticrm/tracker": "~0.6.0",
|
||||||
"@anticrm/tracker-resources": "~0.6.0",
|
"@anticrm/tracker-resources": "~0.6.0",
|
||||||
"@anticrm/model-chunter": "~0.6.0",
|
"@anticrm/model-chunter": "~0.6.0",
|
||||||
|
@ -35,8 +35,8 @@ import attachment from '@anticrm/model-attachment'
|
|||||||
import chunter from '@anticrm/model-chunter'
|
import chunter from '@anticrm/model-chunter'
|
||||||
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TType } from '@anticrm/model-core'
|
import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TType } from '@anticrm/model-core'
|
||||||
import view, { createAction } from '@anticrm/model-view'
|
import view, { createAction } from '@anticrm/model-view'
|
||||||
import { KeyBinding } from '@anticrm/view'
|
|
||||||
import workbench, { createNavigateAction } from '@anticrm/model-workbench'
|
import workbench, { createNavigateAction } from '@anticrm/model-workbench'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
import { Asset, IntlString } from '@anticrm/platform'
|
import { Asset, IntlString } from '@anticrm/platform'
|
||||||
import setting from '@anticrm/setting'
|
import setting from '@anticrm/setting'
|
||||||
import {
|
import {
|
||||||
@ -49,6 +49,7 @@ import {
|
|||||||
ProjectStatus,
|
ProjectStatus,
|
||||||
Team
|
Team
|
||||||
} from '@anticrm/tracker'
|
} from '@anticrm/tracker'
|
||||||
|
import { KeyBinding } from '@anticrm/view'
|
||||||
import tracker from './plugin'
|
import tracker from './plugin'
|
||||||
|
|
||||||
import presentation from '@anticrm/model-presentation'
|
import presentation from '@anticrm/model-presentation'
|
||||||
@ -403,6 +404,11 @@ export function createModel (builder: Builder): void {
|
|||||||
editor: tracker.component.ProjectStatusEditor
|
editor: tracker.component.ProjectStatusEditor
|
||||||
})
|
})
|
||||||
|
|
||||||
|
builder.mixin(tracker.class.Issue, core.class.Class, notification.mixin.LastViewAttached, {})
|
||||||
|
builder.mixin(tracker.class.Issue, core.class.Class, notification.mixin.AnotherUserNotifications, {
|
||||||
|
fields: ['assignee']
|
||||||
|
})
|
||||||
|
|
||||||
builder.createDoc(
|
builder.createDoc(
|
||||||
workbench.class.Application,
|
workbench.class.Application,
|
||||||
core.space.Model,
|
core.space.Model,
|
||||||
|
@ -462,6 +462,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List */
|
||||||
|
|
||||||
|
.antiList-cells {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&__checkCell, &__notifyCell {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
&__checkCell { visibility: hidden; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.antiList__row {
|
||||||
|
.antiList-cells__notifyCell {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &.checking {
|
||||||
|
.antiList-cells__checkCell { visibility: visible; }
|
||||||
|
.antiList-cells__notifyCell .notify-table-kind {
|
||||||
|
width: 1.15rem;
|
||||||
|
height: 1.15rem;
|
||||||
|
background-color: var(--highlight-hover);
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
border-radius: .375rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Select */
|
/* Select */
|
||||||
.antiSelect {
|
.antiSelect {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Doc } from '@anticrm/core'
|
import { Doc } from '@anticrm/core'
|
||||||
import { Button, Tooltip } from '@anticrm/ui'
|
import { Button, tooltip } from '@anticrm/ui'
|
||||||
import notification from '../plugin'
|
import notification from '../plugin'
|
||||||
import { NotificationClientImpl } from '../utils'
|
import { NotificationClientImpl } from '../utils'
|
||||||
|
|
||||||
@ -26,14 +26,14 @@
|
|||||||
$: subscribed = lastView !== undefined && lastView !== -1
|
$: subscribed = lastView !== undefined && lastView !== -1
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Tooltip label={subscribed ? notification.string.DontTrack : notification.string.Track}>
|
<div use:tooltip={{ label: subscribed ? notification.string.DontTrack : notification.string.Track }}>
|
||||||
<Button
|
<Button
|
||||||
size={'medium'}
|
size={'medium'}
|
||||||
kind={'transparent'}
|
kind={'transparent'}
|
||||||
icon={subscribed ? notification.icon.DontTrack : notification.icon.Track}
|
icon={subscribed ? notification.icon.Track : notification.icon.DontTrack}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
if (subscribed) notificationClient.unsubscribe(value._id)
|
if (subscribed) notificationClient.unsubscribe(value._id)
|
||||||
else notificationClient.updateLastView(value._id, value._class, undefined, true)
|
else notificationClient.updateLastView(value._id, value._class, undefined, true)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</div>
|
||||||
|
@ -86,6 +86,18 @@ export interface SpaceLastEdit extends Class<Doc> {
|
|||||||
lastEditField: string
|
lastEditField: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface LastViewAttached extends Class<AttachedDoc> {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export interface AnotherUserNotifications extends Class<Doc> {
|
||||||
|
fields: string[]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -109,7 +121,9 @@ export type NotificationClientFactoy = () => NotificationClient
|
|||||||
*/
|
*/
|
||||||
const notification = plugin(notificationId, {
|
const notification = plugin(notificationId, {
|
||||||
mixin: {
|
mixin: {
|
||||||
SpaceLastEdit: '' as Ref<Mixin<SpaceLastEdit>>
|
SpaceLastEdit: '' as Ref<Mixin<SpaceLastEdit>>,
|
||||||
|
AnotherUserNotifications: '' as Ref<Mixin<AnotherUserNotifications>>,
|
||||||
|
LastViewAttached: '' as Ref<Mixin<LastViewAttached>>
|
||||||
},
|
},
|
||||||
class: {
|
class: {
|
||||||
LastView: '' as Ref<Class<LastView>>,
|
LastView: '' as Ref<Class<LastView>>,
|
||||||
|
@ -18,12 +18,13 @@
|
|||||||
import { Kanban, TypeState } from '@anticrm/kanban'
|
import { Kanban, TypeState } from '@anticrm/kanban'
|
||||||
import { createQuery } from '@anticrm/presentation'
|
import { createQuery } from '@anticrm/presentation'
|
||||||
import type { Issue, IssueStatus, Team } from '@anticrm/tracker'
|
import type { Issue, IssueStatus, Team } from '@anticrm/tracker'
|
||||||
import { Button, Icon, IconAdd, showPopup, Tooltip, showPanel } from '@anticrm/ui'
|
import { Button, Icon, IconAdd, showPopup, Tooltip, showPanel, Component } from '@anticrm/ui'
|
||||||
import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '@anticrm/view-resources'
|
import { focusStore, ListSelectionProvider, SelectDirection, selectionStore } from '@anticrm/view-resources'
|
||||||
import ActionContext from '@anticrm/view-resources/src/components/ActionContext.svelte'
|
import ActionContext from '@anticrm/view-resources/src/components/ActionContext.svelte'
|
||||||
import Menu from '@anticrm/view-resources/src/components/Menu.svelte'
|
import Menu from '@anticrm/view-resources/src/components/Menu.svelte'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
import CreateIssue from '../CreateIssue.svelte'
|
import CreateIssue from '../CreateIssue.svelte'
|
||||||
import AssigneePresenter from './AssigneePresenter.svelte'
|
import AssigneePresenter from './AssigneePresenter.svelte'
|
||||||
import IssuePresenter from './IssuePresenter.svelte'
|
import IssuePresenter from './IssuePresenter.svelte'
|
||||||
@ -34,8 +35,6 @@
|
|||||||
export let currentSpace: Ref<Team>
|
export let currentSpace: Ref<Team>
|
||||||
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
|
export let baseMenuClass: Ref<Class<Doc>> | undefined = undefined
|
||||||
|
|
||||||
/* eslint-disable no-undef */
|
|
||||||
|
|
||||||
const spaceQuery = createQuery()
|
const spaceQuery = createQuery()
|
||||||
const statusesQuery = createQuery()
|
const statusesQuery = createQuery()
|
||||||
|
|
||||||
@ -64,10 +63,6 @@
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/* eslint-disable prefer-const */
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
let issue: Issue
|
|
||||||
|
|
||||||
function toIssue (object: any): WithLookup<Issue> {
|
function toIssue (object: any): WithLookup<Issue> {
|
||||||
return object as WithLookup<Issue>
|
return object as WithLookup<Issue>
|
||||||
}
|
}
|
||||||
@ -175,6 +170,9 @@
|
|||||||
{currentSpace}
|
{currentSpace}
|
||||||
isEditable={true}
|
isEditable={true}
|
||||||
/>
|
/>
|
||||||
|
<div class="flex-center mt-2">
|
||||||
|
<Component is={notification.component.NotificationPresenter} props={{ value: object }} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons-group xxsmall-gap mt-10px">
|
<div class="buttons-group xxsmall-gap mt-10px">
|
||||||
{#if issue && issueStatuses && issue.subIssues > 0}
|
{#if issue && issueStatuses && issue.subIssues > 0}
|
||||||
|
@ -17,13 +17,24 @@
|
|||||||
import { Class, Doc, FindOptions, getObjectValue, Ref, WithLookup } from '@anticrm/core'
|
import { Class, Doc, FindOptions, getObjectValue, Ref, WithLookup } from '@anticrm/core'
|
||||||
import { getClient } from '@anticrm/presentation'
|
import { getClient } from '@anticrm/presentation'
|
||||||
import { Issue, IssueStatus, Team } from '@anticrm/tracker'
|
import { Issue, IssueStatus, Team } from '@anticrm/tracker'
|
||||||
import { Button, CheckBox, Component, eventToHTMLElement, IconAdd, showPopup, Spinner, Tooltip } from '@anticrm/ui'
|
import {
|
||||||
|
Button,
|
||||||
|
CheckBox,
|
||||||
|
Component,
|
||||||
|
eventToHTMLElement,
|
||||||
|
IconAdd,
|
||||||
|
showPopup,
|
||||||
|
Spinner,
|
||||||
|
tooltip,
|
||||||
|
Tooltip
|
||||||
|
} from '@anticrm/ui'
|
||||||
import { AttributeModel, BuildModelKey } from '@anticrm/view'
|
import { AttributeModel, BuildModelKey } from '@anticrm/view'
|
||||||
import { buildModel, getObjectPresenter, LoadingProps, Menu } from '@anticrm/view-resources'
|
import { buildModel, getObjectPresenter, LoadingProps, Menu } from '@anticrm/view-resources'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import tracker from '../../plugin'
|
import tracker from '../../plugin'
|
||||||
import { IssuesGroupByKeys, issuesGroupEditorMap, IssuesOrderByKeys, issuesSortOrderMap } from '../../utils'
|
import { IssuesGroupByKeys, issuesGroupEditorMap, IssuesOrderByKeys, issuesSortOrderMap } from '../../utils'
|
||||||
import CreateIssue from '../CreateIssue.svelte'
|
import CreateIssue from '../CreateIssue.svelte'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
|
|
||||||
export let _class: Ref<Class<Doc>>
|
export let _class: Ref<Class<Doc>>
|
||||||
export let currentSpace: Ref<Team> | undefined = undefined
|
export let currentSpace: Ref<Team> | undefined = undefined
|
||||||
@ -181,8 +192,8 @@
|
|||||||
{#each groupedIssues[category] as docObject (docObject._id)}
|
{#each groupedIssues[category] as docObject (docObject._id)}
|
||||||
<div
|
<div
|
||||||
bind:this={objectRefs[combinedGroupedIssues.findIndex((x) => x === docObject)]}
|
bind:this={objectRefs[combinedGroupedIssues.findIndex((x) => x === docObject)]}
|
||||||
class="listGrid"
|
class="listGrid antiList__row"
|
||||||
class:mListGridChecked={selectedObjectIdsSet.has(docObject._id)}
|
class:checking={selectedObjectIdsSet.has(docObject._id)}
|
||||||
class:mListGridFixed={selectedRowIndex === combinedGroupedIssues.findIndex((x) => x === docObject)}
|
class:mListGridFixed={selectedRowIndex === combinedGroupedIssues.findIndex((x) => x === docObject)}
|
||||||
class:mListGridSelected={selectedRowIndex === combinedGroupedIssues.findIndex((x) => x === docObject)}
|
class:mListGridSelected={selectedRowIndex === combinedGroupedIssues.findIndex((x) => x === docObject)}
|
||||||
on:contextmenu|preventDefault={(event) =>
|
on:contextmenu|preventDefault={(event) =>
|
||||||
@ -195,26 +206,33 @@
|
|||||||
on:mouseover={() => handleRowFocused(docObject)}
|
on:mouseover={() => handleRowFocused(docObject)}
|
||||||
>
|
>
|
||||||
<div class="contentWrapper">
|
<div class="contentWrapper">
|
||||||
|
<div
|
||||||
|
class="flex-center relative"
|
||||||
|
use:tooltip={{ label: tracker.string.SelectIssue, direction: 'bottom' }}
|
||||||
|
>
|
||||||
|
<div class="antiList-cells__notifyCell">
|
||||||
|
<div class="antiList-cells__checkCell">
|
||||||
|
<CheckBox
|
||||||
|
checked={selectedObjectIdsSet.has(docObject._id)}
|
||||||
|
on:value={(event) => {
|
||||||
|
onObjectChecked([docObject], event.detail)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Component
|
||||||
|
is={notification.component.NotificationPresenter}
|
||||||
|
props={{ value: docObject, kind: 'table' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{#each itemModels as attributeModel, attributeModelIndex}
|
{#each itemModels as attributeModel, attributeModelIndex}
|
||||||
{#if attributeModelIndex === 0}
|
{#if attributeModelIndex === 0}
|
||||||
<div class="gridElement">
|
<div class="priorityPresenter">
|
||||||
<Tooltip direction={'bottom'} label={tracker.string.SelectIssue}>
|
<svelte:component
|
||||||
<div class="eListGridCheckBox">
|
this={attributeModel.presenter}
|
||||||
<CheckBox
|
value={getObjectValue(attributeModel.key, docObject) ?? ''}
|
||||||
checked={selectedObjectIdsSet.has(docObject._id)}
|
{...attributeModel.props}
|
||||||
on:value={(event) => {
|
/>
|
||||||
onObjectChecked([docObject], event.detail)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
<div class="priorityPresenter">
|
|
||||||
<svelte:component
|
|
||||||
this={attributeModel.presenter}
|
|
||||||
value={getObjectValue(attributeModel.key, docObject) ?? ''}
|
|
||||||
{...attributeModel.props}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{:else if attributeModelIndex === 1}
|
{:else if attributeModelIndex === 1}
|
||||||
<div class="issuePresenter">
|
<div class="issuePresenter">
|
||||||
@ -299,28 +317,13 @@
|
|||||||
color: var(--theme-caption-color);
|
color: var(--theme-caption-color);
|
||||||
border-bottom: 1px solid var(--theme-button-border-hovered);
|
border-bottom: 1px solid var(--theme-button-border-hovered);
|
||||||
|
|
||||||
&.mListGridChecked {
|
&.checking {
|
||||||
background-color: var(--theme-table-bg-hover);
|
background-color: var(--theme-table-bg-hover);
|
||||||
|
|
||||||
.eListGridCheckBox {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mListGridSelected {
|
&.mListGridSelected {
|
||||||
background-color: var(--menu-bg-select);
|
background-color: var(--menu-bg-select);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eListGridCheckBox {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
opacity: 0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filler {
|
.filler {
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Class, Data, Ref, SortingOrder, WithLookup } from '@anticrm/core'
|
import { Class, Data, Doc, Ref, SortingOrder, WithLookup } from '@anticrm/core'
|
||||||
import { AttachmentDocList } from '@anticrm/attachment-resources'
|
import { AttachmentDocList } from '@anticrm/attachment-resources'
|
||||||
import { Panel } from '@anticrm/panel'
|
import { Panel } from '@anticrm/panel'
|
||||||
import presentation, { createQuery, getClient, MessageViewer } from '@anticrm/presentation'
|
import presentation, { createQuery, getClient, MessageViewer } from '@anticrm/presentation'
|
||||||
@ -33,17 +33,21 @@
|
|||||||
} from '@anticrm/ui'
|
} from '@anticrm/ui'
|
||||||
import { ContextMenu } from '@anticrm/view-resources'
|
import { ContextMenu } from '@anticrm/view-resources'
|
||||||
import { StyledTextArea } from '@anticrm/text-editor'
|
import { StyledTextArea } from '@anticrm/text-editor'
|
||||||
import { createEventDispatcher, onMount } from 'svelte'
|
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
import { getIssueId } from '../../../utils'
|
import { getIssueId } from '../../../utils'
|
||||||
import ControlPanel from './ControlPanel.svelte'
|
import ControlPanel from './ControlPanel.svelte'
|
||||||
import CopyToClipboard from './CopyToClipboard.svelte'
|
import CopyToClipboard from './CopyToClipboard.svelte'
|
||||||
import SubIssueSelector from './SubIssueSelector.svelte'
|
import SubIssueSelector from './SubIssueSelector.svelte'
|
||||||
import SubIssues from './SubIssues.svelte'
|
import SubIssues from './SubIssues.svelte'
|
||||||
|
import { getResource } from '@anticrm/platform'
|
||||||
|
import notification from '@anticrm/notification'
|
||||||
|
|
||||||
export let _id: Ref<Issue>
|
export let _id: Ref<Issue>
|
||||||
export let _class: Ref<Class<Issue>>
|
export let _class: Ref<Class<Issue>>
|
||||||
|
|
||||||
|
let lastId: Ref<Doc> = _id
|
||||||
|
let lastClass: Ref<Class<Doc>> = _class
|
||||||
const query = createQuery()
|
const query = createQuery()
|
||||||
const statusesQuery = createQuery()
|
const statusesQuery = createQuery()
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
@ -57,6 +61,23 @@
|
|||||||
let innerWidth: number
|
let innerWidth: number
|
||||||
let isEditing = false
|
let isEditing = false
|
||||||
|
|
||||||
|
const notificationClient = getResource(notification.function.GetNotificationClient).then((res) => res())
|
||||||
|
|
||||||
|
$: read(_id)
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(async () => {
|
||||||
|
notificationClient.then((client) => client.updateLastView(_id, _class))
|
||||||
|
})
|
||||||
|
|
||||||
$: _id &&
|
$: _id &&
|
||||||
_class &&
|
_class &&
|
||||||
query.query(
|
query.query(
|
||||||
|
@ -13,69 +13,13 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import core, { Doc, Tx, TxCreateDoc, TxProcessor, TxUpdateDoc } from '@anticrm/core'
|
import { Doc } from '@anticrm/core'
|
||||||
import inventory, { Product } from '@anticrm/inventory'
|
import inventory, { Product } from '@anticrm/inventory'
|
||||||
import login from '@anticrm/login'
|
import login from '@anticrm/login'
|
||||||
import { getMetadata } from '@anticrm/platform'
|
import { getMetadata } from '@anticrm/platform'
|
||||||
import { extractTx, TriggerControl } from '@anticrm/server-core'
|
|
||||||
import { getUpdateLastViewTx } from '@anticrm/server-notification'
|
|
||||||
import view from '@anticrm/view'
|
import view from '@anticrm/view'
|
||||||
import workbench from '@anticrm/workbench'
|
import workbench from '@anticrm/workbench'
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -95,10 +39,6 @@ export function productTextPresenter (doc: Doc): string {
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
export default async () => ({
|
export default async () => ({
|
||||||
trigger: {
|
|
||||||
OnProductCreate,
|
|
||||||
OnProductUpdate
|
|
||||||
},
|
|
||||||
function: {
|
function: {
|
||||||
ProductHTMLPresenter: productHTMLPresenter,
|
ProductHTMLPresenter: productHTMLPresenter,
|
||||||
ProductTextPresenter: productTextPresenter
|
ProductTextPresenter: productTextPresenter
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import type { Resource, Plugin } from '@anticrm/platform'
|
|
||||||
import { plugin } from '@anticrm/platform'
|
|
||||||
import { Doc } from '@anticrm/core'
|
import { Doc } from '@anticrm/core'
|
||||||
import { TriggerFunc } from '@anticrm/server-core'
|
import type { Plugin, Resource } from '@anticrm/platform'
|
||||||
|
import { plugin } from '@anticrm/platform'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -27,10 +26,6 @@ export const serverInventoryId = 'server-inventory' as Plugin
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export default plugin(serverInventoryId, {
|
export default plugin(serverInventoryId, {
|
||||||
trigger: {
|
|
||||||
OnProductCreate: '' as Resource<TriggerFunc>,
|
|
||||||
OnProductUpdate: '' as Resource<TriggerFunc>
|
|
||||||
},
|
|
||||||
function: {
|
function: {
|
||||||
ProductHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
ProductHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
||||||
ProductTextPresenter: '' as Resource<(doc: Doc) => string>
|
ProductTextPresenter: '' as Resource<(doc: Doc) => string>
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import chunter, { Backlink } from '@anticrm/chunter'
|
import chunter, { Backlink } from '@anticrm/chunter'
|
||||||
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
import contact, { Employee, EmployeeAccount, formatName } from '@anticrm/contact'
|
||||||
import core, {
|
import core, {
|
||||||
|
Account,
|
||||||
AttachedDoc,
|
AttachedDoc,
|
||||||
Class,
|
Class,
|
||||||
Data,
|
Data,
|
||||||
@ -26,6 +27,7 @@ import core, {
|
|||||||
Obj,
|
Obj,
|
||||||
Ref,
|
Ref,
|
||||||
Space,
|
Space,
|
||||||
|
Timestamp,
|
||||||
Tx,
|
Tx,
|
||||||
TxCollectionCUD,
|
TxCollectionCUD,
|
||||||
TxCreateDoc,
|
TxCreateDoc,
|
||||||
@ -36,7 +38,7 @@ import notification, { EmailNotification, Notification, NotificationStatus } fro
|
|||||||
import { getResource } from '@anticrm/platform'
|
import { getResource } from '@anticrm/platform'
|
||||||
import type { TriggerControl } from '@anticrm/server-core'
|
import type { TriggerControl } from '@anticrm/server-core'
|
||||||
import { extractTx } from '@anticrm/server-core'
|
import { extractTx } from '@anticrm/server-core'
|
||||||
import { getUpdateLastViewTx } from '@anticrm/server-notification'
|
import { createLastViewTx, getUpdateLastViewTx } from '@anticrm/server-notification'
|
||||||
import view, { HTMLPresenter, TextPresenter } from '@anticrm/view'
|
import view, { HTMLPresenter, TextPresenter } from '@anticrm/view'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,6 +75,42 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getUpdateLastViewTxes (
|
||||||
|
doc: Doc,
|
||||||
|
_id: Ref<Doc>,
|
||||||
|
_class: Ref<Class<Doc>>,
|
||||||
|
modifiedOn: Timestamp,
|
||||||
|
user: Ref<Account>,
|
||||||
|
control: TriggerControl
|
||||||
|
): Promise<Tx[]> {
|
||||||
|
const updatedUsers: Set<Ref<Account>> = new Set<Ref<Account>>()
|
||||||
|
const result: Tx[] = []
|
||||||
|
const tx = await getUpdateLastViewTx(control.findAll, _id, _class, modifiedOn, user)
|
||||||
|
if (tx !== undefined) {
|
||||||
|
updatedUsers.add(user)
|
||||||
|
result.push(tx)
|
||||||
|
}
|
||||||
|
const docClass = control.hierarchy.getClass(doc._class)
|
||||||
|
const anotherUserNotifications = control.hierarchy.as(docClass, notification.mixin.AnotherUserNotifications)
|
||||||
|
for (const field of anotherUserNotifications?.fields ?? []) {
|
||||||
|
const value = (doc as any)[field]
|
||||||
|
if (value != null) {
|
||||||
|
for (const employeeId of Array.isArray(value) ? value : [value]) {
|
||||||
|
const account = (await control.modelDb.findAll(core.class.Account, { employee: employeeId }, { limit: 1 }))[0]
|
||||||
|
if (account !== undefined) {
|
||||||
|
if (updatedUsers.has(account._id)) continue
|
||||||
|
const assigneeTx = await createLastViewTx(control.findAll, _id, _class, account._id)
|
||||||
|
if (assigneeTx !== undefined) {
|
||||||
|
updatedUsers.add(account._id)
|
||||||
|
result.push(assigneeTx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -92,40 +130,36 @@ export async function UpdateLastView (tx: Tx, control: TriggerControl): Promise<
|
|||||||
}
|
}
|
||||||
if (control.hierarchy.isDerived(createTx.objectClass, core.class.AttachedDoc)) {
|
if (control.hierarchy.isDerived(createTx.objectClass, core.class.AttachedDoc)) {
|
||||||
const doc = TxProcessor.createDoc2Doc(createTx as TxCreateDoc<AttachedDoc>)
|
const doc = TxProcessor.createDoc2Doc(createTx as TxCreateDoc<AttachedDoc>)
|
||||||
const attachedTx = await getUpdateLastViewTx(
|
const attachedTxes = await getUpdateLastViewTxes(
|
||||||
control.findAll,
|
doc,
|
||||||
doc.attachedTo,
|
doc.attachedTo,
|
||||||
doc.attachedToClass,
|
doc.attachedToClass,
|
||||||
createTx.modifiedOn,
|
createTx.modifiedOn,
|
||||||
createTx.modifiedBy
|
createTx.modifiedBy,
|
||||||
|
control
|
||||||
)
|
)
|
||||||
if (attachedTx !== undefined) {
|
const docClass = control.hierarchy.getClass(doc._class)
|
||||||
result.push(attachedTx)
|
if (!control.hierarchy.hasMixin(docClass, notification.mixin.LastViewAttached)) return attachedTxes
|
||||||
}
|
const parentTxes = await getUpdateLastViewTxes(
|
||||||
} else {
|
doc,
|
||||||
const doc = TxProcessor.createDoc2Doc(createTx)
|
|
||||||
const tx = await getUpdateLastViewTx(
|
|
||||||
control.findAll,
|
|
||||||
doc._id,
|
doc._id,
|
||||||
doc._class,
|
doc._class,
|
||||||
createTx.modifiedOn,
|
createTx.modifiedOn,
|
||||||
createTx.modifiedBy
|
createTx.modifiedBy,
|
||||||
|
control
|
||||||
)
|
)
|
||||||
if (tx !== undefined) {
|
return [...attachedTxes, ...parentTxes]
|
||||||
result.push(tx)
|
} else {
|
||||||
}
|
const doc = TxProcessor.createDoc2Doc(createTx)
|
||||||
|
return await getUpdateLastViewTxes(doc, doc._id, doc._class, createTx.modifiedOn, createTx.modifiedBy, control)
|
||||||
}
|
}
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case core.class.TxUpdateDoc:
|
case core.class.TxUpdateDoc:
|
||||||
case core.class.TxMixin: {
|
case core.class.TxMixin: {
|
||||||
const tx = actualTx as TxCUD<Doc>
|
const tx = actualTx as TxCUD<Doc>
|
||||||
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
|
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
|
||||||
if (doc !== undefined) {
|
if (doc !== undefined) {
|
||||||
const resTx = await getUpdateLastViewTx(control.findAll, doc._id, doc._class, tx.modifiedOn, tx.modifiedBy)
|
return await getUpdateLastViewTxes(doc, doc._id, doc._class, tx.modifiedOn, tx.modifiedBy, control)
|
||||||
if (resTx !== undefined) {
|
|
||||||
result.push(resTx)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,40 @@ export async function getUpdateLastViewTx (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export async function createLastViewTx (
|
||||||
|
findAll: TriggerControl['findAll'],
|
||||||
|
attachedTo: Ref<Doc>,
|
||||||
|
attachedToClass: Ref<Class<Doc>>,
|
||||||
|
user: Ref<Account>
|
||||||
|
): Promise<TxCreateDoc<LastView> | undefined> {
|
||||||
|
const current = (
|
||||||
|
await findAll(
|
||||||
|
notification.class.LastView,
|
||||||
|
{
|
||||||
|
attachedTo,
|
||||||
|
attachedToClass,
|
||||||
|
user
|
||||||
|
},
|
||||||
|
{ limit: 1 }
|
||||||
|
)
|
||||||
|
)[0]
|
||||||
|
if (current === undefined) {
|
||||||
|
const factory = new TxFactory(user)
|
||||||
|
const u = factory.createTxCreateDoc(notification.class.LastView, notification.space.Notifications, {
|
||||||
|
user,
|
||||||
|
lastView: 1,
|
||||||
|
attachedTo,
|
||||||
|
attachedToClass,
|
||||||
|
collection: 'lastViews'
|
||||||
|
})
|
||||||
|
u.space = core.space.DerivedTx
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import core, { Doc, Tx, TxCreateDoc, TxProcessor, TxUpdateDoc } from '@anticrm/core'
|
import core, { Doc, Tx, TxUpdateDoc } from '@anticrm/core'
|
||||||
import login from '@anticrm/login'
|
import login from '@anticrm/login'
|
||||||
import { getMetadata } from '@anticrm/platform'
|
import { getMetadata } from '@anticrm/platform'
|
||||||
import { extractTx, TriggerControl } from '@anticrm/server-core'
|
import { extractTx, TriggerControl } from '@anticrm/server-core'
|
||||||
@ -39,53 +39,6 @@ export function issueTextPresenter (doc: Doc): string {
|
|||||||
return `Task-${issue.number}`
|
return `Task-${issue.number}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
export async function OnTaskCreate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
|
|
||||||
const actualTx = extractTx(tx)
|
|
||||||
if (actualTx._class !== core.class.TxCreateDoc) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
const createTx = actualTx 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
|
* @public
|
||||||
*/
|
*/
|
||||||
@ -135,10 +88,6 @@ export async function OnTaskUpdate (tx: Tx, control: TriggerControl): Promise<Tx
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
export default async () => ({
|
export default async () => ({
|
||||||
trigger: {
|
|
||||||
OnTaskCreate,
|
|
||||||
OnTaskUpdate
|
|
||||||
},
|
|
||||||
function: {
|
function: {
|
||||||
IssueHTMLPresenter: issueHTMLPresenter,
|
IssueHTMLPresenter: issueHTMLPresenter,
|
||||||
IssueTextPresenter: issueTextPresenter
|
IssueTextPresenter: issueTextPresenter
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import type { Resource, Plugin } from '@anticrm/platform'
|
|
||||||
import { plugin } from '@anticrm/platform'
|
|
||||||
import { Doc } from '@anticrm/core'
|
import { Doc } from '@anticrm/core'
|
||||||
import { TriggerFunc } from '@anticrm/server-core'
|
import type { Plugin, Resource } from '@anticrm/platform'
|
||||||
|
import { plugin } from '@anticrm/platform'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
@ -27,10 +26,6 @@ export const serverTaskId = 'server-task' as Plugin
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export default plugin(serverTaskId, {
|
export default plugin(serverTaskId, {
|
||||||
trigger: {
|
|
||||||
OnTaskCreate: '' as Resource<TriggerFunc>,
|
|
||||||
OnTaskUpdate: '' as Resource<TriggerFunc>
|
|
||||||
},
|
|
||||||
function: {
|
function: {
|
||||||
IssueHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
IssueHTMLPresenter: '' as Resource<(doc: Doc) => string>,
|
||||||
IssueTextPresenter: '' as Resource<(doc: Doc) => string>
|
IssueTextPresenter: '' as Resource<(doc: Doc) => string>
|
||||||
|
Loading…
Reference in New Issue
Block a user