diff --git a/models/activity/src/index.ts b/models/activity/src/index.ts index b1c1be217a..7d57f38ce8 100644 --- a/models/activity/src/index.ts +++ b/models/activity/src/index.ts @@ -21,8 +21,6 @@ import { type ActivityInfoMessage, type ActivityMessage, type ActivityMessageControl, - type ActivityMessageExtension, - type ActivityMessageExtensionKind, type ActivityMessagePreview, type ActivityMessagesFilter, type ActivityReference, @@ -70,7 +68,7 @@ import { } from '@hcengineering/model' import { TAttachedDoc, TClass, TDoc } from '@hcengineering/model-core' import preference, { TPreference } from '@hcengineering/model-preference' -import view from '@hcengineering/model-view' +import view, { createAction } from '@hcengineering/model-view' import notification from '@hcengineering/notification' import type { Asset, IntlString, Resource } from '@hcengineering/platform' import { type AnyComponent } from '@hcengineering/ui/src/types' @@ -210,15 +208,6 @@ export class TDocUpdateMessageViewlet extends TDoc implements DocUpdateMessageVi onlyWithParent?: boolean } -@Model(activity.class.ActivityMessageExtension, core.class.Doc, DOMAIN_MODEL) -export class TActivityMessageExtension extends TDoc implements ActivityMessageExtension { - @Prop(TypeRef(activity.class.ActivityMessage), core.string.Class) - @Index(IndexKind.Indexed) - ofMessage!: Ref> - - components!: { kind: ActivityMessageExtensionKind, component: AnyComponent }[] -} - @Model(activity.class.ActivityExtension, core.class.Doc, DOMAIN_MODEL) export class TActivityExtension extends TDoc implements ActivityExtension { @Prop(TypeRef(core.class.Class), core.string.Class) @@ -275,7 +264,6 @@ export function createModel (builder: Builder): void { TTxViewlet, TActivityDoc, TActivityMessagesFilter, - TActivityMessageExtension, TActivityMessage, TDocUpdateMessage, TDocUpdateMessageViewlet, @@ -426,6 +414,113 @@ export function createModel (builder: Builder): void { { attachedToClass: 1 } ] }) + + createAction( + builder, + { + action: activity.actionImpl.AddReaction, + label: activity.string.AddReaction, + icon: activity.icon.Emoji, + input: 'focus', + category: activity.category.Activity, + target: activity.class.ActivityMessage, + inline: true, + context: { + mode: 'context', + group: 'edit' + } + }, + activity.ids.AddReactionAction + ) + + createAction( + builder, + { + action: activity.actionImpl.SaveForLater, + label: activity.string.SaveForLater, + icon: activity.icon.Bookmark, + input: 'focus', + inline: true, + actionProps: { + size: 'x-small' + }, + category: activity.category.Activity, + target: activity.class.ActivityMessage, + visibilityTester: activity.function.CanSaveForLater, + context: { + mode: 'context', + group: 'edit' + } + }, + activity.ids.SaveForLaterAction + ) + + createAction( + builder, + { + action: activity.actionImpl.RemoveFromSaved, + label: activity.string.RemoveFromLater, + icon: activity.icon.BookmarkFilled, + input: 'focus', + inline: true, + actionProps: { + iconProps: { + fill: 'var(--global-accent-TextColor)' + } + }, + category: activity.category.Activity, + target: activity.class.ActivityMessage, + visibilityTester: activity.function.CanRemoveFromSaved, + context: { + mode: 'context', + group: 'edit' + } + }, + activity.ids.RemoveFromLaterAction + ) + + createAction( + builder, + { + action: activity.actionImpl.PinMessage, + label: view.string.Pin, + icon: view.icon.Pin, + input: 'focus', + inline: true, + category: activity.category.Activity, + target: activity.class.ActivityMessage, + visibilityTester: activity.function.CanPinMessage, + context: { + mode: 'context', + group: 'edit' + } + }, + activity.ids.PinMessageAction + ) + + createAction( + builder, + { + action: activity.actionImpl.UnpinMessage, + label: view.string.Unpin, + icon: view.icon.Pin, + input: 'focus', + inline: true, + actionProps: { + iconProps: { + fill: 'var(--global-accent-TextColor)' + } + }, + category: activity.category.Activity, + target: activity.class.ActivityMessage, + visibilityTester: activity.function.CanUnpinMessage, + context: { + mode: 'context', + group: 'edit' + } + }, + activity.ids.UnpinMessageAction + ) } export default activity diff --git a/models/activity/src/plugin.ts b/models/activity/src/plugin.ts index d61dc2b8f4..210ab46c36 100644 --- a/models/activity/src/plugin.ts +++ b/models/activity/src/plugin.ts @@ -16,7 +16,13 @@ import { activityId, type ActivityMessage, type DocUpdateMessageViewlet } from ' import activity from '@hcengineering/activity-resources/src/plugin' import { type IntlString, mergeIds, type Resource } from '@hcengineering/platform' import { type Doc, type Ref } from '@hcengineering/core' -import { type ActionCategory } from '@hcengineering/view' +import type { Location } from '@hcengineering/ui' +import { + type Action, + type ActionCategory, + type ViewAction, + type ViewActionAvailabilityFunction +} from '@hcengineering/view' import { type NotificationGroup, type NotificationType } from '@hcengineering/notification' export default mergeIds(activityId, activity, { @@ -24,7 +30,10 @@ export default mergeIds(activityId, activity, { Attributes: '' as IntlString, Pinned: '' as IntlString, Emoji: '' as IntlString, - Replies: '' as IntlString + Replies: '' as IntlString, + AddReaction: '' as IntlString, + SaveForLater: '' as IntlString, + RemoveFromLater: '' as IntlString }, filter: { AttributesFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean>, @@ -35,9 +44,28 @@ export default mergeIds(activityId, activity, { ids: { ReactionAddedActivityViewlet: '' as Ref, ActivityNotificationGroup: '' as Ref, - AddReactionNotification: '' as Ref + AddReactionNotification: '' as Ref, + AddReactionAction: '' as Ref, + SaveForLaterAction: '' as Ref, + RemoveFromLaterAction: '' as Ref, + PinMessageAction: '' as Ref, + UnpinMessageAction: '' as Ref + }, + function: { + GetFragment: '' as Resource<(doc: Doc, props: Record) => Promise>, + CanSaveForLater: '' as Resource, + CanRemoveFromSaved: '' as Resource, + CanPinMessage: '' as Resource, + CanUnpinMessage: '' as Resource }, category: { Activity: '' as Ref + }, + actionImpl: { + AddReaction: '' as ViewAction, + SaveForLater: '' as ViewAction, + RemoveFromSaved: '' as ViewAction, + PinMessage: '' as ViewAction, + UnpinMessage: '' as ViewAction } }) diff --git a/models/chunter/src/index.ts b/models/chunter/src/index.ts index 05088a648e..7aa21e303e 100644 --- a/models/chunter/src/index.ts +++ b/models/chunter/src/index.ts @@ -677,46 +677,6 @@ export function createModel (builder: Builder, options = { addApplication: true components: { input: chunter.component.ChatMessageInput } }) - builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { - ofMessage: chunter.class.ChatMessage, - components: [{ kind: 'footer', component: chunter.component.Replies }] - }) - - builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { - ofMessage: activity.class.DocUpdateMessage, - components: [{ kind: 'footer', component: chunter.component.Replies }] - }) - - builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { - ofMessage: activity.class.ActivityInfoMessage, - 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 }] - }) - - builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { - ofMessage: activity.class.DocUpdateMessage, - components: [{ kind: 'action', component: chunter.component.ReplyToThreadAction }] - }) - - builder.createDoc(activity.class.ActivityMessageExtension, core.space.Model, { - ofMessage: activity.class.ActivityInfoMessage, - 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'] }) @@ -741,6 +701,25 @@ export function createModel (builder: Builder, options = { addApplication: true builder.createDoc(activity.class.ReplyProvider, core.space.Model, { function: chunter.function.ReplyToThread }) + + createAction( + builder, + { + action: chunter.actionImpl.ReplyToThread, + label: chunter.string.ReplyToThread, + icon: chunter.icon.Thread, + input: 'focus', + category: chunter.category.Chunter, + target: activity.class.ActivityMessage, + visibilityTester: chunter.function.CanReplyToThread, + inline: true, + context: { + mode: 'context', + group: 'edit' + } + }, + chunter.action.ReplyToThreadAction + ) } export default chunter diff --git a/models/chunter/src/plugin.ts b/models/chunter/src/plugin.ts index f5dd431945..9d5a183f37 100644 --- a/models/chunter/src/plugin.ts +++ b/models/chunter/src/plugin.ts @@ -40,13 +40,15 @@ export default mergeIds(chunterId, chunter, { ArchiveChannel: '' as Ref, UnarchiveChannel: '' as Ref, ConvertToPrivate: '' as Ref, - CopyChatMessageLink: '' as Ref> + CopyChatMessageLink: '' as Ref>, + ReplyToThreadAction: '' as Ref }, actionImpl: { ArchiveChannel: '' as ViewAction, UnarchiveChannel: '' as ViewAction, ConvertDmToPrivateChannel: '' as ViewAction, - DeleteChatMessage: '' as ViewAction + DeleteChatMessage: '' as ViewAction, + ReplyToThread: '' as ViewAction }, category: { Chunter: '' as Ref @@ -100,8 +102,9 @@ export default mergeIds(chunterId, chunter, { CanCopyMessageLink: '' as Resource<(doc?: Doc | Doc[]) => Promise>, GetChunterSpaceLinkFragment: '' as Resource<(doc: Doc, props: Record) => Promise>, GetThreadLink: '' as Resource<(doc: Doc, props: Record) => Promise>, - GetMessageLink: '' as Resource<(doc: Doc, props: Record) => Promise>, - ReplyToThread: '' as Resource<(doc: ActivityMessage) => Promise> + ReplyToThread: '' as Resource<(doc: ActivityMessage) => Promise>, + CanReplyToThread: '' as Resource<(doc?: Doc | Doc[]) => Promise>, + GetMessageLink: '' as Resource<(doc: Doc, props: Record) => Promise> }, filter: { ChatMessagesFilter: '' as Resource<(message: ActivityMessage, _class?: Ref) => boolean> diff --git a/packages/ui/src/popups.ts b/packages/ui/src/popups.ts index c7fab42683..75b5b1032f 100644 --- a/packages/ui/src/popups.ts +++ b/packages/ui/src/popups.ts @@ -111,6 +111,7 @@ export function closePopup (category?: string): void { } else { for (let i = popups.length - 1; i >= 0; i--) { if (popups[i].options.fixed !== true) { + popups[i].onClose?.(undefined) popups.splice(i, 1) break } diff --git a/packages/ui/src/types.ts b/packages/ui/src/types.ts index ac38985b53..eb94495039 100644 --- a/packages/ui/src/types.ts +++ b/packages/ui/src/types.ts @@ -239,6 +239,7 @@ export type IconSize = | 'inline' | 'tiny' | 'card' + | 'xx-small' | 'x-small' | 'smaller' | 'small' @@ -258,6 +259,7 @@ export function getIconSize2x (size: IconSize): IconSize { switch (size) { case 'inline': case 'tiny': + case 'xx-small': case 'x-small': case 'small': case 'card': diff --git a/plugins/activity-assets/assets/icons.svg b/plugins/activity-assets/assets/icons.svg index a4415d8f79..c89feca615 100644 --- a/plugins/activity-assets/assets/icons.svg +++ b/plugins/activity-assets/assets/icons.svg @@ -2,13 +2,16 @@ - - - - - - - - - + + + + + + + + + + + + diff --git a/plugins/activity-assets/lang/en.json b/plugins/activity-assets/lang/en.json index 863d44a246..77e9345d45 100644 --- a/plugins/activity-assets/lang/en.json +++ b/plugins/activity-assets/lang/en.json @@ -40,6 +40,9 @@ "Mentions": "Mentions", "MentionedYouIn": "Mentioned you in {title}", "Messages": "Messages", - "Thread": "Thread" + "Thread": "Thread", + "AddReaction": "Add reaction", + "SaveForLater": "Save for later", + "RemoveFromLater": "Remove from saved" } } \ No newline at end of file diff --git a/plugins/activity-assets/lang/ru.json b/plugins/activity-assets/lang/ru.json index a25eefe488..ba7a29ce60 100644 --- a/plugins/activity-assets/lang/ru.json +++ b/plugins/activity-assets/lang/ru.json @@ -40,6 +40,9 @@ "Mentions": "Упоминания", "MentionedYouIn": "Упомянул(а) вас в {title}", "Messages": "Cообщения", - "Thread": "Обсуждение" + "Thread": "Обсуждение", + "AddReaction": "Добавить реакцию", + "SaveForLater": "Cохранить", + "RemoveFromLater": "Удалить из сохраненных" } } \ No newline at end of file diff --git a/plugins/activity-assets/src/index.ts b/plugins/activity-assets/src/index.ts index e8076e1fa2..f0dea9226c 100644 --- a/plugins/activity-assets/src/index.ts +++ b/plugins/activity-assets/src/index.ts @@ -20,5 +20,6 @@ const icons = require('../assets/icons.svg') as string // eslint-disable-line loadMetadata(activity.icon, { Activity: `${icons}#activity`, Emoji: `${icons}#emoji`, - Bookmark: `${icons}#bookmark` + Bookmark: `${icons}#bookmark`, + BookmarkFilled: `${icons}#bookmark-filled` }) diff --git a/plugins/activity-resources/src/components/ActivityMessageAction.svelte b/plugins/activity-resources/src/components/ActivityMessageAction.svelte index b6a87e2abe..52e687427c 100644 --- a/plugins/activity-resources/src/components/ActivityMessageAction.svelte +++ b/plugins/activity-resources/src/components/ActivityMessageAction.svelte @@ -14,9 +14,10 @@ --> - + diff --git a/plugins/activity-resources/src/components/ActivityMessageActions.svelte b/plugins/activity-resources/src/components/ActivityMessageActions.svelte index 69cd50fa08..d64271c98b 100644 --- a/plugins/activity-resources/src/components/ActivityMessageActions.svelte +++ b/plugins/activity-resources/src/components/ActivityMessageActions.svelte @@ -13,60 +13,95 @@ // limitations under the License. --> {#if message}
- - - - + {#each inlineActions as inline} + {#if inline.icon} + {#await getResource(inline.action) then action} + action(message, ev, { onOpen, onClose })} + /> + {/await} + {/if} + {/each} {#if withActionMenu} - + {/if}
{/if} diff --git a/plugins/activity-resources/src/components/BasePreview.svelte b/plugins/activity-resources/src/components/BasePreview.svelte index d70c711819..d2b36aade7 100644 --- a/plugins/activity-resources/src/components/BasePreview.svelte +++ b/plugins/activity-resources/src/components/BasePreview.svelte @@ -26,9 +26,10 @@ import core, { Account, Doc, Ref, Timestamp } from '@hcengineering/core' import { Icon, Label, resizeObserver, TimeSince, tooltip } from '@hcengineering/ui' import { Asset, getEmbeddedLabel, IntlString } from '@hcengineering/platform' - import activity, { ActivityMessagePreviewType } from '@hcengineering/activity' - import { classIcon, DocNavLink } from '@hcengineering/view-resources' + import activity, { ActivityMessage, ActivityMessagePreviewType } from '@hcengineering/activity' + import { classIcon, DocNavLink, showMenu } from '@hcengineering/view-resources' + export let message: ActivityMessage | undefined = undefined export let text: string | undefined = undefined export let intlLabel: IntlString | undefined = undefined export let readonly = false @@ -99,6 +100,12 @@ width = element.clientWidth }} on:click + on:contextmenu={(evt) => { + showMenu(evt, { object: message, baseMenuClass: activity.class.ActivityMessage }, () => { + isActionsOpened = false + }) + isActionsOpened = true + }} > {#if type === 'full'} diff --git a/plugins/activity-resources/src/components/PinMessageAction.svelte b/plugins/activity-resources/src/components/PinMessageAction.svelte deleted file mode 100644 index a80fefbf00..0000000000 --- a/plugins/activity-resources/src/components/PinMessageAction.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - - - diff --git a/plugins/activity-resources/src/components/Replies.svelte b/plugins/activity-resources/src/components/Replies.svelte index 5598bd6ebb..efb187444d 100644 --- a/plugins/activity-resources/src/components/Replies.svelte +++ b/plugins/activity-resources/src/components/Replies.svelte @@ -29,7 +29,6 @@ export let object: ActivityMessage export let embedded = false - export let onReply: (() => void) | undefined = undefined const client = getClient() const maxDisplayPersons = 5 @@ -83,11 +82,6 @@ e.stopPropagation() e.preventDefault() - if (onReply) { - onReply() - return - } - if (replyProvider) { const fn = await getResource(replyProvider.function) fn(object) diff --git a/plugins/activity-resources/src/components/SaveMessageAction.svelte b/plugins/activity-resources/src/components/SaveMessageAction.svelte deleted file mode 100644 index 476a2d9ce5..0000000000 --- a/plugins/activity-resources/src/components/SaveMessageAction.svelte +++ /dev/null @@ -1,52 +0,0 @@ - - - - diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessageExtension.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessageExtension.svelte deleted file mode 100644 index 1fd83e8bcf..0000000000 --- a/plugins/activity-resources/src/components/activity-message/ActivityMessageExtension.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -{#each extensions as extension} - {#each extension.components as component} - {#if component.kind === kind} - - {/if} - {/each} -{/each} diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessagePresenter.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessagePresenter.svelte index e2b6eab9dd..759b0b011a 100644 --- a/plugins/activity-resources/src/components/activity-message/ActivityMessagePresenter.svelte +++ b/plugins/activity-resources/src/components/activity-message/ActivityMessagePresenter.svelte @@ -39,7 +39,6 @@ export let hideLink = false export let compact = false export let onClick: (() => void) | undefined = undefined - export let onReply: (() => void) | undefined = undefined const client = getClient() const hierarchy = client.getHierarchy() @@ -70,8 +69,7 @@ videoPreload, hideLink, compact, - onClick, - onReply + onClick }} /> {/if} diff --git a/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte b/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte index 3f46d11ae4..3aef41eaf1 100644 --- a/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte +++ b/plugins/activity-resources/src/components/activity-message/ActivityMessageTemplate.svelte @@ -13,23 +13,18 @@ // limitations under the License. --> - + {#if previewElement} + + {/if} diff --git a/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte b/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte index 9a30b4a27c..e4e267bde1 100644 --- a/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte +++ b/plugins/activity-resources/src/components/activity-reference/ActivityReferencePresenter.svelte @@ -43,7 +43,6 @@ export let hideLink = false export let compact = false export let onClick: (() => void) | undefined = undefined - export let onReply: (() => void) | undefined = undefined const client = getClient() const hierarchy = client.getHierarchy() @@ -112,7 +111,6 @@ {hoverStyles} showDatePreposition {onClick} - {onReply} > diff --git a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte index f9c5df53d3..6b4034b93d 100644 --- a/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte +++ b/plugins/activity-resources/src/components/doc-update-message/DocUpdateMessagePresenter.svelte @@ -51,7 +51,6 @@ export let hoverStyles: 'borderedHover' | 'filledHover' = 'borderedHover' export let hideLink = false export let onClick: (() => void) | undefined = undefined - export let onReply: (() => void) | undefined = undefined const client = getClient() const hierarchy = client.getHierarchy() @@ -172,7 +171,6 @@ {hoverStyles} showDatePreposition={hideLink} {onClick} - {onReply} > - - - - - diff --git a/plugins/activity-resources/src/components/icons/BookmarkBorder.svelte b/plugins/activity-resources/src/components/icons/BookmarkBorder.svelte deleted file mode 100644 index baf1d18147..0000000000 --- a/plugins/activity-resources/src/components/icons/BookmarkBorder.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - diff --git a/plugins/activity-resources/src/components/reactions/AddReactionAction.svelte b/plugins/activity-resources/src/components/reactions/AddReactionAction.svelte deleted file mode 100644 index 6c0f0c92c6..0000000000 --- a/plugins/activity-resources/src/components/reactions/AddReactionAction.svelte +++ /dev/null @@ -1,52 +0,0 @@ - - - - diff --git a/plugins/activity-resources/src/index.ts b/plugins/activity-resources/src/index.ts index 1bb5fa582c..bdb1626cd5 100644 --- a/plugins/activity-resources/src/index.ts +++ b/plugins/activity-resources/src/index.ts @@ -28,6 +28,17 @@ import ActivityInfoMessagePreview from './components/activity-info-message/Activ import { attributesFilter, pinnedFilter, allFilter, referencesFilter } from './activityMessagesUtils' import { updateReferences } from './references' +import { + addReactionAction, + canPinMessage, + canRemoveFromSaved, + saveForLater, + unpinMessage, + pinMessage, + canSaveForLater, + canUnpinMessage, + removeFromSaved +} from './utils' export * from './activity' export * from './utils' @@ -42,7 +53,6 @@ export { default as ActivityDocLink } from './components/ActivityDocLink.svelte' export { default as ReactionPresenter } from './components/reactions/ReactionPresenter.svelte' export { default as ActivityMessageNotificationLabel } from './components/activity-message/ActivityMessageNotificationLabel.svelte' export { default as ActivityMessageHeader } from './components/activity-message/ActivityMessageHeader.svelte' -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' @@ -70,7 +80,20 @@ export default async (): Promise => ({ AllFilter: allFilter, ReferencesFilter: referencesFilter }, + function: { + CanSaveForLater: canSaveForLater, + CanRemoveFromSaved: canRemoveFromSaved, + CanPinMessage: canPinMessage, + CanUnpinMessage: canUnpinMessage + }, backreference: { Update: updateReferences + }, + actionImpl: { + AddReaction: addReactionAction, + SaveForLater: saveForLater, + RemoveFromSaved: removeFromSaved, + PinMessage: pinMessage, + UnpinMessage: unpinMessage } }) diff --git a/plugins/activity-resources/src/utils.ts b/plugins/activity-resources/src/utils.ts index b09ac26a4d..00f5f3a60f 100644 --- a/plugins/activity-resources/src/utils.ts +++ b/plugins/activity-resources/src/utils.ts @@ -20,18 +20,23 @@ import core, { getCurrentAccount } from '@hcengineering/core' import { type Asset, type IntlString, getResource, translate } from '@hcengineering/platform' -import { getAttributePresenterClass } from '@hcengineering/presentation' +import { getAttributePresenterClass, getClient } from '@hcengineering/presentation' import { type AnyComponent, type AnySvelteComponent, ErrorPresenter, themeStore, - type Location + type Location, + getEventPositionElement, + closePopup, + showPopup, + EmojiPopup } from '@hcengineering/ui' import view, { type AttributeModel, type BuildModelKey, type BuildModelOptions } from '@hcengineering/view' import { getObjectPresenter } from '@hcengineering/view-resources' +import preference from '@hcengineering/preference' -import { type ActivityKey, activityKey } from './activity' +import { type ActivityKey, activityKey, savedMessagesStore } from './activity' import activity from './plugin' const valueTypes: ReadonlyArray>> = [ @@ -427,3 +432,90 @@ export async function updateDocReactions ( export function getMessageFromLoc (loc: Location): Ref | undefined { return (loc.query?.message ?? undefined) as Ref | undefined } + +interface ActivityMessageActionParams { + onClose?: () => void + onOpen?: () => void +} + +export async function addReactionAction ( + message?: ActivityMessage, + ev?: MouseEvent, + params?: ActivityMessageActionParams +): Promise { + if (message === undefined || ev === undefined) return + + const client = getClient() + const reactions: Reaction[] = + (message.reactions ?? 0) > 0 + ? await client.findAll(activity.class.Reaction, { attachedTo: message._id }) + : [] + const element = getEventPositionElement(ev) + + closePopup() + + showPopup(EmojiPopup, {}, element, (emoji: string) => { + void updateDocReactions(client, reactions, message, emoji) + params?.onClose?.() + }) + params?.onOpen?.() +} + +export async function saveForLater (message?: ActivityMessage): Promise { + if (message === undefined) return + closePopup() + const client = getClient() + + await client.createDoc(activity.class.SavedMessage, preference.space.Preference, { + attachedTo: message._id + }) +} + +export async function removeFromSaved (message?: ActivityMessage): Promise { + if (message === undefined) return + closePopup() + const client = getClient() + const saved = get(savedMessagesStore).find((saved) => saved.attachedTo === message._id) + + if (saved !== undefined) { + await client.removeDoc(saved._class, saved.space, saved._id) + } +} + +export async function canSaveForLater (message?: ActivityMessage): Promise { + if (message === undefined) return false + + const saved = get(savedMessagesStore).find((saved) => saved.attachedTo === message._id) + + return saved === undefined +} + +export async function canRemoveFromSaved (message?: ActivityMessage): Promise { + if (message === undefined) return false + + return !(await canSaveForLater(message)) +} + +export async function canPinMessage (message?: ActivityMessage): Promise { + return message !== undefined && message.isPinned !== true +} + +export async function canUnpinMessage (message?: ActivityMessage): Promise { + return message !== undefined && message.isPinned === true +} + +export async function pinMessage (message?: ActivityMessage): Promise { + if (message === undefined) return + closePopup() + const client = getClient() + + await client.update(message, { isPinned: true }) +} + +export async function unpinMessage (message?: ActivityMessage): Promise { + if (message === undefined) return + closePopup() + const client = getClient() + + await client.update(message, { isPinned: false }) +} diff --git a/plugins/activity/src/index.ts b/plugins/activity/src/index.ts index 94c3302f7e..37d54ae882 100644 --- a/plugins/activity/src/index.ts +++ b/plugins/activity/src/index.ts @@ -157,16 +157,6 @@ export interface ActivityInfoMessage extends ActivityMessage { links?: { _class: Ref>, _id: Ref }[] } -export type ActivityMessageExtensionKind = 'action' | 'footer' - -/** - * @public - */ -export interface ActivityMessageExtension extends Doc { - ofMessage: Ref> - components: { kind: ActivityMessageExtensionKind, component: AnyComponent }[] -} - /** * @public */ @@ -333,7 +323,6 @@ export default plugin(activityId, { ActivityInfoMessage: '' as Ref>, ActivityMessageControl: '' as Ref>, DocUpdateMessageViewlet: '' as Ref>, - ActivityMessageExtension: '' as Ref>, ActivityMessagesFilter: '' as Ref>, ActivityExtension: '' as Ref>, Reaction: '' as Ref>, @@ -344,7 +333,8 @@ export default plugin(activityId, { icon: { Activity: '' as Asset, Emoji: '' as Asset, - Bookmark: '' as Asset + Bookmark: '' as Asset, + BookmarkFilled: '' as Asset }, string: { Activity: '' as IntlString, diff --git a/plugins/chunter-resources/src/components/ReplyToThreadAction.svelte b/plugins/chunter-resources/src/components/ReplyToThreadAction.svelte deleted file mode 100644 index 6eb9727a96..0000000000 --- a/plugins/chunter-resources/src/components/ReplyToThreadAction.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - - -{#if canReplyToThread(object)} - -{/if} diff --git a/plugins/chunter-resources/src/components/chat-message/ChatMessagePresenter.svelte b/plugins/chunter-resources/src/components/chat-message/ChatMessagePresenter.svelte index 60df9f91e3..01c289d203 100644 --- a/plugins/chunter-resources/src/components/chat-message/ChatMessagePresenter.svelte +++ b/plugins/chunter-resources/src/components/chat-message/ChatMessagePresenter.svelte @@ -50,7 +50,6 @@ export let hideLink = false export let compact = false export let onClick: (() => void) | undefined = undefined - export let onReply: (() => void) | undefined = undefined const client = getClient() const hierarchy = client.getHierarchy() @@ -183,7 +182,6 @@ {skipLabel} showDatePreposition={hideLink} {onClick} - {onReply} > diff --git a/plugins/chunter-resources/src/components/threads/ThreadMessagePresenter.svelte b/plugins/chunter-resources/src/components/threads/ThreadMessagePresenter.svelte index 8c654ead91..6da8f37048 100644 --- a/plugins/chunter-resources/src/components/threads/ThreadMessagePresenter.svelte +++ b/plugins/chunter-resources/src/components/threads/ThreadMessagePresenter.svelte @@ -40,7 +40,6 @@ export let attachmentImageSize: AttachmentImageSize = 'x-large' export let videoPreload = true export let onClick: (() => void) | undefined = undefined - export let onReply: (() => void) | undefined = undefined const client = getClient() @@ -76,6 +75,5 @@ {videoPreload} showLinksPreview={false} {onClick} - {onReply} /> {/if} diff --git a/plugins/chunter-resources/src/index.ts b/plugins/chunter-resources/src/index.ts index f3410ad898..7e2879a89b 100644 --- a/plugins/chunter-resources/src/index.ts +++ b/plugins/chunter-resources/src/index.ts @@ -48,7 +48,6 @@ import ChannelIcon from './components/ChannelIcon.svelte' import ThreadNotificationPresenter from './components/notification/ThreadNotificationPresenter.svelte' import ChatMessageNotificationLabel from './components/notification/ChatMessageNotificationLabel.svelte' import ChatAside from './components/chat/ChatAside.svelte' -import ReplyToThreadAction from './components/ReplyToThreadAction.svelte' import ThreadMessagePreview from './components/threads/ThreadMessagePreview.svelte' import ChatMessagePreview from './components/chat-message/ChatMessagePreview.svelte' @@ -62,7 +61,8 @@ import { getUnreadThreadsCount, canCopyMessageLink, leaveChannelAction, - removeChannelAction + removeChannelAction, + canReplyToThread } from './utils' import { chunterSpaceLinkFragmentProvider, @@ -180,7 +180,6 @@ export default async (): Promise => ({ ChatMessageNotificationLabel, ThreadNotificationPresenter, ChatAside, - ReplyToThreadAction, ThreadMessagePreview, ChatMessagePreview }, @@ -197,8 +196,9 @@ export default async (): Promise => ({ GetChunterSpaceLinkFragment: chunterSpaceLinkFragmentProvider, GetUnreadThreadsCount: getUnreadThreadsCount, GetThreadLink: getThreadLink, - GetMessageLink: getMessageLocation, - ReplyToThread: replyToThread + ReplyToThread: replyToThread, + CanReplyToThread: canReplyToThread, + GetMessageLink: getMessageLocation }, actionImpl: { ArchiveChannel, @@ -206,6 +206,7 @@ export default async (): Promise => ({ ConvertDmToPrivateChannel, DeleteChatMessage: deleteChatMessage, LeaveChannel: leaveChannelAction, - RemoveChannel: removeChannelAction + RemoveChannel: removeChannelAction, + ReplyToThread: replyToThread } }) diff --git a/plugins/chunter/src/index.ts b/plugins/chunter/src/index.ts index bde84675c0..5f3923e0aa 100644 --- a/plugins/chunter/src/index.ts +++ b/plugins/chunter/src/index.ts @@ -138,8 +138,6 @@ export default plugin(chunterId, { ChatMessagePresenter: '' as AnyComponent, ThreadMessagePresenter: '' as AnyComponent, ChatAside: '' as AnyComponent, - Replies: '' as AnyComponent, - ReplyToThreadAction: '' as AnyComponent, ChatMessagePreview: '' as AnyComponent, ThreadMessagePreview: '' as AnyComponent }, diff --git a/plugins/view-assets/lang/en.json b/plugins/view-assets/lang/en.json index 7aa2fbd22b..d7986cc0e5 100644 --- a/plugins/view-assets/lang/en.json +++ b/plugins/view-assets/lang/en.json @@ -119,6 +119,7 @@ "ToViewCommands": "to view available commands", "UnArchive": "Unarchive", "Pin": "Pin", - "Unpin": "Unpin" + "Unpin": "Unpin", + "MoreActions": "More actions" } } diff --git a/plugins/view-assets/lang/ru.json b/plugins/view-assets/lang/ru.json index 62000f761e..963168c039 100644 --- a/plugins/view-assets/lang/ru.json +++ b/plugins/view-assets/lang/ru.json @@ -116,6 +116,7 @@ "ToViewCommands": "чтобы увидеть команды", "UnArchive": "Разархивировать", "Pin": "Закрепить", - "Unpin": "Открепить" + "Unpin": "Открепить", + "MoreActions": "Больше действий" } } diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index f00dfa51e8..419083b2b3 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -194,7 +194,8 @@ const view = plugin(viewId, { Type: '' as IntlString, UnArchive: '' as IntlString, Save: '' as IntlString, - PublicView: '' as IntlString + PublicView: '' as IntlString, + MoreActions: '' as IntlString }, icon: { Table: '' as Asset,