mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-22 19:11:33 +03:00
UBERF-7489: Some more chat optimizations (#5999)
This commit is contained in:
parent
29f3198b69
commit
630ae21a66
@ -13,36 +13,36 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Doc, getDay, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import activity, {
|
||||
ActivityExtension,
|
||||
ActivityMessage,
|
||||
ActivityMessagesFilter,
|
||||
DisplayActivityMessage
|
||||
} from '@hcengineering/activity'
|
||||
import { Loading, Scroller, ScrollParams } from '@hcengineering/ui'
|
||||
import {
|
||||
ActivityExtension as ActivityExtensionComponent,
|
||||
ActivityMessagePresenter,
|
||||
canGroupMessages
|
||||
} from '@hcengineering/activity-resources'
|
||||
import { Class, Doc, getDay, Ref, Timestamp } from '@hcengineering/core'
|
||||
import { InboxNotificationsClientImpl } from '@hcengineering/notification-resources'
|
||||
import { get } from 'svelte/store'
|
||||
import { tick, beforeUpdate, afterUpdate, onMount, onDestroy } from 'svelte'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Loading, Scroller, ScrollParams } from '@hcengineering/ui'
|
||||
import { afterUpdate, beforeUpdate, onDestroy, onMount, tick } from 'svelte'
|
||||
import { get } from 'svelte/store'
|
||||
|
||||
import ActivityMessagesSeparator from './ChannelMessagesSeparator.svelte'
|
||||
import { ChannelDataProvider, MessageMetadata } from '../channelDataProvider'
|
||||
import {
|
||||
chatReadMessagesStore,
|
||||
filterChatMessages,
|
||||
getClosestDate,
|
||||
readChannelMessages,
|
||||
chatReadMessagesStore,
|
||||
recheckNotifications
|
||||
} from '../utils'
|
||||
import HistoryLoading from './LoadingHistory.svelte'
|
||||
import { ChannelDataProvider, MessageMetadata } from '../channelDataProvider'
|
||||
import ActivityMessagesSeparator from './ChannelMessagesSeparator.svelte'
|
||||
import JumpToDateSelector from './JumpToDateSelector.svelte'
|
||||
import HistoryLoading from './LoadingHistory.svelte'
|
||||
|
||||
export let provider: ChannelDataProvider
|
||||
export let object: Doc | undefined
|
||||
@ -313,6 +313,9 @@
|
||||
return messageRect.top >= containerRect.top && messageRect.bottom - messageRect.height / 2 <= containerRect.bottom
|
||||
}
|
||||
|
||||
const messagesToReadAccumulator: DisplayActivityMessage[] = []
|
||||
let messagesToReadAccumulatorTimer: any
|
||||
|
||||
function readViewportMessages (): void {
|
||||
if (!scrollElement || !scrollContentBox) {
|
||||
return
|
||||
@ -320,7 +323,6 @@
|
||||
|
||||
const containerRect = scrollElement.getBoundingClientRect()
|
||||
|
||||
const messagesToRead: DisplayActivityMessage[] = []
|
||||
const messagesElements = scrollContentBox?.getElementsByClassName('activityMessage')
|
||||
|
||||
for (const message of displayMessages) {
|
||||
@ -331,11 +333,15 @@
|
||||
}
|
||||
|
||||
if (messageInView(msgElement, containerRect)) {
|
||||
messagesToRead.push(message)
|
||||
messagesToReadAccumulator.push(message)
|
||||
}
|
||||
}
|
||||
|
||||
void readChannelMessages(messagesToRead, notifyContext)
|
||||
clearTimeout(messagesToReadAccumulatorTimer)
|
||||
messagesToReadAccumulatorTimer = setTimeout(() => {
|
||||
const messagesToRead = [...messagesToReadAccumulator]
|
||||
void readChannelMessages(messagesToRead, notifyContext)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function updateSelectedDate (): void {
|
||||
|
@ -12,24 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
import { type Channel, type ChatMessage, type DirectMessage, type ThreadMessage } from '@hcengineering/chunter'
|
||||
import contact, { type Employee, getName, type Person, type PersonAccount } from '@hcengineering/contact'
|
||||
import { employeeByIdStore, PersonIcon } from '@hcengineering/contact-resources'
|
||||
import {
|
||||
type Account,
|
||||
type Class,
|
||||
type Client,
|
||||
type Doc,
|
||||
getCurrentAccount,
|
||||
type IdMap,
|
||||
type Ref,
|
||||
type Space,
|
||||
type Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { type AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { type Asset, translate } from '@hcengineering/platform'
|
||||
import { classIcon, getDocLinkTitle, getDocTitle } from '@hcengineering/view-resources'
|
||||
import activity, {
|
||||
type ActivityMessage,
|
||||
type ActivityMessagesFilter,
|
||||
@ -37,19 +19,38 @@ import activity, {
|
||||
type DisplayDocUpdateMessage,
|
||||
type DocUpdateMessage
|
||||
} from '@hcengineering/activity'
|
||||
import { type Channel, type ChatMessage, type DirectMessage, type ThreadMessage } from '@hcengineering/chunter'
|
||||
import contact, { getName, type Employee, type Person, type PersonAccount } from '@hcengineering/contact'
|
||||
import { PersonIcon, employeeByIdStore } from '@hcengineering/contact-resources'
|
||||
import {
|
||||
generateId,
|
||||
getCurrentAccount,
|
||||
type Account,
|
||||
type Class,
|
||||
type Client,
|
||||
type Doc,
|
||||
type IdMap,
|
||||
type Ref,
|
||||
type Space,
|
||||
type Timestamp
|
||||
} from '@hcengineering/core'
|
||||
import notification, { type DocNotifyContext, type InboxNotification } from '@hcengineering/notification'
|
||||
import {
|
||||
archiveContextNotifications,
|
||||
InboxNotificationsClientImpl,
|
||||
archiveContextNotifications,
|
||||
isActivityNotification,
|
||||
isMentionNotification
|
||||
} from '@hcengineering/notification-resources'
|
||||
import notification, { type DocNotifyContext } from '@hcengineering/notification'
|
||||
import { get, type Unsubscriber, writable } from 'svelte/store'
|
||||
import { translate, type Asset } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { type AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { classIcon, getDocLinkTitle, getDocTitle } from '@hcengineering/view-resources'
|
||||
import { get, writable, type Unsubscriber } from 'svelte/store'
|
||||
|
||||
import chunter from './plugin'
|
||||
import DirectIcon from './components/DirectIcon.svelte'
|
||||
import ChannelIcon from './components/ChannelIcon.svelte'
|
||||
import DirectIcon from './components/DirectIcon.svelte'
|
||||
import { resetChunterLocIfEqual } from './navigation'
|
||||
import chunter from './plugin'
|
||||
|
||||
export async function getDmName (client: Client, space?: Space): Promise<string> {
|
||||
if (space === undefined) {
|
||||
@ -366,6 +367,9 @@ function getAllIds (messages: DisplayActivityMessage[]): Array<Ref<ActivityMessa
|
||||
.flat()
|
||||
}
|
||||
|
||||
let toReadTimer: any
|
||||
const toRead = new Set<Ref<InboxNotification>>()
|
||||
|
||||
export function recheckNotifications (context: DocNotifyContext): void {
|
||||
const client = getClient()
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
@ -378,7 +382,7 @@ export function recheckNotifications (context: DocNotifyContext): void {
|
||||
|
||||
const notifications = get(inboxClient.inboxNotificationsByContext).get(context._id) ?? []
|
||||
|
||||
const toRead = notifications
|
||||
notifications
|
||||
.filter((it) => {
|
||||
if (it.isViewed) {
|
||||
return false
|
||||
@ -394,9 +398,18 @@ export function recheckNotifications (context: DocNotifyContext): void {
|
||||
|
||||
return false
|
||||
})
|
||||
.map((n) => n._id)
|
||||
.forEach((n) => toRead.add(n._id))
|
||||
|
||||
void inboxClient.readNotifications(client, toRead)
|
||||
clearTimeout(toReadTimer)
|
||||
toReadTimer = setTimeout(() => {
|
||||
const toReadData = Array.from(toRead)
|
||||
toRead.clear()
|
||||
void (async () => {
|
||||
const _client = client.apply(generateId())
|
||||
await inboxClient.readNotifications(_client, toReadData)
|
||||
await _client.commit()
|
||||
})()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
export async function readChannelMessages (
|
||||
@ -408,38 +421,42 @@ export async function readChannelMessages (
|
||||
}
|
||||
|
||||
const inboxClient = InboxNotificationsClientImpl.getClient()
|
||||
const client = getClient()
|
||||
|
||||
const readMessages = get(chatReadMessagesStore)
|
||||
const allIds = getAllIds(messages).filter((id) => !readMessages.has(id))
|
||||
const client = getClient().apply(generateId())
|
||||
try {
|
||||
const readMessages = get(chatReadMessagesStore)
|
||||
const allIds = getAllIds(messages).filter((id) => !readMessages.has(id))
|
||||
|
||||
const notifications = get(inboxClient.activityInboxNotifications)
|
||||
.filter(({ _id, attachedTo }) => allIds.includes(attachedTo))
|
||||
.map((n) => n._id)
|
||||
const notifications = get(inboxClient.activityInboxNotifications)
|
||||
.filter(({ _id, attachedTo }) => allIds.includes(attachedTo))
|
||||
.map((n) => n._id)
|
||||
|
||||
const relatedMentions = get(inboxClient.otherInboxNotifications)
|
||||
.filter((n) => !n.isViewed && isMentionNotification(n) && allIds.includes(n.mentionedIn as Ref<ActivityMessage>))
|
||||
.map((n) => n._id)
|
||||
const relatedMentions = get(inboxClient.otherInboxNotifications)
|
||||
.filter((n) => !n.isViewed && isMentionNotification(n) && allIds.includes(n.mentionedIn as Ref<ActivityMessage>))
|
||||
.map((n) => n._id)
|
||||
|
||||
chatReadMessagesStore.update((store) => new Set([...store, ...allIds]))
|
||||
chatReadMessagesStore.update((store) => new Set([...store, ...allIds]))
|
||||
|
||||
void inboxClient.readNotifications(client, [...notifications, ...relatedMentions])
|
||||
await inboxClient.readNotifications(client, [...notifications, ...relatedMentions])
|
||||
|
||||
if (context === undefined) {
|
||||
return
|
||||
}
|
||||
if (context === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
const storedTimestampUpdates = get(contextsTimestampStore).get(context._id)
|
||||
const newTimestamp = messages[messages.length - 1].createdOn ?? 0
|
||||
const prevTimestamp = Math.max(storedTimestampUpdates ?? 0, context.lastViewedTimestamp ?? 0)
|
||||
const storedTimestampUpdates = get(contextsTimestampStore).get(context._id)
|
||||
const newTimestamp = messages[messages.length - 1].createdOn ?? 0
|
||||
const prevTimestamp = Math.max(storedTimestampUpdates ?? 0, context.lastViewedTimestamp ?? 0)
|
||||
|
||||
if (prevTimestamp < newTimestamp) {
|
||||
context.lastViewedTimestamp = newTimestamp
|
||||
contextsTimestampStore.update((store) => {
|
||||
store.set(context._id, newTimestamp)
|
||||
return store
|
||||
})
|
||||
void client.update(context, { lastViewedTimestamp: newTimestamp })
|
||||
if (prevTimestamp < newTimestamp) {
|
||||
context.lastViewedTimestamp = newTimestamp
|
||||
contextsTimestampStore.update((store) => {
|
||||
store.set(context._id, newTimestamp)
|
||||
return store
|
||||
})
|
||||
await client.update(context, { lastViewedTimestamp: newTimestamp })
|
||||
}
|
||||
} finally {
|
||||
await client.commit()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { type Blob, type Ref } from '@hcengineering/core'
|
||||
import { getBlobRef, type BlobMetadata } from '@hcengineering/presentation'
|
||||
import { Loading } from '@hcengineering/ui'
|
||||
|
||||
export let value: Blob | Ref<Blob>
|
||||
export let name: string
|
||||
@ -26,15 +27,25 @@
|
||||
$: height = metadata?.originalHeight
|
||||
? `min(${metadata.originalHeight / metadata?.pixelRatio ?? 1}px, ${fit ? '100%' : '80vh'})`
|
||||
: '100%'
|
||||
let loading = true
|
||||
</script>
|
||||
|
||||
{#await p then blobRef}
|
||||
{#if loading}
|
||||
<div class="flex justify-center">
|
||||
<Loading />
|
||||
</div>
|
||||
{/if}
|
||||
<img
|
||||
on:load={(evt) => {
|
||||
loading = false
|
||||
}}
|
||||
class="object-contain mx-auto"
|
||||
style:max-width={width}
|
||||
style:max-height={height}
|
||||
src={blobRef.src}
|
||||
srcset={blobRef.srcset}
|
||||
alt={name}
|
||||
style:height={loading ? '0' : ''}
|
||||
/>
|
||||
{/await}
|
||||
|
@ -1198,6 +1198,10 @@ export async function restore (
|
||||
async function sendChunk (doc: Doc | undefined, len: number): Promise<void> {
|
||||
if (doc !== undefined) {
|
||||
docsToAdd.delete(doc._id)
|
||||
if (opt.recheck === true) {
|
||||
// We need to clear %hash% in case our is wrong.
|
||||
delete (doc as any)['%hash%']
|
||||
}
|
||||
docs.push(doc)
|
||||
}
|
||||
sendSize = sendSize + len
|
||||
|
@ -15,7 +15,7 @@
|
||||
//
|
||||
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { MeasureContext, Blob as PlatformBlob, WorkspaceId, metricsAggregate } from '@hcengineering/core'
|
||||
import { MeasureContext, Blob as PlatformBlob, WorkspaceId, metricsAggregate, type Ref } from '@hcengineering/core'
|
||||
import { Token, decodeToken } from '@hcengineering/server-token'
|
||||
import { StorageAdapter, removeAllObjects } from '@hcengineering/storage'
|
||||
import bp from 'body-parser'
|
||||
@ -798,8 +798,22 @@ async function getGeneratePreview (
|
||||
pipeline.destroy()
|
||||
|
||||
// Add support of avif as well.
|
||||
await config.storageAdapter.put(ctx, payload.workspace, sizeId, dataBuff, contentType, dataBuff.length)
|
||||
return (await config.storageAdapter.stat(ctx, payload.workspace, sizeId)) ?? blob
|
||||
const upload = await config.storageAdapter.put(
|
||||
ctx,
|
||||
payload.workspace,
|
||||
sizeId,
|
||||
dataBuff,
|
||||
contentType,
|
||||
dataBuff.length
|
||||
)
|
||||
return {
|
||||
...blob,
|
||||
_id: sizeId as Ref<PlatformBlob>,
|
||||
size: dataBuff.length,
|
||||
contentType,
|
||||
etag: upload.etag,
|
||||
storageId: sizeId
|
||||
}
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
ctx.error('failed to resize image', {
|
||||
|
Loading…
Reference in New Issue
Block a user