diff --git a/package-lock.json b/package-lock.json index 5a2b2a8e0..4ef0ae308 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26860,6 +26860,7 @@ "graphiql": "3.7.1", "graphql": "^16.6.0", "graphql-request": "^3.7.0", + "hexy": "^0.3.5", "httpsnippet": "^3.0.9", "i18next": "24.1.2", "idb": "^7.0.0", diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json index a55bb9f64..1959a15dc 100644 --- a/packages/bruno-app/package.json +++ b/packages/bruno-app/package.json @@ -37,6 +37,7 @@ "graphiql": "3.7.1", "graphql": "^16.6.0", "graphql-request": "^3.7.0", + "hexy": "^0.3.5", "httpsnippet": "^3.0.9", "i18next": "24.1.2", "idb": "^7.0.0", diff --git a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js index cfbe77f58..a1d7dd86a 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryUrl/index.js @@ -41,9 +41,9 @@ const QueryUrl = ({ item, collection, handleRun }) => { if (!editorRef.current?.editor) return; const editor = editorRef.current.editor; const cursor = editor.getCursor(); - + const finalUrl = value?.trim() ?? value; - + dispatch( requestUrlChanged({ itemUid: item.uid, @@ -51,7 +51,7 @@ const QueryUrl = ({ item, collection, handleRun }) => { url: finalUrl }) ); - + // Restore cursor position only if URL was trimmed if (finalUrl !== value) { setTimeout(() => { @@ -81,7 +81,9 @@ const QueryUrl = ({ item, collection, handleRun }) => { } }; - const handleCancelRequest = () => { + const handleCancelRequest = (e) => { + e.preventDefault(); + e.stopPropagation(); dispatch(cancelRequest(item.cancelTokenUid, item, collection)); }; @@ -92,7 +94,6 @@ const QueryUrl = ({ item, collection, handleRun }) => {
gRPC
- ) : ( )} @@ -126,15 +127,8 @@ const QueryUrl = ({ item, collection, handleRun }) => { handleGenerateCode(e); }} > - - - Generate Code - + + Generate Code
{ Save ({saveShortcut})
- - {isLoading ? ( + {isLoading || item.response?.stream?.running ? ( { {generateCodeItemModalOpen && ( - setGenerateCodeItemModalOpen(false)} /> + setGenerateCodeItemModalOpen(false)} + /> )} ); diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index f7880e509..f8d3aba83 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -10,7 +10,7 @@ import GrpcResponsePane from 'components/ResponsePane/GrpcResponsePane'; import Welcome from 'components/Welcome'; import { findItemInCollection } from 'utils/collections'; import { updateRequestPaneTabWidth } from 'providers/ReduxStore/slices/tabs'; -import { sendRequest } from 'providers/ReduxStore/slices/collections/actions'; +import { cancelRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import RequestNotFound from './RequestNotFound'; import QueryUrl from 'components/RequestPane/QueryUrl/index'; import GrpcQueryUrl from 'components/RequestPane/GrpcQueryUrl/index'; @@ -263,11 +263,17 @@ const RequestTabPanel = () => { return; } - dispatch(sendRequest(item, collection.uid)).catch((err) => - toast.custom((t) => toast.dismiss(t.id)} />, { - duration: 5000 - }) - ); + if (item.response?.stream?.running) { + dispatch(cancelRequest(item.cancelTokenUid, item, collection)).catch((err) => + toast.custom((t) => toast.dismiss(t.id)} />, { + duration: 5000 + })); + } else if (item.requestState !== 'sending' && item.requestState !== 'queued') { + dispatch(sendRequest(item, collection.uid)).catch((err) => + toast.custom((t) => toast.dismiss(t.id)} />, { + duration: 5000 + })); + } }; // TODO: reaper, improve selection of panes diff --git a/packages/bruno-app/src/components/ResponsePane/ResponseBookmark/index.js b/packages/bruno-app/src/components/ResponsePane/ResponseBookmark/index.js index b00440c3a..9efe51f2e 100644 --- a/packages/bruno-app/src/components/ResponsePane/ResponseBookmark/index.js +++ b/packages/bruno-app/src/components/ResponsePane/ResponseBookmark/index.js @@ -12,12 +12,25 @@ import { getInitialExampleName } from 'utils/collections/index'; import classnames from 'classnames'; import StyledWrapper from './StyledWrapper'; +const getTitleText = ({ isResponseTooLarge, isStreamingResponse }) => { + if (isStreamingResponse) { + return 'Response Examples aren\'t supported in streaming responses yet.'; + } + + if (isResponseTooLarge) { + return 'Response size exceeds 5MB limit. Cannot save as example.'; + } + + return 'Save current response as example'; +}; + const ResponseBookmark = ({ item, collection, responseSize }) => { const dispatch = useDispatch(); const [showSaveResponseExampleModal, setShowSaveResponseExampleModal] = useState(false); const response = item.response || {}; const isResponseTooLarge = responseSize >= 5 * 1024 * 1024; // 5 MB + const isStreamingResponse = response.stream; // Only show for HTTP requests if (item.type !== 'http-request') { @@ -96,19 +109,22 @@ const ResponseBookmark = ({ item, collection, responseSize }) => { toast.success(`Example "${name}" created successfully`); }; + const disabledMessage = getTitleText({ + isResponseTooLarge, + isStreamingResponse + }); + return ( <>