diff --git a/models/activity/src/index.ts b/models/activity/src/index.ts index a99855115f..dd3bd0adb3 100644 --- a/models/activity/src/index.ts +++ b/models/activity/src/index.ts @@ -32,7 +32,8 @@ import { type TxViewlet, type ActivityMessageControl, type SavedMessage, - type IgnoreActivity + type IgnoreActivity, + type ActivityReference } from '@hcengineering/activity' import core, { DOMAIN_MODEL, @@ -60,7 +61,8 @@ import { TypeIntlString, ArrOf, TypeTimestamp, - UX + UX, + TypeMarkup } from '@hcengineering/model' import { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core' import type { Asset, IntlString, Resource } from '@hcengineering/platform' @@ -146,6 +148,26 @@ export class TDocUpdateMessage extends TActivityMessage implements DocUpdateMess attributeUpdates?: DocAttributeUpdates } +@Model(activity.class.ActivityReference, activity.class.ActivityMessage) +export class TActivityReference extends TActivityMessage implements ActivityReference { + // Source document we have reference from, it should be parent document for Comment/Message. + @Prop(TypeRef(core.class.Doc), core.string.Object) + @Index(IndexKind.Indexed) + srcDocId!: Ref + + @Prop(TypeRef(core.class.Class), core.string.Class) + @Index(IndexKind.Indexed) + srcDocClass!: Ref> + + // Reference to comment/message in source doc + attachedDocId?: Ref + attachedDocClass?: Ref> + + @Prop(TypeMarkup(), activity.string.Message) + @Index(IndexKind.FullText) + message!: string +} + @Model(activity.class.ActivityInfoMessage, activity.class.ActivityMessage) export class TActivityInfoMessage extends TActivityMessage implements ActivityInfoMessage { @Prop(TypeIntlString(), activity.string.Update) @@ -251,7 +273,8 @@ export function createModel (builder: Builder): void { TActivityInfoMessage, TActivityMessageControl, TSavedMessage, - TIgnoreActivity + TIgnoreActivity, + TActivityReference ) builder.mixin(activity.class.DocUpdateMessage, core.class.Class, view.mixin.ObjectPresenter, { @@ -262,6 +285,10 @@ export function createModel (builder: Builder): void { presenter: activity.component.ActivityInfoMessagePresenter }) + builder.mixin(activity.class.ActivityReference, core.class.Class, view.mixin.ObjectPresenter, { + presenter: activity.component.ActivityReferencePresenter + }) + builder.mixin(activity.class.DocUpdateMessage, core.class.Class, view.mixin.LinkProvider, { encode: activity.function.GetFragment }) @@ -289,6 +316,12 @@ export function createModel (builder: Builder): void { filter: activity.filter.PinnedFilter }) + builder.createDoc(activity.class.ActivityMessagesFilter, core.space.Model, { + label: activity.string.Mentions, + position: 60, + filter: activity.filter.ReferencesFilter + }) + builder.createDoc( activity.class.DocUpdateMessageViewlet, core.space.Model, @@ -297,23 +330,11 @@ export function createModel (builder: Builder): void { action: 'create', component: activity.component.ReactionPresenter, label: activity.string.Reacted, - onlyWithParent: true, - hideIfRemoved: true + onlyWithParent: true }, activity.ids.ReactionAddedActivityViewlet ) - builder.createDoc( - activity.class.DocUpdateMessageViewlet, - core.space.Model, - { - objectClass: activity.class.Reaction, - action: 'remove', - hideIfRemoved: true - }, - activity.ids.ReactionRemovedActivityViewlet - ) - builder.mixin(activity.class.ActivityMessage, core.class.Class, notification.mixin.ClassCollaborators, { fields: ['createdBy', 'repliedPersons'] }) @@ -330,6 +351,14 @@ export function createModel (builder: Builder): void { labelPresenter: activity.component.ActivityMessageNotificationLabel }) + builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, { + messageMatch: { + _class: activity.class.DocUpdateMessage, + objectClass: activity.class.Reaction + }, + presenter: activity.component.ReactionNotificationPresenter + }) + builder.createDoc( notification.class.NotificationType, core.space.Model, @@ -346,14 +375,6 @@ export function createModel (builder: Builder): void { }, activity.ids.AddReactionNotification ) - - builder.createDoc(notification.class.ActivityNotificationViewlet, core.space.Model, { - messageMatch: { - _class: activity.class.DocUpdateMessage, - objectClass: activity.class.Reaction - }, - presenter: activity.component.ReactionNotificationPresenter - }) } export default activity diff --git a/models/activity/src/plugin.ts b/models/activity/src/plugin.ts index 9fa2ccf565..ee62147376 100644 --- a/models/activity/src/plugin.ts +++ b/models/activity/src/plugin.ts @@ -30,11 +30,11 @@ export default mergeIds(activityId, activity, { filter: { AttributesFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean>, PinnedFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean>, - AllFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> + AllFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean>, + ReferencesFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> }, ids: { ReactionAddedActivityViewlet: '' as Ref, - ReactionRemovedActivityViewlet: '' as Ref, ActivityNotificationGroup: '' as Ref, AddReactionNotification: '' as Ref }, diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index f8445f6048..5ca551d9e3 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -15,12 +15,10 @@ import activity, { type ActivityMessage } from '@hcengineering/activity' import { - type Backlink, type Channel, chunterId, type ChunterMessage, type ChunterMessageExtension, - type Comment, type DirectMessage, type Message, type DirectMessageInput, @@ -63,17 +61,16 @@ import core, { TAttachedDoc, TClass, TDoc, TSpace } from '@hcengineering/model-c import notification from '@hcengineering/model-notification' import view, { createAction, actionTemplates as viewTemplates } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' -import chunter from './plugin' import { type AnyComponent } from '@hcengineering/ui/src/types' -import { TypeBoolean } from '@hcengineering/model' import type { IntlString, Resource } from '@hcengineering/platform' import { TActivityMessage } from '@hcengineering/model-activity' +import chunter from './plugin' + export { chunterId } from '@hcengineering/chunter' export { chunterOperation } from './migration' export const DOMAIN_CHUNTER = 'chunter' as Domain -export const DOMAIN_COMMENT = 'comment' as Domain @Model(chunter.class.ChunterSpace, core.class.Space) export class TChunterSpace extends TSpace implements ChunterSpace { @@ -135,30 +132,6 @@ export class TMessage extends TChunterMessage implements Message { lastReply?: Timestamp } -@Model(chunter.class.Comment, core.class.AttachedDoc, DOMAIN_COMMENT) -@UX(chunter.string.Comment, undefined, 'COM') -export class TComment extends TAttachedDoc implements Comment { - @Prop(TypeMarkup(), chunter.string.Message) - @Index(IndexKind.FullText) - message!: string - - @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) - attachments?: number - - @Prop(Collection(activity.class.Reaction), activity.string.Reactions) - reactions?: number - - @Prop(TypeBoolean(), chunter.string.PinMessage) - pinned?: boolean -} - -@Model(chunter.class.Backlink, chunter.class.Comment) -@UX(chunter.string.Reference, chunter.icon.Chunter) -export class TBacklink extends TComment implements Backlink { - backlinkId!: Ref - backlinkClass!: Ref> -} - @Mixin(chunter.mixin.DirectMessageInput, core.class.Class) export class TDirectMessageInput extends TClass implements DirectMessageInput { component!: AnyComponent @@ -227,8 +200,6 @@ export function createModel (builder: Builder, options = { addApplication: true TMessage, TChunterMessage, TChunterMessageExtension, - TComment, - TBacklink, TDirectMessage, TDirectMessageInput, TChatMessage, @@ -442,12 +413,6 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.action.CopyChatMessageLink ) - builder.createDoc(activity.class.ActivityMessagesFilter, core.space.Model, { - label: chunter.string.FilterBacklinks, - position: 60, - filter: chunter.filter.BacklinksFilter - }) - builder.mixin(chunter.class.ChunterMessage, core.class.Class, view.mixin.ClassFilters, { filters: ['space', '_class'] }) @@ -466,29 +431,6 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.ChunterNotificationGroup ) - builder.createDoc( - notification.class.NotificationType, - core.space.Model, - { - label: chunter.string.MentionNotification, - generated: false, - hidden: false, - txClasses: [core.class.TxCreateDoc], - objectClass: chunter.class.Backlink, - group: chunter.ids.ChunterNotificationGroup, - providers: { - [notification.providers.EmailNotification]: true, - [notification.providers.PlatformNotification]: true - }, - templates: { - textTemplate: '{sender} mentioned you in {doc} {data}', - htmlTemplate: '

{sender} mentioned you in {doc}

{data}', - subjectTemplate: 'You were mentioned in {doc}' - } - }, - chunter.ids.MentionNotification - ) - builder.createDoc( notification.class.NotificationType, core.space.Model, @@ -546,43 +488,6 @@ export function createModel (builder: Builder, options = { addApplication: true chunter.ids.ThreadNotification ) - builder.createDoc( - activity.class.DocUpdateMessageViewlet, - core.space.Model, - { - objectClass: chunter.class.Backlink, - action: 'create', - component: chunter.component.BacklinkContent, - labelComponent: chunter.activity.BacklinkCreatedLabel, - hideIfRemoved: true - }, - chunter.ids.BacklinkCreatedActivityViewlet - ) - - builder.createDoc( - activity.class.DocUpdateMessageViewlet, - core.space.Model, - { - objectClass: chunter.class.Backlink, - action: 'update', - component: chunter.component.BacklinkContent, - labelComponent: chunter.activity.BacklinkCreatedLabel, - hideIfRemoved: true - }, - chunter.ids.BacklinkUpdateActivityViewlet - ) - - builder.createDoc( - activity.class.DocUpdateMessageViewlet, - core.space.Model, - { - objectClass: chunter.class.Backlink, - action: 'remove', - hideIfRemoved: true - }, - chunter.ids.BacklinkRemovedActivityViewlet - ) - createAction(builder, { ...viewTemplates.open, target: chunter.class.Channel, @@ -679,6 +584,11 @@ export function createModel (builder: Builder, options = { addApplication: true components: { input: chunter.component.ChatMessageInput } }) + builder.createDoc(activity.class.ActivityExtension, core.space.Model, { + ofClass: activity.class.ActivityReference, + components: { input: chunter.component.ChatMessageInput } + }) + builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { ofMessage: chunter.class.ChatMessage, components: [{ kind: 'footer', component: chunter.component.Replies }] @@ -694,6 +604,11 @@ export function createModel (builder: Builder, options = { addApplication: true components: [{ kind: 'footer', component: chunter.component.Replies }] }) + builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { + ofMessage: activity.class.ActivityReference, + components: [{ kind: 'footer', component: chunter.component.Replies }] + }) + builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { ofMessage: chunter.class.ChatMessage, components: [{ kind: 'action', component: chunter.component.ReplyToThreadAction }] @@ -709,6 +624,11 @@ export function createModel (builder: Builder, options = { addApplication: true components: [{ kind: 'action', component: chunter.component.ReplyToThreadAction }] }) + builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { + ofMessage: activity.class.ActivityReference, + components: [{ kind: 'action', component: chunter.component.ReplyToThreadAction }] + }) + builder.mixin(chunter.class.Channel, core.class.Class, chunter.mixin.ObjectChatPanel, { ignoreKeys: ['archived', 'collaborators', 'lastMessage', 'pinned', 'topic', 'description'] }) diff --git a/models/chunter/src/migration.ts b/models/chunter/src/migration.ts index ee2a1593ad..63802c1752 100644 --- a/models/chunter/src/migration.ts +++ b/models/chunter/src/migration.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import core, { type Class, type Doc, type Ref, TxOperations } from '@hcengineering/core' +import core, { type Class, type Doc, type Domain, type Ref, TxOperations } from '@hcengineering/core' import { type MigrateOperation, type MigrationClient, @@ -21,12 +21,13 @@ import { tryMigrate } from '@hcengineering/model' import { chunterId } from '@hcengineering/chunter' -import { DOMAIN_ACTIVITY } from '@hcengineering/model-activity' +import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity' import notification from '@hcengineering/notification' -import { DOMAIN_COMMENT } from './index' import chunter from './plugin' +const DOMAIN_COMMENT = 'comment' as Domain + export async function createDocNotifyContexts ( client: MigrationUpgradeClient, tx: TxOperations, @@ -103,29 +104,21 @@ export async function createRandom (client: MigrationUpgradeClient, tx: TxOperat await createDocNotifyContexts(client, tx, chunter.space.Random, chunter.class.Channel) } -async function createBacklink (tx: TxOperations): Promise { - const current = await tx.findOne(core.class.Space, { - _id: chunter.space.Backlinks - }) - if (current === undefined) { - await tx.createDoc( - core.class.Space, - core.space.Space, - { - name: 'Backlinks', - description: 'Backlinks', - private: false, - archived: false, - members: [] - }, - chunter.space.Backlinks - ) - } +async function convertCommentsToChatMessages (client: MigrationClient): Promise { + await client.update( + DOMAIN_COMMENT, + { _class: 'chunter:class:Comment' as Ref> }, + { _class: chunter.class.ChatMessage } + ) + await client.move(DOMAIN_COMMENT, { _class: chunter.class.ChatMessage }, DOMAIN_ACTIVITY) } -async function convertCommentsToChatMessages (client: MigrationClient): Promise { - await client.update(DOMAIN_COMMENT, { _class: chunter.class.Comment }, { _class: chunter.class.ChatMessage }) - await client.move(DOMAIN_COMMENT, { _class: chunter.class.ChatMessage }, DOMAIN_ACTIVITY) +async function removeBacklinks (client: MigrationClient): Promise { + await client.deleteMany(DOMAIN_COMMENT, { _class: 'chunter:class:Backlink' as Ref> }) + await client.deleteMany(DOMAIN_ACTIVITY, { + _class: activity.class.DocUpdateMessage, + objectClass: 'chunter:class:Backlink' as Ref> + }) } export const chunterOperation: MigrateOperation = { @@ -136,11 +129,16 @@ export const chunterOperation: MigrateOperation = { func: convertCommentsToChatMessages } ]) + await tryMigrate(client, chunterId, [ + { + state: 'remove-backlinks', + func: removeBacklinks + } + ]) }, async upgrade (client: MigrationUpgradeClient): Promise { const tx = new TxOperations(client, core.account.System) await createGeneral(client, tx) await createRandom(client, tx) - await createBacklink(tx) } } diff --git a/models/chunter/src/plugin.ts b/models/chunter/src/plugin.ts index 7192212621..a3744fd9c5 100644 --- a/models/chunter/src/plugin.ts +++ b/models/chunter/src/plugin.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import type { ActivityMessage, DocUpdateMessageViewlet, TxViewlet } from '@hcengineering/activity' +import type { ActivityMessage, TxViewlet } from '@hcengineering/activity' import { chunterId, type Channel } from '@hcengineering/chunter' import chunter from '@hcengineering/chunter-resources/src/plugin' import { type Client, type Doc, type Ref } from '@hcengineering/core' @@ -29,8 +29,6 @@ export default mergeIds(chunterId, chunter, { DirectMessagePresenter: '' as AnyComponent, MessagePresenter: '' as AnyComponent, DmPresenter: '' as AnyComponent, - BacklinkContent: '' as AnyComponent, - BacklinkReference: '' as AnyComponent, ChannelsPanel: '' as AnyComponent, Chat: '' as AnyComponent, ChatMessageNotificationLabel: '' as AnyComponent, @@ -68,7 +66,6 @@ export default mergeIds(chunterId, chunter, { PinnedMessages: '' as IntlString, SavedMessages: '' as IntlString, Emoji: '' as IntlString, - FilterBacklinks: '' as IntlString, DM: '' as IntlString, DMNotification: '' as IntlString, ConfigLabel: '' as IntlString, @@ -81,21 +78,15 @@ export default mergeIds(chunterId, chunter, { }, ids: { TxCommentCreate: '' as Ref, - TxBacklinkCreate: '' as Ref, TxCommentRemove: '' as Ref, - TxBacklinkRemove: '' as Ref, TxMessageCreate: '' as Ref, TxChatMessageCreate: '' as Ref, TxChatMessageRemove: '' as Ref, - ChunterNotificationGroup: '' as Ref, - BacklinkCreatedActivityViewlet: '' as Ref, - BacklinkUpdateActivityViewlet: '' as Ref, - BacklinkRemovedActivityViewlet: '' as Ref + ChunterNotificationGroup: '' as Ref }, activity: { TxCommentCreate: '' as AnyComponent, - TxMessageCreate: '' as AnyComponent, - BacklinkCreatedLabel: '' as AnyComponent + TxMessageCreate: '' as AnyComponent }, space: { General: '' as Ref, @@ -111,7 +102,6 @@ export default mergeIds(chunterId, chunter, { GetThreadLink: '' as Resource<(doc: Doc, props: Record) => Promise> }, filter: { - BacklinksFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean>, ChatMessagesFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> } }) diff --git a/models/contact/package.json b/models/contact/package.json index 27ee1e2de8..6f906b6075 100644 --- a/models/contact/package.json +++ b/models/contact/package.json @@ -35,6 +35,7 @@ "@hcengineering/contact-resources": "^0.6.0", "@hcengineering/core": "^0.6.28", "@hcengineering/model": "^0.6.7", + "@hcengineering/model-activity": "^0.6.0", "@hcengineering/model-attachment": "^0.6.0", "@hcengineering/model-chunter": "^0.6.0", "@hcengineering/model-core": "^0.6.0", diff --git a/models/contact/src/migration.ts b/models/contact/src/migration.ts index 2fc82e2de6..0ae8950c0d 100644 --- a/models/contact/src/migration.ts +++ b/models/contact/src/migration.ts @@ -8,9 +8,10 @@ import { type ModelLogger, tryMigrate } from '@hcengineering/model' -import { DOMAIN_COMMENT } from '@hcengineering/model-chunter' import core from '@hcengineering/model-core' import { DOMAIN_VIEW } from '@hcengineering/model-view' +import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity' + import contact, { DOMAIN_CONTACT, contactId } from './index' async function createSpace (tx: TxOperations): Promise { @@ -111,20 +112,20 @@ export const contactOperation: MigrateOperation = { await client.update( DOMAIN_TX, { - 'tx.attributes.backlinkClass': 'contact:class:Employee' + 'tx.attributes.srcDocClass': 'contact:class:Employee' }, { - $set: { 'tx.attributes.backlinkClass': contact.mixin.Employee } + $set: { 'tx.attributes.srcDocClass': contact.mixin.Employee } } ) await client.update( DOMAIN_TX, { - 'tx.attributes.backlinkClass': 'contact:class:Employee' + 'tx.attributes.srcDocClass': 'contact:class:Employee' }, { - $set: { 'tx.attributes.backlinkClass': contact.mixin.Employee } + $set: { 'tx.attributes.srcDocClass': contact.mixin.Employee } } ) @@ -167,9 +168,12 @@ export const contactOperation: MigrateOperation = { ) } await client.update( - DOMAIN_COMMENT, - { backlinkClass: 'contact:class:Employee' }, - { $set: { backlinkClass: contact.mixin.Employee } } + DOMAIN_ACTIVITY, + { + _class: activity.class.ActivityReference, + srcDocClass: 'contact:class:Employee' + }, + { $set: { srcDocClass: contact.mixin.Employee } } ) await client.update( 'tags' as Domain, diff --git a/models/document/src/index.ts b/models/document/src/index.ts index 12c2bd5d79..4192a0a959 100644 --- a/models/document/src/index.ts +++ b/models/document/src/index.ts @@ -99,15 +99,15 @@ export class TDocument extends TAttachedDoc implements Document { @Prop(Collection(attachment.class.Attachment), attachment.string.Attachments, { shortLabel: attachment.string.Files }) attachments?: number - @Prop(Collection(chunter.class.Comment), chunter.string.Comments) + @Prop(Collection(chunter.class.ChatMessage), chunter.string.Comments) comments?: number @Prop(Collection(tags.class.TagReference), document.string.Labels) labels?: number - @Prop(Collection(chunter.class.Backlink), document.string.Backlinks) + @Prop(Collection(activity.class.ActivityReference), document.string.Backlinks) @Hidden() - backlinks!: number + references!: number @Prop(TypeString(), document.string.Icon) @Hidden() diff --git a/models/notification/src/index.ts b/models/notification/src/index.ts index eeedda3428..ae159e30b7 100644 --- a/models/notification/src/index.ts +++ b/models/notification/src/index.ts @@ -71,7 +71,9 @@ import { type ActivityInboxNotification, type CommonInboxNotification, type NotificationContextPresenter, - type ActivityNotificationViewlet + type ActivityNotificationViewlet, + type BaseNotificationType, + type CommonNotificationType } from '@hcengineering/notification' import { type Asset, type IntlString } from '@hcengineering/platform' import setting from '@hcengineering/setting' @@ -99,19 +101,26 @@ export class TNotification extends TAttachedDoc implements Notification { type!: Ref } -@Model(notification.class.NotificationType, core.class.Doc, DOMAIN_MODEL) -export class TNotificationType extends TDoc implements NotificationType { +@Model(notification.class.BaseNotificationType, core.class.Doc, DOMAIN_MODEL) +export class TBaseNotificationType extends TDoc implements BaseNotificationType { generated!: boolean label!: IntlString group!: Ref - txClasses!: Ref>[] providers!: Record, boolean> - objectClass!: Ref> hidden!: boolean templates?: NotificationTemplate +} + +@Model(notification.class.NotificationType, notification.class.BaseNotificationType) +export class TNotificationType extends TBaseNotificationType implements NotificationType { + txClasses!: Ref>[] + objectClass!: Ref> onlyOwn?: boolean } +@Model(notification.class.CommonNotificationType, notification.class.BaseNotificationType) +export class TCommonNotificationType extends TBaseNotificationType implements CommonNotificationType {} + @Model(notification.class.NotificationGroup, core.class.Doc, DOMAIN_MODEL) export class TNotificationGroup extends TDoc implements NotificationGroup { label!: IntlString @@ -136,7 +145,7 @@ export class TNotificationProvider extends TDoc implements NotificationProvider @Model(notification.class.NotificationSetting, preference.class.Preference) export class TNotificationSetting extends TPreference implements NotificationSetting { declare attachedTo: Ref - type!: Ref + type!: Ref enabled!: boolean } @@ -245,13 +254,18 @@ export class TActivityInboxNotification extends TInboxNotification implements Ac @Model(notification.class.CommonInboxNotification, notification.class.InboxNotification) export class TCommonInboxNotification extends TInboxNotification implements CommonInboxNotification { - header?: IntlString - @Prop(TypeIntlString(), notification.string.Message) - message!: IntlString + @Prop(TypeIntlString(), core.string.String) + header?: IntlString - props!: Record - icon!: Asset - iconProps!: Record + @Prop(TypeIntlString(), notification.string.Message) + message?: IntlString + + @Prop(TypeString(), notification.string.Message) + messageHtml?: string + + props?: Record + icon?: Asset + iconProps?: Record } @Model(notification.class.ActivityNotificationViewlet, core.class.Doc, DOMAIN_MODEL) @@ -279,7 +293,9 @@ export function createModel (builder: Builder): void { TActivityInboxNotification, TCommonInboxNotification, TNotificationContextPresenter, - TActivityNotificationViewlet + TActivityNotificationViewlet, + TBaseNotificationType, + TCommonNotificationType ) // Temporarily disabled, we should think about it @@ -599,6 +615,27 @@ export function createModel (builder: Builder): void { }) defineViewlets(builder) + + builder.createDoc( + notification.class.CommonNotificationType, + core.space.Model, + { + label: activity.string.Mentions, + generated: false, + hidden: false, + group: notification.ids.NotificationGroup, + providers: { + [notification.providers.EmailNotification]: true, + [notification.providers.PlatformNotification]: true + }, + templates: { + textTemplate: '{sender} mentioned you in {doc} {data}', + htmlTemplate: '

{sender} mentioned you in {doc}

{data}', + subjectTemplate: 'You were mentioned in {doc}' + } + }, + notification.ids.MentionCommonNotificationType + ) } export function generateClassNotificationTypes ( diff --git a/models/request/src/index.ts b/models/request/src/index.ts index 9587756d6b..ab92752541 100644 --- a/models/request/src/index.ts +++ b/models/request/src/index.ts @@ -30,7 +30,7 @@ import { TypeString, UX } from '@hcengineering/model' -import chunter, { TComment } from '@hcengineering/model-chunter' +import chunter, { TChatMessage } from '@hcengineering/model-chunter' import core, { TAttachedDoc, TClass } from '@hcengineering/model-core' import { generateClassNotificationTypes } from '@hcengineering/model-notification' import view from '@hcengineering/model-view' @@ -77,7 +77,7 @@ export class TRequest extends TAttachedDoc implements Request { } @Mixin(request.mixin.RequestDecisionComment, chunter.class.ChatMessage) -export class TRequestDecisionComment extends TComment implements RequestDecisionComment {} +export class TRequestDecisionComment extends TChatMessage implements RequestDecisionComment {} @Mixin(request.mixin.RequestPresenter, core.class.Class) export class TRequestPresenter extends TClass implements RequestPresenter { diff --git a/models/server-activity/package.json b/models/server-activity/package.json index fc63a55e93..b4bcb38010 100644 --- a/models/server-activity/package.json +++ b/models/server-activity/package.json @@ -36,6 +36,8 @@ "@hcengineering/platform": "^0.6.9", "@hcengineering/server-activity": "^0.6.0", "@hcengineering/server-activity-resources": "^0.6.0", - "@hcengineering/server-core": "^0.6.1" + "@hcengineering/server-core": "^0.6.1", + "@hcengineering/notification": "^0.6.16", + "@hcengineering/server-notification": "^0.6.1" } } diff --git a/models/server-activity/src/index.ts b/models/server-activity/src/index.ts index 86697ebe89..9857a24c58 100644 --- a/models/server-activity/src/index.ts +++ b/models/server-activity/src/index.ts @@ -37,4 +37,8 @@ export function createModel (builder: Builder): void { builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverActivity.trigger.OnDocRemoved }) + + builder.createDoc(serverCore.class.Trigger, core.space.Model, { + trigger: serverActivity.trigger.ReferenceTrigger + }) } diff --git a/models/server-chunter/package.json b/models/server-chunter/package.json index b6c7daa62e..321461bab5 100644 --- a/models/server-chunter/package.json +++ b/models/server-chunter/package.json @@ -36,6 +36,7 @@ "@hcengineering/server-core": "^0.6.1", "@hcengineering/chunter": "^0.6.12", "@hcengineering/notification": "^0.6.16", - "@hcengineering/server-notification": "^0.6.1" + "@hcengineering/server-notification": "^0.6.1", + "@hcengineering/activity": "^0.6.0" } } diff --git a/models/server-chunter/src/index.ts b/models/server-chunter/src/index.ts index a4a889629a..508cd3d24a 100644 --- a/models/server-chunter/src/index.ts +++ b/models/server-chunter/src/index.ts @@ -50,10 +50,6 @@ export function createModel (builder: Builder): void { presenter: serverChunter.function.ChunterNotificationContentProvider }) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverChunter.trigger.BacklinkTrigger - }) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverChunter.trigger.ChunterTrigger }) @@ -86,15 +82,6 @@ export function createModel (builder: Builder): void { } }) - builder.mixin( - chunter.ids.MentionNotification, - notification.class.NotificationType, - serverNotification.mixin.TypeMatch, - { - func: serverChunter.function.IsMeMentioned - } - ) - builder.mixin(chunter.ids.DMNotification, notification.class.NotificationType, serverNotification.mixin.TypeMatch, { func: serverChunter.function.IsDirectMessage }) diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index dc62f67dd7..f3864cf94e 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -76,14 +76,6 @@ export function createModel (builder: Builder): void { } }) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.OnBacklinkCreate, - txMatch: { - _class: core.class.TxCollectionCUD, - 'tx._class': core.class.TxCreateDoc - } - }) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverNotification.trigger.OnAttributeCreate, txMatch: { @@ -99,4 +91,8 @@ export function createModel (builder: Builder): void { _class: core.class.TxUpdateDoc } }) + + builder.createDoc(serverCore.class.Trigger, core.space.Model, { + trigger: serverNotification.trigger.OnDocRemove + }) } diff --git a/plugins/activity-assets/lang/en.json b/plugins/activity-assets/lang/en.json index 9ae5b17841..17d76f910f 100644 --- a/plugins/activity-assets/lang/en.json +++ b/plugins/activity-assets/lang/en.json @@ -33,6 +33,10 @@ "Update": "Update", "Updated": "Updated", "UpdatedCollection": "Updated", - "Message": "Message" + "Message": "Message", + "Mentioned": "Mentioned", + "You": "You", + "Mentions": "Mentions", + "MentionedYouIn": "Mentioned you in" } } \ No newline at end of file diff --git a/plugins/activity-assets/lang/ru.json b/plugins/activity-assets/lang/ru.json index 27eacbb63a..3141df940f 100644 --- a/plugins/activity-assets/lang/ru.json +++ b/plugins/activity-assets/lang/ru.json @@ -33,6 +33,10 @@ "Update": "Обновить", "Updated": "Обновил(а)", "UpdatedCollection": "Обновленные", - "Message": "Сообщение" + "Message": "Сообщение", + "Mentioned": "Упомянул(а)", + "You": "Вы", + "Mentions": "Упоминания", + "MentionedYouIn": "Упомянул(а) вас в" } } \ No newline at end of file diff --git a/plugins/activity-resources/src/activity.ts b/plugins/activity-resources/src/activity.ts index d16f74f573..441f27cbee 100644 --- a/plugins/activity-resources/src/activity.ts +++ b/plugins/activity-resources/src/activity.ts @@ -75,3 +75,5 @@ export function loadSavedMessages (): void { }, 50) } } + +loadSavedMessages() diff --git a/plugins/activity-resources/src/activityMessagesUtils.ts b/plugins/activity-resources/src/activityMessagesUtils.ts index 104c2df386..7f2a96d580 100644 --- a/plugins/activity-resources/src/activityMessagesUtils.ts +++ b/plugins/activity-resources/src/activityMessagesUtils.ts @@ -227,9 +227,7 @@ export async function combineActivityMessages ( const client = getClient() const uncombinedMessages = messages.filter((message) => message._class !== activity.class.DocUpdateMessage) - const docUpdateMessages = combineByCreateThreshold( - messages.filter((message): message is DocUpdateMessage => message._class === activity.class.DocUpdateMessage) - ) + const docUpdateMessages = combineByCreateThreshold(messages.filter(isDocUpdateMessage)) if (docUpdateMessages.length === 0) { return sortActivityMessages(uncombinedMessages, sortingOrder) @@ -472,6 +470,10 @@ function getAttributeUpdatesKey (message: DocUpdateMessage): string { return [attrKey, attrClass, isMixin].join('-') } +export function referencesFilter (message: ActivityMessage, _class?: Ref): boolean { + return message._class === activity.class.ActivityReference +} + export function attributesFilter (message: ActivityMessage, _class?: Ref): boolean { if (message._class === activity.class.DocUpdateMessage) { return (message as DocUpdateMessage).objectClass === _class @@ -548,14 +550,22 @@ export async function getMessageFragment (doc: Doc): Promise { return `${label}-${doc._id}` } -export function isReactionMessage (message?: ActivityMessage): message is DocUpdateMessage { +function isDocUpdateMessage (message?: ActivityMessage): message is DocUpdateMessage { if (message === undefined) { return false } - if (message._class !== activity.class.DocUpdateMessage) { + return message._class === activity.class.DocUpdateMessage +} + +export function isReactionMessage (message?: ActivityMessage): boolean { + if (message === undefined) { return false } - return (message as DocUpdateMessage).objectClass === activity.class.Reaction + if (!isDocUpdateMessage(message)) { + return false + } + + return message.objectClass === activity.class.Reaction } diff --git a/plugins/activity-resources/src/components/Activity.svelte b/plugins/activity-resources/src/components/Activity.svelte index 67594db7fd..26297155fe 100644 --- a/plugins/activity-resources/src/components/Activity.svelte +++ b/plugins/activity-resources/src/components/Activity.svelte @@ -22,7 +22,6 @@ import ActivityExtensionComponent from './ActivityExtension.svelte' import ActivityFilter from './ActivityFilter.svelte' import { combineActivityMessages } from '../activityMessagesUtils' - import { loadSavedMessages } from '../activity' export let object: Doc export let showCommenInput: boolean = true @@ -50,9 +49,9 @@ const res = activityMessagesQuery.query( activity.class.ActivityMessage, - { attachedTo: objectId }, + { attachedTo: objectId, hidden: { $ne: true } }, (result: ActivityMessage[]) => { - combineActivityMessages(result, order).then((messages) => { + void combineActivityMessages(result, order).then((messages) => { activityMessages = messages isLoading = false }) @@ -69,10 +68,6 @@ } $: void updateActivityMessages(object._id, isNewestFirst ? SortingOrder.Descending : SortingOrder.Ascending) - - onMount(() => { - loadSavedMessages() - })
diff --git a/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte b/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte new file mode 100644 index 0000000000..be4577f599 --- /dev/null +++ b/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte @@ -0,0 +1,156 @@ + + + + + + + + + {#if targetDoc} + + + {#if currentAccount.person === targetDoc._id} + + + {/if} + {#if srcDoc} + + + + + + + {/if} + + + + + + + + diff --git a/plugins/chunter-resources/src/components/BacklinkContent.svelte b/plugins/activity-resources/src/components/activity-reference/ReferenceContent.svelte similarity index 68% rename from plugins/chunter-resources/src/components/BacklinkContent.svelte rename to plugins/activity-resources/src/components/activity-reference/ReferenceContent.svelte index 10d1431202..dc3dae0d68 100644 --- a/plugins/chunter-resources/src/components/BacklinkContent.svelte +++ b/plugins/activity-resources/src/components/activity-reference/ReferenceContent.svelte @@ -1,5 +1,5 @@ {#if value} diff --git a/plugins/chunter-resources/src/components/BacklinkReference.svelte b/plugins/activity-resources/src/components/activity-reference/ReferenceSrcPresenter.svelte similarity index 64% rename from plugins/chunter-resources/src/components/BacklinkReference.svelte rename to plugins/activity-resources/src/components/activity-reference/ReferenceSrcPresenter.svelte index 55bd4c8066..1f99b0a4e1 100644 --- a/plugins/chunter-resources/src/components/BacklinkReference.svelte +++ b/plugins/activity-resources/src/components/activity-reference/ReferenceSrcPresenter.svelte @@ -1,5 +1,5 @@ {#if presenter} - + {/if} diff --git a/plugins/activity-resources/src/index.ts b/plugins/activity-resources/src/index.ts index cad101800b..03c13fed51 100644 --- a/plugins/activity-resources/src/index.ts +++ b/plugins/activity-resources/src/index.ts @@ -22,12 +22,21 @@ import ActivityInfoMessagePresenter from './components/activity-message/Activity import ReactionPresenter from './components/reactions/ReactionPresenter.svelte' import ReactionNotificationPresenter from './components/reactions/ReactionNotificationPresenter.svelte' import ActivityMessageNotificationLabel from './components/activity-message/ActivityMessageNotificationLabel.svelte' +import ActivityReferencePresenter from './components/activity-reference/ActivityReferencePresenter.svelte' -import { getMessageFragment, attributesFilter, pinnedFilter, allFilter } from './activityMessagesUtils' +import { + getMessageFragment, + attributesFilter, + pinnedFilter, + allFilter, + referencesFilter +} from './activityMessagesUtils' +import { updateReferences } from './references' export * from './activity' export * from './utils' export * from './activityMessagesUtils' +export * from './references' export { default as Reactions } from './components/reactions/Reactions.svelte' export { default as ActivityMessageTemplate } from './components/activity-message/ActivityMessageTemplate.svelte' @@ -40,6 +49,7 @@ export { default as ActivityMessageHeader } from './components/activity-message/ export { default as AddReactionAction } from './components/reactions/AddReactionAction.svelte' export { default as ActivityMessageAction } from './components/ActivityMessageAction.svelte' export { default as ActivityMessagesFilterPopup } from './components/FilterPopup.svelte' +export { default as ActivityReferencePresenter } from './components/activity-reference/ActivityReferencePresenter.svelte' export default async (): Promise => ({ component: { @@ -49,14 +59,19 @@ export default async (): Promise => ({ ReactionPresenter, ActivityInfoMessagePresenter, ReactionNotificationPresenter, - ActivityMessageNotificationLabel + ActivityMessageNotificationLabel, + ActivityReferencePresenter }, filter: { AttributesFilter: attributesFilter, PinnedFilter: pinnedFilter, - AllFilter: allFilter + AllFilter: allFilter, + ReferencesFilter: referencesFilter }, function: { GetFragment: getMessageFragment + }, + backreference: { + Update: updateReferences } }) diff --git a/plugins/activity-resources/src/references.ts b/plugins/activity-resources/src/references.ts new file mode 100644 index 0000000000..da36affd42 --- /dev/null +++ b/plugins/activity-resources/src/references.ts @@ -0,0 +1,169 @@ +import core, { + type Class, + type Data, + type Doc, + type DocumentQuery, + type Ref, + type RelatedDocument, + type Space, + type TxOperations +} from '@hcengineering/core' +import activity, { type ActivityReference } from '@hcengineering/activity' +import { type IntlString, translate } from '@hcengineering/platform' +import { getClient } from '@hcengineering/presentation' +import contact from '@hcengineering/contact' + +async function updateReferencesList ( + client: TxOperations, + q: DocumentQuery, + references: Array>, + space: Ref +): Promise { + const currentRefs: ActivityReference[] = await client.findAll(activity.class.ActivityReference, q) + + // We need to find ones we need to remove, and ones we need to update. + for (const c of currentRefs) { + // Find existing and check if we need to update message. + const pos = references.findIndex( + (ref) => ref.srcDocId === c.srcDocId && ref.srcDocClass === c.srcDocClass && ref.attachedTo === c.attachedTo + ) + if (pos !== -1) { + // We need to check and update if required. + const data = references[pos] + if (c.message !== data.message) { + await client.updateCollection(c._class, c.space, c._id, c.attachedTo, c.attachedToClass, c.collection, { + message: data.message + }) + } + references.splice(pos, 1) + } else { + // We need to remove reference. + await client.removeCollection(c._class, c.space, c._id, c.attachedTo, c.attachedToClass, c.collection) + } + } + // Add missing references + for (const ref of references) { + const { attachedTo, attachedToClass, collection, ...adata } = ref + await client.addCollection(activity.class.ActivityReference, space, attachedTo, attachedToClass, collection, adata) + } +} + +export async function updateReferences ( + source: Doc, + key: string, + target: RelatedDocument[], + msg: IntlString +): Promise { + const client = getClient() + const hierarchy = client.getHierarchy() + + const message = await translate(msg, {}) + const references: Array> = target + .filter((it) => !hierarchy.isDerived(it._class, contact.class.Person)) + .map((it) => ({ + srcDocId: source._id, + srcDocClass: source._class, + attachedTo: it._id, + attachedToClass: it._class, + message, + collection: key + })) + + const query: DocumentQuery = { srcDocId: source._id, srcDocClass: source._class, collection: key } + const space: Ref = hierarchy.isDerived(source._class, core.class.Space) + ? (source._id as Ref) + : source.space + + await updateReferencesList(client, query, references, space) +} + +function extractReferences ( + srcDocId: Ref, + srcDocClass: Ref>, + attachedDocId: Ref | undefined, + attachedDocClass: Ref> | undefined, + kids: NodeListOf +): Array> { + const result: Array> = [] + + const nodes: Array> = [kids] + while (true) { + const nds = nodes.shift() + if (nds === undefined) { + break + } + nds.forEach((kid) => { + if ( + kid.nodeType === Node.ELEMENT_NODE && + (kid as HTMLElement).localName === 'span' && + (kid as HTMLElement).getAttribute('data-type') === 'reference' + ) { + const el = kid as HTMLElement + const ato = el.getAttribute('data-id') as Ref + const atoClass = el.getAttribute('data-objectclass') as Ref> + const e = result.find((e) => e.attachedTo === ato && e.attachedToClass === atoClass) + if (e === undefined && ato !== attachedDocId && ato !== srcDocId) { + result.push({ + attachedTo: ato, + attachedToClass: atoClass, + collection: 'references', + srcDocId, + srcDocClass, + message: el.parentElement?.innerHTML ?? '', + attachedDocId, + attachedDocClass + }) + } + } + nodes.push(kid.childNodes) + }) + } + return result +} + +/** + * @public + */ +export function getReferences ( + srcDocId: Ref, + srcDocClass: Ref>, + attachedDocId: Ref | undefined, + attachedDocClass: Ref> | undefined, + content: string +): Array> { + const parser = new DOMParser() + const doc = parser.parseFromString(content, 'text/html') + + return extractReferences( + srcDocId, + srcDocClass, + attachedDocId, + attachedDocClass, + doc.childNodes as NodeListOf + ) +} + +/** + * @public + */ +export async function createReferences ( + client: TxOperations, + srcDocId: Ref, + srcDocClass: Ref>, + attachedDocId: Ref | undefined, + attachedDocClass: Ref> | undefined, + content: string, + space: Ref +): Promise { + const hierarchy = client.getHierarchy() + + const references = getReferences(srcDocId, srcDocClass, attachedDocId, attachedDocClass, content) + for (const ref of references) { + if (hierarchy.isDerived(ref.attachedToClass, contact.class.Person)) { + continue + } + + const { attachedTo, attachedToClass, collection, ...adata } = ref + await client.addCollection(activity.class.ActivityReference, space, attachedTo, attachedToClass, collection, adata) + } +} diff --git a/plugins/activity/src/index.ts b/plugins/activity/src/index.ts index c027abe2ba..7cdd10211b 100644 --- a/plugins/activity/src/index.ts +++ b/plugins/activity/src/index.ts @@ -24,6 +24,7 @@ import { DocumentQuery, Mixin, Ref, + type RelatedDocument, Timestamp, Tx, TxCreateDoc, @@ -180,6 +181,22 @@ export interface DocUpdateMessage extends ActivityMessage { attributeUpdates?: DocAttributeUpdates } +export interface ActivityReference extends ActivityMessage { + // A mentioned document + // attachedTo: Ref + // attachedToClass: Ref> + + // Source document we have reference from, it should be parent document for Comment/Message. + srcDocId: Ref + srcDocClass: Ref> + + // Reference to comment/message in source doc + attachedDocId?: Ref + attachedDocClass?: Ref> + + message: string +} + /** * @public */ @@ -310,7 +327,8 @@ export default plugin(activityId, { ActivityMessagesFilter: '' as Ref>, ActivityExtension: '' as Ref>, Reaction: '' as Ref>, - SavedMessage: '' as Ref> + SavedMessage: '' as Ref>, + ActivityReference: '' as Ref> }, icon: { Activity: '' as Asset, @@ -342,7 +360,11 @@ export default plugin(activityId, { LastReply: '' as IntlString, RepliesCount: '' as IntlString, Reacted: '' as IntlString, - Message: '' as IntlString + Message: '' as IntlString, + Mentioned: '' as IntlString, + You: '' as IntlString, + Mentions: '' as IntlString, + MentionedYouIn: '' as IntlString }, component: { Activity: '' as AnyComponent, @@ -351,9 +373,15 @@ export default plugin(activityId, { ActivityInfoMessagePresenter: '' as AnyComponent, ReactionPresenter: '' as AnyComponent, ReactionNotificationPresenter: '' as AnyComponent, - ActivityMessageNotificationLabel: '' as AnyComponent + ActivityMessageNotificationLabel: '' as AnyComponent, + ActivityReferencePresenter: '' as AnyComponent }, ids: { - AllFilter: '' as Ref + AllFilter: '' as Ref, + MentionNotification: '' as Ref + }, + backreference: { + // Update list of back references + Update: '' as Resource<(source: Doc, key: string, target: RelatedDocument[], label: IntlString) => Promise> } }) diff --git a/plugins/chunter-resources/src/backlinks.ts b/plugins/chunter-resources/src/backlinks.ts deleted file mode 100644 index 1dddcbde25..0000000000 --- a/plugins/chunter-resources/src/backlinks.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { type Backlink } from '@hcengineering/chunter' -import { type Data, type DocumentQuery, type TxOperations } from '@hcengineering/core' -import chunter from './plugin' - -/** - * @public - */ -export async function updateBacklinksList ( - client: TxOperations, - q: DocumentQuery, - backlinks: Array> -): Promise { - const current = await client.findAll(chunter.class.Backlink, q) - - // We need to find ones we need to remove, and ones we need to update. - for (const c of current) { - // Find existing and check if we need to update message. - const pos = backlinks.findIndex( - (b) => b.backlinkId === c.backlinkId && b.backlinkClass === c.backlinkClass && b.attachedTo === c.attachedTo - ) - if (pos !== -1) { - // We need to check and update if required. - const data = backlinks[pos] - if (c.message !== data.message) { - await client.updateCollection(c._class, c.space, c._id, c.attachedTo, c.attachedToClass, c.collection, { - message: data.message - }) - } - backlinks.splice(pos, 1) - } else { - // We need to remove backlink. - await client.removeCollection(c._class, c.space, c._id, c.attachedTo, c.attachedToClass, c.collection) - } - } - // Add missing backlinks - for (const backlink of backlinks) { - const { attachedTo, attachedToClass, collection, ...adata } = backlink - await client.addCollection( - chunter.class.Backlink, - chunter.space.Backlinks, - attachedTo, - attachedToClass, - collection, - adata - ) - } -} diff --git a/plugins/chunter-resources/src/channelDataProvider.ts b/plugins/chunter-resources/src/channelDataProvider.ts index 002f82138a..20124ba5b4 100644 --- a/plugins/chunter-resources/src/channelDataProvider.ts +++ b/plugins/chunter-resources/src/channelDataProvider.ts @@ -159,7 +159,7 @@ export class ChannelDataProvider implements IChannelDataProvider { this.metadataQuery.query( this.msgClass, - { attachedTo: this.chatId }, + { attachedTo: this.chatId, hidden: { $ne: true } }, (res) => { this.updatesDates(res) this.metadataStore.set(res) @@ -235,6 +235,7 @@ export class ChannelDataProvider implements IChannelDataProvider { this.msgClass, { attachedTo: this.chatId, + hidden: { $ne: true }, ...(this.tailStart !== undefined ? { createdOn: { $gte: this.tailStart } } : {}) }, async (res) => { @@ -287,6 +288,7 @@ export class ChannelDataProvider implements IChannelDataProvider { chunter.class.ChatMessage, { attachedTo: this.chatId, + hidden: { $ne: true }, createdOn: isBackward ? loadEqual ? { $lte: loadAfter } diff --git a/plugins/chunter-resources/src/components/activity/BacklinkCreatedLabel.svelte b/plugins/chunter-resources/src/components/activity/BacklinkCreatedLabel.svelte deleted file mode 100644 index ed2efaa50a..0000000000 --- a/plugins/chunter-resources/src/components/activity/BacklinkCreatedLabel.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -{#if target} - - - {#if currentAccount.person === target._id} - - -{/if} -{#if doc && value} - - - - -{/if} - - diff --git a/plugins/chunter-resources/src/components/chat-message/ChatMessagePopup.svelte b/plugins/chunter-resources/src/components/chat-message/ChatMessagePopup.svelte index 72dd6a7ff1..4d6d0bf9f5 100644 --- a/plugins/chunter-resources/src/components/chat-message/ChatMessagePopup.svelte +++ b/plugins/chunter-resources/src/components/chat-message/ChatMessagePopup.svelte @@ -21,7 +21,6 @@ import chunter, { ChatMessage } from '@hcengineering/chunter' import { closeTooltip, Label, Lazy, Spinner, resizeObserver, MiniToggle } from '@hcengineering/ui' import { ObjectPresenter, DocNavLink } from '@hcengineering/view-resources' - import { loadSavedMessages } from '@hcengineering/activity-resources' import ChatMessageInput from './ChatMessageInput.svelte' import ChatMessagePresenter from './ChatMessagePresenter.svelte' @@ -53,10 +52,6 @@ $: if (isTextMode) { dispatch('tooltip', { kind: 'popup' }) } - - onMount(() => { - loadSavedMessages() - })
diff --git a/plugins/chunter-resources/src/components/chat/Chat.svelte b/plugins/chunter-resources/src/components/chat/Chat.svelte index 5263a16df0..d9084f3198 100644 --- a/plugins/chunter-resources/src/components/chat/Chat.svelte +++ b/plugins/chunter-resources/src/components/chat/Chat.svelte @@ -28,7 +28,6 @@ import { NavigatorModel, SpecialNavModel } from '@hcengineering/workbench' import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources' - import { loadSavedMessages } from '@hcengineering/activity-resources' import { onMount } from 'svelte' import ChatNavigator from './navigator/ChatNavigator.svelte' @@ -118,7 +117,6 @@ ]) onMount(() => { - loadSavedMessages() loadSavedAttachments() }) diff --git a/plugins/chunter-resources/src/components/chat/utils.ts b/plugins/chunter-resources/src/components/chat/utils.ts index 8c93ae3f1a..5c66b388c5 100644 --- a/plugins/chunter-resources/src/components/chat/utils.ts +++ b/plugins/chunter-resources/src/components/chat/utils.ts @@ -95,7 +95,7 @@ export const chatNavGroupsModel: ChatNavGroupModel[] = [ label: activity.string.Activity, query: { attachedToClass: { - $nin: [chunter.class.DirectMessage, chunter.class.Channel, chunter.class.Backlink] + $nin: [chunter.class.DirectMessage, chunter.class.Channel] } } } diff --git a/plugins/chunter-resources/src/components/threads/ThreadView.svelte b/plugins/chunter-resources/src/components/threads/ThreadView.svelte index 56aae3bc14..ab67d8af4c 100644 --- a/plugins/chunter-resources/src/components/threads/ThreadView.svelte +++ b/plugins/chunter-resources/src/components/threads/ThreadView.svelte @@ -18,7 +18,7 @@ import { Breadcrumbs, IconClose, Label, location as locationStore } from '@hcengineering/ui' import { createEventDispatcher, onMount } from 'svelte' import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity' - import { getMessageFromLoc, loadSavedMessages } from '@hcengineering/activity-resources' + import { getMessageFromLoc } from '@hcengineering/activity-resources' import contact from '@hcengineering/contact' import chunter from '../../plugin' @@ -88,10 +88,6 @@ { label: chunter.string.Thread } ] } - - onMount(() => { - loadSavedMessages() - })
diff --git a/plugins/chunter-resources/src/index.ts b/plugins/chunter-resources/src/index.ts index 7b69620d20..5c3b0e190d 100644 --- a/plugins/chunter-resources/src/index.ts +++ b/plugins/chunter-resources/src/index.ts @@ -14,25 +14,12 @@ // import { get, writable } from 'svelte/store' -import chunter, { - type Backlink, - type Channel, - type ChatMessage, - chunterId, - type DirectMessage -} from '@hcengineering/chunter' -import { - type Data, - type Doc, - type DocumentQuery, - getCurrentAccount, - type Ref, - type RelatedDocument -} from '@hcengineering/core' -import { type IntlString, type Resources, translate } from '@hcengineering/platform' +import chunter, { type Channel, type ChatMessage, chunterId, type DirectMessage } from '@hcengineering/chunter' +import { getCurrentAccount, type Ref } from '@hcengineering/core' +import { type Resources } from '@hcengineering/platform' import { MessageBox, getClient } from '@hcengineering/presentation' import { closePanel, getCurrentLocation, getLocation, navigate, showPopup } from '@hcengineering/ui' -import activity, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/activity' +import { type ActivityMessage } from '@hcengineering/activity' import notification, { type DocNotifyContext, inboxId } from '@hcengineering/notification' import ChannelPresenter from './components/ChannelPresenter.svelte' @@ -50,9 +37,6 @@ import EditChannel from './components/EditChannel.svelte' import ChannelPreview from './components/ChannelPreview.svelte' import ThreadView from './components/threads/ThreadView.svelte' import ThreadViewPanel from './components/threads/ThreadViewPanel.svelte' -import BacklinkContent from './components/BacklinkContent.svelte' -import BacklinkReference from './components/BacklinkReference.svelte' -import BacklinkCreatedLabel from './components/activity/BacklinkCreatedLabel.svelte' import ChatMessagePresenter from './components/chat-message/ChatMessagePresenter.svelte' import ChatMessageInput from './components/chat-message/ChatMessageInput.svelte' import ChatMessagesPresenter from './components/chat-message/ChatMessagesPresenter.svelte' @@ -70,7 +54,6 @@ import ChatAside from './components/chat/ChatAside.svelte' import Replies from './components/Replies.svelte' import ReplyToThreadAction from './components/ReplyToThreadAction.svelte' -import { updateBacklinksList } from './backlinks' import { ChannelTitleProvider, DirectTitleProvider, @@ -186,29 +169,6 @@ export async function chunterBrowserVisible (): Promise { return false } -async function update (source: Doc, key: string, target: RelatedDocument[], msg: IntlString): Promise { - const message = await translate(msg, {}) - const backlinks: Array> = target.map((it) => ({ - backlinkId: source._id, - backlinkClass: source._class, - attachedTo: it._id, - attachedToClass: it._class, - message, - collection: key - })) - - const q: DocumentQuery = { backlinkId: source._id, backlinkClass: source._class, collection: key } - - await updateBacklinksList(getClient(), q, backlinks) -} - -export function backlinksFilter (message: ActivityMessage, _class?: Ref): boolean { - if (message._class === activity.class.DocUpdateMessage) { - return (message as DocUpdateMessage).objectClass === chunter.class.Backlink - } - return false -} - export function chatMessagesFilter (message: ActivityMessage): boolean { return message._class === chunter.class.ChatMessage } @@ -250,7 +210,6 @@ export async function replyToThread (message: ActivityMessage): Promise { export default async (): Promise => ({ filter: { - BacklinksFilter: backlinksFilter, ChatMessagesFilter: chatMessagesFilter }, component: { @@ -271,8 +230,6 @@ export default async (): Promise => ({ EditChannel, ThreadView, SavedMessages, - BacklinkContent, - BacklinkReference, ChatMessagePresenter, ChatMessageInput, ChatMessagesPresenter, @@ -301,9 +258,6 @@ export default async (): Promise => ({ GetUnreadThreadsCount: getUnreadThreadsCount, GetThreadLink: getThreadLink }, - activity: { - BacklinkCreatedLabel - }, actionImpl: { ArchiveChannel, UnarchiveChannel, @@ -311,8 +265,5 @@ export default async (): Promise => ({ DeleteChatMessage: deleteChatMessage, OpenChannel, UnpinAllChannels - }, - backreference: { - Update: update } }) diff --git a/plugins/chunter/src/index.ts b/plugins/chunter/src/index.ts index 1476d9c51d..87155a99ac 100644 --- a/plugins/chunter/src/index.ts +++ b/plugins/chunter/src/index.ts @@ -15,17 +15,7 @@ import { ActivityMessage, ActivityMessageViewlet } from '@hcengineering/activity' import type { Person } from '@hcengineering/contact' -import type { - Account, - AttachedDoc, - Class, - Doc, - Mixin, - Ref, - RelatedDocument, - Space, - Timestamp -} from '@hcengineering/core' +import type { Account, AttachedDoc, Class, Doc, Mixin, Ref, Space, Timestamp } from '@hcengineering/core' import { NotificationType } from '@hcengineering/notification' import type { Asset, Plugin, Resource } from '@hcengineering/platform' import { IntlString, plugin } from '@hcengineering/platform' @@ -81,35 +71,6 @@ export interface Message extends ChunterMessage { lastReply?: Timestamp } -/** - * @public - * @deprecated use ChatMessage instead - */ -// TODO: remove comment -export interface Comment extends AttachedDoc { - message: string - attachments?: number - reactions?: number - pinned?: boolean -} - -/** - * @public - */ -export interface Backlink extends Comment { - // A target document - // attachedTo <- target document we point to - // A target document class - // attachedToClass - - // Source document we have reference from, it should be parent document for Comment/Message. - backlinkId: Ref - // Source document class - backlinkClass: Ref> - // Reference to comment documentId - attachedDocId?: Ref -} - /** * @public */ @@ -186,8 +147,6 @@ export default plugin(chunterId, { Message: '' as Ref>, ChunterMessage: '' as Ref>, ThreadMessage: '' as Ref>, - Backlink: '' as Ref>, - Comment: '' as Ref>, ChunterSpace: '' as Ref>, Channel: '' as Ref>, DirectMessage: '' as Ref>, @@ -199,9 +158,6 @@ export default plugin(chunterId, { ChunterMessageExtension: '' as Ref>, ObjectChatPanel: '' as Ref> }, - space: { - Backlinks: '' as Ref - }, string: { Reactions: '' as IntlString, EditUpdate: '' as IntlString, @@ -238,7 +194,6 @@ export default plugin(chunterId, { }, ids: { DMNotification: '' as Ref, - MentionNotification: '' as Ref, ThreadNotification: '' as Ref, ChannelNotification: '' as Ref, ThreadMessageViewlet: '' as Ref @@ -246,10 +201,6 @@ export default plugin(chunterId, { app: { Chunter: '' as Ref }, - backreference: { - // Update list of back references - Update: '' as Resource<(source: Doc, key: string, target: RelatedDocument[], label: IntlString) => Promise> - }, action: { DeleteChatMessage: '' as Ref, OpenChannel: '' as Ref diff --git a/plugins/chunter/src/utils.ts b/plugins/chunter/src/utils.ts index 354f3f3e31..362e20b42f 100644 --- a/plugins/chunter/src/utils.ts +++ b/plugins/chunter/src/utils.ts @@ -1,8 +1,8 @@ import { deepEqual } from 'fast-equals' -import core, { Class, Data, Doc, Ref, TxOperations } from '@hcengineering/core' +import core, { Ref, TxOperations } from '@hcengineering/core' import { PersonAccount } from '@hcengineering/contact' -import chunter, { Backlink, DirectMessage } from '.' +import chunter, { DirectMessage } from '.' /** * @public @@ -28,84 +28,3 @@ export async function getDirectChannel ( members: accIds }) } - -function extractBacklinks ( - backlinkId: Ref, - backlinkClass: Ref>, - attachedDocId: Ref | undefined, - message: string, - kids: NodeListOf -): Array> { - const result: Array> = [] - - const nodes: Array> = [kids] - while (true) { - const nds = nodes.shift() - if (nds === undefined) { - break - } - nds.forEach((kid) => { - if ( - kid.nodeType === Node.ELEMENT_NODE && - (kid as HTMLElement).localName === 'span' && - (kid as HTMLElement).getAttribute('data-type') === 'reference' - ) { - const el = kid as HTMLElement - const ato = el.getAttribute('data-id') as Ref - const atoClass = el.getAttribute('data-objectclass') as Ref> - const e = result.find((e) => e.attachedTo === ato && e.attachedToClass === atoClass) - if (e === undefined && ato !== attachedDocId && ato !== backlinkId) { - result.push({ - attachedTo: ato, - attachedToClass: atoClass, - collection: 'backlinks', - backlinkId, - backlinkClass, - message: el.parentElement?.innerHTML ?? '', - attachedDocId - }) - } - } - nodes.push(kid.childNodes) - }) - } - return result -} - -/** - * @public - */ -export function getBacklinks ( - backlinkId: Ref, - backlinkClass: Ref>, - attachedDocId: Ref | undefined, - content: string -): Array> { - const parser = new DOMParser() - const doc = parser.parseFromString(content, 'text/html') - return extractBacklinks(backlinkId, backlinkClass, attachedDocId, content, doc.childNodes as NodeListOf) -} - -/** - * @public - */ -export async function createBacklinks ( - client: TxOperations, - backlinkId: Ref, - backlinkClass: Ref>, - attachedDocId: Ref | undefined, - content: string -): Promise { - const backlinks = getBacklinks(backlinkId, backlinkClass, attachedDocId, content) - for (const backlink of backlinks) { - const { attachedTo, attachedToClass, collection, ...adata } = backlink - await client.addCollection( - chunter.class.Backlink, - chunter.space.Backlinks, - attachedTo, - attachedToClass, - collection, - adata - ) - } -} diff --git a/plugins/contact/src/index.ts b/plugins/contact/src/index.ts index 45d9ff817d..9d5f3529c5 100644 --- a/plugins/contact/src/index.ts +++ b/plugins/contact/src/index.ts @@ -300,6 +300,9 @@ export const contactPlugin = plugin(contactId, { ContactName: '' as Ref, ContactFirstName: '' as Ref, ContactLastName: '' as Ref + }, + ids: { + MentionCommonNotificationType: '' as Ref } }) diff --git a/plugins/document-assets/assets/icons.svg b/plugins/document-assets/assets/icons.svg index 8dd7af1cca..1264df684f 100644 --- a/plugins/document-assets/assets/icons.svg +++ b/plugins/document-assets/assets/icons.svg @@ -33,7 +33,7 @@ - + diff --git a/plugins/document-assets/src/index.ts b/plugins/document-assets/src/index.ts index be33a05e87..73ecc92408 100644 --- a/plugins/document-assets/src/index.ts +++ b/plugins/document-assets/src/index.ts @@ -26,7 +26,7 @@ loadMetadata(document.icon, { Videofile: `${icons}#videofile`, Library: `${icons}#library`, Teamspace: `${icons}#teamspace`, - Backlinks: `${icons}#backlinks`, + References: `${icons}#references`, History: `${icons}#history`, Star: `${icons}#star`, Starred: `${icons}#starred` diff --git a/plugins/document-resources/package.json b/plugins/document-resources/package.json index 39802ee118..840ac771dd 100644 --- a/plugins/document-resources/package.json +++ b/plugins/document-resources/package.json @@ -37,6 +37,8 @@ "svelte-eslint-parser": "^0.33.1" }, "dependencies": { + "@hcengineering/activity": "^0.6.0", + "@hcengineering/activity-resources": "^0.6.1", "@hcengineering/platform": "^0.6.9", "svelte": "^4.2.5", "@hcengineering/ui": "^0.6.11", @@ -50,7 +52,6 @@ "@hcengineering/attachment": "^0.6.9", "@hcengineering/notification": "^0.6.16", "@hcengineering/login": "^0.6.8", - "@hcengineering/chunter": "^0.6.12", "@hcengineering/contact": "^0.6.20", "@hcengineering/contact-resources": "^0.6.0", "@hcengineering/preference": "^0.6.9", diff --git a/plugins/document-resources/src/components/CreateDocument.svelte b/plugins/document-resources/src/components/CreateDocument.svelte index 6777d73224..b2176bc397 100644 --- a/plugins/document-resources/src/components/CreateDocument.svelte +++ b/plugins/document-resources/src/components/CreateDocument.svelte @@ -49,7 +49,7 @@ attachments: 0, labels: 0, comments: 0, - backlinks: 0 + references: 0 } const dispatch = createEventDispatcher() diff --git a/plugins/document-resources/src/components/EditDoc.svelte b/plugins/document-resources/src/components/EditDoc.svelte index e82158bc57..1003e2f80b 100644 --- a/plugins/document-resources/src/components/EditDoc.svelte +++ b/plugins/document-resources/src/components/EditDoc.svelte @@ -56,7 +56,7 @@ import DocumentEditor from './DocumentEditor.svelte' import DocumentPresenter from './DocumentPresenter.svelte' import DocumentTitle from './DocumentTitle.svelte' - import Backlinks from './sidebar/Backlinks.svelte' + import References from './sidebar/References.svelte' import History from './sidebar/History.svelte' export let _id: Ref @@ -182,8 +182,8 @@ const aside: ButtonItem[] = [ { - id: 'backlinks', - icon: document.icon.Backlinks + id: 'references', + icon: document.icon.References }, { id: 'history', @@ -339,8 +339,8 @@
- {#if selectedAside === 'backlinks'} - + {#if selectedAside === 'references'} + {:else if selectedAside === 'history'} {/if} diff --git a/plugins/document-resources/src/components/sidebar/BacklinkView.svelte b/plugins/document-resources/src/components/sidebar/BacklinkView.svelte deleted file mode 100644 index c0bc638f7d..0000000000 --- a/plugins/document-resources/src/components/sidebar/BacklinkView.svelte +++ /dev/null @@ -1,49 +0,0 @@ - - - -
-
-
- -
-
- -
-
-
- -
-
- - diff --git a/plugins/document-resources/src/components/sidebar/Backlinks.svelte b/plugins/document-resources/src/components/sidebar/References.svelte similarity index 80% rename from plugins/document-resources/src/components/sidebar/Backlinks.svelte rename to plugins/document-resources/src/components/sidebar/References.svelte index 990d8600fb..8bcd1c4001 100644 --- a/plugins/document-resources/src/components/sidebar/Backlinks.svelte +++ b/plugins/document-resources/src/components/sidebar/References.svelte @@ -15,28 +15,28 @@ // --> @@ -48,11 +48,11 @@
- {#if backlinks.length > 0} - - {#each backlinks as backlink} + {#if references.length > 0} + + {#each references as reference} - + {/each} diff --git a/plugins/document-resources/src/utils.ts b/plugins/document-resources/src/utils.ts index d2adff0d4a..6e333902c2 100644 --- a/plugins/document-resources/src/utils.ts +++ b/plugins/document-resources/src/utils.ts @@ -47,7 +47,7 @@ export async function createEmptyDocument ( embeddings: 0, labels: 0, comments: 0, - backlinks: 0, + references: 0, ...data } diff --git a/plugins/document/src/index.ts b/plugins/document/src/index.ts index 72d9b38cab..5ffbc08e80 100644 --- a/plugins/document/src/index.ts +++ b/plugins/document/src/index.ts @@ -43,7 +43,7 @@ export interface Document extends AttachedDoc, comments?: number embeddings?: number labels?: number - backlinks?: number + references?: number } /** @@ -105,7 +105,7 @@ const documentPlugin = plugin(documentId, { Videofile: '' as Asset, Library: '' as Asset, Teamspace: '' as Asset, - Backlinks: '' as Asset, + References: '' as Asset, History: '' as Asset, Star: '' as Asset, Starred: '' as Asset diff --git a/plugins/notification-resources/src/components/BrowserNotificatator.svelte b/plugins/notification-resources/src/components/BrowserNotificatator.svelte index 0046e97a85..ce84162baf 100644 --- a/plugins/notification-resources/src/components/BrowserNotificatator.svelte +++ b/plugins/notification-resources/src/components/BrowserNotificatator.svelte @@ -19,8 +19,8 @@ NotificationProvider, NotificationSetting, NotificationStatus, - NotificationType, - Notification as PlatformNotification + Notification as PlatformNotification, + BaseNotificationType } from '@hcengineering/notification' import { createQuery, getClient } from '@hcengineering/presentation' import { getCurrentLocation, showPanel } from '@hcengineering/ui' @@ -32,7 +32,10 @@ const providersQuery = createQuery() let settingsReceived = false - let settings: Map, NotificationSetting> = new Map, NotificationSetting>() + let settings: Map, NotificationSetting> = new Map< + Ref, + NotificationSetting + >() let provider: NotificationProvider | undefined $: enabled = 'Notification' in window && Notification?.permission !== 'denied' diff --git a/plugins/notification-resources/src/components/NotificationGroupSetting.svelte b/plugins/notification-resources/src/components/NotificationGroupSetting.svelte index db080c4c1d..925c298695 100644 --- a/plugins/notification-resources/src/components/NotificationGroupSetting.svelte +++ b/plugins/notification-resources/src/components/NotificationGroupSetting.svelte @@ -15,6 +15,7 @@ diff --git a/plugins/notification-resources/src/components/NotificationSettings.svelte b/plugins/notification-resources/src/components/NotificationSettings.svelte index 37e2745726..fb736f8276 100644 --- a/plugins/notification-resources/src/components/NotificationSettings.svelte +++ b/plugins/notification-resources/src/components/NotificationSettings.svelte @@ -16,10 +16,10 @@ import { createEventDispatcher, onDestroy } from 'svelte' import { Ref } from '@hcengineering/core' import type { + BaseNotificationType, NotificationGroup, NotificationPreferencesGroup, - NotificationSetting, - NotificationType + NotificationSetting } from '@hcengineering/notification' import { getResource } from '@hcengineering/platform' import { createQuery, getClient } from '@hcengineering/presentation' @@ -51,7 +51,7 @@ groups = res }) - let settings = new Map, NotificationSetting[]>() + let settings = new Map, NotificationSetting[]>() const query = createQuery() diff --git a/plugins/notification-resources/src/components/inbox/CommonInboxNotificationPresenter.svelte b/plugins/notification-resources/src/components/inbox/CommonInboxNotificationPresenter.svelte index 958127fd8f..e067a7ecba 100644 --- a/plugins/notification-resources/src/components/inbox/CommonInboxNotificationPresenter.svelte +++ b/plugins/notification-resources/src/components/inbox/CommonInboxNotificationPresenter.svelte @@ -23,7 +23,7 @@ EmployeePresenter } from '@hcengineering/contact-resources' import core, { Doc, getDisplayTime, Ref } from '@hcengineering/core' - import { translate } from '@hcengineering/platform' + import { IntlString, translate } from '@hcengineering/platform' import { createQuery, getClient, MessageViewer } from '@hcengineering/presentation' import notification, { CommonInboxNotification } from '@hcengineering/notification' import { ActionIcon, IconMoreH, Label, showPopup } from '@hcengineering/ui' @@ -61,13 +61,15 @@ object = result[0] }) - $: void translate(value.message, value.props) - .then((message) => { - content = message - }) - .catch((err) => { - content = JSON.stringify(err, null, 2) - }) + $: void updateContent(value.message, value.messageHtml) + + async function updateContent (message?: IntlString, messageHtml?: string): Promise { + if (messageHtml !== undefined) { + content = messageHtml + } else if (message !== undefined) { + content = await translate(message, value.props) + } + } function handleActionMenuOpened (): void { isActionMenuOpened = true diff --git a/plugins/notification-resources/src/components/inbox/Inbox.svelte b/plugins/notification-resources/src/components/inbox/Inbox.svelte index bc698c6ae8..666db1efeb 100644 --- a/plugins/notification-resources/src/components/inbox/Inbox.svelte +++ b/plugins/notification-resources/src/components/inbox/Inbox.svelte @@ -41,8 +41,7 @@ import { Ref, WithLookup } from '@hcengineering/core' import { ViewletSelector } from '@hcengineering/view-resources' import activity, { ActivityMessage } from '@hcengineering/activity' - import { isReactionMessage, loadSavedMessages } from '@hcengineering/activity-resources' - import { onMount } from 'svelte' + import { isReactionMessage } from '@hcengineering/activity-resources' import { inboxMessagesStore, InboxNotificationsClientImpl } from '../../inboxNotificationsClient' import Filter from '../Filter.svelte' @@ -256,10 +255,6 @@ { size: 'auto', minSize: 30, maxSize: 'auto', float: undefined } ]) - onMount(() => { - loadSavedMessages() - }) - function archiveAll (): void { showPopup( MessageBox, diff --git a/plugins/notification/src/index.ts b/plugins/notification/src/index.ts index c2a002e629..ff29d7cedc 100644 --- a/plugins/notification/src/index.ts +++ b/plugins/notification/src/index.ts @@ -96,18 +96,24 @@ export interface NotificationContent { intlParamsNotLocalized?: Record } +export interface BaseNotificationType extends Doc { + label: IntlString + // Is autogenerated + generated: boolean + // allowed to change setting (probably we should show it, but disable toggle??) + hidden: boolean + group: Ref + // allowed providers and default value for it + providers: Record, boolean> + // templates for email (and browser/push?) + templates?: NotificationTemplate +} /** * @public */ -export interface NotificationType extends Doc { +export interface NotificationType extends BaseNotificationType { // For show/hide with attributes attribute?: Ref - // Is autogenerated - generated: boolean - // allowed to to change setting (probably we should show it, but disable toggle??) - hidden: boolean - label: IntlString - group: Ref txClasses: Ref>[] objectClass: Ref> // not allowed to parent doc @@ -119,14 +125,12 @@ export interface NotificationType extends Doc { txMatch?: DocumentQuery // use for space collaborators, not object spaceSubscribe?: boolean - // allowed providers and default value for it - providers: Record, boolean> - // templates for email (and browser/push?) - templates?: NotificationTemplate // when true notification will be created for user which trigger it (default - false) allowedForAuthor?: boolean } +export interface CommonNotificationType extends BaseNotificationType {} + /** * @public */ @@ -139,7 +143,7 @@ export interface NotificationProvider extends Doc { */ export interface NotificationSetting extends Preference { attachedTo: Ref - type: Ref + type: Ref enabled: boolean } @@ -239,7 +243,8 @@ export interface ActivityInboxNotification extends InboxNotification { export interface CommonInboxNotification extends InboxNotification { header?: IntlString - message: IntlString + message?: IntlString + messageHtml?: string props?: Record icon?: Asset iconProps?: Record @@ -312,7 +317,9 @@ const notification = plugin(notificationId, { }, class: { Notification: '' as Ref>, + BaseNotificationType: '' as Ref>, NotificationType: '' as Ref>, + CommonNotificationType: '' as Ref>, NotificationProvider: '' as Ref>, NotificationSetting: '' as Ref>, DocUpdates: '' as Ref>, @@ -327,7 +334,8 @@ const notification = plugin(notificationId, { ids: { NotificationSettings: '' as Ref, NotificationGroup: '' as Ref, - CollaboratoAddNotification: '' as Ref + CollaboratoAddNotification: '' as Ref, + MentionCommonNotificationType: '' as Ref }, providers: { PlatformNotification: '' as Ref, diff --git a/plugins/recruit-resources/src/components/CreateApplication.svelte b/plugins/recruit-resources/src/components/CreateApplication.svelte index ec1845e169..1496ed4e2f 100644 --- a/plugins/recruit-resources/src/components/CreateApplication.svelte +++ b/plugins/recruit-resources/src/components/CreateApplication.svelte @@ -163,7 +163,7 @@ await descriptionBox.createAttachments() if (_comment.trim().length > 0) { - await client.addCollection(chunter.class.Comment, _space, doc._id, recruit.class.Applicant, 'comments', { + await client.addCollection(chunter.class.ChatMessage, _space, doc._id, recruit.class.Applicant, 'comments', { message: _comment }) } diff --git a/plugins/request-resources/src/components/RequestActions.svelte b/plugins/request-resources/src/components/RequestActions.svelte index 27ee605d05..7adba7d171 100644 --- a/plugins/request-resources/src/components/RequestActions.svelte +++ b/plugins/request-resources/src/components/RequestActions.svelte @@ -14,13 +14,14 @@ -->