diff --git a/src/components/ChatView.vue b/src/components/ChatView.vue index 5f202470f2e..0f5ad4b61c9 100644 --- a/src/components/ChatView.vue +++ b/src/components/ChatView.vue @@ -211,7 +211,8 @@ export default { }, scrollToBottom() { - this.$router.replace({ hash: '' }) + // Reset the hash from focused message id (but keep the thread id) + this.$router.replace({ query: this.$route.query, hash: '' }) EventBus.emit('scroll-chat-to-bottom', { smooth: false, force: true }) }, }, diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index b92c8ffb2b9..5af165be43c 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -213,14 +213,9 @@ export default { * @return {Array} */ messagesList() { - if (!this.threadId) { - return this.chatStore.getMessagesList(this.token) - } - - return this.chatStore.getMessagesList(this.token) - .filter((message) => { - return message.threadId === this.threadId - }) + return this.chatStore.getMessagesList(this.token, { + threadId: this.threadId, + }) }, isMessagesListPopulated() { diff --git a/src/components/NewMessage/NewMessage.vue b/src/components/NewMessage/NewMessage.vue index d2c63d4084d..40c5a6b8f37 100644 --- a/src/components/NewMessage/NewMessage.vue +++ b/src/components/NewMessage/NewMessage.vue @@ -967,7 +967,9 @@ export default { } // last message within 24 hours - const lastMessageByCurrentUser = this.chatStore.getMessagesList(this.token).findLast((message) => { + const lastMessageByCurrentUser = this.chatStore.getMessagesList(this.token, { + threadId: this.threadId, + }).findLast((message) => { return this.actorStore.checkIfSelfIsActor(message) && !message.isTemporary && !message.systemMessage && (Date.now() - message.timestamp * 1000 < ONE_DAY_IN_MS) diff --git a/src/composables/useDocumentTitle.ts b/src/composables/useDocumentTitle.ts index 1848bcb4add..a979b06c0c6 100644 --- a/src/composables/useDocumentTitle.ts +++ b/src/composables/useDocumentTitle.ts @@ -125,7 +125,7 @@ export function useDocumentTitle() { } else { // @ts-expect-error: Property 'id' does not exist on type ChatProxyMessage const lastMessageId = lastMessage.id ?? 0 - const lastKnownMessageId = Math.max(...chatStore.chatBlocks[token][0]) ?? 0 + const lastKnownMessageId = chatStore.chatBlocks[token] ? Math.max(...chatStore.chatBlocks[token][0]) : 0 acc[token].lastMessageId = Math.max(lastMessageId, lastKnownMessageId) } acc[token].unreadMessages = unreadMessages diff --git a/src/composables/useGetMessages.ts b/src/composables/useGetMessages.ts index 0e8eeff5197..10f2c0e3a99 100644 --- a/src/composables/useGetMessages.ts +++ b/src/composables/useGetMessages.ts @@ -177,7 +177,7 @@ export function useGetMessagesProvider() { const hasMessageInStore = ('id' in (store.getters.message(to.params.token, focusMessageId) as ChatMessage | Record)) if (!hasMessageInStore) { // message not found in the list, need to fetch it first - await getMessageContext(to.params.token, focusMessageId) + await getMessageContext(to.params.token, focusMessageId, threadId.value) } // need some delay (next tick is too short) to be able to run // after the browser's native "scroll to anchor" from the hash @@ -191,7 +191,7 @@ export function useGetMessagesProvider() { // FIXME temporary get thread messages from the start const hasMessageInStore = ('id' in (store.getters.message(to.params.token, to.query.threadId) as ChatMessage | Record)) if (!hasMessageInStore) { - await getMessageContext(to.params.token, +to.query.threadId) + await getMessageContext(to.params.token, +to.query.threadId, +to.query.threadId) } } } @@ -222,7 +222,7 @@ export function useGetMessagesProvider() { throw new Error(`[DEBUG] spreed: context message ID is ${startingMessageId}`) } - await getMessageContext(token, startingMessageId) + await getMessageContext(token, startingMessageId, threadId.value) } catch (exception) { console.debug(exception) // Request was cancelled, stop getting preconditions and restore initial state @@ -242,9 +242,10 @@ export function useGetMessagesProvider() { * Fetches the messages of a conversation given the conversation token. * Creates a long polling request for new messages. * @param token token of conversation where a method was called - * @param messageId messageId + * @param messageId context messageId + * @param threadId context thread id */ - async function getMessageContext(token: string, messageId: number) { + async function getMessageContext(token: string, messageId: number, threadId: number) { loadingOldMessages.value = true try { debugTimer.start(`${token} | get context`) @@ -258,6 +259,7 @@ export function useGetMessagesProvider() { // using 0 as the API does not support negative values // Get chat messages before last read message and after it messageId: messageId !== MESSAGE.CHAT_BEGIN_ID ? messageId : 0, + threadId: threadId !== 0 ? threadId : undefined, minimumVisible: CHAT.MINIMUM_VISIBLE, }) debugTimer.end(`${token} | get context`, 'status 200') @@ -301,6 +303,7 @@ export function useGetMessagesProvider() { token, lastKnownMessageId: store.getters.getFirstKnownMessageId(token), includeLastKnown, + threadId: threadId.value !== 0 ? threadId.value : undefined, minimumVisible: CHAT.MINIMUM_VISIBLE, }) debugTimer.end(`${token} | fetch history`, 'status 200') diff --git a/src/services/messagesService.ts b/src/services/messagesService.ts index 0b958d373a3..93ca04717ac 100644 --- a/src/services/messagesService.ts +++ b/src/services/messagesService.ts @@ -49,6 +49,7 @@ type EditMessagePayload = { token: string, messageId: number, updatedMessage: ed * @param data.token the conversation token; * @param data.lastKnownMessageId last known message id; * @param data.includeLastKnown whether to include the last known message in the response; + * @param data.threadId The thread id to retrieve data * @param [data.lookIntoFuture=0] direction of message fetch * @param [data.limit=100] Number of messages to load * @param [options] Axios request options @@ -110,6 +111,7 @@ async function pollNewMessages({ * @param data the wrapping object; * @param data.token the conversation token; * @param data.messageId last known message id; + * @param data.threadId The thread id to retrieve data * @param [data.limit=50] Number of messages to load * @param [options] Axios request options */ diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index 1b823e0c075..34bfc9b0c0e 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -936,6 +936,7 @@ const actions = { * @param {string} data.token the conversation token; * @param {object} data.requestOptions request options; * @param {string} data.lastKnownMessageId last known message id; + * @param {number} data.threadId Thread id to fetch messages for; * @param {number} data.minimumVisible Minimum number of chat messages we want to load * @param {boolean} data.includeLastKnown whether to include the last known message in the response; * @param {number} [data.lookIntoFuture=0] direction of message fetch @@ -944,6 +945,7 @@ const actions = { token, lastKnownMessageId, includeLastKnown, + threadId, requestOptions, minimumVisible, lookIntoFuture = CHAT.FETCH_OLD, @@ -961,6 +963,7 @@ const actions = { token, lastKnownMessageId, includeLastKnown, + threadId, lookIntoFuture, limit: CHAT.FETCH_LIMIT, }, requestOptions) @@ -1018,6 +1021,7 @@ const actions = { const chatStore = useChatStore() chatStore.processChatBlocks(token, response.data.ocs.data, { mergeBy: +lastKnownMessageId, + threadId, }) if (minimumVisible > 0) { @@ -1031,6 +1035,7 @@ const actions = { token, lastKnownMessageId, includeLastKnown, + threadId, lookIntoFuture, minimumVisible, }) @@ -1047,10 +1052,17 @@ const actions = { * @param {object} data the wrapping object; * @param {string} data.token the conversation token; * @param {number} data.messageId Message id to get the context for; + * @param {number} data.threadId Thread id to get the context for; * @param {object} data.requestOptions request options; * @param {number} data.minimumVisible Minimum number of chat messages we want to load */ - async getMessageContext(context, { token, messageId, requestOptions, minimumVisible }) { + async getMessageContext(context, { + token, + messageId, + threadId, + requestOptions, + minimumVisible, + }) { minimumVisible = (typeof minimumVisible === 'undefined') ? Math.floor(CHAT.MINIMUM_VISIBLE / 2) : minimumVisible context.dispatch('cancelGetMessageContext') @@ -1063,6 +1075,7 @@ const actions = { const response = await request({ token, messageId, + threadId, limit: CHAT.FETCH_LIMIT / 2, }, requestOptions) @@ -1116,7 +1129,7 @@ const actions = { context.commit('loadedMessagesOfConversation', { token }) const chatStore = useChatStore() - chatStore.processChatBlocks(token, response.data.ocs.data) + chatStore.processChatBlocks(token, response.data.ocs.data, { threadId }) if (minimumVisible > 0) { debugTimer.tick(`${token} | get context`, 'first chunk') @@ -1126,6 +1139,7 @@ const actions = { token, lastKnownMessageId: context.getters.getFirstKnownMessageId(token), includeLastKnown: false, + threadId, lookIntoFuture: CHAT.FETCH_OLD, minimumVisible: minimumVisible * 2, }) diff --git a/src/stores/__tests__/chat.spec.js b/src/stores/__tests__/chat.spec.js index 17eff5cb0a0..4ac904a3c9d 100644 --- a/src/stores/__tests__/chat.spec.js +++ b/src/stores/__tests__/chat.spec.js @@ -20,19 +20,24 @@ describe('chatStore', () => { * | | [109,108] | | [106,105] | | [103,102,101] | * | D | | E | | F | | * | [110] | | [108,107,106] | | [104] | | + * + * Threads are as follows: + * - 101, 103, 106 are in thread 101 + * - 104, 107, 109 are in thread 104 + * - 102, 105, 108, 110 are not in any thread */ const mockMessages = { - 101: { id: 101, message: 'Hello' }, - 102: { id: 102, message: 'World' }, - 103: { id: 103, message: '!' }, - 104: { id: 104, message: 'Lorem ipsum' }, - 105: { id: 105, message: 'dolor sit amet' }, - 106: { id: 106, message: 'consectetur adipiscing elit' }, - 107: { id: 107, message: 'Vestibulum quis' }, - 108: { id: 108, message: 'sed diam nonumy' }, - 109: { id: 109, message: 'eirmod tempor invidunt' }, - 110: { id: 110, message: 'ut labore et dolore' }, + 101: { id: 101, threadId: 101, isThread: true, message: 'Hello' }, + 102: { id: 102, threadId: 102, isThread: false, message: 'World' }, + 103: { id: 103, threadId: 101, isThread: true, message: '!' }, + 104: { id: 104, threadId: 104, isThread: true, message: 'Lorem ipsum' }, + 105: { id: 105, threadId: 105, isThread: false, message: 'dolor sit amet' }, + 106: { id: 106, threadId: 101, isThread: true, message: 'consectetur adipiscing elit' }, + 107: { id: 107, threadId: 104, isThread: true, message: 'Vestibulum quis' }, + 108: { id: 108, threadId: 108, isThread: false, message: 'sed diam nonumy' }, + 109: { id: 109, threadId: 104, isThread: true, message: 'eirmod tempor invidunt' }, + 110: { id: 110, threadId: 110, isThread: false, message: 'ut labore et dolore' }, } const chatBlockA = [mockMessages[109], mockMessages[108]] @@ -46,6 +51,13 @@ describe('chatStore', () => { return new Set([...messages, ...rest.flat()].map((message) => message.id)) } + function processMessages(token, messages, chatBlockOptions = {}) { + messages.forEach((message) => { + vuexStore.dispatch('processMessage', { token, message }) + }) + chatStore.processChatBlocks(token, messages, chatBlockOptions) + } + beforeEach(() => { vuexStore = createStore(storeConfig) jest.spyOn(require('vuex'), 'useStore').mockReturnValue(vuexStore) @@ -69,25 +81,41 @@ describe('chatStore', () => { it('returns boolean whether message is known by the store', () => { // Act - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Assert expect(chatStore.hasMessage(TOKEN, { messageId: mockMessages[109].id })).toBeTruthy() expect(chatStore.hasMessage(TOKEN, { messageId: mockMessages[101].id })).toBeFalsy() }) + + it('returns boolean whether thread message is known by the store', () => { + // Act + processMessages(TOKEN, chatBlockA) + + // Assert + expect(chatStore.hasMessage(TOKEN, { messageId: mockMessages[109].id, threadId: 104 })).toBeTruthy() + expect(chatStore.hasMessage(TOKEN, { messageId: mockMessages[108].id, threadId: 104 })).toBeFalsy() + }) }) describe('get a list of messages', () => { it('returns an array if both messages and blocks present', () => { // Arrange - vuexStore.dispatch('processMessage', { token: TOKEN, message: mockMessages[110] }) - vuexStore.dispatch('processMessage', { token: TOKEN, message: mockMessages[109] }) - chatStore.processChatBlocks(TOKEN, [mockMessages[110], mockMessages[109]]) + processMessages(TOKEN, [mockMessages[110], mockMessages[109]]) // Assert expect(chatStore.getMessagesList(TOKEN)).toEqual([mockMessages[109], mockMessages[110]]) }) + it('returns an array of thread messages only', () => { + // Arrange + processMessages(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockE) + + // Assert + expect(chatStore.getMessagesList(TOKEN, { threadId: 101 })).toEqual([mockMessages[101], mockMessages[103], mockMessages[106]]) + }) + it('returns an empty array if no messages or blocks present', () => { // Arrange vuexStore.dispatch('processMessage', { token: 'token1', message: mockMessages[109] }) @@ -107,10 +135,19 @@ describe('chatStore', () => { expect(chatStore.getFirstKnownId(TOKEN, { messageId: mockMessages[109].id })).toBe(mockMessages[109].id) }) + it('returns thread id of containing block if thread id was given and message is in the store', () => { + // Act + processMessages(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockB) + + // Assert + expect(chatStore.getFirstKnownId(TOKEN, { messageId: chatBlockB[0].id, threadId: 101 })).toBe(chatBlockC[2].id) + }) + it('returns first / last known id of first block if no message id was given', () => { // Act - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockE) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockE) // Assert expect(chatStore.getLastKnownId(TOKEN)).toBe(chatBlockA[0].id) @@ -119,8 +156,8 @@ describe('chatStore', () => { it('returns first / last known id of first block if no message id was given', () => { // Act - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockC) // Assert expect(chatStore.getLastKnownId(TOKEN, { messageId: chatBlockB[0].id })).toBe(chatBlockA[0].id) @@ -129,19 +166,29 @@ describe('chatStore', () => { it('returns first / last known id of containing block if message id was given', () => { // Act - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) // Assert expect(chatStore.getLastKnownId(TOKEN, { messageId: chatBlockB[0].id })).toBe(chatBlockB[0].id) expect(chatStore.getFirstKnownId(TOKEN, { messageId: chatBlockB[0].id })).toBe(chatBlockB[1].id) }) + + it('returns first / last known id of containing thread block if message id was given', () => { + // Act + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) + + // Assert + expect(chatStore.getLastKnownId(TOKEN, { messageId: chatBlockB[0].id, threadId: 101 })).toBe(chatBlockB[0].id) + expect(chatStore.getFirstKnownId(TOKEN, { messageId: chatBlockB[0].id, threadId: 101 })).toBe(chatBlockB[0].id) + }) }) describe('process messages chunks', () => { it('creates a new block, if not created yet', () => { // Act - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Assert expect(chatStore.chatBlocks[TOKEN]).toEqual([outputSet(chatBlockA)]) @@ -149,10 +196,10 @@ describe('chatStore', () => { it('extends an existing block, if messages overlap', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Act - chatStore.processChatBlocks(TOKEN, chatBlockE) + processMessages(TOKEN, chatBlockE) // Assert expect(chatStore.chatBlocks[TOKEN]).toHaveLength(1) @@ -161,10 +208,10 @@ describe('chatStore', () => { it('creates a new block, if adjacent status to existing blocks is unknown', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Act - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockB) // Assert expect(chatStore.chatBlocks[TOKEN]).toHaveLength(2) @@ -173,12 +220,12 @@ describe('chatStore', () => { it('extends an existing block, if messages are adjacent by options.mergeBy', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) // Act - chatStore.processChatBlocks(TOKEN, chatBlockD, { mergeBy: mockMessages[109].id }) - chatStore.processChatBlocks(TOKEN, chatBlockF, { mergeBy: mockMessages[105].id }) + processMessages(TOKEN, chatBlockD, { mergeBy: mockMessages[109].id }) + processMessages(TOKEN, chatBlockF, { mergeBy: mockMessages[105].id }) // Assert expect(chatStore.chatBlocks[TOKEN]).toHaveLength(2) @@ -187,13 +234,13 @@ describe('chatStore', () => { it('merges existing blocks, if resulting sets overlap', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) expect(chatStore.chatBlocks[TOKEN]).toHaveLength(2) // Act - chatStore.processChatBlocks(TOKEN, chatBlockF, { mergeBy: mockMessages[105].id }) - chatStore.processChatBlocks(TOKEN, chatBlockE) + processMessages(TOKEN, chatBlockF, { mergeBy: mockMessages[105].id }) + processMessages(TOKEN, chatBlockE) // Assert expect(chatStore.chatBlocks[TOKEN]).toHaveLength(1) @@ -202,11 +249,11 @@ describe('chatStore', () => { it('retains the correct order of blocks', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockC) // Act - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockB) // Assert expect(chatStore.chatBlocks[TOKEN]).toHaveLength(3) @@ -225,8 +272,8 @@ describe('chatStore', () => { it('extends the most recent block', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) // Act chatStore.addMessageToChatBlocks(TOKEN, chatBlockD[0]) @@ -237,7 +284,7 @@ describe('chatStore', () => { it('does nothing, if message is already present in the most recent block', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Act chatStore.addMessageToChatBlocks(TOKEN, chatBlockA[0]) @@ -258,7 +305,7 @@ describe('chatStore', () => { it('does nothing, if message is not present in existing blocks', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Act chatStore.removeMessagesFromChatBlocks(TOKEN, chatBlockD[0].id) @@ -269,7 +316,7 @@ describe('chatStore', () => { it('removes a message id from all blocks', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockA) // Act chatStore.removeMessagesFromChatBlocks(TOKEN, chatBlockA[0].id) @@ -280,8 +327,8 @@ describe('chatStore', () => { it('removes a list of message ids and clears up empty blocks', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) // Act chatStore.removeMessagesFromChatBlocks(TOKEN, chatBlockB.map((message) => message.id)) @@ -293,8 +340,8 @@ describe('chatStore', () => { it('clears up store after removing of all blocks', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockB) - chatStore.processChatBlocks(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) // Act chatStore.removeMessagesFromChatBlocks(TOKEN, chatBlockB.map((message) => message.id)) @@ -316,8 +363,8 @@ describe('chatStore', () => { it('does nothing, if no blocks are behind id to delete', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockA) - chatStore.processChatBlocks(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockA) + processMessages(TOKEN, chatBlockB) // Act chatStore.clearMessagesHistory(TOKEN, chatBlockC[0].id) @@ -328,8 +375,8 @@ describe('chatStore', () => { it('purges a store, if all blocks are behind id to delete', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockB) - chatStore.processChatBlocks(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockC) // Act chatStore.clearMessagesHistory(TOKEN, chatBlockA[0].id) @@ -340,8 +387,8 @@ describe('chatStore', () => { it('cleans up messages behind id to delete', () => { // Arrange - chatStore.processChatBlocks(TOKEN, chatBlockB) - chatStore.processChatBlocks(TOKEN, chatBlockC) + processMessages(TOKEN, chatBlockB) + processMessages(TOKEN, chatBlockC) // Act chatStore.clearMessagesHistory(TOKEN, chatBlockB[0].id) diff --git a/src/stores/chat.ts b/src/stores/chat.ts index 7f777b2fe7d..3da41b223c9 100644 --- a/src/stores/chat.ts +++ b/src/stores/chat.ts @@ -22,6 +22,8 @@ type GetMessagesListOptions = { type ProcessChatBlocksOptions = { /** if given, look for Set that has it */ mergeBy?: number + /** if given, look for thread Set */ + threadId?: number } /** @@ -48,12 +50,23 @@ export const useChatStore = defineStore('chat', () => { /** * Returns list of messages, belonging to current context */ - function getMessagesList(token: string): ChatMessage[] { + function getMessagesList( + token: string, + { messageId = 0, threadId = 0 }: GetMessagesListOptions = { messageId: 0, threadId: 0 }, + ): ChatMessage[] { if (!store.state.messagesStore.messages[token] || !chatBlocks[token]) { return [] } - // FIXME temporary show all messages for given thread from all chat blocks - no behaviour change + if (threadId) { + // FIXME temporary show all messages for given thread from all chat blocks - no behaviour change + return prepareMessagesList(token, new Set(chatBlocks[token].flatMap((set) => Array.from(set)))) + .filter((message) => { + return message.threadId === threadId + }) + } + + // FIXME temporary show all messages for given token from all chat blocks - no behaviour change const contextBlock = chatBlocks[token].reduce>((acc, set) => { set.forEach((id) => acc.add(id)) return acc @@ -66,7 +79,6 @@ export const useChatStore = defineStore('chat', () => { */ function prepareMessagesList(token: string, block: Set): ChatMessage[] { return Array.from(block).sort((a, b) => a - b) - .sort((a, b) => a - b) .reduce((acc, id) => { const message = store.state.messagesStore.messages[token][id] if (message) { @@ -91,6 +103,7 @@ export const useChatStore = defineStore('chat', () => { if (threadId) { // FIXME temporary check all messages for given thread from all chat blocks return chatBlocks[token].findIndex((set) => set.has(messageId)) !== -1 + && store.state.messagesStore.messages[token][messageId]?.threadId === threadId } return chatBlocks[token].findIndex((set) => set.has(messageId)) !== -1 @@ -113,7 +126,7 @@ export const useChatStore = defineStore('chat', () => { return threadId } // FIXME temporary check all messages for given thread from all chat blocks - return Math.min(...prepareMessagesList(token, new Set(Array.from(chatBlocks[token].flatMap((set) => Array.from(set))))) + return Math.min(...prepareMessagesList(token, new Set(chatBlocks[token].flatMap((set) => Array.from(set)))) .filter((message) => { return message.threadId === threadId }).map((message) => message.id)) @@ -140,7 +153,7 @@ export const useChatStore = defineStore('chat', () => { if (threadId) { // FIXME temporary check all messages for given thread from all chat blocks - return Math.max(...prepareMessagesList(token, new Set(Array.from(chatBlocks[token].flatMap((set) => Array.from(set))))) + return Math.max(...prepareMessagesList(token, new Set(chatBlocks[token].flatMap((set) => Array.from(set)))) .filter((message) => { return message.threadId === threadId }).map((message) => message.id)) @@ -161,6 +174,10 @@ export const useChatStore = defineStore('chat', () => { function processChatBlocks(token: string, messages: ChatMessage[], options?: ProcessChatBlocksOptions): void { const newMessageIdsSet = new Set(messages.map((message) => message.id)) + if (options?.threadId) { + // FIXME handle thread messages separately + } + if (!chatBlocks[token]) { // If no blocks exist, create a new one with the first message. First in array will be considered main block chatBlocks[token] = [newMessageIdsSet]