diff --git a/dev/tool/src/communication.ts b/dev/tool/src/communication.ts index a32cf2cf55..f5a3d6abc4 100644 --- a/dev/tool/src/communication.ts +++ b/dev/tool/src/communication.ts @@ -746,8 +746,10 @@ async function migrateMessages ( ): Promise { if (cards.length === 0) return - for (const card of cards) { - await createGroupsBlob(hulylake, card._id) + if (doc.__migratedUntil == null) { + for (const card of cards) { + await createGroupsBlob(hulylake, card._id) + } } const iterator = await getActivityCursor(db, ws.uuid, doc._id, chunter.class.ChatMessage, 400, doc.__migratedUntil) @@ -1139,6 +1141,16 @@ function toMessage (r: any): RawMessage | undefined { } function toAttachment (a: any): RawAttachment | undefined { + let metadata = a.metadata ?? {} + + if (typeof metadata === 'string') { + try { + metadata = JSON.parse(metadata) + } catch (e) { + metadata = {} + } + } + try { return { _id: a._id, @@ -1147,7 +1159,7 @@ function toAttachment (a: any): RawAttachment | undefined { type: a.type, name: a.name, size: Number(a.size ?? 0), - metadata: a.metadata ?? {}, + metadata, file: a.file } } catch (e) { diff --git a/models/chat/src/index.ts b/models/chat/src/index.ts index fc7db551cd..2a7d45e156 100644 --- a/models/chat/src/index.ts +++ b/models/chat/src/index.ts @@ -18,7 +18,7 @@ import core from '@hcengineering/model-core' import workbench from '@hcengineering/model-workbench' import { chatId } from '@hcengineering/chat' import { createSystemType } from '@hcengineering/model-card' -import communication, { MessagesNavigationAnchors } from '@hcengineering/communication' +import communication from '@hcengineering/communication' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' import chat from './plugin' @@ -55,8 +55,7 @@ export function createModel (builder: Builder): void { chat.string.Thread, chat.string.Threads, { - defaultSection: communication.ids.CardMessagesSection, - defaultNavigation: MessagesNavigationAnchors.LatestMessages + defaultSection: communication.ids.CardMessagesSection }, PaletteColorIndexes.Houseplant ) diff --git a/models/communication/src/index.ts b/models/communication/src/index.ts index c946db4ddd..7976885ab3 100644 --- a/models/communication/src/index.ts +++ b/models/communication/src/index.ts @@ -12,9 +12,6 @@ // limitations under the License. import { type Builder } from '@hcengineering/model' -import core from '@hcengineering/core' -import card from '@hcengineering/model-card' -import { MessagesNavigationAnchors } from '@hcengineering/communication' import communication from './plugin' import { buildTypes } from './types' @@ -29,27 +26,6 @@ export function createModel (builder: Builder): void { buildMessageActions(builder) buildCardActions(builder) buildApplets(builder) - - builder.createDoc( - card.class.CardSection, - core.space.Model, - { - label: communication.string.Messages, - component: communication.component.CardMessagesSection, - order: 9999, - navigation: [ - { - id: MessagesNavigationAnchors.ConversationStart, - label: communication.string.FirstMessages - }, - { - id: MessagesNavigationAnchors.LatestMessages, - label: communication.string.LatestMessages - } - ] - }, - communication.ids.CardMessagesSection - ) } export default communication diff --git a/models/communication/src/types.ts b/models/communication/src/types.ts index a45ef4d19b..007cfce056 100644 --- a/models/communication/src/types.ts +++ b/models/communication/src/types.ts @@ -25,8 +25,7 @@ import { type Poll, type CustomActivityPresenter, type GuestCommunicationSettings, - type AppletGetTitleFnResource, - MessagesNavigationAnchors + type AppletGetTitleFnResource } from '@hcengineering/communication' import { PaletteColorIndexes } from '@hcengineering/ui/src/colors' import { type AppletType } from '@hcengineering/communication-types' @@ -100,8 +99,7 @@ function defineDirect (builder: Builder): void { communication.string.Direct, communication.string.Directs, { - defaultSection: communication.ids.CardMessagesSection, - defaultNavigation: MessagesNavigationAnchors.LatestMessages + defaultSection: communication.ids.CardMessagesSection }, PaletteColorIndexes.Lavander ) diff --git a/packages/presentation/src/components/MessageViewer.svelte b/packages/presentation/src/components/MessageViewer.svelte index 761e4c91d4..2183a364a0 100644 --- a/packages/presentation/src/components/MessageViewer.svelte +++ b/packages/presentation/src/components/MessageViewer.svelte @@ -16,7 +16,7 @@
@@ -269,7 +232,7 @@ selected={toc.find((it) => it.id === selectedToc?.id)} position="right" on:select={(evt) => { - onNavigationClick(evt.detail) + handleNavigationClick(evt.detail) }} />
@@ -279,14 +242,12 @@ {hideBar} bottomPadding="var(--spacing-3)" disablePointerEventsOnScroll + disableOverscroll bind:divScroll={scrollDiv} onScroll={handleScroll} > -
- {#each sections as section, i} - - - {@const isLoadingBefore = false} +
+ {#each sections as section (section._id)}
{ handleSectionLoaded(section._id) @@ -315,15 +273,46 @@ />
{/each} +
+ { + renderTopSections = true + }} + on:top-hidden={() => { + renderTopSections = false + }} + on:loaded={() => { + handleSectionLoaded(messagesId) + }} + on:change={(ev) => { + handleChangeNavigation(messagesId, ev.detail) + }} + on:action={(ev) => { + handleAction(messagesId, ev.detail) + }} + /> +
- {#if toc.length > 0 && (bottomOffset > 400 || canScrollDown())} - {@const lastToc = toc[toc.length - 1]} - {#await getDownButtonTitle(lastToc, $languageStore) then title} -
- -
- {/await} + {#if toc.length > 0 && (bottomOffset > 400 || canScrollDown()) && selectedToc?.group === messagesId} +
+ +
{/if}
diff --git a/plugins/card-resources/src/components/sections/AttachmentsSection.svelte b/plugins/card-resources/src/components/sections/AttachmentsSection.svelte index 1a2d323ee7..6147dc81c1 100644 --- a/plugins/card-resources/src/components/sections/AttachmentsSection.svelte +++ b/plugins/card-resources/src/components/sections/AttachmentsSection.svelte @@ -20,6 +20,7 @@ export let readonly: boolean = false export let doc: Card + export let hidden: boolean = false const dispatch = createEventDispatcher() @@ -30,16 +31,18 @@ }) -
- dispatch('loaded')} - /> -
+{#if !hidden} +
+ dispatch('loaded')} + /> +
+{/if} diff --git a/plugins/card-resources/src/components/sections/PropertiesSection.svelte b/plugins/card-resources/src/components/sections/PropertiesSection.svelte index fec5a77ee6..996a89f534 100644 --- a/plugins/card-resources/src/components/sections/PropertiesSection.svelte +++ b/plugins/card-resources/src/components/sections/PropertiesSection.svelte @@ -23,6 +23,7 @@ export let readonly: boolean = false export let doc: Card + export let hidden: boolean = false const dispatch = createEventDispatcher() @@ -33,9 +34,11 @@ }) -
- -
+{#if !hidden} +
+ +
+{/if} diff --git a/plugins/communication-resources/src/components/input/BlobPreview.svelte b/plugins/communication-resources/src/components/input/BlobPreview.svelte new file mode 100644 index 0000000000..f6957e4693 --- /dev/null +++ b/plugins/communication-resources/src/components/input/BlobPreview.svelte @@ -0,0 +1,43 @@ + + + +
+ { + if (result !== undefined) { + dispatch('delete', blob.blobId) + } + }} + /> +
diff --git a/plugins/communication-resources/src/components/input/LinkPreview.svelte b/plugins/communication-resources/src/components/input/LinkPreview.svelte new file mode 100644 index 0000000000..1f72aa878e --- /dev/null +++ b/plugins/communication-resources/src/components/input/LinkPreview.svelte @@ -0,0 +1,32 @@ + + +
+ { + const result = event.detail + if (result !== undefined) { + dispatch('delete', link.url) + } + }} + /> +
diff --git a/plugins/communication-resources/src/components/message/MessageInput.svelte b/plugins/communication-resources/src/components/input/MessageInput.svelte similarity index 52% rename from plugins/communication-resources/src/components/message/MessageInput.svelte rename to plugins/communication-resources/src/components/input/MessageInput.svelte index 945cd3bb87..530a2f2e8f 100644 --- a/plugins/communication-resources/src/components/message/MessageInput.svelte +++ b/plugins/communication-resources/src/components/input/MessageInput.svelte @@ -14,35 +14,18 @@ --> @@ -586,11 +468,10 @@ on:change={fileSelected} />
- {#if draft.blobs.length > 0 || draft.links.length > 0 || draft.applets.length > 0} -
- {#each draft.applets as appletDraft} - {@const applet = applets.find((it) => it._id === appletDraft.appletId)} - {#if applet} - it.id === appletDraft.id) - }} - on:change={() => { - showPopup(applet.createComponent, { applet, params: appletDraft.params }, 'center', (result) => { - if (result != null) { - draft = { - ...draft, - applets: draft.applets.map((it) => { - if (it.id === appletDraft.id) { - return { ...it, params: result } - } - return it - }) - } - } - }) - }} - on:delete={() => { - draft = { - ...draft, - applets: draft.applets.filter((it) => it.id !== appletDraft.id) - } - }} - /> - {/if} - {/each} - {#each draft.blobs as attachedBlob (attachedBlob.blobId)} -
- { - if (result !== undefined) { - draft = { - ...draft, - blobs: draft.blobs.filter((it) => it.blobId !== attachedBlob.blobId) - } - - if ( - !message?.attachments?.some( - (it) => isBlobAttachment(it) && it.params.blobId === attachedBlob.blobId - ) - ) { - void deleteFile(attachedBlob.blobId) - } - } - }} - /> -
- {/each} - {#if draft.links.length > 0 && draft.blobs.length > 0} -
- {/if} - - {#each draft.links as link} -
- { - const result = event.detail - if (result !== undefined) { - previewUrls.set(result.url, false) - draft = { - ...draft, - links: draft.links.filter((it) => it.url !== result.url) - } - } - }} - /> -
- {/each} -
+ {#if attachmentsDraft.blobs.length > 0 || attachmentsDraft.links.length > 0 || attachmentsDraft.applets.length > 0 || progress} + {/if}
@@ -715,15 +509,4 @@ min-width: 0; width: 100%; } - - .divider { - height: 100%; - border-left: 1px solid var(--theme-divider-color); - } - .files-list { - overflow-x: auto; - overflow-y: hidden; - display: flex; - gap: 0.5rem; - } diff --git a/plugins/communication-resources/src/components/message/MessageBody.svelte b/plugins/communication-resources/src/components/message/MessageBody.svelte index 31532b6e5a..5f8ae41194 100644 --- a/plugins/communication-resources/src/components/message/MessageBody.svelte +++ b/plugins/communication-resources/src/components/message/MessageBody.svelte @@ -21,7 +21,7 @@ import { Label } from '@hcengineering/ui' import communication from '../../plugin' - import MessageInput from './MessageInput.svelte' + import MessageInput from '../input/MessageInput.svelte' import MessageContentViewer from './MessageContentViewer.svelte' import MessageFooter from './MessageFooter.svelte' import { diff --git a/plugins/communication-resources/src/components/message/MessageFooter.svelte b/plugins/communication-resources/src/components/message/MessageFooter.svelte index 1f1714454c..56c1739c14 100644 --- a/plugins/communication-resources/src/components/message/MessageFooter.svelte +++ b/plugins/communication-resources/src/components/message/MessageFooter.svelte @@ -14,7 +14,7 @@ --> @@ -65,8 +45,8 @@ {/if} - {#if threadCard && clientWidth > 300} - + {#if clientWidth > 300} + {/if} {#if threadCard && clientWidth > 300} diff --git a/plugins/communication-resources/src/components/thread/ThreadTags.svelte b/plugins/communication-resources/src/components/thread/ThreadTags.svelte index aa1cc8fcea..5d663a8b51 100644 --- a/plugins/communication-resources/src/components/thread/ThreadTags.svelte +++ b/plugins/communication-resources/src/components/thread/ThreadTags.svelte @@ -12,10 +12,26 @@ - +{#if card} + +{:else if clazz} + +{/if} diff --git a/plugins/communication-resources/src/draft.ts b/plugins/communication-resources/src/draft.ts index 0caa29aa45..f85183bd90 100644 --- a/plugins/communication-resources/src/draft.ts +++ b/plugins/communication-resources/src/draft.ts @@ -90,7 +90,7 @@ export function saveDraft (card: Ref, draft: MessageDraft, force = false): } else { timer = setTimeout(() => { localStorage.setItem(key, JSON.stringify(draft)) - }, 1000) + }, 3000) } } diff --git a/plugins/communication-resources/src/index.ts b/plugins/communication-resources/src/index.ts index c7143873a7..feb0df38e2 100644 --- a/plugins/communication-resources/src/index.ts +++ b/plugins/communication-resources/src/index.ts @@ -15,7 +15,6 @@ import { type Resources } from '@hcengineering/platform' -import CardMessagesSection from './components/CardMessagesSection.svelte' import PollPresenter from './components/poll/PollPresenter.svelte' import CreatePoll from './components/poll/CreatePoll.svelte' import PollPreview from './components/poll/PollPreview.svelte' @@ -47,16 +46,16 @@ export * from './stores' export { defaultMessageInputActions } from './utils' export { default as MessagePresenter } from './components/message/MessagePresenter.svelte' -export { default as MessageInput } from './components/message/MessageInput.svelte' +export { default as MessageInput } from './components/input/MessageInput.svelte' export { default as ActivityMessageViewer } from './components/message/ActivityMessageViewer.svelte' export { default as AttachmentsPreview } from './components/AttachmentsPreview.svelte' export { default as MessagePreview } from './components/MessagePreview.svelte' export { default as ExtendedMessagePreview } from './components/preview/ExtendedMessagePreview.svelte' export { default as PreviewTemplate } from './components/preview/PreviewTemplate.svelte' +export { default as MessagesSection } from './components/MessagesSection.svelte' export default async (): Promise => ({ component: { - CardMessagesSection, DirectIcon, CreateDirect }, diff --git a/plugins/communication-resources/src/plugin.ts b/plugins/communication-resources/src/plugin.ts index c48754cbd8..939c02b5db 100644 --- a/plugins/communication-resources/src/plugin.ts +++ b/plugins/communication-resources/src/plugin.ts @@ -89,7 +89,9 @@ export default mergeIds(communicationId, communication, { MessageAlreadyHasCardAttached: '' as IntlString, Direct: '' as IntlString, Directs: '' as IntlString, - Members: '' as IntlString + Members: '' as IntlString, + WriteMessageEllipsis: '' as IntlString, + EditMessageEllipsis: '' as IntlString }, messageActionImpl: { AddReaction: '' as MessageActionFunctionResource, diff --git a/plugins/communication-resources/src/types.ts b/plugins/communication-resources/src/types.ts index 29bfba5a36..f64443e37a 100644 --- a/plugins/communication-resources/src/types.ts +++ b/plugins/communication-resources/src/types.ts @@ -46,10 +46,13 @@ export interface AppletDraft { params: Record } +export type LinkPreviewDraft = LinkPreviewParams +export type BlobDraft = BlobParams & { mimeType: string } + export interface MessageDraft { _id: string content: Markup - blobs: Array - links: LinkPreviewParams[] + blobs: BlobDraft[] + links: LinkPreviewDraft[] applets: AppletDraft[] } diff --git a/plugins/communication/src/index.ts b/plugins/communication/src/index.ts index 307a86a60e..9854d12894 100644 --- a/plugins/communication/src/index.ts +++ b/plugins/communication/src/index.ts @@ -87,7 +87,8 @@ export default plugin(communicationId, { Voted: '' as IntlString, VotedFor: '' as IntlString, RevokedVote: '' as IntlString, - AnonymousQuiz: '' as IntlString + AnonymousQuiz: '' as IntlString, + ArrowDownMessages: '' as IntlString }, ids: { CardMessagesSection: '' as Ref, diff --git a/plugins/communication/src/types.ts b/plugins/communication/src/types.ts index 83ef43892e..8e6405a2f5 100644 --- a/plugins/communication/src/types.ts +++ b/plugins/communication/src/types.ts @@ -21,11 +21,6 @@ import { PersonSpace } from '@hcengineering/contact' export * from './poll' export * from './direct' -export enum MessagesNavigationAnchors { - ConversationStart = 'conversationStart', - LatestMessages = 'latestMessages' -} - export type MessageActionFunction = ( message: Message, card: Card, diff --git a/plugins/emoji/src/utils.ts b/plugins/emoji/src/utils.ts index 6e52bdcba8..24fd921d96 100644 --- a/plugins/emoji/src/utils.ts +++ b/plugins/emoji/src/utils.ts @@ -28,7 +28,7 @@ import { type ShortcodesDataset } from 'emojibase' import emojiPlugin from './plugin' -import { getResource } from '@hcengineering/platform' +import { getResource, getResourceP } from '@hcengineering/platform' import { ParsedTextWithEmojis } from './types' export const emojiRegex = new RegExp(`(?:^|\\s)(${EMOJI_REGEX.source})$`) @@ -81,4 +81,17 @@ async function loadParseEmojisFunction (): Promise<((text: string) => ParsedText } } -export { fetchEmojis, fetchMessages, loadParseEmojisFunction, type Locale } +function getParseEmojisFunction (): ((text: string) => ParsedTextWithEmojis) | undefined { + try { + const c = getResourceP(emojiPlugin.functions.ParseTextWithEmojis) + if (c instanceof Promise) { + return undefined + } + return c + } catch (e) { + console.log('Cannot locate emoji parsing function') + return undefined + } +} + +export { fetchEmojis, fetchMessages, loadParseEmojisFunction, type Locale, getParseEmojisFunction } diff --git a/plugins/inbox-resources/src/components/InboxApplication.svelte b/plugins/inbox-resources/src/components/InboxApplication.svelte index fed8e6bd91..6c62fc2ad8 100644 --- a/plugins/inbox-resources/src/components/InboxApplication.svelte +++ b/plugins/inbox-resources/src/components/InboxApplication.svelte @@ -90,7 +90,7 @@ if (docInfo._id !== doc?._id) { doc = await client.findOne(docInfo._class, { _id: docInfo._id }) - if (doc != null && !hierarchy.isDerived(doc._class, cardPlugin.class.Card)) { + if (doc != null) { const queryContext = loc.query?.context as Ref const ctx = $contextByIdStore.get(queryContext) ?? $contextByDocStore.get(thread) ?? $contextByDocStore.get(urlObjectId) diff --git a/plugins/process-resources/src/components/ProcessesCardSection.svelte b/plugins/process-resources/src/components/ProcessesCardSection.svelte index 4fcf02a89d..88bdc6e234 100644 --- a/plugins/process-resources/src/components/ProcessesCardSection.svelte +++ b/plugins/process-resources/src/components/ProcessesCardSection.svelte @@ -18,11 +18,14 @@ import ProcessesExtension from './ProcessesExtension.svelte' export let doc: Card + export let hidden: boolean = false -
- -
+{#if !hidden} +
+ +
+{/if}