mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-23 04:35:40 +00:00
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.
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 (
|
||||
<div
|
||||
ref={(node) => {
|
||||
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
|
||||
})}
|
||||
>
|
||||
<div
|
||||
@@ -141,18 +157,13 @@ const WSMessagesList = ({ order = -1, messages = [] }) => {
|
||||
if (!messages.length) {
|
||||
return <div className="p-4 text-gray-500">No messages yet.</div>;
|
||||
}
|
||||
|
||||
const ordered = order === -1 ? messages : messages.slice().reverse()
|
||||
return (
|
||||
<StyledWrapper className="ws-messages-list flex flex-col gap-1 mt-4">
|
||||
{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 <WSMessageItem isLast={isLast} id={idx} message={msg} />;
|
||||
const inFocus = order === -1 ? src.length - 1 === idx : idx === 0;
|
||||
return <WSMessageItem inFocus={inFocus} id={idx} message={msg} />;
|
||||
})}
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
@@ -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 (
|
||||
<StyledWrapper className="ml-2 flex items-center">
|
||||
<button onClick={toggleSortOrder} title={order > 0 ? 'Latest Last' : 'Latest First'}>
|
||||
{ order == -1
|
||||
? <IconSortAscending2 size={16} strokeWidth={1.5} />
|
||||
: <IconSortDescending2 size={16} strokeWidth={1.5} />}
|
||||
<button onClick={toggleSortOrder} title={order === -1 ? 'Latest Last' : 'Latest First'}>
|
||||
{ order === -1
|
||||
? <IconSortDescending2 size={16} strokeWidth={1.5} />
|
||||
: <IconSortAscending2 size={16} strokeWidth={1.5} />}
|
||||
</button>
|
||||
</StyledWrapper>
|
||||
);
|
||||
|
||||
@@ -22,7 +22,7 @@ const WSResult = ({ response }) => {
|
||||
{response.error}
|
||||
</div>
|
||||
) : (
|
||||
<WSMessagesList order={response?.initiatedWsResponse?.sortOrder} messages={response.responses || []} />
|
||||
<WSMessagesList order={response?.sortOrder} messages={response.responses || []} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user