From b5bb679998ed033a7d5f5f3ad54c52f643ae18b8 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Fri, 22 Dec 2023 01:13:02 +0700 Subject: [PATCH] UBERF-4716: Activity info message (#4241) Signed-off-by: Andrey Sobolev --- models/activity/src/index.ts | 33 +++++- packages/platform/src/i18n.ts | 2 +- .../src/components/Activity.svelte | 4 +- .../ActivityInfoMessagePresenter.svelte | 107 ++++++++++++++++++ .../ActivityMessageHeader.svelte | 63 +++++++++++ .../ActivityMessageTemplate.svelte | 45 ++++---- .../DocUpdateMessageHeader.svelte | 2 +- .../DocUpdateMessagePresenter.svelte | 63 ++++------- plugins/activity-resources/src/index.ts | 4 +- plugins/activity/src/index.ts | 29 ++++- .../src/components/SystemAvatar.svelte | 16 ++- .../activity-resources/src/index.ts | 28 ++++- 12 files changed, 318 insertions(+), 78 deletions(-) create mode 100644 plugins/activity-resources/src/components/activity-message/ActivityInfoMessagePresenter.svelte create mode 100644 plugins/activity-resources/src/components/activity-message/ActivityMessageHeader.svelte diff --git a/models/activity/src/index.ts b/models/activity/src/index.ts index 8a16ae5a11..45e0ff456c 100644 --- a/models/activity/src/index.ts +++ b/models/activity/src/index.ts @@ -15,6 +15,7 @@ import { type ActivityAttributeUpdatesPresenter, + type ActivityInfoMessage, type ActivityDoc, type ActivityExtension, type ActivityExtensionKind, @@ -28,7 +29,8 @@ import { type DocUpdateMessageViewlet, type DocUpdateMessageViewletAttributesConfig, type Reaction, - type TxViewlet + type TxViewlet, + type ActivityMessageControl } from '@hcengineering/activity' import core, { DOMAIN_MODEL, @@ -51,7 +53,8 @@ import { TypeString, Mixin, Collection, - TypeBoolean + TypeBoolean, + TypeIntlString } from '@hcengineering/model' import { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core' import type { Asset, IntlString, Resource } from '@hcengineering/platform' @@ -119,6 +122,24 @@ export class TDocUpdateMessage extends TActivityMessage implements DocUpdateMess attributeUpdates?: DocAttributeUpdates } +@Model(activity.class.ActivityInfoMessage, activity.class.ActivityMessage, DOMAIN_ACTIVITY) +export class TActivityInfoMessage extends TActivityMessage implements ActivityInfoMessage { + @Prop(TypeIntlString(), activity.string.Update) + message!: IntlString + + props!: Record + icon!: Asset + iconProps!: Record +} + +@Model(activity.class.ActivityMessageControl, core.class.Doc, DOMAIN_MODEL) +export class TActivityMessageControl extends TDoc implements ActivityMessageControl { + objectClass!: Ref> + + // A set of rules to be skipped from generate doc update activity messages + skip!: DocumentQuery[] +} + @Model(activity.class.DocUpdateMessageViewlet, core.class.Doc, DOMAIN_MODEL) export class TDocUpdateMessageViewlet extends TDoc implements DocUpdateMessageViewlet { @Prop(TypeRef(core.class.Doc), core.string.Class) @@ -184,7 +205,9 @@ export function createModel (builder: Builder): void { TDocUpdateMessageViewlet, TActivityExtension, TReaction, - TActivityAttributeUpdatesPresenter + TActivityAttributeUpdatesPresenter, + TActivityInfoMessage, + TActivityMessageControl ) builder.mixin(activity.class.DocUpdateMessage, core.class.Class, activity.mixin.ActivityDoc, {}) @@ -193,6 +216,10 @@ export function createModel (builder: Builder): void { presenter: activity.component.DocUpdateMessagePresenter }) + builder.mixin(activity.class.ActivityInfoMessage, core.class.Class, view.mixin.ObjectPresenter, { + presenter: activity.component.ActivityInfoMessagePresenter + }) + builder.createDoc(activity.class.ActivityMessagesFilter, core.space.Model, { label: activity.string.Attributes, filter: activity.filter.AttributesFilter diff --git a/packages/platform/src/i18n.ts b/packages/platform/src/i18n.ts index eaf74cde80..e5c2071156 100644 --- a/packages/platform/src/i18n.ts +++ b/packages/platform/src/i18n.ts @@ -127,7 +127,7 @@ export async function translate

> ( cache.set(message, translation) return message } - const compiled = new IntlMessageFormat(translation, locale) + const compiled = new IntlMessageFormat(translation, locale, undefined, { ignoreTag: true }) cache.set(message, compiled) return compiled.format(params) } catch (err) { diff --git a/plugins/activity-resources/src/components/Activity.svelte b/plugins/activity-resources/src/components/Activity.svelte index 9062941d64..f20f2ca87d 100644 --- a/plugins/activity-resources/src/components/Activity.svelte +++ b/plugins/activity-resources/src/components/Activity.svelte @@ -39,7 +39,7 @@ let isNewestFirst = JSON.parse(localStorage.getItem('activity-newest-first') ?? 'false') - $: client.findAll(activity.class.ActivityExtension, { ofClass: object._class }).then((res) => { + $: void client.findAll(activity.class.ActivityExtension, { ofClass: object._class }).then((res) => { extensions = res }) @@ -64,7 +64,7 @@ } } - $: updateActivityMessages(object._id, isNewestFirst ? SortingOrder.Descending : SortingOrder.Ascending) + $: void updateActivityMessages(object._id, isNewestFirst ? SortingOrder.Descending : SortingOrder.Ascending)

diff --git a/plugins/activity-resources/src/components/activity-message/ActivityInfoMessagePresenter.svelte b/plugins/activity-resources/src/components/activity-message/ActivityInfoMessagePresenter.svelte new file mode 100644 index 0000000000..48fcaacb4b --- /dev/null +++ b/plugins/activity-resources/src/components/activity-message/ActivityInfoMessagePresenter.svelte @@ -0,0 +1,107 @@ + + + + + + {#if value.icon} + + {:else if person} + + {:else} + + {/if} + + + + + +
+
+ +
+
+
+
+ + diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessageHeader.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessageHeader.svelte new file mode 100644 index 0000000000..74f8b7c6fa --- /dev/null +++ b/plugins/activity-resources/src/components/activity-message/ActivityMessageHeader.svelte @@ -0,0 +1,63 @@ + + + + + {#if label} + + +{#if linkData} + + + + {linkData.title} + + + {#if isEdited} + + {/if} +{/if} + + diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte index eb826b3e6c..4035be4519 100644 --- a/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte +++ b/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte @@ -13,23 +13,22 @@ // limitations under the License. --> -{#if !isLoading && (!viewlet?.hideIfRemoved || !isObjectRemoved) && (value.action !== 'update' || attributeModel !== undefined)} +{#if !isLoading && (!(viewlet?.hideIfRemoved ?? false) || !isObjectRemoved) && (value.action !== 'update' || attributeModel !== undefined)} => ({ Activity, ActivityMessagePresenter, DocUpdateMessagePresenter, - ReactionAddedMessage + ReactionAddedMessage, + ActivityInfoMessagePresenter }, filter: { AttributesFilter: attributesFilter, diff --git a/plugins/activity/src/index.ts b/plugins/activity/src/index.ts index 889d0ed4af..5e1120a755 100644 --- a/plugins/activity/src/index.ts +++ b/plugins/activity/src/index.ts @@ -113,13 +113,37 @@ export interface ActivityMessage extends AttachedDoc { reactions?: number } -export type DisplayActivityMessage = DisplayDocUpdateMessage | ActivityMessage +export type DisplayActivityMessage = DisplayDocUpdateMessage | ActivityMessage | ActivityInfoMessage export interface DisplayDocUpdateMessage extends DocUpdateMessage { previousMessages?: DocUpdateMessage[] combinedMessagesIds?: Ref[] } +/** + * Designed to control and filter some of changes from being to be propagated into activity. + * @public + */ +export interface ActivityMessageControl extends Doc { + objectClass: Ref> + + // A set of rules to be skipped from generate doc update activity messages + skip: DocumentQuery[] +} + +/** + * + * General information activity message. + * @public + */ +export interface ActivityInfoMessage extends ActivityMessage { + title?: IntlString + message: IntlString + props?: Record + icon?: Asset + iconProps?: Record +} + export type ActivityMessageExtensionKind = 'action' | 'footer' /** @@ -252,6 +276,8 @@ export default plugin(activityId, { TxViewlet: '' as Ref>, DocUpdateMessage: '' as Ref>, ActivityMessage: '' as Ref>, + ActivityInfoMessage: '' as Ref>, + ActivityMessageControl: '' as Ref>, DocUpdateMessageViewlet: '' as Ref>, ActivityMessageExtension: '' as Ref>, ActivityMessagesFilter: '' as Ref>, @@ -288,6 +314,7 @@ export default plugin(activityId, { Activity: '' as AnyComponent, ActivityMessagePresenter: '' as AnyComponent, DocUpdateMessagePresenter: '' as AnyComponent, + ActivityInfoMessagePresenter: '' as AnyComponent, ReactionAddedMessage: '' as AnyComponent } }) diff --git a/plugins/contact-resources/src/components/SystemAvatar.svelte b/plugins/contact-resources/src/components/SystemAvatar.svelte index a97728a217..9cfa3e8fac 100644 --- a/plugins/contact-resources/src/components/SystemAvatar.svelte +++ b/plugins/contact-resources/src/components/SystemAvatar.svelte @@ -13,17 +13,24 @@ // limitations under the License. -->
- {workspace?.toUpperCase()?.[0]} + {#if icon} + + {:else} + {workspace?.toUpperCase()?.[0]} + {/if}
@@ -32,11 +39,12 @@ display: flex; justify-content: center; align-items: center; - color: var(--white-color); - background-color: rgb(246, 105, 77); + color: var(--avatar-border-color); + background-color: var(--avatar-bg-color); .text { font-weight: 500; + color: var(--theme-accent-color); } &.circle { diff --git a/server-plugins/activity-resources/src/index.ts b/server-plugins/activity-resources/src/index.ts index 0e31b3c069..cca248dc15 100644 --- a/server-plugins/activity-resources/src/index.ts +++ b/server-plugins/activity-resources/src/index.ts @@ -13,11 +13,13 @@ // limitations under the License. // +import activity, { DocUpdateMessage } from '@hcengineering/activity' import { Account, AttachedDoc, Data, Doc, + matchQuery, Ref, Tx, TxCollectionCUD, @@ -25,10 +27,9 @@ import { TxCUD, TxProcessor } from '@hcengineering/core' -import type { TriggerControl } from '@hcengineering/server-core' -import activity, { DocUpdateMessage } from '@hcengineering/activity' import core from '@hcengineering/core/lib/component' import { ActivityControl, DocObjectCache } from '@hcengineering/server-activity' +import type { TriggerControl } from '@hcengineering/server-core' import { getDocUpdateAction, getTxAttributesUpdates } from './utils' // export async function OnReactionChanged (originTx: Tx, control: TriggerControl): Promise { @@ -222,6 +223,29 @@ export async function generateDocUpdateMessages ( if (control.hierarchy.isDerived(tx.objectClass, activity.class.ActivityMessage)) { return res } + const etx = TxProcessor.extractTx(tx) + if ( + control.hierarchy.isDerived(etx._class, core.class.TxCUD) && + control.hierarchy.isDerived((etx as TxCUD).objectClass, activity.class.ActivityMessage) + ) { + return res + } + + // Check if we have override control over transaction => activity mappings + const controlRules = control.modelDb.findAllSync(activity.class.ActivityMessageControl, { + objectClass: { $in: control.hierarchy.getDescendants(tx.objectClass) } + }) + if (controlRules.length > 0) { + for (const r of controlRules) { + for (const s of r.skip) { + const otx = originTx ?? TxProcessor.extractTx(tx) + if (matchQuery(otx !== undefined ? [tx, otx] : [tx], s, r.objectClass, control.hierarchy).length > 0) { + // Match found, we need to skip + return res + } + } + } + } switch (tx._class) { case core.class.TxCreateDoc: {