diff --git a/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/StyledWrapper.js
new file mode 100644
index 000000000..3d571b4bf
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/StyledWrapper.js
@@ -0,0 +1,30 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ font-size: 0.8125rem;
+
+ .body-mode-selector {
+ background: transparent;
+ border-radius: 3px;
+
+ .dropdown-item {
+ padding: 0.2rem 0.6rem !important;
+ padding-left: 1.5rem !important;
+ }
+
+ .label-item {
+ padding: 0.2rem 0.6rem !important;
+ }
+
+ .selected-body-mode {
+ color: ${(props) => props.theme.colors.text.yellow};
+ }
+ }
+
+ .caret {
+ color: rgb(140, 140, 140);
+ fill: rgb(140 140 140);
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/index.js b/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/index.js
new file mode 100644
index 000000000..b6d2b1f5f
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestPane/WsBody/BodyMode/index.js
@@ -0,0 +1,68 @@
+import React, { useRef, forwardRef } from 'react';
+import { IconCaretDown } from '@tabler/icons';
+import Dropdown from 'components/Dropdown';
+import { humanizeRequestBodyMode } from 'utils/collections';
+import StyledWrapper from './StyledWrapper';
+
+
+const WSRequestBodyMode = ({ mode, onModeChange }) => {
+ const dropdownTippyRef = useRef();
+ const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
+
+
+ const Icon = forwardRef((props, ref) => {
+ return (
+
+ {humanizeRequestBodyMode(mode)}
+
+ );
+ });
+
+ return (
+
+
+
} placement="bottom-end">
+
Raw
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('json');
+ }}
+ >
+ JSON
+
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('xml');
+ }}
+ >
+ XML
+
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('text');
+ }}
+ >
+ TEXT
+
+ {/*
Other
+
{
+ dropdownTippyRef.current.hide();
+ onModeChange('file');
+ }}
+ >
+ File / Binary
+
*/}
+
+
+
+ );
+};
+export default WSRequestBodyMode;
diff --git a/packages/bruno-app/src/components/RequestPane/WsBody/index.js b/packages/bruno-app/src/components/RequestPane/WsBody/index.js
index 41a7d6eee..e99cc0576 100644
--- a/packages/bruno-app/src/components/RequestPane/WsBody/index.js
+++ b/packages/bruno-app/src/components/RequestPane/WsBody/index.js
@@ -4,14 +4,14 @@ import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import { useTheme } from 'providers/Theme';
import React, { useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
-import { generateGrpcSampleMessage, sendWsRequest } from 'utils/network/index';
-import { IconChevronDown, IconChevronUp, IconPlus, IconRefresh, IconSend, IconTrash, IconWand } from '@tabler/icons';
+import { IconChevronDown, IconChevronUp, IconPlus, IconTrash, IconWand } from '@tabler/icons';
import CodeEditor from 'components/CodeEditor/index';
import ToolHint from 'components/ToolHint/index';
import { applyEdits, format } from 'jsonc-parser';
-import toast from 'react-hot-toast';
import { toastError } from 'utils/common/error';
import StyledWrapper from './StyledWrapper';
+import WSRequestBodyMode from './BodyMode/index';
+import { autoDetectLang } from 'utils/codemirror/lang-detect';
const SingleWSMessage = ({
message,
@@ -25,14 +25,12 @@ const SingleWSMessage = ({
canClientSendMultipleMessages
}) => {
const dispatch = useDispatch();
- const { displayedTheme, theme } = useTheme();
+ const { displayedTheme } = useTheme();
const preferences = useSelector((state) => state.app.preferences);
const body = item.draft ? get(item, 'draft.request.body') : get(item, 'request.body');
- const isConnectionActive = useSelector((state) => state.collections.activeConnections.includes(item.uid));
-
- const canClientStream = methodType === 'client-streaming' || methodType === 'bidi-streaming';
const { name, content } = message;
+ const [messageFormat, setMessageFormat] = useState(autoDetectLang(content));
const onEdit = (value) => {
const currentMessages = [...(body.ws || [])];
@@ -92,6 +90,12 @@ const SingleWSMessage = ({
const getContainerHeight =
canClientSendMultipleMessages && body.ws.length > 1 ? `${isCollapsed ? '' : 'h-80'}` : 'h-full';
+ const codemirrorMode = {
+ text: 'application/text',
+ xml: 'application/xml',
+ json: 'application/ld+json'
+ };
+
return (
)}
- {`Message ${canClientStream ? index + 1 : ''}`}
e.stopPropagation()}>
+
-
{!isCollapsed && (
diff --git a/packages/bruno-app/src/utils/codemirror/lang-detect.js b/packages/bruno-app/src/utils/codemirror/lang-detect.js
new file mode 100644
index 000000000..49ea56a7f
--- /dev/null
+++ b/packages/bruno-app/src/utils/codemirror/lang-detect.js
@@ -0,0 +1,34 @@
+/**
+ * @param {string} snippet
+ * @returns {boolean}
+ */
+export function isXML(snippet){
+ return /<\/?[a-z][\s\S]*>/i.test(snippet)
+}
+
+/**
+ * @param {string} snippet
+ * @returns {boolean}
+ */
+export function isJSON(snippet) {
+ try {
+ JSON.parse(snippet);
+ return true;
+ } catch (err) {
+ return false;
+ }
+}
+
+/**
+ * @param {string} snippet
+ * @returns {string}
+ */
+export function autoDetectLang(snippet) {
+ if (isJSON(snippet)) {
+ return 'json';
+ }
+ if(isXML(snippet)){
+ return 'xml'
+ }
+ return 'text'
+}
diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js
index 572e126bd..732bf77b9 100644
--- a/packages/bruno-lang/v2/src/bruToJson.js
+++ b/packages/bruno-lang/v2/src/bruToJson.js
@@ -1016,14 +1016,13 @@ const sem = grammar.createSemantics().addAttribute('ast', {
try {
JSON.parse(messageContent);
} catch (error) {
- console.error('Error validating ws message JSON:', error);
return {
body: {
mode: 'ws',
ws: [
{
name: messageName,
- content: '{}'
+ content: messageContent
}
]
}