diff --git a/dev/generator/package.json b/dev/generator/package.json index b5ba45d693..b7ef8e5286 100644 --- a/dev/generator/package.json +++ b/dev/generator/package.json @@ -37,29 +37,29 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "commander": "^8.1.0", "@hcengineering/account": "^0.6.0", - "@hcengineering/core": "^0.6.28", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/tracker": "^0.6.13", - "@hcengineering/model-all": "^0.6.0", - "@hcengineering/model-telegram": "^0.6.0", - "@hcengineering/telegram": "^0.6.14", - "@hcengineering/client-resources": "^0.6.23", - "ws": "^8.10.0", - "@hcengineering/client": "^0.6.14", - "@hcengineering/platform": "^0.6.9", - "@hcengineering/model": "^0.6.7", - "@hcengineering/recruit": "^0.6.21", - "faker": "~5.5.3", - "@hcengineering/model-recruit": "^0.6.0", - "@hcengineering/chunter": "^0.6.12", - "pdfkit": "~0.13.0", "@hcengineering/attachment": "^0.6.9", - "@types/pdfkit": "~0.12.3", - "@hcengineering/task": "^0.6.13", - "jpeg-js": "~0.4.3", + "@hcengineering/client": "^0.6.14", + "@hcengineering/client-resources": "^0.6.23", + "@hcengineering/contact": "^0.6.20", + "@hcengineering/core": "^0.6.28", + "@hcengineering/minio": "^0.6.0", + "@hcengineering/model": "^0.6.7", + "@hcengineering/model-all": "^0.6.0", + "@hcengineering/model-recruit": "^0.6.0", + "@hcengineering/model-telegram": "^0.6.0", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/recruit": "^0.6.21", "@hcengineering/server-token": "^0.6.7", - "@hcengineering/minio": "^0.6.0" + "@hcengineering/task": "^0.6.13", + "@hcengineering/telegram": "^0.6.14", + "@hcengineering/tracker": "^0.6.13", + "@hcengineering/notification": "^0.6.16", + "@types/pdfkit": "~0.12.3", + "commander": "^8.1.0", + "faker": "~5.5.3", + "jpeg-js": "~0.4.3", + "pdfkit": "~0.13.0", + "ws": "^8.10.0" } } diff --git a/dev/generator/src/comments.ts b/dev/generator/src/comments.ts index d078f85fe2..fe314a736d 100644 --- a/dev/generator/src/comments.ts +++ b/dev/generator/src/comments.ts @@ -1,5 +1,5 @@ -import chunter, { Comment } from '@hcengineering/chunter' import { AttachedData, Class, Doc, generateId, Ref, Space, TxOperations } from '@hcengineering/core' +import notification, { ChatMessage } from '@hcengineering/notification' import faker from 'faker' export interface CommentOptions { @@ -20,17 +20,25 @@ export async function addComments ( ): Promise { const commentsCount = options.min + faker.datatype.number(options.max) for (let i = 0; i < commentsCount; i++) { - const commentId = `candidate-comment-${generateId()}-${i}` as Ref + const commentId = `candidate-comment-${generateId()}-${i}` as Ref - const commentData: AttachedData = { + const commentData: AttachedData = { message: faker.lorem.paragraphs(options.paragraphMin + faker.datatype.number(options.paragraphMax)) } - await client.addCollection(chunter.class.Comment, space, objectId, _class, collection, commentData, commentId) + await client.addCollection( + notification.class.ChatMessage, + space, + objectId, + _class, + collection, + commentData, + commentId + ) if (faker.datatype.number(100) > options.updateFactor) { const updateMsg = faker.lorem.paragraphs(options.paragraphMin + faker.datatype.number(options.paragraphMax)) - await client.updateCollection(chunter.class.Comment, space, commentId, objectId, _class, collection, { + await client.updateCollection(notification.class.ChatMessage, space, commentId, objectId, _class, collection, { message: updateMsg }) } diff --git a/dev/tool/package.json b/dev/tool/package.json index ee09ff70c6..33f918d8fd 100644 --- a/dev/tool/package.json +++ b/dev/tool/package.json @@ -46,81 +46,81 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "mongodb": "^4.11.0", - "commander": "^8.1.0", - "@hcengineering/account": "^0.6.0", - "@hcengineering/core": "^0.6.28", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/model-all": "^0.6.0", - "@hcengineering/model-telegram": "^0.6.0", - "@hcengineering/telegram": "^0.6.14", - "@hcengineering/client-resources": "^0.6.23", - "ws": "^8.10.0", - "@hcengineering/client": "^0.6.14", - "@hcengineering/platform": "^0.6.9", - "@hcengineering/model": "^0.6.7", - "fast-equals": "^2.0.3", "@elastic/elasticsearch": "^7.14.0", + "@hcengineering/account": "^0.6.0", + "@hcengineering/attachment": "^0.6.9", + "@hcengineering/client": "^0.6.14", + "@hcengineering/client-resources": "^0.6.23", + "@hcengineering/contact": "^0.6.20", + "@hcengineering/core": "^0.6.28", + "@hcengineering/dev-storage": "^0.6.6", "@hcengineering/elastic": "^0.6.0", - "@hcengineering/server-core": "^0.6.1", - "@hcengineering/server-token": "^0.6.7", + "@hcengineering/lead": "^0.6.0", + "@hcengineering/minio": "^0.6.0", + "@hcengineering/model": "^0.6.7", + "@hcengineering/model-all": "^0.6.0", "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/model-contact": "^0.6.1", + "@hcengineering/model-recruit": "^0.6.0", + "@hcengineering/model-telegram": "^0.6.0", "@hcengineering/mongo": "^0.6.1", - "@hcengineering/dev-storage": "^0.6.6", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/openai": "^0.6.0", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/recruit": "^0.6.21", + "@hcengineering/rekoni": "^0.6.0", "@hcengineering/server-attachment": "^0.6.1", "@hcengineering/server-attachment-resources": "^0.6.0", - "xml2js": "~0.4.23", - "@hcengineering/model-recruit": "^0.6.0", - "@hcengineering/recruit": "^0.6.21", - "@hcengineering/task": "^0.6.13", - "@hcengineering/chunter": "^0.6.12", - "mime-types": "~2.1.34", - "@hcengineering/attachment": "^0.6.9", - "@hcengineering/server-contact": "^0.6.1", - "@hcengineering/server-contact-resources": "^0.6.0", - "@hcengineering/server-notification": "^0.6.1", - "@hcengineering/server-notification-resources": "^0.6.0", - "@hcengineering/server-setting": "^0.6.0", - "@hcengineering/server-setting-resources": "^0.6.0", - "@hcengineering/server-tool": "^0.6.0", + "@hcengineering/server-backup": "^0.6.0", + "@hcengineering/server-calendar": "^0.6.0", + "@hcengineering/server-calendar-resources": "^0.6.0", "@hcengineering/server-chunter": "^0.6.0", "@hcengineering/server-chunter-resources": "^0.6.0", + "@hcengineering/server-contact": "^0.6.1", + "@hcengineering/server-contact-resources": "^0.6.0", + "@hcengineering/server-core": "^0.6.1", + "@hcengineering/server-gmail": "^0.6.0", + "@hcengineering/server-gmail-resources": "^0.6.0", + "@hcengineering/server-hr": "^0.6.0", + "@hcengineering/server-hr-resources": "^0.6.0", "@hcengineering/server-inventory": "^0.6.1", "@hcengineering/server-inventory-resources": "^0.6.0", "@hcengineering/server-lead": "^0.6.0", "@hcengineering/server-lead-resources": "^0.6.0", + "@hcengineering/server-notification": "^0.6.1", + "@hcengineering/server-notification-resources": "^0.6.0", "@hcengineering/server-recruit": "^0.6.0", "@hcengineering/server-recruit-resources": "^0.6.0", - "@hcengineering/server-task": "^0.6.0", - "@hcengineering/server-task-resources": "^0.6.0", - "@hcengineering/server-tracker": "^0.6.0", - "@hcengineering/server-tracker-resources": "^0.6.0", - "@hcengineering/server-tags": "^0.6.0", - "@hcengineering/server-tags-resources": "^0.6.0", - "@hcengineering/server-calendar": "^0.6.0", - "@hcengineering/server-calendar-resources": "^0.6.0", - "@hcengineering/server-gmail": "^0.6.0", - "@hcengineering/server-gmail-resources": "^0.6.0", - "@hcengineering/server-telegram": "^0.6.0", - "@hcengineering/server-telegram-resources": "^0.6.0", - "@hcengineering/server-hr": "^0.6.0", - "@hcengineering/server-hr-resources": "^0.6.0", "@hcengineering/server-request": "^0.6.0", "@hcengineering/server-request-resources": "^0.6.0", + "@hcengineering/server-setting": "^0.6.0", + "@hcengineering/server-setting-resources": "^0.6.0", + "@hcengineering/server-tags": "^0.6.0", + "@hcengineering/server-tags-resources": "^0.6.0", + "@hcengineering/server-task": "^0.6.0", + "@hcengineering/server-task-resources": "^0.6.0", + "@hcengineering/server-telegram": "^0.6.0", + "@hcengineering/server-telegram-resources": "^0.6.0", + "@hcengineering/server-token": "^0.6.7", + "@hcengineering/server-tool": "^0.6.0", + "@hcengineering/server-tracker": "^0.6.0", + "@hcengineering/server-tracker-resources": "^0.6.0", "@hcengineering/server-view": "^0.6.0", "@hcengineering/server-view-resources": "^0.6.0", - "@hcengineering/rekoni": "^0.6.0", - "got": "^11.8.3", - "@hcengineering/tags": "^0.6.12", - "@hcengineering/server-backup": "^0.6.0", - "csv-parse": "~5.1.0", - "@hcengineering/lead": "^0.6.0", - "email-addresses": "^5.0.0", - "libphonenumber-js": "^1.9.46", "@hcengineering/setting": "^0.6.11", - "@hcengineering/minio": "^0.6.0", - "@hcengineering/openai": "^0.6.0", - "@hcengineering/tracker": "^0.6.13" + "@hcengineering/tags": "^0.6.12", + "@hcengineering/task": "^0.6.13", + "@hcengineering/telegram": "^0.6.14", + "@hcengineering/tracker": "^0.6.13", + "commander": "^8.1.0", + "csv-parse": "~5.1.0", + "email-addresses": "^5.0.0", + "fast-equals": "^2.0.3", + "got": "^11.8.3", + "libphonenumber-js": "^1.9.46", + "mime-types": "~2.1.34", + "mongodb": "^4.11.0", + "ws": "^8.10.0", + "xml2js": "~0.4.23" } } diff --git a/dev/tool/src/clean.ts b/dev/tool/src/clean.ts index f6d8d986be..3303c21646 100644 --- a/dev/tool/src/clean.ts +++ b/dev/tool/src/clean.ts @@ -14,7 +14,6 @@ // import attachment from '@hcengineering/attachment' -import chunter, { Comment } from '@hcengineering/chunter' import contact from '@hcengineering/contact' import { deepEqual } from 'fast-equals' import core, { @@ -39,6 +38,7 @@ import { connect } from '@hcengineering/server-tool' import tracker from '@hcengineering/tracker' import tags, { TagCategory, TagElement, TagReference } from '@hcengineering/tags' import { MongoClient } from 'mongodb' +import notification, { ChatMessage } from '@hcengineering/notification' export const DOMAIN_COMMENT = 'comment' as Domain @@ -322,11 +322,11 @@ export async function fixCommentDoubleIdCreate (workspaceId: WorkspaceId, transa try { const commentTxes = await connection.findAll(core.class.TxCollectionCUD, { 'tx._class': core.class.TxCreateDoc, - 'tx.objectClass': chunter.class.Comment + 'tx.objectClass': notification.class.ChatMessage }) const commentTxesRemoved = await connection.findAll(core.class.TxCollectionCUD, { 'tx._class': core.class.TxRemoveDoc, - 'tx.objectClass': chunter.class.Comment + 'tx.objectClass': notification.class.ChatMessage }) const removed = new Map(commentTxesRemoved.map((it) => [it.tx.objectId, it])) // Do not checked removed @@ -341,7 +341,7 @@ export async function fixCommentDoubleIdCreate (workspaceId: WorkspaceId, transa objSet.add(cid) if (has) { // We have found duplicate one, let's rename it. - const doc = TxProcessor.createDoc2Doc(c.tx as unknown as TxCreateDoc) + const doc = TxProcessor.createDoc2Doc(c.tx as unknown as TxCreateDoc) if (doc.message !== '' && doc.message.trim() !== '

') { await connection.clean(DOMAIN_TX, [c._id]) if (oldValue.get(cid) === doc.message.trim()) { @@ -351,7 +351,7 @@ export async function fixCommentDoubleIdCreate (workspaceId: WorkspaceId, transa console.log('renaming', cid, doc.message) // Remove previous transaction. c.tx.objectId = generateId() - doc._id = c.tx.objectId as Ref + doc._id = c.tx.objectId as Ref await connection.upload(DOMAIN_TX, [c]) // Also we need to create snapsot await connection.upload(DOMAIN_COMMENT, [doc]) diff --git a/models/activity/package.json b/models/activity/package.json index ec23e95b59..fe1ddfcaa9 100644 --- a/models/activity/package.json +++ b/models/activity/package.json @@ -15,23 +15,22 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { + "@hcengineering/activity": "^0.6.0", + "@hcengineering/activity-resources": "^0.6.1", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/platform": "^0.6.9", "@hcengineering/model-core": "^0.6.0", - "@hcengineering/activity": "^0.6.0", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/activity-resources": "^0.6.1" + "@hcengineering/platform": "^0.6.9", + "@hcengineering/ui": "^0.6.11" } } diff --git a/models/activity/src/index.ts b/models/activity/src/index.ts index 1017261eb9..42b8a3b812 100644 --- a/models/activity/src/index.ts +++ b/models/activity/src/index.ts @@ -13,18 +13,11 @@ // limitations under the License. // -import type { - ActivityExtension, - ActivityExtensionKind, - ActivityFilter, - DisplayTx, - ExtraActivityComponent, - TxViewlet -} from '@hcengineering/activity' +import type { TxViewlet } from '@hcengineering/activity' import core, { DOMAIN_MODEL, type Class, type Doc, type DocumentQuery, type Ref, type Tx } from '@hcengineering/core' -import { Mixin, Model, type Builder } from '@hcengineering/model' -import { TClass, TDoc } from '@hcengineering/model-core' -import type { Asset, IntlString, Resource } from '@hcengineering/platform' +import { Model, type Builder } from '@hcengineering/model' +import { TDoc } from '@hcengineering/model-core' +import type { Asset, IntlString } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui/src/types' import activity from './plugin' @@ -46,31 +39,8 @@ export class TTxViewlet extends TDoc implements TxViewlet { hideOnRemove!: boolean } -@Model(activity.class.ActivityFilter, core.class.Doc, DOMAIN_MODEL) -export class TActivityFilter extends TDoc implements ActivityFilter { - label!: IntlString - filter!: Resource<(tx: DisplayTx, _class?: Ref) => boolean> -} - -@Model(activity.class.ActivityExtension, core.class.Doc, DOMAIN_MODEL) -export class TActivityExtension extends TDoc implements ActivityExtension { - ofClass!: Ref> - components?: Partial> - mentionClass?: Ref> -} - -@Mixin(activity.mixin.ExtraActivityComponent, core.class.Class) -export class TExtraActivityComponent extends TClass implements ExtraActivityComponent { - component!: AnyComponent -} - export function createModel (builder: Builder): void { - builder.createModel(TTxViewlet, TActivityFilter, TExtraActivityComponent, TActivityExtension) - - builder.createDoc(activity.class.ActivityFilter, core.space.Model, { - label: activity.string.Attributes, - filter: activity.filter.AttributeFilter - }) + builder.createModel(TTxViewlet) } export default activity diff --git a/models/activity/src/plugin.ts b/models/activity/src/plugin.ts index 50905c0f66..ecac7b59a8 100644 --- a/models/activity/src/plugin.ts +++ b/models/activity/src/plugin.ts @@ -12,18 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -import type { DisplayTx } from '@hcengineering/activity' import { activityId } from '@hcengineering/activity' import activity from '@hcengineering/activity-resources/src/plugin' -import type { Resource, IntlString } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' -import { type Doc, type Ref } from '@hcengineering/core' -export default mergeIds(activityId, activity, { - filter: { - AttributeFilter: '' as Resource<(tx: DisplayTx, _class?: Ref) => boolean> - }, - string: { - Attributes: '' as IntlString - } -}) +export default mergeIds(activityId, activity, {}) diff --git a/models/all/src/migration.ts b/models/all/src/migration.ts index d5e11911c3..a2fbe38b92 100644 --- a/models/all/src/migration.ts +++ b/models/all/src/migration.ts @@ -36,6 +36,7 @@ import { boardOperation } from '@hcengineering/model-board' import { hrOperation } from '@hcengineering/model-hr' import { bitrixOperation } from '@hcengineering/model-bitrix' import { calendarOperation } from '@hcengineering/model-calendar' +import { notificationServerOperation } from '@hcengineering/model-server-notification' export const migrateOperations: [string, MigrateOperation][] = [ ['core', coreOperation], @@ -58,5 +59,6 @@ export const migrateOperations: [string, MigrateOperation][] = [ ['board', boardOperation], ['hr', hrOperation], ['bitrix', bitrixOperation], - ['inventiry', inventoryOperation] + ['inventiry', inventoryOperation], + ['notificationServer', notificationServerOperation] ] diff --git a/models/attachment/package.json b/models/attachment/package.json index 98a18ee5ec..a16d569ce8 100644 --- a/models/attachment/package.json +++ b/models/attachment/package.json @@ -15,26 +15,27 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/core": "^0.6.28", - "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", + "@hcengineering/activity": "^0.6.0", "@hcengineering/attachment": "^0.6.9", "@hcengineering/attachment-resources": "^0.6.0", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/core": "^0.6.28", + "@hcengineering/model": "^0.6.7", "@hcengineering/model-core": "^0.6.0", - "@hcengineering/model-view": "^0.6.0", - "@hcengineering/activity": "^0.6.0", "@hcengineering/model-preference": "^0.6.0", + "@hcengineering/model-view": "^0.6.0", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/ui": "^0.6.11", "@hcengineering/view": "^0.6.9" } } diff --git a/models/attachment/src/index.ts b/models/attachment/src/index.ts index 8cf3da567f..97783eccea 100644 --- a/models/attachment/src/index.ts +++ b/models/attachment/src/index.ts @@ -32,6 +32,7 @@ import core, { TAttachedDoc } from '@hcengineering/model-core' import preference, { TPreference } from '@hcengineering/model-preference' import view, { createAction } from '@hcengineering/model-view' import attachment from './plugin' +import notification from '@hcengineering/notification' export { attachmentId } from '@hcengineering/attachment' export { attachmentOperation } from './migration' @@ -122,7 +123,33 @@ export function createModel (builder: Builder): void { attachment.ids.TxAttachmentRemove ) - builder.createDoc(activity.class.ActivityFilter, core.space.Model, { + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: attachment.class.Attachment, + action: 'create', + icon: attachment.icon.Attachment, + label: attachment.string.AddAttachment, + component: attachment.notification.NotificationAttachmentChanged + }, + attachment.ids.NotificationAttachmentCreated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: attachment.class.Attachment, + action: 'remove', + icon: attachment.icon.Attachment, + label: attachment.string.RemovedAttachment, + component: attachment.notification.NotificationAttachmentChanged + }, + attachment.ids.NotificationAttachmentRemoved + ) + + builder.createDoc(notification.class.ActivityMessagesFilter, core.space.Model, { label: attachment.string.FilterAttachments, filter: attachment.filter.AttachmentsFilter }) diff --git a/models/attachment/src/plugin.ts b/models/attachment/src/plugin.ts index 0958be8a12..f74e51257c 100644 --- a/models/attachment/src/plugin.ts +++ b/models/attachment/src/plugin.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import type { DisplayTx, TxViewlet } from '@hcengineering/activity' +import type { TxViewlet } from '@hcengineering/activity' import { attachmentId } from '@hcengineering/attachment' import attachment from '@hcengineering/attachment-resources/src/plugin' import type { Ref, Doc } from '@hcengineering/core' @@ -21,6 +21,7 @@ import type { IntlString, Resource } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import type { AnyComponent } from '@hcengineering/ui/src/types' import type { ActionCategory } from '@hcengineering/view' +import { type ActivityMessage, type DocUpdateMessageViewlet } from '@hcengineering/notification' export default mergeIds(attachmentId, attachment, { component: { @@ -45,15 +46,20 @@ export default mergeIds(attachmentId, attachment, { }, ids: { TxAttachmentCreate: '' as Ref, - TxAttachmentRemove: '' as Ref + TxAttachmentRemove: '' as Ref, + NotificationAttachmentCreated: '' as Ref, + NotificationAttachmentRemoved: '' as Ref }, activity: { TxAttachmentCreate: '' as AnyComponent }, + notification: { + NotificationAttachmentChanged: '' as AnyComponent + }, category: { Attachments: '' as Ref }, filter: { - AttachmentsFilter: '' as Resource<(tx: DisplayTx, _class?: Ref) => boolean> + AttachmentsFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> } }) diff --git a/models/calendar/src/index.ts b/models/calendar/src/index.ts index ff790a1231..39f5d708a0 100644 --- a/models/calendar/src/index.ts +++ b/models/calendar/src/index.ts @@ -243,6 +243,18 @@ export function createModel (builder: Builder): void { calendar.ids.ReminderViewlet ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: calendar.class.Event, + icon: calendar.icon.Reminder, + action: 'update', + hideIfRemoved: true + }, + calendar.ids.UpdateRemainderNotificationViewlet + ) + builder.createDoc( view.class.ViewletDescriptor, core.space.Model, diff --git a/models/calendar/src/plugin.ts b/models/calendar/src/plugin.ts index ba7cfd3623..c9f7eb6599 100644 --- a/models/calendar/src/plugin.ts +++ b/models/calendar/src/plugin.ts @@ -17,7 +17,7 @@ import { type TxViewlet } from '@hcengineering/activity' import { calendarId } from '@hcengineering/calendar' import calendar from '@hcengineering/calendar-resources/src/plugin' import { type Ref } from '@hcengineering/core' -import { type NotificationGroup } from '@hcengineering/notification' +import { type DocUpdateMessageViewlet, type NotificationGroup } from '@hcengineering/notification' import type { IntlString } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui/src/types' @@ -66,6 +66,7 @@ export default mergeIds(calendarId, calendar, { }, ids: { ReminderViewlet: '' as Ref, + UpdateRemainderNotificationViewlet: '' as Ref, CalendarNotificationGroup: '' as Ref } }) diff --git a/models/chunter/package.json b/models/chunter/package.json index 5cf1b3d09b..46e7318370 100644 --- a/models/chunter/package.json +++ b/models/chunter/package.json @@ -15,32 +15,33 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/core": "^0.6.28", - "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/view": "^0.6.9", - "@hcengineering/model-attachment": "^0.6.0", - "@hcengineering/contact": "^0.6.20", + "@hcengineering/activity": "^0.6.0", + "@hcengineering/attachment": "^0.6.9", "@hcengineering/chunter": "^0.6.12", "@hcengineering/chunter-resources": "^0.6.0", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/contact": "^0.6.20", + "@hcengineering/core": "^0.6.28", + "@hcengineering/model": "^0.6.7", + "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/model-preference": "^0.6.0", "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-workbench": "^0.6.1", - "@hcengineering/model-notification": "^0.6.0", "@hcengineering/notification": "^0.6.16", - "@hcengineering/activity": "^0.6.0", - "@hcengineering/workbench": "^0.6.9", - "@hcengineering/model-preference": "^0.6.0" + "@hcengineering/platform": "^0.6.9", + "@hcengineering/ui": "^0.6.11", + "@hcengineering/view": "^0.6.9", + "@hcengineering/workbench": "^0.6.9" } } diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index c69b9f43b0..329892ecec 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -195,6 +195,8 @@ export function createModel (builder: Builder, options = { addApplication: true const spaceClasses = [chunter.class.Channel, chunter.class.DirectMessage] spaceClasses.forEach((spaceClass) => { + builder.mixin(spaceClass, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(spaceClass, core.class.Class, workbench.mixin.SpaceView, { view: { class: chunter.class.Message @@ -475,18 +477,6 @@ export function createModel (builder: Builder, options = { addApplication: true ) } - builder.mixin(chunter.class.Comment, core.class.Class, view.mixin.ObjectPresenter, { - presenter: chunter.component.CommentPresenter - }) - - builder.mixin(chunter.class.Comment, core.class.Class, view.mixin.CollectionPresenter, { - presenter: chunter.component.CommentsPresenter - }) - - builder.mixin(chunter.class.Comment, core.class.Class, view.mixin.ObjectPanel, { - component: chunter.component.CommentPanel - }) - builder.createDoc( activity.class.TxViewlet, core.space.Model, @@ -503,6 +493,22 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.TxCommentCreate ) + builder.createDoc( + activity.class.TxViewlet, + core.space.Model, + { + objectClass: notification.class.ChatMessage, + icon: chunter.icon.Chunter, + txClass: core.class.TxCreateDoc, + component: chunter.activity.TxCommentCreate, + label: chunter.string.LeftComment, + display: 'content', + editable: true, + hideOnRemove: true + }, + chunter.ids.TxChatMessageCreate + ) + createAction( builder, { @@ -606,6 +612,19 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.TxCommentRemove ) + builder.createDoc( + activity.class.TxViewlet, + core.space.Model, + { + objectClass: notification.class.ChatMessage, + icon: chunter.icon.Chunter, + txClass: core.class.TxRemoveDoc, + display: 'inline', + hideOnRemove: true + }, + chunter.ids.TxChatMessageRemove + ) + builder.createDoc( activity.class.TxViewlet, core.space.Model, @@ -629,9 +648,9 @@ export function createModel (builder: Builder, options = { addApplication: true objectClass: chunter.class.Backlink, icon: chunter.icon.Chunter, txClass: core.class.TxCreateDoc, - component: chunter.activity.TxBacklinkCreate, + component: chunter.component.BacklinkContent, label: chunter.string.MentionedIn, - labelComponent: chunter.activity.TxBacklinkReference, + labelComponent: chunter.component.BacklinkReference, display: 'emphasized', editable: false, hideOnRemove: true @@ -653,17 +672,7 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.TxBacklinkRemove ) - builder.createDoc(activity.class.ActivityFilter, core.space.Model, { - label: chunter.string.FilterComments, - filter: chunter.filter.CommentsFilter - }) - - builder.createDoc(activity.class.ActivityFilter, core.space.Model, { - label: chunter.string.FilterPinnedComments, - filter: chunter.filter.PinnedCommentsFilter - }) - - builder.createDoc(activity.class.ActivityFilter, core.space.Model, { + builder.createDoc(notification.class.ActivityMessagesFilter, core.space.Model, { label: chunter.string.FilterBacklinks, filter: chunter.filter.BacklinksFilter }) @@ -750,38 +759,41 @@ export function createModel (builder: Builder, options = { addApplication: true ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ActivityMessageExtension, core.space.Model, { - ofClass: chunter.class.Comment, - components: { - footer: chunter.component.CommentReactions, - action: chunter.component.ReactionsAction - } + ofMessage: notification.class.DocUpdateMessage, + components: [ + { + kind: 'footer', + component: chunter.component.ReactionsPresenter + }, + { + kind: 'action', + component: chunter.component.ActivityMessageReactionsAction + } + ] }, - chunter.ids.ActivityExtension + chunter.ids.DocUpdateMessageExtension ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ActivityMessageExtension, core.space.Model, { - ofClass: chunter.class.Comment, - components: { - action: chunter.component.PinComment - } + ofMessage: notification.class.ChatMessage, + components: [ + { + kind: 'footer', + component: chunter.component.ReactionsPresenter + }, + { + kind: 'action', + component: chunter.component.ActivityMessageReactionsAction + } + ] }, - chunter.ids.PinExtension - ) - - builder.createDoc( - activity.class.ActivityExtension, - core.space.Model, - { - ofClass: chunter.class.Backlink, - isMention: true - }, - chunter.ids.BackLinkActivityExtension + chunter.ids.ChatMessageExtension ) builder.createDoc( @@ -801,6 +813,55 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.ThreadNotification ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: chunter.class.Backlink, + action: 'create', + component: chunter.component.BacklinkContent, + labelComponent: chunter.component.NotificationBacklinkLabel, + hideIfRemoved: true + }, + chunter.ids.NotificationBacklinkCreated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: chunter.class.Backlink, + action: 'remove', + hideIfRemoved: true + }, + chunter.ids.NotificationBacklinkRemoved + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: chunter.class.Reaction, + action: 'create', + component: chunter.component.NotificationReactionCreated, + label: chunter.string.Reacted, + onlyWithParent: true, + hideIfRemoved: true + }, + chunter.ids.NotificationReactionCreated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: chunter.class.Reaction, + action: 'remove', + hideIfRemoved: true + }, + chunter.ids.NotificationReactionRemoved + ) + createAction(builder, { ...viewTemplates.open, target: chunter.class.Channel, diff --git a/models/chunter/src/migration.ts b/models/chunter/src/migration.ts index 5399eceeed..7bd812ba5a 100644 --- a/models/chunter/src/migration.ts +++ b/models/chunter/src/migration.ts @@ -14,7 +14,17 @@ // import core, { TxOperations } from '@hcengineering/core' -import { type MigrateOperation, type MigrationClient, type MigrationUpgradeClient } from '@hcengineering/model' +import { + type MigrateOperation, + type MigrationClient, + type MigrationUpgradeClient, + tryMigrate +} from '@hcengineering/model' +import { chunterId } from '@hcengineering/chunter' +import notification from '@hcengineering/notification' +import { DOMAIN_NOTIFICATION } from '@hcengineering/model-notification' + +import { DOMAIN_COMMENT } from './index' import chunter from './plugin' export async function createGeneral (tx: TxOperations): Promise { @@ -79,8 +89,20 @@ async function createBacklink (tx: TxOperations): Promise { } } +async function convertCommentsToChatMessages (client: MigrationClient): Promise { + await client.update(DOMAIN_COMMENT, { _class: chunter.class.Comment }, { _class: notification.class.ChatMessage }) + await client.move(DOMAIN_COMMENT, { _class: notification.class.ChatMessage }, DOMAIN_NOTIFICATION) +} + export const chunterOperation: MigrateOperation = { - async migrate (client: MigrationClient): Promise {}, + async migrate (client: MigrationClient): Promise { + await tryMigrate(client, chunterId, [ + { + state: 'create-chat-messages', + func: convertCommentsToChatMessages + } + ]) + }, async upgrade (client: MigrationUpgradeClient): Promise { const tx = new TxOperations(client, core.account.System) await createGeneral(tx) diff --git a/models/chunter/src/plugin.ts b/models/chunter/src/plugin.ts index 5232008676..f873e2559c 100644 --- a/models/chunter/src/plugin.ts +++ b/models/chunter/src/plugin.ts @@ -13,11 +13,16 @@ // limitations under the License. // -import type { ActivityExtension, DisplayTx, TxViewlet } from '@hcengineering/activity' +import type { TxViewlet } from '@hcengineering/activity' import { chunterId, type Channel } from '@hcengineering/chunter' import chunter from '@hcengineering/chunter-resources/src/plugin' import type { Doc, Ref, Space } from '@hcengineering/core' -import { type NotificationGroup } from '@hcengineering/notification' +import { + type ActivityMessage, + type ActivityMessageExtension, + type DocUpdateMessageViewlet, + type NotificationGroup +} from '@hcengineering/notification' import type { IntlString, Resource } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import type { AnyComponent, Location } from '@hcengineering/ui/src/types' @@ -25,7 +30,6 @@ import type { Action, ActionCategory, ViewAction, ViewletDescriptor } from '@hce export default mergeIds(chunterId, chunter, { component: { - CommentPresenter: '' as AnyComponent, ChannelPresenter: '' as AnyComponent, DirectMessagePresenter: '' as AnyComponent, MessagePresenter: '' as AnyComponent, @@ -33,9 +37,11 @@ export default mergeIds(chunterId, chunter, { Threads: '' as AnyComponent, SavedMessages: '' as AnyComponent, ChunterBrowser: '' as AnyComponent, - CommentReactions: '' as AnyComponent, + ReactionsPresenter: '' as AnyComponent, ReactionsAction: '' as AnyComponent, - PinComment: '' as AnyComponent + ActivityMessageReactionsAction: '' as AnyComponent, + BacklinkContent: '' as AnyComponent, + BacklinkReference: '' as AnyComponent }, action: { MarkCommentUnread: '' as Ref, @@ -74,15 +80,13 @@ export default mergeIds(chunterId, chunter, { PinnedMessages: '' as IntlString, SavedMessages: '' as IntlString, ThreadMessage: '' as IntlString, - Reactions: '' as IntlString, Emoji: '' as IntlString, - FilterComments: '' as IntlString, - FilterPinnedComments: '' as IntlString, FilterBacklinks: '' as IntlString, DM: '' as IntlString, DMNotification: '' as IntlString, ConfigLabel: '' as IntlString, - ConfigDescription: '' as IntlString + ConfigDescription: '' as IntlString, + Reacted: '' as IntlString }, viewlet: { Chat: '' as Ref @@ -93,15 +97,18 @@ export default mergeIds(chunterId, chunter, { TxCommentRemove: '' as Ref, TxBacklinkRemove: '' as Ref, TxMessageCreate: '' as Ref, + TxChatMessageCreate: '' as Ref, + TxChatMessageRemove: '' as Ref, ChunterNotificationGroup: '' as Ref, - ActivityExtension: '' as Ref, - BackLinkActivityExtension: '' as Ref, - PinExtension: '' as Ref + DocUpdateMessageExtension: '' as Ref, + ChatMessageExtension: '' as Ref, + NotificationBacklinkCreated: '' as Ref, + NotificationBacklinkRemoved: '' as Ref, + NotificationReactionCreated: '' as Ref, + NotificationReactionRemoved: '' as Ref }, activity: { TxCommentCreate: '' as AnyComponent, - TxBacklinkCreate: '' as AnyComponent, - TxBacklinkReference: '' as AnyComponent, TxMessageCreate: '' as AnyComponent }, space: { @@ -114,8 +121,6 @@ export default mergeIds(chunterId, chunter, { GetFragment: '' as Resource<(doc: Doc, props: Record) => Promise> }, filter: { - CommentsFilter: '' as Resource<(tx: DisplayTx, _class?: Ref) => boolean>, - PinnedCommentsFilter: '' as Resource<(tx: DisplayTx, _class?: Ref) => boolean>, - BacklinksFilter: '' as Resource<(tx: DisplayTx, _class?: Ref) => boolean> + BacklinksFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> } }) diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index b5b2562fc0..d5005475bf 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -112,7 +112,7 @@ export class TContact extends TDoc implements Contact { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number @Prop(TypeString(), contact.string.Location) @@ -221,6 +221,26 @@ export function createModel (builder: Builder): void { TContactsTab ) + builder.mixin(contact.class.Contact, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(contact.class.Person, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(contact.mixin.Employee, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(contact.class.Organization, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + + builder.mixin(contact.class.Person, core.class.Class, notification.mixin.NotificationObjectPreposition, { + preposition: contact.string.For + }) + builder.mixin(contact.mixin.Employee, core.class.Class, notification.mixin.NotificationObjectPreposition, { + preposition: contact.string.For + }) + builder.mixin(contact.mixin.Employee, core.class.Class, view.mixin.ObjectFactory, { component: contact.component.CreateEmployee }) @@ -309,6 +329,16 @@ export function createModel (builder: Builder): void { match: { 'operations.name': { $exists: true } } }) + builder.createDoc(notification.class.DocUpdateMessageViewlet, core.space.Model, { + objectClass: contact.class.Person, + action: 'update', + config: { + name: { + presenter: contact.notification.NotificationNameChanged + } + } + }) + builder.createDoc( view.class.Viewlet, core.space.Model, @@ -938,32 +968,34 @@ export function createModel (builder: Builder): void { ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: contact.class.Person, - components: { - input: chunter.component.CommentInput - } + objectClass: contact.class.Person, + label: chunter.string.LeftComment }, - contact.ids.PersonActivityExtension + contact.ids.PersonChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: contact.class.Organization, - components: { - input: chunter.component.CommentInput - } + objectClass: contact.mixin.Employee, + label: chunter.string.LeftComment }, - contact.ids.OrganizationActivityExtension + contact.ids.EmployeeChatMessageViewlet ) - builder.mixin(contact.class.Contact, core.class.Class, activity.mixin.ExtraActivityComponent, { - component: contact.component.ActivityChannelMessage - }) + builder.createDoc( + notification.class.ChatMessageViewlet, + core.space.Model, + { + objectClass: contact.class.Organization, + label: chunter.string.LeftComment + }, + contact.ids.OrganizationChatMessageViewlet + ) builder.createDoc( notification.class.NotificationGroup, diff --git a/models/contact/src/plugin.ts b/models/contact/src/plugin.ts index 022e2cb2a1..3cda3bff46 100644 --- a/models/contact/src/plugin.ts +++ b/models/contact/src/plugin.ts @@ -17,19 +17,20 @@ import { contactId } from '@hcengineering/contact' import contact from '@hcengineering/contact-resources/src/plugin' import type { Client, Doc, Ref } from '@hcengineering/core' -import {} from '@hcengineering/core' import { type ObjectSearchCategory, type ObjectSearchFactory } from '@hcengineering/model-presentation' -import { type NotificationGroup } from '@hcengineering/notification' +import { type ChatMessageViewlet, type NotificationGroup } from '@hcengineering/notification' import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform' import { type TemplateFieldFunc } from '@hcengineering/templates' import type { AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ActionCategory, type ViewAction } from '@hcengineering/view' -import { type ActivityExtension } from '@hcengineering/activity' export default mergeIds(contactId, contact, { activity: { TxNameChange: '' as AnyComponent }, + notification: { + NotificationNameChanged: '' as AnyComponent + }, component: { PersonPresenter: '' as AnyComponent, ContactRefPresenter: '' as AnyComponent, @@ -57,7 +58,6 @@ export default mergeIds(contactId, contact, { AccountArrayEditor: '' as AnyComponent, ChannelFilter: '' as AnyComponent, MergePersons: '' as AnyComponent, - ActivityChannelMessage: '' as AnyComponent, ChannelPanel: '' as AnyComponent, ActivityChannelPresenter: '' as AnyComponent, EmployeeFilter: '' as AnyComponent, @@ -116,8 +116,9 @@ export default mergeIds(contactId, contact, { ids: { OrganizationNotificationGroup: '' as Ref, PersonNotificationGroup: '' as Ref, - PersonActivityExtension: '' as Ref, - OrganizationActivityExtension: '' as Ref + OrganizationChatMessageViewlet: '' as Ref, + PersonChatMessageViewlet: '' as Ref, + EmployeeChatMessageViewlet: '' as Ref }, action: { KickEmployee: '' as Ref, @@ -135,6 +136,6 @@ export default mergeIds(contactId, contact, { GetContactName: '' as Resource, GetContactFirstName: '' as Resource, GetContactLastName: '' as Resource, - ContactTitleProvider: '' as Resource<(client: Client, ref: Ref) => Promise> + ContactTitleProvider: '' as Resource<(client: Client, ref: Ref, doc?: Doc) => Promise> } }) diff --git a/models/hr/package.json b/models/hr/package.json index d9cb9c8102..d66814350c 100644 --- a/models/hr/package.json +++ b/models/hr/package.json @@ -35,7 +35,6 @@ "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-workbench": "^0.6.1", "@hcengineering/model-contact": "^0.6.1", - "@hcengineering/model-chunter": "^0.6.0", "@hcengineering/model-calendar": "^0.6.0", "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/hr": "^0.6.12", diff --git a/models/hr/src/index.ts b/models/hr/src/index.ts index 069e6ead48..8cfc91717a 100644 --- a/models/hr/src/index.ts +++ b/models/hr/src/index.ts @@ -51,7 +51,6 @@ import { } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' import calendar from '@hcengineering/model-calendar' -import chunter from '@hcengineering/model-chunter' import contact, { TEmployee, TPersonAccount } from '@hcengineering/model-contact' import core, { TAttachedDoc, TDoc, TSpace, TType } from '@hcengineering/model-core' import view, { classPresenter, createAction } from '@hcengineering/model-view' @@ -84,7 +83,7 @@ export class TDepartment extends TSpace implements Department { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number avatar?: string | null @@ -158,7 +157,7 @@ export class TRequest extends TAttachedDoc implements Request { @Hidden() type!: Ref - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) diff --git a/models/inventory/package.json b/models/inventory/package.json index d722290f85..29a3e54648 100644 --- a/models/inventory/package.json +++ b/models/inventory/package.json @@ -25,7 +25,6 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/activity": "^0.6.0", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", "@hcengineering/model-workbench": "^0.6.1", diff --git a/models/inventory/src/index.ts b/models/inventory/src/index.ts index d5720cc252..c355e96053 100644 --- a/models/inventory/src/index.ts +++ b/models/inventory/src/index.ts @@ -14,7 +14,6 @@ // import { type Domain, IndexKind, type Ref } from '@hcengineering/core' -import activity from '@hcengineering/activity' import { type Category, type Product, type Variant, inventoryId } from '@hcengineering/inventory' import { type Builder, Collection, Index, Model, Prop, TypeRef, TypeString, UX } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' @@ -23,9 +22,10 @@ import { createAction } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import setting from '@hcengineering/setting' import view, { type Viewlet } from '@hcengineering/view' +import notification from '@hcengineering/notification' import chunter from '@hcengineering/model-chunter' -import inventory from './plugin' +import inventory from './plugin' export { inventoryId } from '@hcengineering/inventory' export { inventoryOperation } from './migration' export { default } from './plugin' @@ -79,6 +79,10 @@ export class TVariant extends TAttachedDoc implements Variant { export function createModel (builder: Builder): void { builder.createModel(TCategory, TProduct, TVariant) + builder.mixin(inventory.class.Product, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(inventory.class.Category, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(inventory.class.Variant, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(inventory.class.Category, core.class.Class, view.mixin.ObjectPresenter, { presenter: inventory.component.CategoryPresenter }) @@ -165,27 +169,23 @@ export function createModel (builder: Builder): void { ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: inventory.class.Product, - components: { - input: chunter.component.CommentInput - } + objectClass: inventory.class.Product, + label: chunter.string.LeftComment }, - inventory.ids.ProductActivityExtension + inventory.ids.ProductChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: inventory.class.Category, - components: { - input: chunter.component.CommentInput - } + objectClass: inventory.class.Category, + label: chunter.string.LeftComment }, - inventory.ids.CategoryActivityExtension + inventory.ids.CategoryChatMessageViewlet ) createAction(builder, { diff --git a/models/inventory/src/plugin.ts b/models/inventory/src/plugin.ts index 1e071fc890..b98b60615b 100644 --- a/models/inventory/src/plugin.ts +++ b/models/inventory/src/plugin.ts @@ -20,8 +20,7 @@ import inventory from '@hcengineering/inventory-resources/src/plugin' import { type IntlString, mergeIds } from '@hcengineering/platform' import type { AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ActionCategory, type ViewAction, type Viewlet } from '@hcengineering/view' -import { type ActivityExtension } from '@hcengineering/activity' - +import { type ChatMessageViewlet } from '@hcengineering/notification' export default mergeIds(inventoryId, inventory, { action: { CreateSubcategory: '' as Ref @@ -50,7 +49,7 @@ export default mergeIds(inventoryId, inventory, { ConfigDescription: '' as IntlString }, ids: { - ProductActivityExtension: '' as Ref, - CategoryActivityExtension: '' as Ref + ProductChatMessageViewlet: '' as Ref, + CategoryChatMessageViewlet: '' as Ref } }) diff --git a/models/lead/package.json b/models/lead/package.json index 83a62ff8e1..2e0a04a66b 100644 --- a/models/lead/package.json +++ b/models/lead/package.json @@ -25,7 +25,6 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/activity": "^0.6.0", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", "@hcengineering/ui": "^0.6.11", diff --git a/models/lead/src/index.ts b/models/lead/src/index.ts index ef3110cee3..032eead78a 100644 --- a/models/lead/src/index.ts +++ b/models/lead/src/index.ts @@ -43,7 +43,6 @@ import workbench from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' import setting from '@hcengineering/setting' import { type ViewOptionsModel } from '@hcengineering/view' -import activity from '@hcengineering/activity' import lead from './plugin' export { leadId } from '@hcengineering/lead' @@ -60,7 +59,7 @@ export class TFunnel extends TProject implements Funnel { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number } @@ -103,6 +102,14 @@ export function createModel (builder: Builder): void { builder.createModel(TFunnel, TLead, TCustomer) + builder.mixin(lead.class.Lead, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(lead.mixin.Customer, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(lead.class.Funnel, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(lead.class.Funnel, core.class.Class, workbench.mixin.SpaceView, { view: { class: lead.class.Lead, @@ -511,15 +518,13 @@ export function createModel (builder: Builder): void { ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: lead.class.Lead, - components: { - input: chunter.component.CommentInput - } + objectClass: lead.class.Lead, + label: chunter.string.LeftComment }, - lead.ids.LeadActivityExtension + lead.ids.LeadChatMessageViewlet ) builder.mixin(lead.class.Lead, core.class.Class, task.mixin.KanbanCard, { diff --git a/models/lead/src/plugin.ts b/models/lead/src/plugin.ts index 0e989a3ee6..3630538e04 100644 --- a/models/lead/src/plugin.ts +++ b/models/lead/src/plugin.ts @@ -17,13 +17,12 @@ import type { Ref } from '@hcengineering/core' import { type Funnel, leadId } from '@hcengineering/lead' import lead from '@hcengineering/lead-resources/src/plugin' -import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' +import { type ChatMessageViewlet, type NotificationGroup, type NotificationType } from '@hcengineering/notification' import type { IntlString } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import { type ProjectType } from '@hcengineering/task' import type { AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ActionCategory, type Viewlet } from '@hcengineering/view' -import { type ActivityExtension } from '@hcengineering/activity' export default mergeIds(leadId, lead, { string: { @@ -71,6 +70,6 @@ export default mergeIds(leadId, lead, { FunnelNotificationGroup: '' as Ref, LeadCreateNotification: '' as Ref, AssigneeNotification: '' as Ref, - LeadActivityExtension: '' as Ref + LeadChatMessageViewlet: '' as Ref } }) diff --git a/models/notification/package.json b/models/notification/package.json index 920808fd6f..2f83ec2c6f 100644 --- a/models/notification/package.json +++ b/models/notification/package.json @@ -15,29 +15,30 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { + "@hcengineering/activity": "^0.6.0", + "@hcengineering/chunter": "^0.6.12", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/model-core": "^0.6.0", "@hcengineering/model-preference": "^0.6.0", "@hcengineering/model-view": "^0.6.0", - "@hcengineering/activity": "^0.6.0", - "@hcengineering/view": "^0.6.9", - "@hcengineering/workbench": "^0.6.9", "@hcengineering/model-workbench": "^0.6.1", "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", "@hcengineering/setting": "^0.6.11", - "@hcengineering/chunter": "^0.6.12" + "@hcengineering/ui": "^0.6.11", + "@hcengineering/view": "^0.6.9", + "@hcengineering/workbench": "^0.6.9" } } diff --git a/models/notification/src/activityMessages.ts b/models/notification/src/activityMessages.ts new file mode 100644 index 0000000000..a4db0abd10 --- /dev/null +++ b/models/notification/src/activityMessages.ts @@ -0,0 +1,148 @@ +import { type Builder } from '@hcengineering/model' +import view, { createAction } from '@hcengineering/model-view' +import core from '@hcengineering/model-core' + +import notification from './plugin' + +export function buildActivityMessages (builder: Builder): void { + builder.mixin(notification.class.DocUpdateMessage, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(notification.class.ChatMessage, core.class.Class, notification.mixin.ActivityDoc, {}) + + builder.mixin(notification.class.ChatMessage, core.class.Class, view.mixin.CollectionPresenter, { + presenter: notification.component.ChatMessagesPresenter + }) + + builder.mixin(notification.class.ChatMessage, core.class.Class, view.mixin.ObjectPresenter, { + presenter: notification.component.ChatMessagePresenter + }) + + builder.mixin(notification.class.DocUpdateMessage, core.class.Class, view.mixin.ObjectPresenter, { + presenter: notification.component.DocUpdateMessagePresenter + }) + + builder.createDoc( + notification.class.ActivityMessageExtension, + core.space.Model, + { + ofMessage: notification.class.DocUpdateMessage, + components: [ + { + kind: 'action', + component: notification.component.PinMessageAction + } + ] + }, + notification.ids.DocUpdateMessagePinExtension + ) + + builder.createDoc( + notification.class.ActivityMessageExtension, + core.space.Model, + { + ofMessage: notification.class.ChatMessage, + components: [ + { + kind: 'action', + component: notification.component.PinMessageAction + } + ] + }, + notification.ids.ChatMessagePinExtension + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: notification.mixin.Collaborators, + action: 'update', + icon: notification.icon.Notifications, + component: notification.activity.TxCollaboratorsChange, + label: notification.string.ChangeCollaborators + }, + notification.ids.NotificationCollaboratorsChanged + ) + + builder.mixin(notification.mixin.Collaborators, core.class.Class, notification.mixin.NotificationAttributePresenter, { + presenter: notification.component.NotificationCollaboratorsChanged + }) + + builder.createDoc(notification.class.ActivityMessagesFilter, core.space.Model, { + label: notification.string.Attributes, + filter: notification.filter.AttributesFilter + }) + + builder.createDoc(notification.class.ActivityMessagesFilter, core.space.Model, { + label: notification.string.Pinned, + filter: notification.filter.PinnedFilter + }) + + builder.createDoc(notification.class.ActivityMessagesFilter, core.space.Model, { + label: notification.string.Comments, + filter: notification.filter.ChatMessagesFilter + }) + + buildActions(builder) +} + +function buildActions (builder: Builder): void { + createAction( + builder, + { + action: notification.actionImpl.DeleteChatMessage, + label: view.string.Delete, + icon: view.icon.Delete, + input: 'focus', + keyBinding: ['Backspace'], + category: notification.category.Notification, + target: notification.class.ChatMessage, + context: { mode: ['context', 'browser'], group: 'edit' } + }, + notification.action.DeleteChatMessage + ) + + createAction( + builder, + { + action: notification.actionImpl.MarkAsReadInboxNotification, + label: notification.string.MarkAsRead, + icon: notification.icon.Notifications, + input: 'focus', + visibilityTester: notification.function.HasInboxNotifications, + category: notification.category.Notification, + target: notification.class.ActivityMessage, + context: { mode: 'context', application: notification.app.Notification, group: 'edit' } + }, + notification.action.MarkAsReadInboxNotification + ) + + createAction( + builder, + { + action: notification.actionImpl.MarkAsUnreadInboxNotification, + label: notification.string.MarkAsUnread, + icon: notification.icon.Track, + input: 'focus', + visibilityTester: notification.function.HasntInboxNotifications, + category: notification.category.Notification, + target: notification.class.ActivityMessage, + context: { mode: 'context', application: notification.app.Notification, group: 'edit' } + }, + notification.action.MarkAsUnreadInboxNotification + ) + + createAction( + builder, + { + action: notification.actionImpl.DeleteInboxNotification, + label: notification.string.Archive, + icon: view.icon.Archive, + input: 'focus', + keyBinding: ['Backspace'], + category: notification.category.Notification, + target: notification.class.ActivityMessage, + context: { mode: ['context', 'browser'], group: 'edit' } + }, + notification.action.DeleteInboxNotification + ) +} diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index 0440193031..26a3f85439 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -17,9 +17,6 @@ import activity from '@hcengineering/activity' import chunter from '@hcengineering/chunter' import { - DOMAIN_MODEL, - Hierarchy, - IndexKind, type Account, type AttachedDoc, type Class, @@ -27,20 +24,49 @@ import { type Data, type Doc, type Domain, + DOMAIN_MODEL, + Hierarchy, + IndexKind, type Ref, type Timestamp, type Tx, type TxCUD } from '@hcengineering/core' -import { ArrOf, Index, Mixin, Model, Prop, TypeRef, TypeString, UX, type Builder } from '@hcengineering/model' +import { + ArrOf, + type Builder, + Index, + Mixin, + Model, + Prop, + TypeMarkup, + TypeRef, + TypeString, + UX, + Collection as PropCollection, + TypeBoolean, + TypeDate +} from '@hcengineering/model' import core, { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core' import preference, { TPreference } from '@hcengineering/model-preference' import view, { createAction } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import { - notificationId, - type DocUpdateTx, + type ActivityMessage, + type ActivityMessageExtension, + type ActivityMessageExtensionKind, + type ChatMessage, + type ChatMessageViewlet, + type DocUpdateAction, + type DocAttributeUpdates, + type DocUpdateMessage, + type DocUpdateMessageViewlet, + type DocUpdateMessageViewletAttributesConfig, type DocUpdates, + type DocUpdateTx, + inboxId, + type InboxNotification, + type DocNotifyContext, type Notification, type NotificationGroup, type NotificationObjectPresenter, @@ -50,12 +76,21 @@ import { type NotificationSetting, type NotificationStatus, type NotificationTemplate, - type NotificationType + type NotificationType, + type ActivityMessagesFilter, + type ActivityDoc, + type NotificationObjectPreposition, + notificationId } from '@hcengineering/notification' -import type { Asset, IntlString } from '@hcengineering/platform' +import { type Asset, type IntlString, type Resource } from '@hcengineering/platform' import setting from '@hcengineering/setting' import { type AnyComponent } from '@hcengineering/ui/src/types' +import attachment from '@hcengineering/model-attachment' +import { type NotificationAttributePresenter } from '@hcengineering/view' + import notification from './plugin' +import { buildActivityMessages } from './activityMessages' + export { notificationId } from '@hcengineering/notification' export { notificationOperation } from './migration' export { notification as default } @@ -139,6 +174,21 @@ export class TNotificationPreview extends TClass implements NotificationPreview presenter!: AnyComponent } +@Mixin(notification.mixin.ActivityDoc, core.class.Class) +export class TActivityDoc extends TClass implements ActivityDoc { + ignoreCollections?: string[] +} + +@Mixin(notification.mixin.NotificationObjectPreposition, core.class.Class) +export class TNotificationObjectPreposition extends TClass implements NotificationObjectPreposition { + preposition!: IntlString +} + +@Mixin(notification.mixin.NotificationAttributePresenter, core.class.Class) +export class TNotificationAttributePresenter extends TClass implements NotificationAttributePresenter { + presenter!: AnyComponent +} + @Model(notification.class.DocUpdates, core.class.Doc, DOMAIN_NOTIFICATION) export class TDocUpdates extends TDoc implements DocUpdates { @Index(IndexKind.Indexed) @@ -155,6 +205,149 @@ export class TDocUpdates extends TDoc implements DocUpdates { txes!: DocUpdateTx[] } +@Model(notification.class.DocNotifyContext, core.class.Doc, DOMAIN_NOTIFICATION) +export class TDocNotifyContext extends TDoc implements DocNotifyContext { + @Prop(TypeRef(core.class.Account), core.string.Account) + @Index(IndexKind.Indexed) + user!: Ref + + @Prop(TypeRef(core.class.Doc), core.string.AttachedTo) + @Index(IndexKind.Indexed) + attachedTo!: Ref + + @Prop(TypeRef(core.class.Class), core.string.AttachedToClass) + @Index(IndexKind.Indexed) + attachedToClass!: Ref> + + @Prop(TypeBoolean(), core.string.Archived) + @Index(IndexKind.Indexed) + hidden!: boolean + + @Prop(TypeDate(), core.string.Date) + @Index(IndexKind.Indexed) + lastViewedTimestamp?: Timestamp + + @Prop(TypeDate(), core.string.Date) + @Index(IndexKind.Indexed) + lastUpdateTimestamp?: Timestamp +} + +@Model(notification.class.ActivityMessage, core.class.AttachedDoc, DOMAIN_NOTIFICATION) +export class TActivityMessage extends TAttachedDoc implements ActivityMessage { + @Prop(TypeBoolean(), notification.string.Pinned) + @Index(IndexKind.Indexed) + isPinned?: boolean + + @Prop(PropCollection(chunter.class.Reaction), chunter.string.Reactions) + reactions?: number +} + +@Model(notification.class.DocUpdateMessage, notification.class.ActivityMessage, DOMAIN_NOTIFICATION) +export class TDocUpdateMessage extends TActivityMessage implements DocUpdateMessage { + @Prop(TypeRef(core.class.Doc), core.string.Object) + @Index(IndexKind.Indexed) + objectId!: Ref + + @Prop(TypeRef(core.class.Class), core.string.Class) + @Index(IndexKind.Indexed) + objectClass!: Ref> + + @Prop(TypeRef(core.class.TxCUD), core.string.Object) + @Index(IndexKind.Indexed) + txId!: Ref> + + action!: DocUpdateAction + updateCollection?: string + attributeUpdates?: DocAttributeUpdates +} + +@Model(notification.class.ChatMessage, notification.class.ActivityMessage, DOMAIN_NOTIFICATION) +export class TChatMessage extends TActivityMessage implements ChatMessage { + @Prop(TypeMarkup(), chunter.string.Message) + @Index(IndexKind.FullText) + message!: string + + @Prop(PropCollection(attachment.class.Attachment), attachment.string.Attachments, { + shortLabel: attachment.string.Files + }) + attachments?: number + + @Prop(TypeBoolean(), core.string.Boolean) + @Index(IndexKind.Indexed) + isEdited?: boolean +} + +@Model(notification.class.InboxNotification, core.class.Doc, DOMAIN_NOTIFICATION) +export class TInboxNotification extends TDoc implements InboxNotification { + @Prop(TypeRef(notification.class.ActivityMessage), core.string.AttachedTo) + @Index(IndexKind.Indexed) + attachedTo!: Ref + + @Prop(TypeRef(notification.class.ActivityMessage), core.string.AttachedToClass) + @Index(IndexKind.Indexed) + attachedToClass!: Ref> + + @Prop(TypeRef(notification.class.DocNotifyContext), core.string.AttachedTo) + @Index(IndexKind.Indexed) + docNotifyContext!: Ref + + @Prop(TypeRef(core.class.Account), core.string.Account) + @Index(IndexKind.Indexed) + user!: Ref + + @Prop(TypeBoolean(), core.string.Boolean) + @Index(IndexKind.Indexed) + isViewed!: boolean +} + +@Model(notification.class.DocUpdateMessageViewlet, core.class.Doc, DOMAIN_MODEL) +export class TDocUpdateMessageViewlet extends TDoc implements DocUpdateMessageViewlet { + @Prop(TypeRef(core.class.Doc), core.string.Class) + @Index(IndexKind.Indexed) + objectClass!: Ref> + + @Prop(TypeString(), core.string.String) + @Index(IndexKind.Indexed) + action!: DocUpdateAction + + label?: IntlString + labelComponent?: AnyComponent + + valueAttr?: string + + icon?: Asset + component?: AnyComponent + config?: DocUpdateMessageViewletAttributesConfig + hideIfRemoved?: boolean + onlyWithParent?: boolean +} + +@Model(notification.class.ChatMessageViewlet, core.class.Doc, DOMAIN_MODEL) +export class TChatMessageViewlet extends TDoc implements ChatMessageViewlet { + @Prop(TypeRef(core.class.Doc), core.string.Class) + @Index(IndexKind.Indexed) + objectClass!: Ref> + + label?: IntlString + hidden?: boolean + onlyWithParent?: boolean +} + +@Model(notification.class.ActivityMessageExtension, core.class.Doc, DOMAIN_MODEL) +export class TActivityMessageExtension extends TDoc implements ActivityMessageExtension { + @Prop(TypeRef(notification.class.ActivityMessage), core.string.Class) + @Index(IndexKind.Indexed) + ofMessage!: Ref> + + components!: { kind: ActivityMessageExtensionKind, component: AnyComponent }[] +} + +@Model(notification.class.ActivityMessagesFilter, core.class.Doc, DOMAIN_MODEL) +export class TActivityMessagesFilter extends TDoc implements ActivityMessagesFilter { + label!: IntlString + filter!: Resource<(message: ActivityMessage, _class?: Ref) => boolean> +} + export function createModel (builder: Builder): void { builder.createModel( TNotification, @@ -167,7 +360,19 @@ export function createModel (builder: Builder): void { TCollaborators, TDocUpdates, TNotificationObjectPresenter, - TNotificationPreview + TNotificationPreview, + TDocNotifyContext, + TDocUpdateMessage, + TChatMessage, + TActivityMessage, + TInboxNotification, + TDocUpdateMessageViewlet, + TActivityMessageExtension, + TChatMessageViewlet, + TActivityMessagesFilter, + TActivityDoc, + TNotificationObjectPreposition, + TNotificationAttributePresenter ) // Temporarily disabled, we should think about it @@ -228,6 +433,45 @@ export function createModel (builder: Builder): void { notification.app.Notification ) + builder.createDoc( + workbench.class.Application, + core.space.Model, + { + label: notification.string.Inbox, + icon: notification.icon.Notifications, + alias: inboxId, + hidden: true, + locationResolver: notification.resolver.Location, + navigatorModel: { + aside: notification.component.InboxAside, + spaces: [], + specials: [ + { + id: 'all', + component: notification.component.NewInbox, + icon: notification.icon.Activity, + label: notification.string.AllActivity, + componentProps: { + type: 'all', + label: notification.string.AllActivity + } + }, + { + id: 'reactions', + component: notification.component.NewInbox, + icon: notification.icon.Emoji, + label: notification.string.Reactions, + componentProps: { + _class: chunter.class.Reaction, + label: notification.string.Reactions + } + } + ] + } + }, + notification.app.Inbox + ) + createAction( builder, { @@ -352,6 +596,8 @@ export function createModel (builder: Builder): void { }, notification.ids.TxDmCreation ) + + buildActivityMessages(builder) } export function generateClassNotificationTypes ( diff --git a/models/notification/src/plugin.ts b/models/notification/src/plugin.ts index a84b0d821a..37dcd9e6b0 100644 --- a/models/notification/src/plugin.ts +++ b/models/notification/src/plugin.ts @@ -15,7 +15,11 @@ // import { type Doc, type Ref } from '@hcengineering/core' -import notification, { notificationId } from '@hcengineering/notification' +import notification, { + type ActivityMessageExtension, + type DocUpdateMessageViewlet, + notificationId +} from '@hcengineering/notification' import { type IntlString, type Resource, mergeIds } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ActionCategory, type ViewAction } from '@hcengineering/view' @@ -29,24 +33,39 @@ export default mergeIds(notificationId, notification, { EmailNotification: '' as IntlString, Collaborators: '' as IntlString, Archive: '' as IntlString, - MarkAsUnread: '' as IntlString + MarkAsUnread: '' as IntlString, + MarkAsRead: '' as IntlString, + ChangeCollaborators: '' as IntlString, + AllActivity: '' as IntlString, + Threads: '' as IntlString, + Mentions: '' as IntlString, + Reactions: '' as IntlString }, app: { - Notification: '' as Ref + Notification: '' as Ref, + Inbox: '' as Ref }, activity: { - TxCollaboratorsChange: '' as AnyComponent, TxDmCreation: '' as AnyComponent }, ids: { TxCollaboratorsChange: '' as Ref, - TxDmCreation: '' as Ref + TxDmCreation: '' as Ref, + NotificationCollaboratorsChanged: '' as Ref, + DocUpdateMessagePinExtension: '' as Ref, + ChatMessagePinExtension: '' as Ref }, component: { - NotificationSettings: '' as AnyComponent + NotificationSettings: '' as AnyComponent, + InboxAside: '' as AnyComponent, + ChatMessagePresenter: '' as AnyComponent, + DocUpdateMessagePresenter: '' as AnyComponent, + PinMessageAction: '' as AnyComponent }, function: { - HasntNotifications: '' as Resource<(doc?: Doc | Doc[]) => Promise> + HasntNotifications: '' as Resource<(doc?: Doc | Doc[]) => Promise>, + HasntInboxNotifications: '' as Resource<(doc?: Doc | Doc[]) => Promise>, + HasInboxNotifications: '' as Resource<(doc?: Doc | Doc[]) => Promise> }, category: { Notification: '' as Ref @@ -60,6 +79,10 @@ export default mergeIds(notificationId, notification, { actionImpl: { Unsubscribe: '' as ViewAction, Hide: '' as ViewAction, - MarkAsUnread: '' as ViewAction + MarkAsUnread: '' as ViewAction, + MarkAsUnreadInboxNotification: '' as ViewAction, + MarkAsReadInboxNotification: '' as ViewAction, + DeleteInboxNotification: '' as ViewAction, + DeleteChatMessage: '' as ViewAction } }) diff --git a/models/recruit/package.json b/models/recruit/package.json index 70b3a3204a..76b224dce0 100644 --- a/models/recruit/package.json +++ b/models/recruit/package.json @@ -25,32 +25,30 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/activity": "^0.6.0", + "@anticrm/skillset": "^0.6.0", + "@hcengineering/contact": "^0.6.20", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/model-attachment": "^0.6.0", + "@hcengineering/model-calendar": "^0.6.0", + "@hcengineering/model-chunter": "^0.6.0", + "@hcengineering/model-contact": "^0.6.1", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/model-presentation": "^0.6.0", + "@hcengineering/model-tags": "^0.6.0", + "@hcengineering/model-task": "^0.6.0", + "@hcengineering/model-tracker": "^0.6.0", "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-workbench": "^0.6.1", - "@hcengineering/model-contact": "^0.6.1", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", "@hcengineering/recruit": "^0.6.21", "@hcengineering/recruit-resources": "^0.6.0", - "@hcengineering/chunter": "^0.6.12", - "@hcengineering/notification": "^0.6.16", - "@hcengineering/model-attachment": "^0.6.0", - "@hcengineering/model-chunter": "^0.6.0", - "@hcengineering/view": "^0.6.9", - "@hcengineering/task": "^0.6.13", "@hcengineering/setting": "^0.6.11", - "@hcengineering/model-task": "^0.6.0", - "@hcengineering/workbench": "^0.6.9", - "@hcengineering/model-tracker": "^0.6.0", - "@hcengineering/model-presentation": "^0.6.0", - "@hcengineering/model-notification": "^0.6.0", - "@hcengineering/model-calendar": "^0.6.0", - "@hcengineering/model-tags": "^0.6.0", - "@anticrm/skillset": "^0.6.0" + "@hcengineering/task": "^0.6.13", + "@hcengineering/ui": "^0.6.11", + "@hcengineering/view": "^0.6.9", + "@hcengineering/workbench": "^0.6.9" } } diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index c9aa78a017..a6a42a3f32 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -56,7 +56,7 @@ import { } from '@hcengineering/recruit' import setting from '@hcengineering/setting' import { type KeyBinding, type ViewOptionModel, type ViewOptionsModel } from '@hcengineering/view' -import activity from '@hcengineering/activity' + import recruit from './plugin' import { createReviewModel, reviewTableConfig, reviewTableOptions } from './review' import { TOpinion, TReview } from './review-model' @@ -85,7 +85,7 @@ export class TVacancy extends TProject implements Vacancy { @Prop(TypeRef(contact.class.Organization), recruit.string.Company, { icon: contact.icon.Company }) company?: Ref - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number @Prop(TypeString(), recruit.string.Vacancy) @@ -197,6 +197,18 @@ export class TApplicantMatch extends TAttachedDoc implements ApplicantMatch { export function createModel (builder: Builder): void { builder.createModel(TVacancy, TCandidates, TCandidate, TApplicant, TReview, TOpinion, TVacancyList, TApplicantMatch) + builder.mixin(recruit.class.Vacancy, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(recruit.class.Applicant, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(recruit.class.Review, core.class.Class, notification.mixin.ActivityDoc, {}) + + builder.mixin(recruit.mixin.Candidate, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(recruit.class.Vacancy, core.class.Class, workbench.mixin.SpaceView, { view: { class: recruit.class.Applicant, @@ -832,7 +844,7 @@ export function createModel (builder: Builder): void { key: 'title', props: { kind: 'list', size: 'small', shouldShowName: false } }, - { key: 'comments', displayProps: { key: 'comments', suffix: true } }, + 'comments', { key: '', displayProps: { grow: true } }, { key: '$lookup.channels', @@ -882,7 +894,7 @@ export function createModel (builder: Builder): void { label: recruit.string.Applications, props: { kind: 'list', size: 'small', shouldShowName: false } }, - { key: 'comments', displayProps: { key: 'comments', suffix: true } }, + 'comments', { key: '', presenter: tracker.component.RelatedIssueSelector, @@ -938,7 +950,7 @@ export function createModel (builder: Builder): void { label: recruit.string.Applications }, 'description', - { key: 'comments', displayProps: { key: 'comments', suffix: true } }, + 'comemnts', { key: '', presenter: tracker.component.RelatedIssueSelector, @@ -1073,6 +1085,10 @@ export function createModel (builder: Builder): void { titleProvider: recruit.function.AppTitleProvider }) + builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ObjectIdentifier, { + provider: recruit.function.AppIdentifierProvider + }) + builder.mixin(recruit.class.Review, core.class.Class, view.mixin.ObjectTitle, { titleProvider: recruit.function.RevTitleProvider }) @@ -1569,39 +1585,33 @@ export function createModel (builder: Builder): void { ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: recruit.class.Vacancy, - components: { - input: chunter.component.CommentInput - } + objectClass: recruit.class.Vacancy, + label: chunter.string.LeftComment }, - recruit.ids.VacancyActivityExtension + recruit.ids.VacancyChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: recruit.class.Applicant, - components: { - input: chunter.component.CommentInput - } + objectClass: recruit.class.Applicant, + label: chunter.string.LeftComment }, - recruit.ids.ApplicantActivityExtension + recruit.ids.ApplicantChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: recruit.class.Review, - components: { - input: chunter.component.CommentInput - } + objectClass: recruit.class.Review, + label: chunter.string.LeftComment }, - recruit.ids.ReviewActivityExtension + recruit.ids.ReviewChatMessageViewlet ) // Allow to use fuzzy search for mixins @@ -1615,7 +1625,7 @@ export function createModel (builder: Builder): void { propagate: [recruit.class.Applicant], propagateClasses: [ tags.class.TagReference, - chunter.class.Comment, + notification.class.ChatMessage, attachment.class.Attachment, contact.class.Channel ] @@ -1668,6 +1678,21 @@ export function createModel (builder: Builder): void { } }) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: recruit.class.Applicant, + action: 'update', + config: { + status: { + iconPresenter: task.component.StateIconPresenter + } + } + }, + recruit.ids.NotificationApplicantUpdated + ) + createAction( builder, { diff --git a/models/recruit/src/plugin.ts b/models/recruit/src/plugin.ts index d36b77ea47..c37ae8f61f 100644 --- a/models/recruit/src/plugin.ts +++ b/models/recruit/src/plugin.ts @@ -14,7 +14,12 @@ // import type { Client, Doc, Ref } from '@hcengineering/core' -import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' +import { + type ChatMessageViewlet, + type DocUpdateMessageViewlet, + type NotificationGroup, + type NotificationType +} from '@hcengineering/notification' import type { IntlString, Resource, Status } from '@hcengineering/platform' import { mergeIds } from '@hcengineering/platform' import { recruitId } from '@hcengineering/recruit' @@ -22,7 +27,6 @@ import recruit from '@hcengineering/recruit-resources/src/plugin' import { type ProjectType } from '@hcengineering/task' import type { AnyComponent, Location } from '@hcengineering/ui/src/types' import type { Action, ActionCategory, ViewAction, ViewQueryAction, Viewlet } from '@hcengineering/view' -import { type ActivityExtension } from '@hcengineering/activity' export default mergeIds(recruitId, recruit, { action: { @@ -84,9 +88,10 @@ export default mergeIds(recruitId, recruit, { AssigneeNotification: '' as Ref, ApplicationCreateNotification: '' as Ref, ReviewCreateNotification: '' as Ref, - VacancyActivityExtension: '' as Ref, - ApplicantActivityExtension: '' as Ref, - ReviewActivityExtension: '' as Ref + NotificationApplicantUpdated: '' as Ref, + ApplicantChatMessageViewlet: '' as Ref, + VacancyChatMessageViewlet: '' as Ref, + ReviewChatMessageViewlet: '' as Ref }, component: { CreateApplication: '' as AnyComponent, diff --git a/models/recruit/src/review-model.ts b/models/recruit/src/review-model.ts index c0988e1cce..b640315f44 100644 --- a/models/recruit/src/review-model.ts +++ b/models/recruit/src/review-model.ts @@ -3,12 +3,12 @@ import { type Domain, IndexKind, type Ref } from '@hcengineering/core' import { Collection, Index, Model, Prop, TypeMarkup, TypeRef, TypeString, UX } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' import calendar, { TEvent } from '@hcengineering/model-calendar' -import chunter from '@hcengineering/model-chunter' import contact from '@hcengineering/model-contact' import core, { TAttachedDoc } from '@hcengineering/model-core' import task from '@hcengineering/model-task' import { type Applicant, type Candidate, type Opinion, type Review } from '@hcengineering/recruit' import recruit from './plugin' +import notification from '@hcengineering/notification' @Model(recruit.class.Review, calendar.class.Event) @UX(recruit.string.Review, recruit.icon.Review, 'RVE', 'number') @@ -47,7 +47,7 @@ export class TOpinion extends TAttachedDoc implements Opinion { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number @Prop(TypeMarkup(), recruit.string.Description) diff --git a/models/request/package.json b/models/request/package.json index 5c9c8c9616..6a49244888 100644 --- a/models/request/package.json +++ b/models/request/package.json @@ -25,19 +25,18 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { + "@hcengineering/activity": "^0.6.0", + "@hcengineering/contact": "^0.6.20", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/platform": "^0.6.9", - "@hcengineering/model-core": "^0.6.0", - "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-chunter": "^0.6.0", - "@hcengineering/request": "^0.6.6", - "@hcengineering/notification": "^0.6.16", + "@hcengineering/model-core": "^0.6.0", "@hcengineering/model-notification": "^0.6.0", - "@hcengineering/activity": "^0.6.0", - "@hcengineering/chunter": "^0.6.12", - "@hcengineering/request-resources": "^0.6.0" + "@hcengineering/model-view": "^0.6.0", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/request": "^0.6.6", + "@hcengineering/request-resources": "^0.6.0", + "@hcengineering/ui": "^0.6.11" } } diff --git a/models/request/src/index.ts b/models/request/src/index.ts index 49850932c5..1e7fd89d3f 100644 --- a/models/request/src/index.ts +++ b/models/request/src/index.ts @@ -14,7 +14,6 @@ // import activity from '@hcengineering/activity' -import chunter from '@hcengineering/chunter' import type { PersonAccount } from '@hcengineering/contact' import contact from '@hcengineering/contact' import { type Domain, IndexKind, type Ref, type Tx } from '@hcengineering/core' @@ -73,11 +72,11 @@ export class TRequest extends TAttachedDoc implements Request { @ReadOnly() rejected?: Ref - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number } -@Mixin(request.mixin.RequestDecisionComment, chunter.class.Comment) +@Mixin(request.mixin.RequestDecisionComment, notification.class.ChatMessage) export class TRequestDecisionComment extends TComment implements RequestDecisionComment {} @Mixin(request.mixin.RequestPresenter, core.class.Class) diff --git a/models/server-chunter/src/index.ts b/models/server-chunter/src/index.ts index f6e84af551..b5d14d09d0 100644 --- a/models/server-chunter/src/index.ts +++ b/models/server-chunter/src/index.ts @@ -33,7 +33,7 @@ export function createModel (builder: Builder): void { }) builder.mixin, ObjectDDParticipant>( - chunter.class.Comment, + notification.class.ChatMessage, core.class.Class, serverCore.mixin.ObjectDDParticipant, { diff --git a/models/server-notification/package.json b/models/server-notification/package.json index 16017be045..56ea5b141d 100644 --- a/models/server-notification/package.json +++ b/models/server-notification/package.json @@ -15,12 +15,12 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, @@ -28,10 +28,11 @@ "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", "@hcengineering/model-core": "^0.6.0", - "@hcengineering/platform": "^0.6.9", - "@hcengineering/notification": "^0.6.16", "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/server-core": "^0.6.1", "@hcengineering/server-notification": "^0.6.1", - "@hcengineering/server-core": "^0.6.1" + "@hcengineering/server-notification-resources": "^0.6.0" } } diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index 175890a385..509b476525 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -32,6 +32,7 @@ import serverNotification, { } from '@hcengineering/server-notification' export { serverNotificationId } from '@hcengineering/server-notification' +export { notificationServerOperation } from './migration' @Mixin(serverNotification.mixin.HTMLPresenter, core.class.Class) export class THTMLPresenter extends TClass implements HTMLPresenter { @@ -62,8 +63,25 @@ export function createModel (builder: Builder): void { trigger: serverNotification.trigger.OnBacklinkCreate }) + // NOTE: temporarily disabled + // builder.createDoc(serverCore.class.Trigger, core.space.Model, { + // trigger: serverNotification.trigger.OnReactionChanged, + // txMatch: { + // collection: 'reactions', + // objectClass: notification.class.ActivityMessage, + // _class: core.class.TxCollectionCUD + // } + // }) + builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.CollaboratorDocHandler + trigger: serverNotification.trigger.NotificationMessagesHandler + }) + + builder.createDoc(serverCore.class.Trigger, core.space.Model, { + trigger: serverNotification.trigger.OnChatMessageSent, + txMatch: { + objectClass: notification.class.ChatMessage + } }) builder.createDoc(serverCore.class.Trigger, core.space.Model, { diff --git a/models/server-notification/src/migration.ts b/models/server-notification/src/migration.ts new file mode 100644 index 0000000000..907e132002 --- /dev/null +++ b/models/server-notification/src/migration.ts @@ -0,0 +1,210 @@ +// +// Copyright © 2023 Hardcore Engineering Inc. +// +// Licensed under the Eclipse Public License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import core, { + SortingOrder, + TxFactory, + toFindResult, + toIdMap, + type AttachedDoc, + type Class, + type Doc, + type Ref, + type TxCUD, + type TxCollectionCUD, + type TxCreateDoc, + TxProcessor +} from '@hcengineering/core' +import { type MigrateOperation, type MigrationClient, type MigrationIterator, tryMigrate } from '@hcengineering/model' +import notification, { type DocUpdateMessage } from '@hcengineering/notification' +import { getAllObjectTransactions, type DocObjectCache, serverNotificationId } from '@hcengineering/server-notification' +import { generateDocUpdateMessages, type NotificationControl } from '@hcengineering/server-notification-resources' + +function getNotificationControl (client: MigrationClient): NotificationControl { + const txFactory = new TxFactory(core.account.System, false) + + return { + txFactory, + modelDb: client.model, + hierarchy: client.hierarchy, + findAll: async (_class, query, options) => + toFindResult(await client.find(client.hierarchy.getDomain(_class), query, options)) + } +} + +async function generateDocUpdateMessageByTx ( + tx: TxCUD, + control: NotificationControl, + client: MigrationClient, + objectCache?: DocObjectCache +): Promise { + const createCollectionCUDTxes = await generateDocUpdateMessages(tx, control, undefined, undefined, objectCache) + + for (const collectionTx of createCollectionCUDTxes) { + const createTx = collectionTx.tx as TxCreateDoc + const domain = client.hierarchy.getDomain(createTx.objectClass) + + await client.create(domain, { + _id: createTx.objectId, + _class: createTx.objectClass, + space: createTx.objectSpace, + modifiedOn: createTx.modifiedOn, + modifiedBy: createTx.modifiedBy, + createdOn: createTx.modifiedOn, + createdBy: createTx.createdBy, + ...createTx.attributes + }) + } +} + +async function createDocUpdateMessages (client: MigrationClient): Promise { + const activityDocs = await client.model.findAll(notification.mixin.ActivityDoc, { + _id: { $nin: [notification.class.DocUpdateMessage, notification.class.ChatMessage] } + }) + const activityDocClasses = activityDocs.map(({ _id }) => _id) + + const notificationControl = getNotificationControl(client) + + const txClient: Pick = { + hierarchy: notificationControl.hierarchy, + findAll: notificationControl.findAll + } + + let processed = 0 + + async function generateFor (_class: Ref>, documents: MigrationIterator): Promise { + while (true) { + const docs = await documents.next(50) + + if (docs == null || docs.length === 0) { + break + } + const allTransactions = await getAllObjectTransactions( + txClient, + _class, + docs.map((it) => it._id) + ) + + // We need to find parent collection objects if missing + const byClass = new Map>, Set>>() + for (const vv of allTransactions.values()) { + for (const v of vv) { + try { + const _cl = client.hierarchy.getBaseClass(v.objectClass) + const s = byClass.get(_cl) ?? new Set() + s.add(v.objectId) + byClass.set(_cl, s) + } catch { + console.log('class not found:', v.objectClass) + continue + } + + if (v._class === core.class.TxCollectionCUD) { + try { + const vcol = v as TxCollectionCUD + const _cl = client.hierarchy.getBaseClass(vcol.tx.objectClass) + const s = byClass.get(_cl) ?? new Set() + s.add(vcol.tx.objectId) + byClass.set(_cl, s) + } catch { + console.log('class not found:', (v as TxCollectionCUD).tx.objectClass) + } + } + } + } + + const docIds: Map, Doc | null> = toIdMap(docs) + + for (const [_class, classDocs] of byClass.entries()) { + const ids: Ref[] = Array.from(classDocs.values()).filter((it) => !docIds.has(it)) + if (ids.length > 0) { + for (const di of ids) { + docIds.set(di, null) + } + const edocs = await txClient.findAll(_class, { _id: { $in: ids } }) + for (const ed of edocs) { + docIds.set(ed._id, ed) + } + } + } + + for (const d of docs) { + processed += 1 + if (processed % 1000 === 0) { + console.log('processed', processed) + } + const transactions = allTransactions.get(d._id) ?? [] + for (const tx of transactions) { + const innerTx = TxProcessor.extractTx(tx) as TxCUD + + if (!client.hierarchy.hasClass(innerTx.objectClass)) { + console.log('class not found:', innerTx.objectClass) + continue + } + + try { + await generateDocUpdateMessageByTx(tx, notificationControl, client, { + docs: docIds, + transactions: allTransactions + }) + } catch (e: any) { + console.error('error processing:', d._id, e.stack) + } + } + } + } + await documents.close() + } + + for (const activityClass of activityDocClasses) { + console.log('processing', activityClass) + + if (client.hierarchy.isMixin(activityClass)) { + // Skip mixins + continue + } + + const domain = client.hierarchy.getDomain(activityClass) + + await generateFor( + activityClass, + await client.traverse( + domain, + { + _class: activityClass, + space: { $ne: core.space.Model } + }, + { + sort: { + createdOn: SortingOrder.Ascending + } + } + ) + ) + } + console.log('process-finished', processed) +} + +export const notificationServerOperation: MigrateOperation = { + async migrate (client: MigrationClient): Promise { + await tryMigrate(client, serverNotificationId, [ + { + state: 'notifications', + func: createDocUpdateMessages + } + ]) + }, + async upgrade (): Promise {} +} diff --git a/models/server-openai/package.json b/models/server-openai/package.json index 010aff058f..9296ed6fb2 100644 --- a/models/server-openai/package.json +++ b/models/server-openai/package.json @@ -27,11 +27,11 @@ "dependencies": { "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/platform": "^0.6.9", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-recruit": "^0.6.0", + "@hcengineering/notification": "^0.6.16", "@hcengineering/openai": "^0.6.0", - "@hcengineering/server-core": "^0.6.1", - "@hcengineering/model-chunter": "^0.6.0", - "@hcengineering/model-recruit": "^0.6.0" + "@hcengineering/platform": "^0.6.9", + "@hcengineering/server-core": "^0.6.1" } } diff --git a/models/server-openai/src/index.ts b/models/server-openai/src/index.ts index a7cde3257c..be700f43ac 100644 --- a/models/server-openai/src/index.ts +++ b/models/server-openai/src/index.ts @@ -22,8 +22,8 @@ import core, { DOMAIN_CONFIGURATION } from '@hcengineering/core' import openai, { type OpenAIConfiguration } from '@hcengineering/openai/src/plugin' import serverCore from '@hcengineering/server-core' -import chunter from '@hcengineering/model-chunter' import recruit from '@hcengineering/model-recruit' +import notification from '@hcengineering/notification' export { openAIId } from '@hcengineering/openai/src/plugin' @@ -49,7 +49,7 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: openai.trigger.AsyncOnGPTRequest, txMatch: { - objectClass: { $in: [chunter.class.Comment, recruit.class.ApplicantMatch] }, + objectClass: { $in: [notification.class.ChatMessage, recruit.class.ApplicantMatch] }, _class: core.class.TxCreateDoc } }) diff --git a/models/setting/src/index.ts b/models/setting/src/index.ts index 0721362498..6f14c78fb2 100644 --- a/models/setting/src/index.ts +++ b/models/setting/src/index.ts @@ -328,6 +328,19 @@ export function createModel (builder: Builder): void { setting.ids.TxIntegrationDisable ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: setting.class.Integration, + icon: setting.icon.Integrations, + label: setting.string.IntegrationWith, + action: 'update', + hideIfRemoved: true + }, + setting.ids.UpdateIntegrationNotificationViewlet + ) + builder.mixin(core.class.TypeString, core.class.Class, view.mixin.ObjectEditor, { editor: setting.component.StringTypeEditor }) diff --git a/models/setting/src/plugin.ts b/models/setting/src/plugin.ts index ef2830c504..41729dc301 100644 --- a/models/setting/src/plugin.ts +++ b/models/setting/src/plugin.ts @@ -21,7 +21,11 @@ import setting from '@hcengineering/setting-resources/src/plugin' import { type AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ActionCategory, type ViewAction } from '@hcengineering/view' import { type TemplateFieldFunc } from '@hcengineering/templates' -import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' +import { + type DocUpdateMessageViewlet, + type NotificationGroup, + type NotificationType +} from '@hcengineering/notification' export default mergeIds(settingId, setting, { activity: { @@ -32,7 +36,8 @@ export default mergeIds(settingId, setting, { EnumSetting: '' as Ref, Configure: '' as Ref, SettingNotificationGroup: '' as Ref, - IntegrationDisabledNotification: '' as Ref + IntegrationDisabledNotification: '' as Ref, + UpdateIntegrationNotificationViewlet: '' as Ref }, component: { EnumSetting: '' as AnyComponent, diff --git a/models/tags/package.json b/models/tags/package.json index 5805b4f6c3..811d7f1ad5 100644 --- a/models/tags/package.json +++ b/models/tags/package.json @@ -15,25 +15,25 @@ "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", "@typescript-eslint/eslint-plugin": "^6.11.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-n": "^15.4.0", - "eslint": "^8.54.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.4.0", + "eslint-plugin-promise": "^6.1.1", "prettier": "^3.1.0", "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/activity": "^0.6.0", - "@hcengineering/model": "^0.6.7", "@hcengineering/core": "^0.6.28", + "@hcengineering/model": "^0.6.7", + "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-view": "^0.6.0", + "@hcengineering/notification": "^0.6.16", "@hcengineering/platform": "^0.6.9", "@hcengineering/tags": "^0.6.12", "@hcengineering/tags-resources": "^0.6.0", "@hcengineering/ui": "^0.6.11", - "@hcengineering/model-core": "^0.6.0", - "@hcengineering/view": "^0.6.9", - "@hcengineering/model-view": "^0.6.0" + "@hcengineering/view": "^0.6.9" } } diff --git a/models/task/package.json b/models/task/package.json index 159a87bce0..038f029eae 100644 --- a/models/task/package.json +++ b/models/task/package.json @@ -25,24 +25,23 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { + "@hcengineering/contact": "^0.6.20", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/model-attachment": "^0.6.0", + "@hcengineering/model-contact": "^0.6.1", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-presentation": "^0.6.0", + "@hcengineering/model-tags": "^0.6.0", "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-workbench": "^0.6.1", - "@hcengineering/model-contact": "^0.6.1", - "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/tags": "^0.6.12", "@hcengineering/task": "^0.6.13", "@hcengineering/task-resources": "^0.6.0", - "@hcengineering/model-chunter": "^0.6.0", - "@hcengineering/workbench": "^0.6.9", + "@hcengineering/ui": "^0.6.11", "@hcengineering/view": "^0.6.9", - "@hcengineering/model-presentation": "^0.6.0", - "@hcengineering/tags": "^0.6.12", - "@hcengineering/model-tags": "^0.6.0" + "@hcengineering/workbench": "^0.6.9" } } diff --git a/models/task/src/index.ts b/models/task/src/index.ts index 5580ce67a8..db5224f70c 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -42,7 +42,6 @@ import { UX } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' -import chunter from '@hcengineering/model-chunter' import core, { TAttachedDoc, TClass, TDoc, TSpace } from '@hcengineering/model-core' import view, { createAction, template, actionTemplates as viewTemplates } from '@hcengineering/model-view' import { type IntlString } from '@hcengineering/platform' @@ -61,6 +60,7 @@ import { import type { AnyComponent } from '@hcengineering/ui/src/types' import { type ViewAction } from '@hcengineering/view' import task from './plugin' +import notification from '@hcengineering/notification' export { taskId } from '@hcengineering/task' export { createProjectType, createSequence, taskOperation } from './migration' @@ -95,7 +95,7 @@ export class TTask extends TAttachedDoc implements Task { @Prop(Collection(tags.class.TagReference, task.string.TaskLabels), task.string.TaskLabels) labels?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments?: number @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) diff --git a/models/task/src/plugin.ts b/models/task/src/plugin.ts index 8c3171f0ff..5a5a5e673c 100644 --- a/models/task/src/plugin.ts +++ b/models/task/src/plugin.ts @@ -59,7 +59,8 @@ export default mergeIds(taskId, task, { StateRefPresenter: '' as AnyComponent, StatusSelector: '' as AnyComponent, TemplatesIcon: '' as AnyComponent, - TypesView: '' as AnyComponent + TypesView: '' as AnyComponent, + StateIconPresenter: '' as AnyComponent }, space: { TasksPublic: '' as Ref diff --git a/models/telegram/src/index.ts b/models/telegram/src/index.ts index a0dad72a51..0bef9cb66f 100644 --- a/models/telegram/src/index.ts +++ b/models/telegram/src/index.ts @@ -133,6 +133,19 @@ export function createModel (builder: Builder): void { telegram.ids.TxMessage ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: telegram.class.Message, + action: 'create', + icon: contact.icon.Telegram, + component: telegram.notification.NotificationMessageCreated, + label: telegram.string.SharedMessages + }, + telegram.ids.NotificationMessageCreated + ) + builder.createDoc( contact.class.ChannelProvider, core.space.Model, @@ -177,6 +190,20 @@ export function createModel (builder: Builder): void { telegram.ids.TxSharedCreate ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: telegram.class.SharedMessages, + action: 'create', + icon: contact.icon.Telegram, + component: telegram.component.SharedMessages, + label: telegram.string.SharedMessages, + hideIfRemoved: true + }, + telegram.ids.NotificationMessageShared + ) + builder.createDoc( notification.class.NotificationGroup, core.space.Model, diff --git a/models/telegram/src/plugin.ts b/models/telegram/src/plugin.ts index aba4b290d0..6bc7985776 100644 --- a/models/telegram/src/plugin.ts +++ b/models/telegram/src/plugin.ts @@ -21,7 +21,7 @@ import telegram from '@hcengineering/telegram-resources/src/plugin' import type { AnyComponent } from '@hcengineering/ui/src/types' import type { TxViewlet } from '@hcengineering/activity' import { type TemplateFieldFunc } from '@hcengineering/templates' -import { type NotificationGroup } from '@hcengineering/notification' +import { type DocUpdateMessageViewlet, type NotificationGroup } from '@hcengineering/notification' export default mergeIds(telegramId, telegram, { string: { @@ -42,7 +42,9 @@ export default mergeIds(telegramId, telegram, { TxMessage: '' as Ref, TxSharedCreate: '' as Ref, NewMessageNotificationViewlet: '' as Ref, - NotificationGroup: '' as Ref + NotificationGroup: '' as Ref, + NotificationMessageShared: '' as Ref, + NotificationMessageCreated: '' as Ref }, function: { GetCurrentEmployeeTG: '' as Resource, diff --git a/models/tracker/package.json b/models/tracker/package.json index a8c6249fb3..ca89a082f5 100644 --- a/models/tracker/package.json +++ b/models/tracker/package.json @@ -26,27 +26,26 @@ }, "dependencies": { "@hcengineering/activity": "^0.6.0", + "@hcengineering/contact": "^0.6.20", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/platform": "^0.6.9", + "@hcengineering/model-attachment": "^0.6.0", + "@hcengineering/model-contact": "^0.6.1", "@hcengineering/model-core": "^0.6.0", + "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/model-presentation": "^0.6.0", + "@hcengineering/model-task": "^0.6.0", "@hcengineering/model-view": "^0.6.0", "@hcengineering/model-workbench": "^0.6.1", - "@hcengineering/model-contact": "^0.6.1", - "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/notification": "^0.6.16", - "@hcengineering/model-notification": "^0.6.0", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/setting": "^0.6.11", + "@hcengineering/tags": "^0.6.12", + "@hcengineering/task": "^0.6.13", "@hcengineering/tracker": "^0.6.13", "@hcengineering/tracker-resources": "^0.6.0", - "@hcengineering/model-task": "^0.6.0", - "@hcengineering/model-chunter": "^0.6.0", - "@hcengineering/workbench": "^0.6.9", + "@hcengineering/ui": "^0.6.11", "@hcengineering/view": "^0.6.9", - "@hcengineering/model-presentation": "^0.6.0", - "@hcengineering/setting": "^0.6.11", - "@hcengineering/task": "^0.6.13", - "@hcengineering/tags": "^0.6.12" + "@hcengineering/workbench": "^0.6.9" } } diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index 5c9be41e08..d8d3566e61 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -18,7 +18,6 @@ import { type Builder } from '@hcengineering/model' import core from '@hcengineering/model-core' import task from '@hcengineering/model-task' import view from '@hcengineering/model-view' -import chunter from '@hcengineering/model-chunter' import workbench from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' import setting from '@hcengineering/setting' @@ -259,6 +258,10 @@ function defineFilters (builder: Builder): void { component: tracker.component.MilestoneFilter }) + builder.mixin(tracker.class.Milestone, core.class.Class, view.mixin.ObjectTitle, { + titleProvider: tracker.function.MilestoneTitleProvider + }) + // // Project // @@ -280,6 +283,10 @@ function defineFilters (builder: Builder): void { filters: [] }) + builder.mixin(tracker.class.Component, core.class.Class, view.mixin.ObjectTitle, { + titleProvider: tracker.function.ComponentTitleProvider + }) + // // Type Milestone Status // @@ -438,6 +445,20 @@ export function createModel (builder: Builder): void { TTypeRemainingTime ) + builder.mixin(tracker.class.Project, core.class.Class, notification.mixin.ActivityDoc, {}) + builder.mixin(tracker.class.Issue, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(tracker.class.Milestone, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(tracker.class.Component, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + builder.mixin(tracker.class.IssueTemplate, core.class.Class, notification.mixin.ActivityDoc, { + ignoreCollections: ['comments'] + }) + defineViewlets(builder) defineStatusCategories(builder) @@ -495,6 +516,82 @@ export function createModel (builder: Builder): void { tracker.ids.TxIssueCreated ) + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: tracker.class.Issue, + action: 'update', + icon: tracker.icon.Issue, + config: { + status: { + iconPresenter: tracker.component.IssueStatusIcon + }, + priority: { + iconPresenter: tracker.component.PriorityIconPresenter + }, + estimation: { + icon: tracker.icon.Estimation + } + } + }, + tracker.ids.NotificationIssueUpdated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: tracker.class.Issue, + action: 'create', + icon: tracker.icon.Issue, + valueAttr: 'title' + }, + tracker.ids.NotificationIssueCreated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: tracker.class.Issue, + action: 'remove', + icon: tracker.icon.Issue, + valueAttr: 'title' + }, + tracker.ids.NotificationIssueRemoved + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: tracker.class.Milestone, + action: 'update', + config: { + status: { + iconPresenter: tracker.component.MilestoneStatusIcon + } + } + }, + tracker.ids.NotificationMilestoneUpdated + ) + + builder.createDoc( + notification.class.DocUpdateMessageViewlet, + core.space.Model, + { + objectClass: tracker.class.IssueTemplate, + action: 'update', + config: { + priority: { + iconPresenter: tracker.component.PriorityIconPresenter + } + } + }, + tracker.ids.NotificationIssueTemplateUpdated + ) + defineApplication(builder, { myIssuesId, allIssuesId, issuesId, componentsId, milestonesId, templatesId }) defineActions(builder, issuesId, componentsId, myIssuesId) @@ -528,51 +625,43 @@ export function createModel (builder: Builder): void { }) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: tracker.class.Issue, - components: { - input: chunter.component.CommentInput - } + objectClass: tracker.class.Issue, + label: notification.string.LeftComment }, - tracker.ids.IssueActivityExtension + tracker.ids.IssueChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: tracker.class.IssueTemplate, - components: { - input: chunter.component.CommentInput - } + objectClass: tracker.class.IssueTemplate, + label: notification.string.LeftComment }, - tracker.ids.IssueTemplateActivityExtension + tracker.ids.IssueTemplateChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: tracker.class.Component, - components: { - input: chunter.component.CommentInput - } + objectClass: tracker.class.Component, + label: notification.string.LeftComment }, - tracker.ids.ComponentActivityExtension + tracker.ids.ComponentChatMessageViewlet ) builder.createDoc( - activity.class.ActivityExtension, + notification.class.ChatMessageViewlet, core.space.Model, { - ofClass: tracker.class.Milestone, - components: { - input: chunter.component.CommentInput - } + objectClass: tracker.class.Milestone, + label: notification.string.LeftComment }, - tracker.ids.MilestoneActivityExtension + tracker.ids.MilestoneChatMessageViewlet ) builder.createDoc( diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index c5b053b30b..89d1b0abef 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -22,8 +22,13 @@ import tracker from '@hcengineering/tracker-resources/src/plugin' import type { AnyComponent } from '@hcengineering/ui/src/types' import { type Action, type ViewAction, type Viewlet } from '@hcengineering/view' import { type Application } from '@hcengineering/workbench' -import { type ActivityExtension, type TxViewlet } from '@hcengineering/activity' -import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' +import { type TxViewlet } from '@hcengineering/activity' +import { + type ChatMessageViewlet, + type DocUpdateMessageViewlet, + type NotificationGroup, + type NotificationType +} from '@hcengineering/notification' export default mergeIds(trackerId, tracker, { string: { @@ -75,11 +80,16 @@ export default mergeIds(trackerId, tracker, { TxIssueCreated: '' as Ref, TrackerNotificationGroup: '' as Ref, AssigneeNotification: '' as Ref, - IssueActivityExtension: '' as Ref, - IssueTemplateActivityExtension: '' as Ref, - ComponentActivityExtension: '' as Ref, - MilestoneActivityExtension: '' as Ref, - BaseProjectType: '' as Ref + BaseProjectType: '' as Ref, + NotificationIssueUpdated: '' as Ref, + NotificationIssueCreated: '' as Ref, + NotificationIssueRemoved: '' as Ref, + NotificationMilestoneUpdated: '' as Ref, + NotificationIssueTemplateUpdated: '' as Ref, + IssueChatMessageViewlet: '' as Ref, + IssueTemplateChatMessageViewlet: '' as Ref, + ComponentChatMessageViewlet: '' as Ref, + MilestoneChatMessageViewlet: '' as Ref }, completion: { IssueQuery: '' as Resource, diff --git a/models/tracker/src/types.ts b/models/tracker/src/types.ts index 307479814d..249ede0161 100644 --- a/models/tracker/src/types.ts +++ b/models/tracker/src/types.ts @@ -41,7 +41,6 @@ import { UX } from '@hcengineering/model' import attachment from '@hcengineering/model-attachment' -import chunter from '@hcengineering/model-chunter' import core, { TAttachedDoc, TDoc, TStatus, TType } from '@hcengineering/model-core' import task, { TTask, TProject as TTaskProject } from '@hcengineering/model-task' import { type IntlString } from '@hcengineering/platform' @@ -65,6 +64,7 @@ import { type TimeSpendReport } from '@hcengineering/tracker' import tracker from './plugin' +import notification from '@hcengineering/notification' export const DOMAIN_TRACKER = 'tracker' as Domain @@ -252,7 +252,7 @@ export class TIssue extends TTask implements Issue { */ @Model(tracker.class.IssueTemplate, core.class.Doc, DOMAIN_TRACKER) -@UX(tracker.string.IssueTemplate, tracker.icon.Issue, 'PROCESS') +@UX(tracker.string.IssueTemplate, tracker.icon.IssueTemplates, 'PROCESS') export class TIssueTemplate extends TDoc implements IssueTemplate { @Prop(TypeString(), tracker.string.Title) @Index(IndexKind.FullText) @@ -288,7 +288,7 @@ export class TIssueTemplate extends TDoc implements IssueTemplate { @Prop(ArrOf(TypeRef(tracker.class.IssueTemplate)), tracker.string.IssueTemplate) children!: IssueTemplateChild[] - @Prop(Collection(chunter.class.Comment), tracker.string.Comments) + @Prop(Collection(notification.class.ChatMessage), tracker.string.Comments) comments!: number @Prop(Collection(attachment.class.Attachment), tracker.string.Attachments) @@ -336,7 +336,7 @@ export class TComponent extends TDoc implements Component { @Prop(TypeRef(contact.mixin.Employee), tracker.string.ComponentLead) lead!: Ref | null - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments!: number @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) @@ -362,7 +362,7 @@ export class TMilestone extends TDoc implements Milestone { @Index(IndexKind.Indexed) status!: MilestoneStatus - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(notification.class.ChatMessage), notification.string.Comments) comments!: number @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 162d1200e5..1b84435ca6 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -84,8 +84,11 @@ import { type ViewOptionsModel, type Viewlet, type ViewletDescriptor, - type ViewletPreference + type ViewletPreference, + type NotificationAttributePresenter, + type ObjectIdentifier } from '@hcengineering/view' + import view from './plugin' export { viewId } from '@hcengineering/view' @@ -124,6 +127,9 @@ export function classPresenter ( builder.mixin(_class, core.class.Class, view.mixin.ActivityAttributePresenter, { presenter: activity }) + builder.mixin(_class, core.class.Class, view.mixin.NotificationAttributePresenter, { + presenter: activity + }) } } @@ -204,6 +210,11 @@ export class TActivityAttributePresenter extends TClass implements ActivityAttri presenter!: AnyComponent } +@Mixin(view.mixin.NotificationAttributePresenter, core.class.Class) +export class TNotificationAttributePresenter extends TClass implements NotificationAttributePresenter { + presenter!: AnyComponent +} + @Mixin(view.mixin.SpacePresenter, core.class.Class) export class TSpacePresenter extends TClass implements SpacePresenter { presenter!: AnyComponent @@ -258,7 +269,12 @@ export class TObjectFactory extends TClass implements ObjectFactory { @Mixin(view.mixin.ObjectTitle, core.class.Class) export class TObjectTitle extends TClass implements ObjectTitle { - titleProvider!: Resource<(client: Client, ref: Ref) => Promise> + titleProvider!: Resource<(client: Client, ref: Ref, doc?: T) => Promise> +} + +@Mixin(view.mixin.ObjectIdentifier, core.class.Class) +export class TObjectIdentifier extends TClass implements ObjectIdentifier { + provider!: Resource<(client: Client, ref: Ref, doc?: T) => Promise> } @Mixin(view.mixin.ListHeaderExtra, core.class.Class) @@ -408,6 +424,7 @@ export function createModel (builder: Builder): void { TAttributePresenter, TAttributeFilterPresenter, TActivityAttributePresenter, + TNotificationAttributePresenter, TListItemPresenter, TCollectionEditor, TCollectionPresenter, @@ -436,7 +453,8 @@ export function createModel (builder: Builder): void { TFilteredView, TAllValuesFunc, TAggregation, - TGroupping + TGroupping, + TObjectIdentifier ) classPresenter( diff --git a/packages/core/src/common.ts b/packages/core/src/common.ts new file mode 100644 index 0000000000..a910396d49 --- /dev/null +++ b/packages/core/src/common.ts @@ -0,0 +1,15 @@ +export function groupByArray (array: T[], keyProvider: (item: T) => K): Map { + const result = new Map() + + array.forEach((item) => { + const key = keyProvider(item) + + if (!result.has(key)) { + result.set(key, [item]) + } else { + result.get(key)?.push(item) + } + }) + + return result +} diff --git a/packages/core/src/hierarchy.ts b/packages/core/src/hierarchy.ts index d35f2ea39e..f8bbd9c25a 100644 --- a/packages/core/src/hierarchy.ts +++ b/packages/core/src/hierarchy.ts @@ -151,6 +151,12 @@ export class Hierarchy { return data } + hasClass (_class: Ref>): boolean { + const data = this.classifiers.get(_class) + + return !(data === undefined || this.isInterface(data)) + } + getClassOrInterface (_class: Ref>): Class { const data = this.classifiers.get(_class) if (data === undefined) { diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c8c963bdf9..a38d06dbe5 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -30,3 +30,5 @@ export * from './utils' export * from './backup' export * from './status' export * from './typeof' +export * from './common' +export * from './time' diff --git a/packages/core/src/memdb.ts b/packages/core/src/memdb.ts index ea0188f935..b08c7f1944 100644 --- a/packages/core/src/memdb.ts +++ b/packages/core/src/memdb.ts @@ -175,6 +175,14 @@ export abstract class MemDb extends TxProcessor implements Storage { return toFindResult(res, total) } + async findOne( + _class: Ref>, + query: DocumentQuery, + options?: FindOptions + ): Promise | undefined> { + return (await this.findAll(_class, query, { ...options, limit: 1 }))[0] + } + /** * Only in model find without lookups and sorting. */ diff --git a/packages/core/src/time.ts b/packages/core/src/time.ts new file mode 100644 index 0000000000..912c3932dc --- /dev/null +++ b/packages/core/src/time.ts @@ -0,0 +1,22 @@ +function isToday (time: number): boolean { + const current = new Date() + const target = new Date(time) + return ( + current.getDate() === target.getDate() && + current.getMonth() === target.getMonth() && + current.getFullYear() === target.getFullYear() + ) +} + +export function getDisplayTime (time: number): string { + let options: Intl.DateTimeFormatOptions = { hour: 'numeric', minute: 'numeric' } + if (!isToday(time)) { + options = { + month: 'numeric', + day: 'numeric', + ...options + } + } + + return new Date(time).toLocaleString('default', options) +} diff --git a/packages/model/src/migration.ts b/packages/model/src/migration.ts index f6a5b07ac2..93733772fd 100644 --- a/packages/model/src/migration.ts +++ b/packages/model/src/migration.ts @@ -1,21 +1,21 @@ import core, { Client, - Doc, DOMAIN_MIGRATION, + Data, + Doc, DocumentQuery, Domain, FindOptions, Hierarchy, IncOptions, + MigrationState, ModelDb, ObjQueryType, PushOptions, Ref, - UnsetOptions, - MigrationState, - generateId, TxOperations, - Data + UnsetOptions, + generateId } from '@hcengineering/core' import { ModelLogger } from './utils' @@ -48,6 +48,14 @@ export type MigrationDocumentQuery = { [key: string]: any } +/** + * @public + */ +export interface MigrationIterator { + next: (count: number) => Promise + close: () => Promise +} + /** * @public * Client to perform model upgrades @@ -62,6 +70,13 @@ export interface MigrationClient { options?: Omit, 'lookup'> ) => Promise + // Traverse documents + traverse: ( + domain: Domain, + query: MigrationDocumentQuery, + options?: Omit, 'lookup'> + ) => Promise> + // Allow to raw update documents inside domain. update: ( domain: Domain, @@ -77,8 +92,9 @@ export interface MigrationClient { // Move documents per domain move: (sourceDomain: Domain, query: DocumentQuery, targetDomain: Domain) => Promise - create: (domain: Domain, doc: T) => Promise + create: (domain: Domain, doc: T | T[]) => Promise delete: (domain: Domain, _id: Ref) => Promise + deleteMany: (domain: Domain, ids: Ref[]) => Promise hierarchy: Hierarchy model: ModelDb diff --git a/packages/ui/src/components/calendar/DateRangePresenter.svelte b/packages/ui/src/components/calendar/DateRangePresenter.svelte index 87a4a76b5a..e157157ac6 100644 --- a/packages/ui/src/components/calendar/DateRangePresenter.svelte +++ b/packages/ui/src/components/calendar/DateRangePresenter.svelte @@ -35,15 +35,20 @@ export let kind: 'default' | 'no-border' | 'link' | 'regular' = 'default' export let size: 'small' | 'medium' | 'large' = 'small' export let noShift: boolean = false + export let shouldShowAvatar: boolean = true + export let accent: boolean = false + export let inline: boolean = false const dispatch = createEventDispatcher() type TEdits = 'day' | 'month' | 'year' | 'hour' | 'min' + interface IEdits { id: TEdits value: number el?: HTMLElement } + const editsType: TEdits[] = ['day', 'month', 'year', 'hour', 'min'] const getIndex = (id: TEdits): number => editsType.indexOf(id) const today = new Date() @@ -297,155 +302,13 @@ adaptValue() - + +{:else} + +{/if} diff --git a/plugins/activity-resources/src/components/ActivityFilter.svelte b/plugins/activity-resources/src/components/ActivityFilter.svelte index b4dd5cd58b..b046fe09fb 100644 --- a/plugins/activity-resources/src/components/ActivityFilter.svelte +++ b/plugins/activity-resources/src/components/ActivityFilter.svelte @@ -13,32 +13,36 @@ // limitations under the License. -->
{#if selectedFiltersRefs === 'All'}
-
{:else} {#each selectedFilters as filter} @@ -137,10 +140,3 @@ {/if}
-{#if extraComponent} - {#await getResource(extraComponent) then comp} - {#if comp} - - {/if} - {/await} -{/if} diff --git a/plugins/activity-resources/src/components/FilterPopup.svelte b/plugins/activity-resources/src/components/FilterPopup.svelte index 8e4cc9c7f2..a48df87174 100644 --- a/plugins/activity-resources/src/components/FilterPopup.svelte +++ b/plugins/activity-resources/src/components/FilterPopup.svelte @@ -17,14 +17,17 @@ import { IntlString } from '@hcengineering/platform' import { Label, resizeObserver, CheckBox, MiniToggle } from '@hcengineering/ui' import { Doc, Ref } from '@hcengineering/core' - import { ActivityFilter } from '@hcengineering/activity' + import notification, { ActivityMessagesFilter } from '@hcengineering/notification' + import activity from '../plugin' export let selectedFiltersRefs: Ref[] | 'All' = 'All' - export let filters: ActivityFilter[] = [] - let activityOrderNewestFirst = JSON.parse(localStorage.getItem('activity-newest-first') ?? 'false') + export let filters: ActivityMessagesFilter[] = [] + const dispatch = createEventDispatcher() + let activityOrderNewestFirst = JSON.parse(localStorage.getItem('activity-newest-first') ?? 'false') + interface ActionMenu { label: IntlString checked: boolean @@ -129,7 +132,7 @@
{ dispatch('update', { action: 'toggle', value: activityOrderNewestFirst }) }} diff --git a/plugins/activity-resources/src/components/TxView.svelte b/plugins/activity-resources/src/components/TxView.svelte deleted file mode 100644 index 7506c75b0d..0000000000 --- a/plugins/activity-resources/src/components/TxView.svelte +++ /dev/null @@ -1,550 +0,0 @@ - - - -{#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0} -
- {#if showIcon} - {#if withAvatar} -
- -
- {:else} -
- {#if iconComponent} - - {:else if viewlet} - - {:else if viewlet === undefined && model.length > 0} - - {:else} - - {/if} -
- {/if} - {/if} - -
-
-
- - {#if person} - {getName(client.getHierarchy(), person)} - {:else} - - - {#if viewlet && viewlet?.editable} - {#if viewlet.label} - - {/if} - {#if tx.updated} - - {/if} - - {:else if viewlet && viewlet.label} - - - {/if} - {#if viewlet && viewlet.labelComponent} - - {/if} - - {#if viewlet === undefined && model.length > 0 && tx.updateTx} - {#each model as m} - {#await getValue(client, m, tx) then value} - {#if value.added.length} - - - - {#each value.added as cvalue} - {#if value.isObjectAdded} - - {:else} - - {/if} - {/each} - {:else if value.removed.length} - - - - {#each value.removed as cvalue} - {#if value.isObjectRemoved} - - {:else} - - {/if} - {/each} - {:else if value.set === null || value.set === undefined || value.set === ''} - - - {:else} - - - - {#if !hasMessageType} - - - {#if value.isObjectSet} - - {:else} - - {/if} - - {:else} - - - (showDiff = !showDiff)}> - - {/if} - {/if} - {/await} - {/each} - {:else if viewlet === undefined && model.length > 0 && tx.mixinTx} - {#each model as m} - {#await getValue(client, m, tx) then value} - {#if value.set === null || value.set === ''} - - - {:else} - - - - - {#if !hasMessageType} -
- {#if value.isObjectSet} - - {:else} - - {/if} -
- {/if} - {/if} - {/await} - {/each} - {:else if viewlet && viewlet.display === 'inline' && viewlet.component} - {#if tx.collectionAttribute !== undefined && (tx.txDocIds?.size ?? 0) > 1} - - {:else if typeof viewlet.component === 'string'} - - {:else} - - {/if} - {/if} -
- {#if isComment} -
- - - {#if account?.person === currentAccount?.person} - - {/if} -
- {:else if hasMessageType || isColumn} - - {/if} -
- - {#if !isColumn} - - {/if} - - {#if viewlet && viewlet.display !== 'inline'} -
- - {#if tx.collectionAttribute !== undefined && (tx.txDocIds?.size ?? 0) > 1} -
- -
- {:else if typeof viewlet.component === 'string'} - - {:else} - - {/if} -
-
- {:else if hasMessageType && model.length > 0 && (tx.updateTx || tx.mixinTx)} - {#await getValue(client, model[0], tx) then value} - {@const prevValue = getPrevValue(client, model[0], tx)} -
- - {#if value.isObjectSet} - - {:else if showDiff} - - {/if} - -
- {/await} - {/if} - -
-
-{/if} - - diff --git a/plugins/activity-resources/src/components/TxViewTx.svelte b/plugins/activity-resources/src/components/TxViewTx.svelte deleted file mode 100644 index ae35e73f1f..0000000000 --- a/plugins/activity-resources/src/components/TxViewTx.svelte +++ /dev/null @@ -1,46 +0,0 @@ - - -{#each filterTx([...tx.txes, tx], core.class.TxCreateDoc) as ctx, i} - {#if i === 0 && !presentersOnly} - - {/if} - {#if typeof viewlet?.component === 'string'} - - {:else} - - {/if} -
-{/each} -{#each filterTx([...tx.txes, tx], core.class.TxRemoveDoc) as ctx, i} - {#if i === 0 && !presentersOnly} - - {/if} - {#if typeof viewlet?.component === 'string'} - - {:else} - - {/if} -
-{/each} diff --git a/plugins/activity-resources/src/index.ts b/plugins/activity-resources/src/index.ts index b42d19f7c7..747e14f4dc 100644 --- a/plugins/activity-resources/src/index.ts +++ b/plugins/activity-resources/src/index.ts @@ -13,25 +13,13 @@ // limitations under the License. // -import { type Doc, type Ref } from '@hcengineering/core' import { type Resources } from '@hcengineering/platform' -import type { DisplayTx } from '@hcengineering/activity' -import Activity from './components/Activity.svelte' -import TxView from './components/TxView.svelte' -export { TxView } +import Activity from './components/Activity.svelte' export * from './activity' export * from './utils' - -export function attributeFilter (tx: DisplayTx, _class?: Ref): boolean { - return tx.tx.objectClass === _class -} - export default async (): Promise => ({ - filter: { - AttributeFilter: attributeFilter - }, component: { Activity } diff --git a/plugins/activity-resources/src/plugin.ts b/plugins/activity-resources/src/plugin.ts index f928bfa04c..eca9c8809d 100644 --- a/plugins/activity-resources/src/plugin.ts +++ b/plugins/activity-resources/src/plugin.ts @@ -19,10 +19,10 @@ import { mergeIds } from '@hcengineering/platform' export default mergeIds(activityId, activity, { string: { - DocCreated: '' as IntlString, - DocAdded: '' as IntlString, - DocDeleted: '' as IntlString, + All: '' as IntlString, CollectionUpdated: '' as IntlString, - All: '' as IntlString + DocAdded: '' as IntlString, + DocCreated: '' as IntlString, + DocDeleted: '' as IntlString } }) diff --git a/plugins/activity-resources/src/utils.ts b/plugins/activity-resources/src/utils.ts index de58a4e9b7..99e132de05 100644 --- a/plugins/activity-resources/src/utils.ts +++ b/plugins/activity-resources/src/utils.ts @@ -1,4 +1,5 @@ -import type { ActivityExtension, DisplayTx, TxViewlet } from '@hcengineering/activity' +import { get } from 'svelte/store' +import type { DisplayTx, TxViewlet } from '@hcengineering/activity' import core, { type AttachedDoc, type Class, @@ -15,7 +16,6 @@ import core, { type TxOperations, TxProcessor, type TxUpdateDoc, - getObjectValue, matchQuery } from '@hcengineering/core' import { type Asset, type IntlString, getResource, translate } from '@hcengineering/platform' @@ -23,7 +23,7 @@ import { getAttributePresenterClass } from '@hcengineering/presentation' import { type AnyComponent, type AnySvelteComponent, ErrorPresenter, themeStore } from '@hcengineering/ui' import view, { type AttributeModel, type BuildModelKey, type BuildModelOptions } from '@hcengineering/view' import { getObjectPresenter } from '@hcengineering/view-resources' -import { get } from 'svelte/store' + import { type ActivityKey, activityKey } from './activity' import activity from './plugin' @@ -391,42 +391,3 @@ export async function getValue (client: TxOperations, m: AttributeModel, tx: Dis } return value } - -export function getPrevValue (client: TxOperations, m: AttributeModel, tx: DisplayTx): any { - if (tx.txes.length > 0 && tx.txes[0].prevDoc !== undefined) { - return getObjectValue(m.key, tx.txes[0].prevDoc) - } else if (tx.prevDoc !== undefined) { - return getObjectValue(m.key, tx.prevDoc) - } - return undefined -} - -export function filterCollectionTxes (txes: DisplayTx[]): DisplayTx[] { - return txes.map(filterCollectionTx).filter(Boolean) as DisplayTx[] -} - -function filterCollectionTx (tx: DisplayTx): DisplayTx | undefined { - if (tx.collectionAttribute === undefined) return tx - const txes = tx.txes.reduceRight( - (txes, ctx) => { - const filtredTxes = txes.filter( - ({ tx: { _class }, doc }) => doc?._id !== ctx.doc?._id || _class === core.class.TxUpdateDoc - ) - return ctx.tx._class === core.class.TxUpdateDoc || filtredTxes.length === txes.length - ? [ctx, ...txes] - : filtredTxes - }, - [tx] - ) - const txDocIds = txes.map(({ doc }) => doc?._id).filter(Boolean) as Array> - const ctx = txes.pop() - if (ctx !== undefined) { - ctx.txes = txes - ctx.txDocIds = new Set(txDocIds) - } - return ctx -} - -export async function getExtensions (client: Client, ofClass: Ref>): Promise { - return await client.findAll(activity.class.ActivityExtension, { ofClass }) -} diff --git a/plugins/activity/package.json b/plugins/activity/package.json index 061e8d874f..e435458554 100644 --- a/plugins/activity/package.json +++ b/plugins/activity/package.json @@ -14,23 +14,24 @@ }, "devDependencies": { "@hcengineering/platform-rig": "^0.6.0", + "@types/jest": "^29.5.5", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.4.0", "eslint-plugin-promise": "^6.1.1", - "eslint": "^8.54.0", - "prettier": "^3.1.0", - "typescript": "^5.2.2", "jest": "^29.7.0", + "prettier": "^3.1.0", + "prettier-plugin-svelte": "^3.1.0", "ts-jest": "^29.1.1", - "@types/jest": "^29.5.5", - "prettier-plugin-svelte": "^3.1.0" + "typescript": "^5.2.2" }, "dependencies": { - "@hcengineering/platform": "^0.6.9", "@hcengineering/core": "^0.6.28", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", "@hcengineering/ui": "^0.6.11" } } diff --git a/plugins/activity/src/index.ts b/plugins/activity/src/index.ts index f908803b5a..3805546b96 100644 --- a/plugins/activity/src/index.ts +++ b/plugins/activity/src/index.ts @@ -27,10 +27,11 @@ import type { TxMixin, TxUpdateDoc } from '@hcengineering/core' -import type { Asset, IntlString, Plugin, Resource } from '@hcengineering/platform' +import type { Asset, IntlString, Plugin } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' import type { AnyComponent } from '@hcengineering/ui' +// TODO: remove TxViewlet /** * Define an display for all transaction kinds for particular class. * @public @@ -61,6 +62,7 @@ export interface TxViewlet extends Doc { hideOnRemove?: boolean } +// TODO: remove DisplayTx /** * Transaction being displayed. * @public @@ -96,69 +98,27 @@ export interface DisplayTx { originTx: TxCUD } -/** - * @public - */ -export interface ActivityFilter extends Doc { - label: IntlString - filter: Resource<(tx: DisplayTx, _class?: Ref) => boolean> -} - -/** - * @public - */ -export interface ExtraActivityComponent extends Class { - component: AnyComponent -} - /** * @public */ export const activityId = 'activity' as Plugin -/** - * @public - */ -export type ActivityExtensionKind = 'footer' | 'action' | 'input' - -/** - * @public - */ -export interface ActivityExtension extends Doc { - ofClass: Ref> - components?: Partial> - isMention?: boolean -} - -/** - * @public - */ -export interface TxMention extends Class {} - export default plugin(activityId, { icon: { Activity: '' as Asset }, string: { - Delete: '' as IntlString, - Edit: '' as IntlString, - Edited: '' as IntlString, Activity: '' as IntlString, - Changed: '' as IntlString, - To: '' as IntlString, - Unset: '' as IntlString, Added: '' as IntlString, + Changed: '' as IntlString, + Edited: '' as IntlString, From: '' as IntlString, Removed: '' as IntlString, - NewestFirst: '' as IntlString - }, - mixin: { - ExtraActivityComponent: '' as Ref> + To: '' as IntlString, + Unset: '' as IntlString }, class: { - TxViewlet: '' as Ref>, - ActivityFilter: '' as Ref>, - ActivityExtension: '' as Ref> + TxViewlet: '' as Ref> }, component: { Activity: '' as AnyComponent diff --git a/plugins/attachment-resources/package.json b/plugins/attachment-resources/package.json index 2d2194766f..fd55976034 100644 --- a/plugins/attachment-resources/package.json +++ b/plugins/attachment-resources/package.json @@ -14,43 +14,44 @@ "build:watch": "tsc --noEmit --outDir ./dist_cache" }, "devDependencies": { - "svelte-loader": "^3.1.9", - "sass": "^1.53.0", - "svelte-preprocess": "^5.1.0", "@hcengineering/platform-rig": "^0.6.0", + "@types/jest": "^29.5.5", "@typescript-eslint/eslint-plugin": "^6.11.0", "@typescript-eslint/parser": "^6.11.0", + "eslint": "^8.54.0", "eslint-config-standard-with-typescript": "^40.0.0", "eslint-plugin-import": "^2.26.0", "eslint-plugin-n": "^15.4.0", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-svelte": "^2.34.0", - "prettier-plugin-svelte": "^3.1.0", - "eslint": "^8.54.0", - "prettier": "^3.1.0", - "svelte-check": "^3.6.0", - "typescript": "^5.2.2", "jest": "^29.7.0", + "prettier": "^3.1.0", + "prettier-plugin-svelte": "^3.1.0", + "sass": "^1.53.0", + "svelte-check": "^3.6.0", + "svelte-eslint-parser": "^0.33.1", + "svelte-loader": "^3.1.9", + "svelte-preprocess": "^5.1.0", "ts-jest": "^29.1.1", - "@types/jest": "^29.5.5", - "svelte-eslint-parser": "^0.33.1" + "typescript": "^5.2.2" }, "dependencies": { - "@hcengineering/platform": "^0.6.9", - "svelte": "^4.2.5", - "@hcengineering/ui": "^0.6.11", - "@hcengineering/presentation": "^0.6.2", + "@hcengineering/activity": "^0.6.0", "@hcengineering/attachment": "^0.6.9", "@hcengineering/contact": "^0.6.20", "@hcengineering/core": "^0.6.28", + "@hcengineering/login": "^0.6.8", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/panel": "^0.6.15", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/preference": "^0.6.9", + "@hcengineering/presentation": "^0.6.2", + "@hcengineering/text-editor": "^0.6.0", + "@hcengineering/ui": "^0.6.11", "@hcengineering/view": "^0.6.9", "@hcengineering/view-resources": "^0.6.0", - "@hcengineering/panel": "^0.6.15", - "@hcengineering/text-editor": "^0.6.0", - "@hcengineering/login": "^0.6.8", "filesize": "^8.0.3", - "@hcengineering/preference": "^0.6.9", - "@hcengineering/activity": "^0.6.0" + "svelte": "^4.2.5" }, "repository": "https://github.com/hcengineering/anticrm", "publishConfig": { diff --git a/plugins/attachment-resources/src/components/notification/NotificationAttachmentChanged.svelte b/plugins/attachment-resources/src/components/notification/NotificationAttachmentChanged.svelte new file mode 100644 index 0000000000..d307bc853e --- /dev/null +++ b/plugins/attachment-resources/src/components/notification/NotificationAttachmentChanged.svelte @@ -0,0 +1,32 @@ + + + +{#if value} + {#if message.action === 'remove'} + + {:else} + + {/if} +{/if} diff --git a/plugins/attachment-resources/src/index.ts b/plugins/attachment-resources/src/index.ts index 25d7699055..cc6f2197f6 100644 --- a/plugins/attachment-resources/src/index.ts +++ b/plugins/attachment-resources/src/index.ts @@ -14,17 +14,12 @@ // import attachment, { type Attachment } from '@hcengineering/attachment' -import { - type ObjQueryType, - SortingOrder, - type SortingQuery, - type Markup, - type Ref, - type Doc -} from '@hcengineering/core' +import { type ObjQueryType, SortingOrder, type SortingQuery, type Markup } from '@hcengineering/core' import { type IntlString, type Resources } from '@hcengineering/platform' import preference from '@hcengineering/preference' import { getClient } from '@hcengineering/presentation' +import notification, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/notification' + import TxAttachmentCreate from './components/activity/TxAttachmentCreate.svelte' import AddAttachment from './components/AddAttachment.svelte' import AttachmentDocList from './components/AttachmentDocList.svelte' @@ -44,8 +39,8 @@ import AccordionEditor from './components/AccordionEditor.svelte' import IconUploadDuo from './components/icons/UploadDuo.svelte' import IconAttachment from './components/icons/Attachment.svelte' import { deleteFile, uploadFile } from './utils' -import { type DisplayTx } from '@hcengineering/activity' import AttachmentPreview from './components/AttachmentPreview.svelte' +import NotificationAttachmentChanged from './components/notification/NotificationAttachmentChanged.svelte' export { AddAttachment, @@ -239,8 +234,12 @@ export async function DeleteAttachment (attach: Attachment): Promise { ) } -export function attachmentsFilter (tx: DisplayTx, _class?: Ref): boolean { - return tx.tx.objectClass === attachment.class.Attachment +export function attachmentsFilter (message: ActivityMessage): boolean { + if (message._class === notification.class.DocUpdateMessage) { + return (message as DocUpdateMessage).objectClass === attachment.class.Attachment + } + + return false } export default async (): Promise => ({ @@ -255,6 +254,9 @@ export default async (): Promise => ({ FileBrowser, Photos }, + notification: { + NotificationAttachmentChanged + }, activity: { TxAttachmentCreate }, diff --git a/plugins/bitrix/package.json b/plugins/bitrix/package.json index b5d0164e28..e0b3dab1f3 100644 --- a/plugins/bitrix/package.json +++ b/plugins/bitrix/package.json @@ -30,18 +30,18 @@ "prettier-plugin-svelte": "^3.1.0" }, "dependencies": { - "@hcengineering/platform": "^0.6.9", - "@hcengineering/core": "^0.6.28", - "@hcengineering/preference": "^0.6.9", - "@hcengineering/tags": "^0.6.12", - "@hcengineering/contact": "^0.6.20", - "@hcengineering/chunter": "^0.6.12", "@hcengineering/attachment": "^0.6.9", - "fast-equals": "^2.0.3", - "qs": "~6.11.0", + "@hcengineering/contact": "^0.6.20", + "@hcengineering/core": "^0.6.28", "@hcengineering/gmail": "^0.6.15", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/platform": "^0.6.9", + "@hcengineering/preference": "^0.6.9", "@hcengineering/recruit": "^0.6.21", - "@hcengineering/task": "^0.6.13" + "@hcengineering/tags": "^0.6.12", + "@hcengineering/task": "^0.6.13", + "fast-equals": "^2.0.3", + "qs": "~6.11.0" }, "repository": "https://github.com/hcengineering/anticrm", "publishConfig": { diff --git a/plugins/bitrix/src/sync.ts b/plugins/bitrix/src/sync.ts index 5cf275454d..c4d9606444 100644 --- a/plugins/bitrix/src/sync.ts +++ b/plugins/bitrix/src/sync.ts @@ -1,5 +1,4 @@ import attachment, { Attachment } from '@hcengineering/attachment' -import chunter, { Comment } from '@hcengineering/chunter' import contact, { Channel, combineName, Contact, Employee, PersonAccount } from '@hcengineering/contact' import core, { Account, @@ -41,6 +40,7 @@ import { LoginInfo } from './types' import { convert, ConvertResult } from './utils' +import notification, { ChatMessage } from '@hcengineering/notification' async function updateDoc (client: ApplyOperations, doc: Doc, raw: Doc | Data, date: Timestamp): Promise { // We need to update fields if they are different. @@ -785,9 +785,9 @@ async function downloadComments ( order: { ID: ops.direction } }) for (const it of commentsData.result) { - const c: Comment & BitrixSyncDoc = { + const c: ChatMessage & BitrixSyncDoc = { _id: generateId(), - _class: chunter.class.Comment, + _class: notification.class.ChatMessage, message: processComment(it.COMMENT as string), bitrixId: `${it.ID as string}`, type: it.ENTITY_TYPE, diff --git a/plugins/board-resources/src/components/KanbanCard.svelte b/plugins/board-resources/src/components/KanbanCard.svelte index d990a20bb3..25f9f8389a 100644 --- a/plugins/board-resources/src/components/KanbanCard.svelte +++ b/plugins/board-resources/src/components/KanbanCard.svelte @@ -16,7 +16,6 @@ - +
+ +
+ + diff --git a/plugins/chunter-resources/src/components/activity/TxBacklinkReference.svelte b/plugins/chunter-resources/src/components/BacklinkReference.svelte similarity index 84% rename from plugins/chunter-resources/src/components/activity/TxBacklinkReference.svelte rename to plugins/chunter-resources/src/components/BacklinkReference.svelte index d536d8edea..55bd4c8066 100644 --- a/plugins/chunter-resources/src/components/activity/TxBacklinkReference.svelte +++ b/plugins/chunter-resources/src/components/BacklinkReference.svelte @@ -20,24 +20,19 @@ import { getObjectPresenter } from '@hcengineering/view-resources' export let value: Backlink + export let inline = true const client = getClient() let presenter: AttributeModel | undefined const docQuery = createQuery() - // const targetQuery = createQuery() let doc: Doc | undefined - // let target: Doc | undefined $: value.backlinkClass != null && docQuery.query(value.backlinkClass, { _id: value.backlinkId }, (r) => { doc = r.shift() }) - // $: targetQuery.query(value.attachedToClass, { _id: value.attachedTo }, (r) => { - // target = r.shift() - // }) - $: if (doc !== undefined) { getObjectPresenter(client, doc._class, { key: '' }).then((p) => { presenter = p @@ -47,6 +42,6 @@ {#if presenter} - + {/if} diff --git a/plugins/chunter-resources/src/components/ChannelPresenter.svelte b/plugins/chunter-resources/src/components/ChannelPresenter.svelte index 57d97540c8..ed4466b2ff 100644 --- a/plugins/chunter-resources/src/components/ChannelPresenter.svelte +++ b/plugins/chunter-resources/src/components/ChannelPresenter.svelte @@ -20,6 +20,8 @@ export let value: Channel export let inline: boolean = false + export let shouldShowAvatar = true + const client = getClient() $: icon = client.getHierarchy().getClass(value._class).icon @@ -28,7 +30,7 @@ {#if value}
- {#if !inline} + {#if !inline && shouldShowAvatar}
{#if icon} diff --git a/plugins/chunter-resources/src/components/Comment.svelte b/plugins/chunter-resources/src/components/Comment.svelte deleted file mode 100644 index eda1df8cec..0000000000 --- a/plugins/chunter-resources/src/components/Comment.svelte +++ /dev/null @@ -1,65 +0,0 @@ - - - -
-
-
-
{getName(client.getHierarchy(), user)}{message.createDate}
-
{message.text}
-
-
- - diff --git a/plugins/chunter-resources/src/components/CommentInput.svelte b/plugins/chunter-resources/src/components/CommentInput.svelte deleted file mode 100644 index aaf428db1e..0000000000 --- a/plugins/chunter-resources/src/components/CommentInput.svelte +++ /dev/null @@ -1,134 +0,0 @@ - - - - diff --git a/plugins/chunter-resources/src/components/CommentPanel.svelte b/plugins/chunter-resources/src/components/CommentPanel.svelte deleted file mode 100644 index 6a1f0aa0d2..0000000000 --- a/plugins/chunter-resources/src/components/CommentPanel.svelte +++ /dev/null @@ -1,95 +0,0 @@ - - - -{#if loading} - -{:else if component && attachedDocId && attachedDocClass} - -{/if} diff --git a/plugins/chunter-resources/src/components/CommentPresenter.svelte b/plugins/chunter-resources/src/components/CommentPresenter.svelte deleted file mode 100644 index 8bf18be981..0000000000 --- a/plugins/chunter-resources/src/components/CommentPresenter.svelte +++ /dev/null @@ -1,117 +0,0 @@ - - - -{#if inline} - {#if !inbox} - - {:else} - - {/if} -{:else} -
- {#await getEmployee(value, $personByIdStore, $personAccountByIdStore) then employee} -
- -
-
-
-
- {#if employee}{getName(client.getHierarchy(), employee)}{/if} -
-
- {#if value.pinned} - - {/if} -
- -
-
-
- - - - {#each links as link} - - {/each} - -
- {/await} -
-{/if} - - diff --git a/plugins/chunter-resources/src/components/Message.svelte b/plugins/chunter-resources/src/components/Message.svelte index 4bf9bdc8df..36b0fb6a02 100644 --- a/plugins/chunter-resources/src/components/Message.svelte +++ b/plugins/chunter-resources/src/components/Message.svelte @@ -19,7 +19,7 @@ import type { ChunterMessage, ChunterMessageExtension, Message, Reaction } from '@hcengineering/chunter' import { PersonAccount } from '@hcengineering/contact' import { Avatar, personByIdStore, EmployeePresenter } from '@hcengineering/contact-resources' - import { getCurrentAccount, Mixin, Ref, WithLookup } from '@hcengineering/core' + import { getCurrentAccount, getDisplayTime, Mixin, Ref, WithLookup } from '@hcengineering/core' import { getResource } from '@hcengineering/platform' import { getClient, MessageViewer } from '@hcengineering/presentation' import ui, { ActionIcon, Button, EmojiPopup, IconMoreV, Label, showPopup, tooltip } from '@hcengineering/ui' @@ -35,7 +35,7 @@ import { AddMessageToSaved, DeleteMessageFromSaved, UnpinMessage } from '../index' import chunter from '../plugin' - import { getLinks, getTime, updateDocReactions } from '../utils' + import { getLinks, updateDocReactions } from '../utils' export let message: WithLookup export let savedAttachmentsIds: Ref[] @@ -188,9 +188,9 @@ {#if employee} {/if} - {getTime(message.createdOn ?? 0)} + {getDisplayTime(message.createdOn ?? 0)} {#if message.editedOn} - + {/if} diff --git a/plugins/chunter-resources/src/components/MessagePresenter.svelte b/plugins/chunter-resources/src/components/MessagePresenter.svelte index ac63fd8ea2..2db794b2ac 100644 --- a/plugins/chunter-resources/src/components/MessagePresenter.svelte +++ b/plugins/chunter-resources/src/components/MessagePresenter.svelte @@ -24,6 +24,7 @@ export let value: Message export let inline: boolean = false + export let embedded = false export let disabled = false const client = getClient() @@ -41,7 +42,7 @@ }) -{#if inline} +{#if inline || embedded} {#if presenter && doc}
{#if isThreadMessage} @@ -53,7 +54,7 @@   {/if} - +
{/if} {:else} diff --git a/plugins/chunter-resources/src/components/MessagePreview.svelte b/plugins/chunter-resources/src/components/MessagePreview.svelte index 286c7c3c5e..df10ee0fa2 100644 --- a/plugins/chunter-resources/src/components/MessagePreview.svelte +++ b/plugins/chunter-resources/src/components/MessagePreview.svelte @@ -19,13 +19,13 @@ import { LinkPresenter } from '@hcengineering/view-resources' import { AttachmentList } from '@hcengineering/attachment-resources' import { getEmbeddedLabel } from '@hcengineering/platform' - import { Ref, WithLookup, getCurrentAccount } from '@hcengineering/core' + import { Ref, WithLookup, getCurrentAccount, getDisplayTime } from '@hcengineering/core' import { Attachment } from '@hcengineering/attachment' import { EmployeePresenter, personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources' import { PersonAccount } from '@hcengineering/contact' import chunter from '../plugin' - import { getLinks, getTime } from '../utils' + import { getLinks } from '../utils' export let value: WithLookup @@ -51,9 +51,9 @@
- {getTime(message.createdOn ?? 0)} + {getDisplayTime(message.createdOn ?? 0)}
{/each}
diff --git a/plugins/chunter-resources/src/components/Reactions.svelte b/plugins/chunter-resources/src/components/Reactions.svelte index 8dbf3f7eae..2e50ae0156 100644 --- a/plugins/chunter-resources/src/components/Reactions.svelte +++ b/plugins/chunter-resources/src/components/Reactions.svelte @@ -13,15 +13,20 @@ // limitations under the License. -->
{#each [...reactionsAccounts] as [emoji, accounts]} -
- - -
{ - dispatch('click', emoji) - }} - > + + +
+
{emoji}
{accounts.length}
{/each} + {#if object && reactionsAccounts.size > 0} + + +
+ +
+ {/if}
diff --git a/plugins/chunter-resources/src/components/ReactionsAction.svelte b/plugins/chunter-resources/src/components/ReactionsAction.svelte index 02cb3d53a7..b40cd175de 100644 --- a/plugins/chunter-resources/src/components/ReactionsAction.svelte +++ b/plugins/chunter-resources/src/components/ReactionsAction.svelte @@ -20,12 +20,15 @@ import chunter from '../plugin' import { updateDocReactions } from '../utils' + import { createEventDispatcher } from 'svelte' export let object: Doc | undefined = undefined const client = getClient() const reactionsQuery = createQuery() + const dispatch = createEventDispatcher() + let reactions: Reaction[] = [] $: if (object) { @@ -35,11 +38,15 @@ } function openEmojiPalette (ev: Event) { + dispatch('open') showPopup( EmojiPopup, {}, ev.target as HTMLElement, - (emoji: string) => updateDocReactions(client, reactions, object, emoji), + (emoji: string) => { + updateDocReactions(client, reactions, object, emoji) + dispatch('close') + }, () => {} ) } diff --git a/plugins/chunter-resources/src/components/CommentReactions.svelte b/plugins/chunter-resources/src/components/ReactionsPresenter.svelte similarity index 93% rename from plugins/chunter-resources/src/components/CommentReactions.svelte rename to plugins/chunter-resources/src/components/ReactionsPresenter.svelte index b53e529c8f..90d0553d76 100644 --- a/plugins/chunter-resources/src/components/CommentReactions.svelte +++ b/plugins/chunter-resources/src/components/ReactionsPresenter.svelte @@ -22,7 +22,7 @@ import { updateDocReactions } from '../utils' import chunter from '../plugin' - export let object: Doc | undefined = undefined + export let object: Doc | undefined const client = getClient() const reactionsQuery = createQuery() @@ -42,6 +42,6 @@ {#if reactions.length} {/if} diff --git a/plugins/chunter-resources/src/components/SavedMessages.svelte b/plugins/chunter-resources/src/components/SavedMessages.svelte index c8cb04e8c6..7b98d456bf 100644 --- a/plugins/chunter-resources/src/components/SavedMessages.svelte +++ b/plugins/chunter-resources/src/components/SavedMessages.svelte @@ -4,11 +4,11 @@ import { ChunterMessage } from '@hcengineering/chunter' import { Person, PersonAccount, getName as getContactName } from '@hcengineering/contact' import { personAccountByIdStore, personByIdStore } from '@hcengineering/contact-resources' - import core, { IdMap, Ref, WithLookup } from '@hcengineering/core' + import core, { getDisplayTime, IdMap, Ref, WithLookup } from '@hcengineering/core' import { createQuery, getClient } from '@hcengineering/presentation' import { Label, Scroller } from '@hcengineering/ui' import chunter from '../plugin' - import { getTime, openMessageFromSpecial } from '../utils' + import { openMessageFromSpecial } from '../utils' import Message from './Message.svelte' import Bookmark from './icons/Bookmark.svelte' @@ -123,7 +123,10 @@
diff --git a/plugins/chunter-resources/src/components/notification/ActivityMessageReactionsAction.svelte b/plugins/chunter-resources/src/components/notification/ActivityMessageReactionsAction.svelte new file mode 100644 index 0000000000..cbff356baa --- /dev/null +++ b/plugins/chunter-resources/src/components/notification/ActivityMessageReactionsAction.svelte @@ -0,0 +1,30 @@ + + + +{#if isVisible} + +{/if} diff --git a/plugins/chunter-resources/src/components/notification/NotificationBacklinkLabel.svelte b/plugins/chunter-resources/src/components/notification/NotificationBacklinkLabel.svelte new file mode 100644 index 0000000000..87a0ee007a --- /dev/null +++ b/plugins/chunter-resources/src/components/notification/NotificationBacklinkLabel.svelte @@ -0,0 +1,91 @@ + + + + + +{#if target} + + + {#if currentAccount.person === target._id} + + +{/if} +{#if doc && value} + + + + +{/if} + + diff --git a/plugins/chunter-resources/src/components/notification/NotificationReactionCreated.svelte b/plugins/chunter-resources/src/components/notification/NotificationReactionCreated.svelte new file mode 100644 index 0000000000..e15e7fe3dd --- /dev/null +++ b/plugins/chunter-resources/src/components/notification/NotificationReactionCreated.svelte @@ -0,0 +1,22 @@ + + + + + {value?.emoji} + diff --git a/plugins/chunter-resources/src/index.ts b/plugins/chunter-resources/src/index.ts index 1a9643b00a..c40e56a525 100644 --- a/plugins/chunter-resources/src/index.ts +++ b/plugins/chunter-resources/src/index.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import { type DisplayTx } from '@hcengineering/activity' +import { writable } from 'svelte/store' import chunter, { type Backlink, type Channel, @@ -21,8 +21,7 @@ import chunter, { type ChunterSpace, type DirectMessage, type Message, - type ThreadMessage, - type Comment + type ThreadMessage } from '@hcengineering/chunter' import core, { type Data, @@ -38,17 +37,14 @@ import { type IntlString, type Resources, translate } from '@hcengineering/platf import preference from '@hcengineering/preference' import { MessageBox, getClient } from '@hcengineering/presentation' import { getLocation, navigate, showPopup } from '@hcengineering/ui' +import notification, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/notification' + import ChannelHeader from './components/ChannelHeader.svelte' import ChannelPresenter from './components/ChannelPresenter.svelte' import ChannelView from './components/ChannelView.svelte' import ChannelViewPanel from './components/ChannelViewPanel.svelte' import ChunterBrowser from './components/ChunterBrowser.svelte' -import CommentInput from './components/CommentInput.svelte' -import CommentPopup from './components/CommentPopup.svelte' -import CommentPresenter from './components/CommentPresenter.svelte' -import CommentsPresenter from './components/CommentsPresenter.svelte' import Reactions from './components/Reactions.svelte' -import CommentPanel from './components/CommentPanel.svelte' import ConvertDmToPrivateChannelModal from './components/ConvertDmToPrivateChannel.svelte' import CreateChannel from './components/CreateChannel.svelte' import CreateDirectMessage from './components/CreateDirectMessage.svelte' @@ -66,22 +62,22 @@ import ThreadView from './components/ThreadView.svelte' import ThreadViewPanel from './components/ThreadViewPanel.svelte' import Thread from './components/Thread.svelte' import Threads from './components/Threads.svelte' -import TxBacklinkCreate from './components/activity/TxBacklinkCreate.svelte' -import TxBacklinkReference from './components/activity/TxBacklinkReference.svelte' +import BacklinkContent from './components/BacklinkContent.svelte' +import BacklinkReference from './components/BacklinkReference.svelte' import TxCommentCreate from './components/activity/TxCommentCreate.svelte' import TxMessageCreate from './components/activity/TxMessageCreate.svelte' import ReactionsAction from './components/ReactionsAction.svelte' -import CommentReactions from './components/CommentReactions.svelte' -import PinComment from './components/PinComment.svelte' +import ReactionsPresenter from './components/ReactionsPresenter.svelte' +import NotificationReactionCreated from './components/notification/NotificationReactionCreated.svelte' +import ActivityMessageReactionsAction from './components/notification/ActivityMessageReactionsAction.svelte' +import NotificationBacklinkLabel from './components/notification/NotificationBacklinkLabel.svelte' -import notification from '@hcengineering/notification' -import { writable } from 'svelte/store' import { updateBacklinksList } from './backlinks' import { getDmName, getLink, getTitle, resolveLocation } from './utils' export { default as Header } from './components/Header.svelte' export { classIcon } from './utils' -export { CommentPopup, CommentsPresenter, Thread } +export { Thread } async function MarkUnread (object: Message): Promise { const client = NotificationClientImpl.getClient() @@ -271,26 +267,18 @@ async function update (source: Doc, key: string, target: RelatedDocument[], msg: await updateBacklinksList(getClient(), q, backlinks) } -export function commentsFilter (tx: DisplayTx, _class?: Ref): boolean { - return tx.tx.objectClass === chunter.class.Comment -} - -export function pinnedCommentsFilter (tx: DisplayTx, _class?: Ref): boolean { - return tx.tx.objectClass === chunter.class.Comment && (tx.doc as Comment)?.pinned === true -} - -export function backlinksFilter (tx: DisplayTx, _class?: Ref): boolean { - return tx.tx.objectClass === chunter.class.Backlink +export function backlinksFilter (message: ActivityMessage, _class?: Ref): boolean { + if (message._class === notification.class.DocUpdateMessage) { + return (message as DocUpdateMessage).objectClass === chunter.class.Backlink + } + return false } export default async (): Promise => ({ filter: { - CommentsFilter: commentsFilter, - PinnedCommentsFilter: pinnedCommentsFilter, BacklinksFilter: backlinksFilter }, component: { - CommentInput, CreateChannel, CreateDirectMessage, ThreadParentPresenter, @@ -298,8 +286,6 @@ export default async (): Promise => ({ ChannelHeader, ChannelView, ChannelViewPanel, - CommentPresenter, - CommentsPresenter, Reactions, ChannelPresenter, DirectMessagePresenter, @@ -315,10 +301,13 @@ export default async (): Promise => ({ Threads, ThreadView, SavedMessages, - CommentPanel, ReactionsAction, - CommentReactions, - PinComment + ReactionsPresenter, + BacklinkContent, + NotificationReactionCreated, + ActivityMessageReactionsAction, + NotificationBacklinkLabel, + BacklinkReference }, function: { GetDmName: getDmName, @@ -328,8 +317,6 @@ export default async (): Promise => ({ }, activity: { TxCommentCreate, - TxBacklinkCreate, - TxBacklinkReference, TxMessageCreate }, actionImpl: { diff --git a/plugins/chunter-resources/src/plugin.ts b/plugins/chunter-resources/src/plugin.ts index b8ced6d9f2..dd003f38e6 100644 --- a/plugins/chunter-resources/src/plugin.ts +++ b/plugins/chunter-resources/src/plugin.ts @@ -32,7 +32,8 @@ export default mergeIds(chunterId, chunter, { ChannelPreview: '' as AnyComponent, MessagePreview: '' as AnyComponent, DirectMessageInput: '' as AnyComponent, - CommentPanel: '' as AnyComponent + NotificationBacklinkLabel: '' as AnyComponent, + NotificationReactionCreated: '' as AnyComponent }, function: { GetDmName: '' as Resource<(client: Client, space: Space) => Promise> @@ -92,6 +93,7 @@ export default mergeIds(chunterId, chunter, { You: '' as IntlString, YouHaveJoinedTheConversation: '' as IntlString, NoMessages: '' as IntlString, - On: '' as IntlString + On: '' as IntlString, + Mentioned: '' as IntlString } }) diff --git a/plugins/chunter-resources/src/utils.ts b/plugins/chunter-resources/src/utils.ts index b742e3ae4a..c04261f534 100644 --- a/plugins/chunter-resources/src/utils.ts +++ b/plugins/chunter-resources/src/utils.ts @@ -29,29 +29,6 @@ import { get, type Unsubscriber, writable } from 'svelte/store' import chunter from './plugin' -export function getTime (time: number): string { - let options: Intl.DateTimeFormatOptions = { hour: 'numeric', minute: 'numeric' } - if (!isToday(time)) { - options = { - month: 'numeric', - day: 'numeric', - ...options - } - } - - return new Date(time).toLocaleString('default', options) -} - -export function isToday (time: number): boolean { - const current = new Date() - const target = new Date(time) - return ( - current.getDate() === target.getDate() && - current.getMonth() === target.getMonth() && - current.getFullYear() === target.getFullYear() - ) -} - export function classIcon (client: Client, _class: Ref>): Asset | undefined { return client.getHierarchy().getClass(_class).icon } diff --git a/plugins/chunter/src/index.ts b/plugins/chunter/src/index.ts index 6ef2ae5828..25072ab750 100644 --- a/plugins/chunter/src/index.ts +++ b/plugins/chunter/src/index.ts @@ -98,6 +98,7 @@ export interface Reaction extends AttachedDoc { /** * @public + * @deprecated use ChatMessage instead */ export interface Comment extends AttachedDoc { message: string @@ -154,12 +155,10 @@ export default plugin(chunterId, { ChannelBrowser: '' as Asset }, component: { - CommentInput: '' as AnyComponent, DmHeader: '' as AnyComponent, ChannelView: '' as AnyComponent, ThreadView: '' as AnyComponent, Thread: '' as AnyComponent, - CommentsPresenter: '' as AnyComponent, Reactions: '' as AnyComponent }, class: { @@ -182,6 +181,7 @@ export default plugin(chunterId, { Backlinks: '' as Ref }, string: { + Reactions: '' as IntlString, EditUpdate: '' as IntlString, EditCancel: '' as IntlString, Comments: '' as IntlString, diff --git a/plugins/contact-assets/lang/en.json b/plugins/contact-assets/lang/en.json index b6aaa74f2f..e079197f50 100644 --- a/plugins/contact-assets/lang/en.json +++ b/plugins/contact-assets/lang/en.json @@ -100,6 +100,7 @@ "HasMessagesIn": "has messages in", "HasNewMessagesIn": "has new messages in", "Employees": "Employees", - "People": "People" + "People": "People", + "For": "For" } } diff --git a/plugins/contact-assets/lang/ru.json b/plugins/contact-assets/lang/ru.json index 50c13ba9e2..977cef2ef7 100644 --- a/plugins/contact-assets/lang/ru.json +++ b/plugins/contact-assets/lang/ru.json @@ -100,6 +100,7 @@ "HasMessagesIn": "имеет сообщения в", "HasNewMessagesIn": "имеет новые сообщения в", "Employees": "Сотрудники", - "People": "Люди" + "People": "Люди", + "For": "Для" } } diff --git a/plugins/contact-resources/src/components/Avatar.svelte b/plugins/contact-resources/src/components/Avatar.svelte index 05a3c7f0d9..2d99972f92 100644 --- a/plugins/contact-resources/src/components/Avatar.svelte +++ b/plugins/contact-resources/src/components/Avatar.svelte @@ -48,6 +48,7 @@ export let direct: Blob | undefined = undefined export let size: IconSize export let icon: Asset | AnySvelteComponent | undefined = undefined + export let variant: 'circle' | 'roundedRect' = 'circle' let url: string[] | undefined let avatarProvider: AvatarProvider | undefined @@ -94,7 +95,7 @@
+ + +
+
+ {workspace?.toUpperCase()?.[0]} +
+
+ + diff --git a/plugins/contact-resources/src/components/activity/ActivityChannelMessage.svelte b/plugins/contact-resources/src/components/activity/ActivityChannelMessage.svelte deleted file mode 100644 index 9b1d8c3010..0000000000 --- a/plugins/contact-resources/src/components/activity/ActivityChannelMessage.svelte +++ /dev/null @@ -1,74 +0,0 @@ - - diff --git a/plugins/contact-resources/src/components/notification/NotificationNameChanged.svelte b/plugins/contact-resources/src/components/notification/NotificationNameChanged.svelte new file mode 100644 index 0000000000..351d71d5a1 --- /dev/null +++ b/plugins/contact-resources/src/components/notification/NotificationNameChanged.svelte @@ -0,0 +1,37 @@ + + + +{#if typeof personName === 'string'} + + + +