Fix thread messages pin (#6129)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-07-25 10:40:06 +04:00 committed by GitHub
parent 27c626857a
commit 3b9318e34a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 104 additions and 37 deletions

View File

@ -92,7 +92,7 @@
skipLabels={!isDocChannel}
selectedFilters={filters}
startFromBottom
{selectedMessageId}
bind:selectedMessageId
{collection}
provider={dataProvider}
{isAsideOpened}

View File

@ -78,7 +78,7 @@
on:aside-toggled
on:close
>
<PinnedMessages {_id} {_class} />
<PinnedMessages {_id} {_class} on:select />
</Header>
</div>

View File

@ -55,7 +55,7 @@
export let scrollElement: HTMLDivElement | undefined = undefined
export let startFromBottom = false
export let selectedFilters: Ref<ActivityMessagesFilter>[] = []
export let withDates: boolean = true
export let embedded = false
export let collection: string | undefined = undefined
export let showEmbedded = false
export let skipLabels = false
@ -355,7 +355,7 @@
}
function updateSelectedDate (): void {
if (!withDates) {
if (embedded) {
return
}
@ -468,13 +468,13 @@
if (isLoading || !isScrollInitialized || isInitialScrolling) {
return
}
const msg = messages.find(({ _id }) => _id === selectedMessageId)
const msg = $metadataStore.find(({ _id }) => _id === selectedMessageId)
if (msg !== undefined) {
const isReload = provider.jumpToMessage(msg)
if (isReload) {
reinitializeScroll()
}
} else {
} else if (selectedMessageId === undefined) {
provider.jumpToEnd()
reinitializeScroll()
}
@ -677,7 +677,7 @@
{#if startFromBottom}
<div class="grower" />
{/if}
{#if withDates && displayMessages.length > 0 && selectedDate}
{#if !embedded && displayMessages.length > 0 && selectedDate}
<div class="selectedDate">
<JumpToDateSelector {selectedDate} fixed on:jumpToDate={jumpToDate} />
</div>
@ -702,7 +702,7 @@
{/if}
<slot name="header" />
{#if displayMessages.length === 0 && !hierarchy.isDerived(objectClass, activity.class.ActivityMessage)}
{#if displayMessages.length === 0 && !embedded}
<BlankView
icon={chunter.icon.Thread}
header={chunter.string.NoMessagesInChannel}
@ -717,7 +717,7 @@
<ActivityMessagesSeparator bind:element={separatorElement} label={activity.string.New} />
{/if}
{#if withDates && message.createdOn && $datesStore.includes(message.createdOn)}
{#if !embedded && message.createdOn && $datesStore.includes(message.createdOn)}
<JumpToDateSelector selectedDate={message.createdOn} on:jumpToDate={jumpToDate} />
{/if}
@ -741,7 +741,7 @@
{/if}
</Scroller>
{#if showScrollDownButton}
{#if !embedded && showScrollDownButton}
<div class="down-button absolute">
<ModernButton
label={chunter.string.LatestMessages}

View File

@ -16,23 +16,27 @@
import core, { Doc, getCurrentAccount, Ref, Space } from '@hcengineering/core'
import {
defineSeparators,
getCurrentLocation,
Label,
location as locationStore,
ModernButton,
navigate,
panelSeparators,
Separator
} from '@hcengineering/ui'
import { DocNotifyContext } from '@hcengineering/notification'
import { ActivityMessagesFilter } from '@hcengineering/activity'
import { ActivityMessage, ActivityMessagesFilter } from '@hcengineering/activity'
import { getClient } from '@hcengineering/presentation'
import { Channel } from '@hcengineering/chunter'
import view from '@hcengineering/view'
import { messageInFocus } from '@hcengineering/activity-resources'
import ChannelComponent from './Channel.svelte'
import ChannelHeader from './ChannelHeader.svelte'
import DocAside from './chat/DocAside.svelte'
import chunter from '../plugin'
import ChannelAside from './chat/ChannelAside.svelte'
import { isThreadMessage } from '../utils'
export let object: Doc
export let context: DocNotifyContext | undefined
@ -76,6 +80,18 @@
}
defineSeparators('aside', panelSeparators)
async function handleMessageSelect (event: CustomEvent<ActivityMessage>): Promise<void> {
const message = event.detail
if (isThreadMessage(message)) {
const location = getCurrentLocation()
location.path[4] = message.attachedTo
navigate(location)
}
messageInFocus.set(message._id)
}
</script>
<div class="popupPanel panel" class:embedded>
@ -89,6 +105,7 @@
canOpen={isDocChat}
{isAsideShown}
on:close
on:select={handleMessageSelect}
on:aside-toggled={() => {
isAsideShown = !isAsideShown
}}

View File

@ -19,32 +19,53 @@
import activity, { ActivityMessage } from '@hcengineering/activity'
import { Class, Doc, Ref } from '@hcengineering/core'
import view from '@hcengineering/view'
import { ThreadMessage } from '@hcengineering/chunter'
import { createEventDispatcher } from 'svelte'
import chunter from '../plugin'
export let _class: Ref<Class<Doc>>
export let _id: Ref<Doc>
const dispatch = createEventDispatcher()
const pinnedQuery = createQuery()
const pinnedThreadsQuery = createQuery()
let pinnedMessagesCount = 0
let pinnedThreadsCount = 0
$: pinnedQuery.query(
activity.class.ActivityMessage,
{ attachedTo: _id, isPinned: true },
(res: ActivityMessage[]) => {
pinnedMessagesCount = res.length
}
},
{ projection: { _id: 1, attachedTo: 1, isPinned: 1 } }
)
$: pinnedThreadsQuery.query(
chunter.class.ThreadMessage,
{ objectId: _id, isPinned: true },
(res: ThreadMessage[]) => {
pinnedThreadsCount = res.length
},
{ projection: { _id: 1, objectId: 1, isPinned: 1 } }
)
function openMessagesPopup (ev: MouseEvent) {
showPopup(PinnedMessagesPopup, { attachedTo: _id, attachedToClass: _class }, eventToHTMLElement(ev))
showPopup(PinnedMessagesPopup, { attachedTo: _id, attachedToClass: _class }, eventToHTMLElement(ev), (result) => {
if (result == null) return
dispatch('select', result)
})
}
$: count = pinnedMessagesCount + pinnedThreadsCount
</script>
{#if pinnedMessagesCount > 0}
{#if count > 0}
<div class="antiHSpacer x2" />
<ModernButton size={'extra-small'} on:click={openMessagesPopup}>
<Icon icon={view.icon.Pin} size={'x-small'} />
<span class="text-sm"><Label label={chunter.string.PinnedCount} params={{ count: pinnedMessagesCount }} /></span>
<span class="text-sm"><Label label={chunter.string.PinnedCount} params={{ count }} /></span>
</ModernButton>
{/if}

View File

@ -13,12 +13,13 @@
// limitations under the License.
-->
<script lang="ts">
import { Class, Doc, Ref } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
import { ActivityMessagePresenter } from '@hcengineering/activity-resources'
import { ActivityMessagePresenter, sortActivityMessages } from '@hcengineering/activity-resources'
import { ActionIcon, IconClose } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { ThreadMessage } from '@hcengineering/chunter'
import { Class, Doc, Ref, SortingOrder } from '@hcengineering/core'
import chunter from '../plugin'
@ -26,40 +27,54 @@
export let attachedToClass: Ref<Class<Doc>>
const client = getClient()
const hierarchy = client.getHierarchy()
const messagesQuery = createQuery()
const dispatch = createEventDispatcher()
const pinnedQuery = createQuery()
const pinnedThreadsQuery = createQuery()
let pinnedMessages: DisplayActivityMessage[] = []
let pinnedMessages: ActivityMessage[] = []
let pinnedThreads: ThreadMessage[] = []
$: messagesQuery.query(activity.class.ActivityMessage, { attachedTo, isPinned: true }, (res: ActivityMessage[]) => {
pinnedMessages = res as DisplayActivityMessage[]
if (pinnedMessages.length === 0) {
dispatch('close')
}
$: pinnedQuery.query(activity.class.ActivityMessage, { attachedTo, isPinned: true }, (res: ActivityMessage[]) => {
pinnedMessages = res
})
async function unPinMessaage (message: ActivityMessage): Promise<void> {
$: pinnedThreadsQuery.query(
chunter.class.ThreadMessage,
{ objectId: attachedTo, isPinned: true },
(res: ThreadMessage[]) => {
pinnedThreads = res
}
)
$: if (pinnedMessages.length === 0 && pinnedThreads.length === 0) {
dispatch('close', undefined)
}
async function unpinMessage (message: ActivityMessage): Promise<void> {
await client.update(message, { isPinned: false })
}
$: displayMessages = sortActivityMessages(pinnedMessages.concat(pinnedThreads), SortingOrder.Descending)
</script>
<div class="antiPopup vScroll popup">
{#each pinnedMessages as message}
{#each displayMessages as message}
<div class="message relative">
<ActivityMessagePresenter
value={message}
withActions={false}
hoverable={false}
skipLabel={!hierarchy.isDerived(attachedToClass, chunter.class.ChunterSpace)}
skipLabel={true}
onClick={() => {
dispatch('close', message)
}}
/>
<div class="actions">
<ActionIcon
size="small"
icon={IconClose}
action={() => {
unPinMessaage(message)
unpinMessage(message)
}}
/>
</div>

View File

@ -16,9 +16,9 @@
import { Doc, Ref } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import { Breadcrumbs, IconClose, Label, location as locationStore } from '@hcengineering/ui'
import { createEventDispatcher, onMount } from 'svelte'
import { createEventDispatcher, onDestroy } from 'svelte'
import activity, { ActivityMessage, DisplayActivityMessage } from '@hcengineering/activity'
import { getMessageFromLoc } from '@hcengineering/activity-resources'
import { getMessageFromLoc, messageInFocus } from '@hcengineering/activity-resources'
import contact from '@hcengineering/contact'
import chunter from '../../plugin'
@ -45,8 +45,23 @@
let channelName: string | undefined = undefined
let dataProvider: ChannelDataProvider | undefined = undefined
locationStore.subscribe((newLocation) => {
selectedMessageId = getMessageFromLoc(newLocation)
const unsubscribe = messageInFocus.subscribe((id) => {
if (id !== undefined && id !== selectedMessageId) {
selectedMessageId = id
}
messageInFocus.set(undefined)
})
const unsubscribeLocation = locationStore.subscribe((newLocation) => {
const id = getMessageFromLoc(newLocation)
selectedMessageId = id
messageInFocus.set(id)
})
onDestroy(() => {
unsubscribe()
unsubscribeLocation()
})
$: messageQuery.query(activity.class.ActivityMessage, { _id }, (result: ActivityMessage[]) => {
@ -111,14 +126,13 @@
<div class="container">
{#if message && dataProvider !== undefined}
<ChannelScrollView
{selectedMessageId}
withDates={false}
bind:selectedMessageId
embedded
skipLabels
object={message}
objectId={message._id}
objectClass={message._class}
provider={dataProvider}
loadMoreAllowed={false}
>
<svelte:fragment slot="header">
<div class="mt-3">