Skip to content

Commit 7632ba7

Browse files
committed
fix: update based on suggestions
1 parent 6fd5b5e commit 7632ba7

File tree

4 files changed

+43
-28
lines changed

4 files changed

+43
-28
lines changed

src/components/messageSpace/messageSpace.cy.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import { getMockWebSocketClient } from '../mockWebSocket'
2626
import MessageSpace from './messageSpace'
2727

2828
describe('MessageSpace Component', () => {
29+
const messageCanvas = '[data-cy=message-canvas]'
30+
2931
const supportedElements = {
3032
text: Text,
3133
streamingText: StreamingText,
@@ -169,7 +171,7 @@ describe('MessageSpace Component', () => {
169171
<MessageSpace
170172
ws={mockWsClient}
171173
sender={testUser}
172-
messages={messages}
174+
receivedMessages={messages}
173175
supportedElements={supportedElements}
174176
getProfileComponent={(message: Message) => {
175177
if (message.sender.name?.includes('Agent')) {
@@ -202,14 +204,14 @@ describe('MessageSpace Component', () => {
202204
})
203205
})
204206

205-
it(`can receive and render messages from websocket on ${viewport} screen`, () => {
207+
it.only(`can receive and render messages from websocket on ${viewport} screen`, () => {
206208
setupWebSocketServer()
207209
cy.viewport(viewport)
208210
cy.mount(
209211
<MessageSpace
210212
ws={getMockWebSocketClient(webSocketUrl)}
211213
sender={testUser}
212-
messages={[
214+
receivedMessages={[
213215
{
214216
...humanMessageData,
215217
id: getUUID(),
@@ -237,13 +239,16 @@ describe('MessageSpace Component', () => {
237239
'not.contain',
238240
'Sure! The text is displayed progressively.'
239241
)
242+
cy.get(messageCanvas).should('have.length', 1)
240243
messagesToBeSent.forEach((message) => {
241244
cy.get(messageSpace).should('contain', message.data.text)
242245
})
243246
cy.get(messageSpace).should(
244247
'contain',
245248
'Sure! The text is displayed progressively.'
246249
)
250+
const totalDisplayedMessages = 3
251+
cy.get(messageCanvas).should('have.length', totalDisplayedMessages)
247252
teardownWebSocketServer()
248253
})
249254

@@ -262,7 +267,7 @@ describe('MessageSpace Component', () => {
262267
<MessageSpace
263268
ws={mockWsClient}
264269
sender={testUser}
265-
messages={messages}
270+
receivedMessages={messages}
266271
supportedElements={supportedElements}
267272
/>
268273
</div>

src/components/messageSpace/messageSpace.stories.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ function getProfileIconAndName(message: Message) {
6565
}
6666

6767
meta.argTypes = {
68-
messages: {
68+
receivedMessages: {
6969
table: {
7070
type: {
7171
summary: 'Array of Message.\n',
@@ -86,6 +86,8 @@ meta.argTypes = {
8686
},
8787
},
8888
ws: {
89+
description:
90+
'WebSocket connection to send and receive messages to and from a backend. The onReceive prop will override the default handler once it is set. If you need to use the WebSocket for purposes other than chat, you will need to create a separate WebSocket connection.',
8991
table: {
9092
type: {
9193
summary: 'WebSocketClient',
@@ -203,7 +205,7 @@ export const Default = {
203205
args: {
204206
ws: { send: () => {} },
205207
sender: humanMessageData.sender,
206-
messages: [
208+
receivedMessages: [
207209
{
208210
...humanMessageData,
209211
id: getUUID(),

src/components/messageSpace/messageSpace.tsx

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export interface MessageSpaceProps extends MessageContainerProps {
1818
sender: Sender
1919
/** A component map contains message formats as keys and their corresponding React components as values. */
2020
supportedElements: ComponentMap
21-
messages?: Message[]
21+
/** Messages received before the component was mounted. These messages are rendered along with new messages received from the websocket. */
22+
receivedMessages?: Message[]
2223
/** Text label for scroll down button. Default value is 'scroll down'. */
2324
scrollDownLabel?: string
2425
}
@@ -35,13 +36,28 @@ function getCombinedMessages(
3536
messages: { [key: string]: Message[] },
3637
message: Message
3738
) {
38-
const key = message.format.includes('update') ? message.threadId : message.id
39+
let key = message.format.includes('update') ? message.threadId : message.id
40+
3941
if (key) {
42+
const newMessages = { ...messages }
4043
const existingMessages = messages[key] || []
41-
const newMessages = {
42-
...messages,
43-
[key]: existingMessages.concat(message),
44+
const originalMessage = existingMessages[0]
45+
46+
// Check if sender is the same for update messages
47+
if (
48+
message.format.includes('update') &&
49+
originalMessage &&
50+
originalMessage.sender.id !== message.sender.id
51+
) {
52+
key = message.id
53+
}
54+
55+
if (!newMessages[key]) {
56+
newMessages[key] = []
4457
}
58+
59+
newMessages[key] = newMessages[key].concat(message)
60+
4561
return newMessages
4662
} else {
4763
return messages
@@ -51,7 +67,7 @@ function getCombinedMessages(
5167
/**
5268
The `MessageSpace` component uses `MessageCanvas` and `ElementRenderer` to render a list of messages. It serves as a container for individual message items, each encapsulated within a `MessageCanvas` for consistent styling and layout. It can receive and process messages to dynamically update the displayed content.
5369
54-
The `MessageSpace` component can combine update messages with the original message and render them as a single message. For this to work, the `threadId` of the update message must match the `id` of the original message, and the format of the update message must include 'update'.
70+
The `MessageSpace` component can combine update messages with the original message and render them as a single message. For this to work, the `threadId` of the update message must match the `id` of the original message, and the format of the update message should be prefixed with 'update'. For example, if the original message format is 'streamingText', the update message format should be 'updateStreamingText'.
5571
5672
Note: For more information about the `getActionsComponent` and `getProfileComponent` fields, refer to the [MessageCanvas' docs](http://localhost:6006/?path=/docs/rustic-ui-message-canvas-message-canvas--docs).
5773
*/
@@ -82,14 +98,6 @@ export default function MessageSpace(props: MessageSpaceProps) {
8298
}, hideScrollButtonDuration)
8399
}
84100

85-
function handleScrollDown() {
86-
scrollEndRef.current?.scrollIntoView({
87-
behavior: 'smooth',
88-
block: 'end',
89-
})
90-
hideScrollButton()
91-
}
92-
93101
function getVideoStatus() {
94102
const videos = containerRef.current?.querySelectorAll('video')
95103
if (!videos || videos.length === 0) {
@@ -128,7 +136,7 @@ export default function MessageSpace(props: MessageSpaceProps) {
128136
}
129137
}, [isScrolledToBottom])
130138

131-
function scrollDownIfNeeded() {
139+
function scrollDown() {
132140
if (getVideoStatus()) {
133141
const container = containerRef.current
134142
setAreVideosLoaded(true)
@@ -140,12 +148,12 @@ export default function MessageSpace(props: MessageSpaceProps) {
140148
}, 0)
141149
}
142150
} else {
143-
setTimeout(scrollDownIfNeeded, 1)
151+
setTimeout(scrollDown, 1)
144152
}
145153
}
146154

147155
useEffect(() => {
148-
scrollDownIfNeeded()
156+
scrollDown()
149157
}, [areVideosLoaded])
150158

151159
useEffect(() => {
@@ -155,20 +163,20 @@ export default function MessageSpace(props: MessageSpaceProps) {
155163

156164
if (isScrolledToBottom && hasNewMessage) {
157165
hideScrollButton()
158-
scrollDownIfNeeded()
166+
scrollDown()
159167
}
160168
}, [isScrolledToBottom, Object.keys(chatMessages).length])
161169

162170
useEffect(() => {
163171
let messageDict: { [messageId: string]: Message[] } = {}
164172

165-
props.messages?.forEach((message) => {
173+
props.receivedMessages?.forEach((message) => {
166174
const newMessageDict = getCombinedMessages(messageDict, message)
167175
messageDict = newMessageDict
168176
})
169177

170178
setChatMessages(messageDict)
171-
}, [props.messages?.length])
179+
}, [props.receivedMessages?.length])
172180

173181
function handleIncomingMessage(message: Message) {
174182
setChatMessages((prevMessages) =>
@@ -214,7 +222,7 @@ export default function MessageSpace(props: MessageSpaceProps) {
214222
variant="rusticSecondary"
215223
className="rustic-scroll-down-button"
216224
size="medium"
217-
onClick={handleScrollDown}
225+
onClick={scrollDown}
218226
label={
219227
<>
220228
{props.scrollDownLabel}

src/components/promptBuilder/promptBuilder.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ export const Default = {
301301
ws={boilerplateWs}
302302
sender={user}
303303
supportedElements={{ text: Text }}
304-
messages={messageSpaceMessages}
304+
receivedMessages={messageSpaceMessages}
305305
getProfileComponent={(message) => {
306306
return <>{message.sender.name}</>
307307
}}

0 commit comments

Comments
 (0)