From 58917aa97e4e1f191843e08ab07677fe631fe367 Mon Sep 17 00:00:00 2001 From: Siddharth Gelera Date: Wed, 17 Sep 2025 14:01:25 +0530 Subject: [PATCH] feat: enhance WebSocket message handling and styling - Add new styling for incoming messages in StyledWrapper. - Update WSMessagesList to handle message sorting and focus. - Refactor response sort order handling in WSResponseSortOrder. - Improve WebSocket connection management in ws-client. --- .../WSMessagesList/StyledWrapper.js | 7 +++- .../WsResponsePane/WSMessagesList/index.js | 41 ++++++++++++------- .../WSResponseSortOrder/index.js | 10 ++--- .../ResponsePane/WsResponsePane/index.js | 2 +- .../ReduxStore/slices/collections/index.js | 3 +- packages/bruno-requests/src/ws/ws-client.js | 34 +++++++-------- 6 files changed, 57 insertions(+), 40 deletions(-) diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js index 3709aee51..827dfc55c 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js @@ -3,8 +3,13 @@ import styled from 'styled-components'; const StyledWrapper = styled.div` overflow-y: auto; + .ws-message.new { + color: white; + background-color: ${({theme}) => theme.table.striped}; + } + .ws-message:not(:last-child) { - border-bottom: 1px solid ${(props) => props.theme.table.border}; + border-bottom: 1px solid ${({theme}) => theme.table.border}; } .ws-message:not(:last-child).open { diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js index 912fc26e6..a18acff23 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js @@ -7,7 +7,8 @@ import { useTheme } from 'providers/Theme'; import { useState } from 'react'; import { useSelector } from 'react-redux'; import _ from 'lodash'; -import { forwardRef } from 'react'; +import { useRef } from 'react'; +import { useEffect } from 'react'; const getContentMeta = (content) => { if (typeof content === 'object') { @@ -60,27 +61,42 @@ const TypeIcon = ({type})=>{ }[type] } -const WSMessageItem = ({ message, isLast }) => { +const WSMessageItem = ({ message, inFocus }) => { const [isOpen, setIsOpen] = useState(false); const preferences = useSelector((state) => state.app.preferences); - const { displayedTheme } = useTheme(); + const [isNew, setIsNew] = useState(false) + const notified = useRef(false) const isIncoming = message.type === 'incoming'; const isInfo = message.type === 'info'; let parsedContent = parseContent(message.message); const dataType = getDataTypeText(parsedContent.type); + useEffect(()=>{ + if(notified.current === true) return + const dateDiff = Date.now() - new Date(message.timestamp).getTime() + if(dateDiff < 1000 * 10){ + setIsNew(true) + setTimeout(()=>{ + notified.current = true + setIsNew(false) + },2500) + } + }, [message]) + + return (
{ if (!node) return; - if (isLast) node.scrollIntoView(); + if (inFocus) node.scrollIntoView() }} - className={classnames('ws-message flex flex-col py-2', { + className={classnames('ws-message flex flex-col p-2', { 'ws-incoming': isIncoming, 'ws-outgoing': !isIncoming, - 'open': isOpen + 'open': isOpen, + 'new': isNew })} >
{ if (!messages.length) { return
No messages yet.
; } - + const ordered = order === -1 ? messages : messages.slice().reverse() return ( - {messages - .toSorted((x, y) => { - let a = order == -1 ? x : y - let b = order == -1 ? y : x - return (new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()); - }) + {ordered .map((msg, idx, src) => { - const isLast = src.length - 1 === idx; - return ; + const inFocus = order === -1 ? src.length - 1 === idx : idx === 0; + return ; })} ); diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSResponseSortOrder/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSResponseSortOrder/index.js index 9422da9ab..f91e7359c 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSResponseSortOrder/index.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSResponseSortOrder/index.js @@ -7,7 +7,7 @@ import { wsUpdateResponseSortOrder } from 'providers/ReduxStore/slices/collectio const WSResponseSortOrder = ({ collection, item }) => { const dispatch = useDispatch(); - const order = item.response?.initiatedWsResponse?.sortOrder ?? -1 + const order = item.response?.sortOrder ?? -1 const toggleSortOrder = ()=>{ dispatch( @@ -20,10 +20,10 @@ const WSResponseSortOrder = ({ collection, item }) => { return ( - ); diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js index 931ab973c..d8ef1490a 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js @@ -22,7 +22,7 @@ const WSResult = ({ response }) => { {response.error}
) : ( - + ); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 410ed97bf..fd27fdadd 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -2771,6 +2771,7 @@ export const collectionsSlice = createSlice({ item.requestSent = eventData; item.requestSent.timestamp = Date.now(); item.response = { + ...initiatedWsResponse, initiatedWsResponse, statusText: 'CONNECTING' }; @@ -2891,7 +2892,7 @@ export const collectionsSlice = createSlice({ if (collection) { const item = findItemInCollection(collection, action.payload.itemUid); if (item) { - item.response.initiatedWsResponse.sortOrder = item.response?.initiatedWsResponse?.sortOrder ? -item.response.initiatedWsResponse.sortOrder : -1; + item.response.sortOrder = item.response.sortOrder ? -item.response.sortOrder : -1; } } } diff --git a/packages/bruno-requests/src/ws/ws-client.js b/packages/bruno-requests/src/ws/ws-client.js index 497ddc2e9..c645332f6 100644 --- a/packages/bruno-requests/src/ws/ws-client.js +++ b/packages/bruno-requests/src/ws/ws-client.js @@ -94,10 +94,7 @@ class WsClient { }); // Set up event handlers - this.#setupWsEventHandlers(wsConnection, requestId, collectionUid, { - url: parsedUrl.fullUrl, - headers - }); + this.#setupWsEventHandlers(wsConnection, requestId, collectionUid, {keepAlive,keepAliveInterval}); // Store the connection this.#addConnection(requestId, wsConnection); @@ -105,18 +102,6 @@ class WsClient { // Emit connecting event this.eventCallback('ws:connecting', requestId, collectionUid); - wsConnection.addEventListener('open', () => { - this.#flushQueue(requestId, collectionUid); - - if (keepAlive) { - const handle = setInterval(() => { - wsConnection.isAlive = false; - wsConnection.ping(); - }, keepAliveInterval); - this.connectionKeepAlive.set(requestId, handle); - } - }); - return wsConnection; } catch (error) { console.error('Error creating WebSocket connection:', error); @@ -259,10 +244,25 @@ class WsClient { * @param {WebSocket} ws - The WebSocket instance * @param {string} requestId - The request ID * @param {string} collectionUid - The collection UID + * @param {object} options + * @param {boolean} options.keepAlive - keep the connection alive + * @param {number} options.keepAliveInterval - What the interval for keeping interval * @private */ - #setupWsEventHandlers(ws, requestId, collectionUid) { + #setupWsEventHandlers(ws, requestId, collectionUid, options) { ws.on('open', () => { + this.#flushQueue(requestId, collectionUid); + + if(options.keepAlive){ + const handle = setInterval(() => { + console.log("pinging to keep alive") + ws.isAlive = false; + ws.ping(); + }, options.keepAliveInterval); + + this.connectionKeepAlive.set(requestId, handle); + } + this.eventCallback('ws:open', requestId, collectionUid, { timestamp: Date.now(), url: ws.url