diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/StyledWrapper.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/StyledWrapper.js deleted file mode 100644 index 81b4c33b1..000000000 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/StyledWrapper.js +++ /dev/null @@ -1,96 +0,0 @@ -import styled from 'styled-components'; - -const StyledWrapper = styled.div` - height: 100%; - overflow: hidden; - background: ${(props) => props.theme.bg}; - border-radius: 4px; - - .CodeMirror { - height: 100%; - font-family: ${(props) => (props.font === 'default' ? 'monospace' : props.font)}; - font-size: ${(props) => (props.fontSize ? props.fontSize : '13px')}; - } - - .accordion-header { - background-color: ${(props) => props.theme.requestTabPanel.card.bg}; - - &:hover { - background-color: ${(props) => props.theme.plainGrid.hoverBg}; - } - - &.open { - background-color: ${(props) => props.theme.plainGrid.hoverBg}; - } - } - - .error-header { - background-color: ${(props) => (props.theme.bg === '#1e1e1e' ? 'rgba(185, 28, 28, 0.1)' : '#fee2e2')}; - } - - .error-text { - color: ${(props) => props.theme.colors.text.danger}; - } - - div.tabs { - div.tab { - padding: 6px 0px; - border: none; - border-bottom: solid 2px transparent; - margin-right: 1.25rem; - color: var(--color-tab-inactive); - cursor: pointer; - - &:focus, - &:active, - &:focus-within, - &:focus-visible, - &:target { - outline: none !important; - box-shadow: none !important; - } - - &.active { - color: ${(props) => props.theme.tabs.active.color} !important; - border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important; - } - } - } - - .stream-status { - display: inline-flex; - align-items: center; - - &.complete { - color: ${(props) => props.theme.colors.text.green}; - } - - &.cancelled { - color: ${(props) => props.theme.colors.text.danger}; - } - - &.streaming { - color: ${(props) => props.theme.colors.text.blue}; - } - } - - .message-counter { - display: inline-flex; - align-items: center; - margin-left: 10px; - } - - .response-list { - max-height: 500px; - overflow-y: auto; - } - - .response-message { - margin-bottom: 8px; - padding: 8px; - border-radius: 4px; - background-color: var(--color-panel-background); - } -`; - -export default StyledWrapper; diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/index.js deleted file mode 100644 index bb4bf36c0..000000000 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSQueryResult/index.js +++ /dev/null @@ -1,130 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import Accordion from 'components/Accordion'; -import CodeEditor from 'components/CodeEditor'; -import { get } from 'lodash'; -import { useSelector } from 'react-redux'; -import { useTheme } from 'providers/Theme/index'; -import StyledWrapper from './StyledWrapper'; -import { formatISO9075 } from 'date-fns'; -import WSError from '../WSError'; - -const WSQueryResult = ({ item, collection }) => { - const { displayedTheme } = useTheme(); - const preferences = useSelector((state) => state.app.preferences); - const [showErrorMessage, setShowErrorMessage] = useState(true); - - const response = item.response || {}; - const responsesList = response?.responses || []; - // Reverse the responses list to show the most recent at the top - const reversedResponsesList = [...responsesList].reverse(); - const hasError = response.isError; - const hasResponses = responsesList.length > 0; - const errorMessage = response.error; - - // Reset error visibility when a new response is received - useEffect(() => { - if (hasError) { - setShowErrorMessage(true); - } - }, [response, hasError]); - - // Format a timestamp to a human-readable format - const formatTimestamp = (timestamp) => { - if (!timestamp) return 'Unknown time'; - - try { - const date = new Date(timestamp); - return formatISO9075(date); - } catch (e) { - return 'Invalid time'; - } - }; - - // Format JSON for display - const formatJSON = (data) => { - try { - if (typeof data === 'string') { - return JSON.stringify(JSON.parse(data), null, 2); - } - return JSON.stringify(data, null, 2); - } catch (e) { - return typeof data === 'string' ? data : JSON.stringify(data); - } - }; - - if (!hasResponses && !hasError) { - return ( - -
No messages received
-
- ); - } - - return ( - - {hasError && showErrorMessage && setShowErrorMessage(false)} />} - {hasResponses && ( -
- {responsesList.length === 1 ? ( - // Single message - render directly without accordion -
- -
- ) : ( - // Multiple messages - use accordion - - {reversedResponsesList.map((response, index) => { - // Calculate the original response number (for display purposes) - const originalIndex = responsesList.length - index - 1; - - return ( - - -
-
- Response - {' '} - {originalIndex + 1} - {' '} - {index === 0 ? '(Latest)' : ''} -
-
-
- -
- -
-
-
- ); - })} -
- )} -
- )} - {hasError && !hasResponses && !showErrorMessage && ( -
- No messages received. A server error occurred but has been dismissed. -
- )} -
- ); -}; - -export default WSQueryResult; diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/StyledWrapper.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/StyledWrapper.js deleted file mode 100644 index f302b86dd..000000000 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/StyledWrapper.js +++ /dev/null @@ -1,44 +0,0 @@ -import styled from 'styled-components'; - -const StyledWrapper = styled.div` - border-left: 4px solid ${(props) => props.theme.colors.text.danger}; - border-top: 1px solid transparent; - border-right: 1px solid transparent; - border-bottom: 1px solid transparent; - border-radius: 0.375rem; - box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - max-height: 200px; - min-height: 70px; - overflow-y: auto; - background-color: ${(props) => (props.theme.bg === '#1e1e1e' ? 'rgba(40, 40, 40, 0.5)' : 'rgba(250, 250, 250, 0.9)')}; - - .close-button { - opacity: 0.7; - transition: opacity 0.2s; - - &:hover { - opacity: 1; - } - - svg { - color: ${(props) => props.theme.text}; - } - } - - .error-title { - font-weight: 600; - margin-bottom: 0.375rem; - color: ${(props) => props.theme.colors.text.danger}; - } - - .error-message { - font-family: monospace; - font-size: 0.6875rem; - line-height: 1.25rem; - white-space: pre-wrap; - word-break: break-all; - color: ${(props) => props.theme.text}; - } -`; - -export default StyledWrapper; diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/index.js deleted file mode 100644 index 1095794b8..000000000 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WsError/index.js +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import { IconX } from '@tabler/icons'; -import StyledWrapper from './StyledWrapper'; - -const WSError = ({ error, onClose }) => { - if (!error) return null; - - return ( - -
-
-
WebSocket Server Error
-
{typeof error === 'string' ? error : JSON.stringify(error, null, 2)}
-
-
- -
-
-
- ); -}; - -export default WSError; diff --git a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js index 4aa25f037..473f2387b 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js @@ -17,13 +17,7 @@ import WSResponseSortOrder from './WSResponseSortOrder'; import WSResponseHeaders from './WSResponseHeaders'; const WSResult = ({ response }) => { - return response.isError ? ( -
- {response.error} -
- ) : ( - - ); + return ; }; const WSResponsePane = ({ item, collection }) => { diff --git a/packages/bruno-requests/src/ws/ws-client.js b/packages/bruno-requests/src/ws/ws-client.js index 093c822cb..f8dfd0bf3 100644 --- a/packages/bruno-requests/src/ws/ws-client.js +++ b/packages/bruno-requests/src/ws/ws-client.js @@ -297,6 +297,13 @@ class WsClient { }); }); + ws.on('unexpected-response', (req, res) => { + this.eventCallback('ws:error', requestId, collectionUid, { + message: res.statusMessage, + timestamp: Date.now() + }); + }); + ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); diff --git a/tests/websockets/subproto.spec.ts b/tests/websockets/subproto.spec.ts index 0832f501f..5b845f035 100644 --- a/tests/websockets/subproto.spec.ts +++ b/tests/websockets/subproto.spec.ts @@ -31,7 +31,7 @@ test.describe.serial('headers', () => { await page.keyboard.insertText(wrongProtocol); await locators.runner().click(); - expect(await messages[0].locator('.text-ellipsis').innerText()).toMatch(/^(Unexpected server response: 400)/); + expect(await messages[0].locator('.text-ellipsis').innerText()).toMatch(/^(Bad Request)/); await page.locator('pre').filter({ hasText: wrongProtocol }).click(); await clearText(wrongProtocol);