diff --git a/package-lock.json b/package-lock.json index 33d5cc87e..7ac76a441 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15363,6 +15363,18 @@ "he": "bin/he" } }, + "node_modules/hexy": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.3.5.tgz", + "integrity": "sha512-UCP7TIZPXz5kxYJnNOym+9xaenxCLor/JyhKieo8y8/bJWunGh9xbhy3YrgYJUQ87WwfXGm05X330DszOfINZw==", + "license": "MIT", + "bin": { + "hexy": "bin/hexy_cmd.js" + }, + "engines": { + "node": ">=10.4" + } + }, "node_modules/hey-listen": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz", @@ -30112,6 +30124,7 @@ "form-data": "^4.0.0", "fs-extra": "^10.1.0", "graphql": "^16.6.0", + "hexy": "^0.3.5", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "iconv-lite": "^0.6.3", diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 4a8f0591a..ea53de958 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -45,7 +45,7 @@ export default class CodeEditor extends React.Component { const editor = (this.editor = CodeMirror(this._node, { value: this.props.value || '', lineNumbers: true, - lineWrapping: true, + lineWrapping: this.props.enableLineWrapping ?? true, tabSize: TAB_SIZE, mode: this.props.mode || 'application/ld+json', brunoVarInfo: { @@ -237,6 +237,14 @@ export default class CodeEditor extends React.Component { this.editor.scrollTo(null, this.props.initialScroll); } + if (this.props.enableLineWrapping !== prevProps.enableLineWrapping){ + this.editor.setOption("lineWrapping", this.props.enableLineWrapping); + } + + if (this.props.mode !== prevProps.mode){ + this.editor.setOption("mode", this.props.mode); + } + this.ignoreChangeEvent = false; } 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 709012c97..733c644d4 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/StyledWrapper.js @@ -25,11 +25,20 @@ const StyledWrapper = styled.div` border-color: ${(props) => props.theme.table.border}; } + .CodeMirror { + border-radius: 0.25rem; + } .CodeMirror-foldgutter, .CodeMirror-linenumbers, .CodeMirror-lint-markers { background: ${({theme})=> theme.bg}; } + div[role='tablist'] { + .active { + color: ${(props) => props.theme.colors.text.yellow}; + } + } + `; export default StyledWrapper; 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 98f76f1ac..6c96b33a8 100644 --- a/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js +++ b/packages/bruno-app/src/components/ResponsePane/WsResponsePane/WSMessagesList/index.js @@ -34,7 +34,7 @@ const parseContent = (content) => { let contentMeta = getContentMeta(content); return { type: contentMeta.isJSON ? 'application/json' : 'text/plain', - content: contentMeta.isJSON ? JSON.stringify(JSON.parse(contentMeta.content), null, 2) : contentMeta.content, + content: contentMeta.isJSON ? JSON.stringify(JSON.parse(contentMeta.content), null, 2) : contentMeta.content }; }; @@ -47,67 +47,66 @@ const getDataTypeText = (type) => { }; /** - * - * @param {"incoming"|"outgoing"|"info"} type + * + * @param {"incoming"|"outgoing"|"info"} type */ -const TypeIcon = ({type})=>{ +const TypeIcon = ({ type }) => { const commonProps = { size: 18 - } + }; return { - "incoming": , - "outgoing": , - "info": - }[type] -} + incoming: , + outgoing: , + info: + }[type]; +}; const WSMessageItem = ({ message, inFocus }) => { const [isOpen, setIsOpen] = useState(false); + const [showHex, setShowHex] = useState(false); const preferences = useSelector((state) => state.app.preferences); const { displayedTheme } = useTheme(); - const [isNew, setIsNew] = useState(false) - const notified = useRef(false) + const [isNew, setIsNew] = useState(false); + const notified = useRef(false); const isIncoming = message.type === 'incoming'; const isInfo = message.type === 'info'; + let contentHexdump = message.messageHexdump; 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) + 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]) - + }, [message]); return (
{ if (!node) return; - if (inFocus) node.scrollIntoView() + if (inFocus) node.scrollIntoView(); }} className={classnames('ws-message flex flex-col p-2', { 'ws-incoming': isIncoming, 'ws-outgoing': !isIncoming, - 'open': isOpen, - 'new': isNew + open: isOpen, + new: isNew })} >
{ - if(isInfo) return + if (isInfo) return; setIsOpen(!isOpen); }} > @@ -126,26 +125,50 @@ const WSMessageItem = ({ message, inFocus }) => { {message.timestamp && ( {new Date(message.timestamp).toISOString()} )} - {!isInfo && - {isOpen? ( - - ) : ( - - )} - } + {!isInfo && ( + + {isOpen ? ( + + ) : ( + + )} + + )}
{isOpen && ( -
- -
- {isOpen ? {dataType} : null} +
+
+
+
setShowHex(true)} + > + hexdump +
+
setShowHex(false)} + > + {dataType.toLowerCase()} +
+
+
)}
@@ -156,14 +179,13 @@ const WSMessagesList = ({ order = -1, messages = [] }) => { if (!messages.length) { return
No messages yet.
; } - const ordered = order === -1 ? messages : messages.slice().reverse() + const ordered = order === -1 ? messages : messages.slice().reverse(); return ( - {ordered - .map((msg, idx, src) => { - const inFocus = order === -1 ? src.length - 1 === idx : idx === 0; - return ; - })} + {ordered.map((msg, idx, src) => { + const inFocus = order === -1 ? src.length - 1 === idx : idx === 0; + return ; + })} ); }; diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 3e0defb81..56ff911a4 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -57,6 +57,7 @@ "form-data": "^4.0.0", "fs-extra": "^10.1.0", "graphql": "^16.6.0", + "hexy": "^0.3.5", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "iconv-lite": "^0.6.3", diff --git a/packages/bruno-requests/src/ws/ws-client.js b/packages/bruno-requests/src/ws/ws-client.js index 37b9f2a79..eb2f2a5d3 100644 --- a/packages/bruno-requests/src/ws/ws-client.js +++ b/packages/bruno-requests/src/ws/ws-client.js @@ -1,4 +1,5 @@ import ws from 'ws'; +import { hexy as hexdump } from "hexy" /** * Safely parse JSON string with error handling @@ -169,6 +170,7 @@ class WsClient { // Emit message sent event this.eventCallback('ws:message', requestId, collectionUid, { message: messageToSend, + messageHexdump: hexdump(messageToSend), type: 'outgoing', timestamp: Date.now() }); @@ -291,6 +293,7 @@ class WsClient { const message = JSON.parse(data.toString()); this.eventCallback('ws:message', requestId, collectionUid, { message, + messageHexdump: hexdump(data), type: 'incoming', timestamp: Date.now() }); @@ -298,6 +301,7 @@ class WsClient { // If parsing fails, send as raw data this.eventCallback('ws:message', requestId, collectionUid, { message: data.toString(), + messageHexdump: hexdump(data), type: 'incoming', timestamp: Date.now() });