diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json index d4fb47bcf..a19a281ec 100644 --- a/packages/bruno-app/package.json +++ b/packages/bruno-app/package.json @@ -34,7 +34,7 @@ "graphiql": "3.7.1", "graphql": "^16.6.0", "graphql-request": "^3.7.0", - "httpsnippet": "^3.0.6", + "httpsnippet": "^3.0.9", "i18next": "24.1.2", "idb": "^7.0.0", "immer": "^9.0.15", diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js index c2dfb3bdf..848048c13 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js @@ -78,7 +78,10 @@ const EnvironmentSelector = ({ collection }) => { No Environment -
+
{ + handleSettingsIconClick(); + dropdownTippyRef.current.hide(); + }}>
diff --git a/packages/bruno-app/src/components/FilePickerEditor/index.js b/packages/bruno-app/src/components/FilePickerEditor/index.js index d976a3e79..be7d689a3 100644 --- a/packages/bruno-app/src/components/FilePickerEditor/index.js +++ b/packages/bruno-app/src/components/FilePickerEditor/index.js @@ -6,10 +6,9 @@ import { IconX } from '@tabler/icons'; import { isWindowsOS } from 'utils/common/platform'; import slash from 'utils/common/slash'; -const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = false}) => { - value = value || []; +const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = false }) => { const dispatch = useDispatch(); - const filenames = value + const filenames = (isSingleFilePicker ? [value] : value || []) .filter((v) => v != null && v != '') .map((v) => { const separator = isWindowsOS() ? '\\' : '/'; @@ -20,7 +19,7 @@ const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = fa const title = filenames.map((v) => `- ${v}`).join('\n'); const browse = () => { - dispatch(browseFiles([],[''])) + dispatch(browseFiles([], [!isSingleFilePicker ? "multiSelections": ""])) .then((filePaths) => { // If file is in the collection's directory, then we use relative path // Otherwise, we use the absolute path @@ -34,7 +33,7 @@ const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = fa return filePath; }); - onChange(filePaths); + onChange(isSingleFilePicker ? filePaths[0] : filePaths); }) .catch((error) => { console.error(error); @@ -42,7 +41,7 @@ const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = fa }; const clear = () => { - onChange([]); + onChange(isSingleFilePicker ? '' : []); }; const renderButtonText = (filenames) => { @@ -66,9 +65,9 @@ const FilePickerEditor = ({ value, onChange, collection, isSingleFilePicker = fa
) : ( ); }; -export default FilePickerEditor; +export default FilePickerEditor; \ No newline at end of file diff --git a/packages/bruno-app/src/components/MarkDown/StyledWrapper.js b/packages/bruno-app/src/components/MarkDown/StyledWrapper.js index 85be8f137..fa1269e14 100644 --- a/packages/bruno-app/src/components/MarkDown/StyledWrapper.js +++ b/packages/bruno-app/src/components/MarkDown/StyledWrapper.js @@ -55,7 +55,7 @@ const StyledMarkdownBodyWrapper = styled.div` height: 1px; padding: 0; margin: 24px 0; - background-color: var(--color-border-default); + background-color: var(--color-sidebar-collection-item-active-indent-border); border: 0; } diff --git a/packages/bruno-app/src/components/Modal/index.js b/packages/bruno-app/src/components/Modal/index.js index 3ee08cbb9..0b44b928b 100644 --- a/packages/bruno-app/src/components/Modal/index.js +++ b/packages/bruno-app/src/components/Modal/index.js @@ -62,7 +62,7 @@ const Modal = ({ confirmText, cancelText, handleCancel, - handleConfirm, + handleConfirm = () => {}, children, confirmDisabled, hideCancel, @@ -92,7 +92,7 @@ const Modal = ({ }; useFocusTrap(modalRef); - + const closeModal = (args) => { setIsClosing(true); setTimeout(() => handleCancel(args), closeModalFadeTimeout); @@ -103,7 +103,7 @@ const Modal = ({ return () => { document.removeEventListener('keydown', handleKeydown); }; - }, [disableEscapeKey, document]); + }, [disableEscapeKey, document, handleConfirm]); let classes = 'bruno-modal'; if (isClosing) { diff --git a/packages/bruno-app/src/components/RequestPane/Binary/index.js b/packages/bruno-app/src/components/RequestPane/Binary/index.js index 77bbda8d5..f4a6eb007 100644 --- a/packages/bruno-app/src/components/RequestPane/Binary/index.js +++ b/packages/bruno-app/src/components/RequestPane/Binary/index.js @@ -1,21 +1,13 @@ -import React from 'react'; -import get from 'lodash/get'; -import cloneDeep from 'lodash/cloneDeep'; +import React, { useState, useEffect } from 'react'; +import { get, cloneDeep, isArray } from 'lodash'; import { IconTrash } from '@tabler/icons'; import { useDispatch } from 'react-redux'; import { useTheme } from 'providers/Theme'; -import { - addBinaryFile, - updateBinaryFile, - deleteBinaryFile -} from 'providers/ReduxStore/slices/collections'; +import { addBinaryFile, updateBinaryFile, deleteBinaryFile } from 'providers/ReduxStore/slices/collections/index'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; -import FilePickerEditor from 'components/FilePickerEditor'; +import FilePickerEditor from 'components/FilePickerEditor/index'; import SingleLineEditor from 'components/SingleLineEditor/index'; -import { isArray } from 'lodash'; -import path from 'node:path'; -import { useState } from 'react'; const Binary = ({ item, collection }) => { const dispatch = useDispatch(); @@ -29,35 +21,28 @@ const Binary = ({ item, collection }) => { addBinaryFile({ itemUid: item.uid, collectionUid: collection.uid, - type: 'binaryFile', - value: [''], }) ); }; const onSave = () => dispatch(saveRequest(item.uid, collection.uid)); const handleRun = () => dispatch(sendRequest(item, collection.uid)); - + const handleParamChange = (e, _param, type) => { - const param = cloneDeep(_param); - switch (type) { - - case 'value': { - param.value = isArray(e.target.value) && e.target.value.length > 0 ? e.target.value : ['']; - param.name = param.value.length === 0 ? '': path.basename(param.value[0], path.extname(param.value[0])); + case 'filePath': { + param.filePath = e.target.filePath; + param.contentType = ""; break; } case 'contentType': { - param.contentType = e.target.value; + param.contentType = e.target.contentType; break; } - case 'enabled': { - param.enabled = e.target.checked; - - setEnableFileUid(param.uid); - + case 'selected': { + param.selected = e.target.selected; + setEnableFileUid(param.uid) break; } } @@ -85,9 +70,15 @@ const Binary = ({ item, collection }) => { - - - + + + @@ -97,26 +88,26 @@ const Binary = ({ item, collection }) => { return ( @@ -170,4 +161,4 @@ const Binary = ({ item, collection }) => { ); }; -export default Binary; +export default Binary; \ No newline at end of file diff --git a/packages/bruno-app/src/components/RequestPane/RequestBody/RequestBodyMode/index.js b/packages/bruno-app/src/components/RequestPane/RequestBody/RequestBodyMode/index.js index 95b3b6a55..6e5d575c4 100644 --- a/packages/bruno-app/src/components/RequestPane/RequestBody/RequestBodyMode/index.js +++ b/packages/bruno-app/src/components/RequestPane/RequestBody/RequestBodyMode/index.js @@ -135,7 +135,7 @@ const RequestBodyMode = ({ item, collection }) => { onModeChange('binaryFile'); }} > - Binary File + File / Binary
{
{ style={{ width: 16, minWidth: 16, color: 'rgb(160 160 160)' }} onClick={handleClick} /> - diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js index 6c4031729..47f0f553e 100644 --- a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js @@ -68,7 +68,7 @@ const ImportCollection = ({ onClose, handleSubmit }) => { ); }; return ( - +

Select the type of your existing collection :

diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 0737cb133..2807bc11b 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -1041,13 +1041,16 @@ export const browseDirectory = () => (dispatch, getState) => { export const browseFiles = (filters = [], properties = ['multiSelections']) => - (dispatch, getState) => { + (_dispatch, _getState) => { const { ipcRenderer } = window; return new Promise((resolve, reject) => { - ipcRenderer.invoke('renderer:browse-files', undefined, undefined, undefined, filters, properties).then(resolve).catch(reject); + ipcRenderer + .invoke('renderer:browse-files', filters, properties) + .then(resolve) + .catch(reject); }); - }; +}; export const updateBrunoConfig = (brunoConfig, collectionUid) => (dispatch, getState) => { const state = getState(); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 35ccf244c..105901369 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -865,80 +865,82 @@ export const collectionsSlice = createSlice({ } } }, - moveMultipartFormParam: (state, action) => { - // Ensure item.draft is a deep clone of item if not already present - if (!item.draft) { - item.draft = cloneDeep(item); - } - - // Extract payload data - const { updateReorderedItem } = action.payload; - const params = item.draft.request.body.multipartForm; - - item.draft.request.body.multipartForm = updateReorderedItem.map((uid) => { - return params.find((param) => param.uid === uid); - }); - }, - addBinaryFile: (state, action) => { + moveMultipartFormParam: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); if (collection) { const item = findItemInCollection(collection, action.payload.itemUid); + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + const params = item.draft.request.body.multipartForm; + + item.draft.request.body.multipartForm = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, + addBinaryFile: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + if (item && isItemARequest(item)) { if (!item.draft) { item.draft = cloneDeep(item); } item.draft.request.body.binaryFile = item.draft.request.body.binaryFile || []; - + item.draft.request.body.binaryFile.push({ uid: uuid(), - type: action.payload.type, - name: '', - value: [''], + filePath: '', contentType: '', - enabled: false + selected: false }); } } }, updateBinaryFile: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); - + if (collection) { const item = findItemInCollection(collection, action.payload.itemUid); - + if (item && isItemARequest(item)) { if (!item.draft) { item.draft = cloneDeep(item); } - - item.draft.request.body.binaryFile = item.draft.request.body.binaryFile.map((p) => { - p.enabled = false; - return p; - }); - + const param = find(item.draft.request.body.binaryFile, (p) => p.uid === action.payload.param.uid); - + if (param) { - - const contentType = mime.contentType(path.extname(action.payload.param.value[0])); - - param.type = action.payload.param.type; - param.name = action.payload.param.name; - param.value = action.payload.param.value; + const contentType = mime.contentType(path.extname(action.payload.param.filePath)); + param.filePath = action.payload.param.filePath; param.contentType = action.payload.param.contentType || contentType || ''; - param.enabled = action.payload.param.enabled; + param.selected = action.payload.param.selected; + + item.draft.request.body.binaryFile = item.draft.request.body.binaryFile.map((p) => { + p.selected = p.uid === param.uid; + return p; + }); } } } }, deleteBinaryFile: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); - + if (collection) { const item = findItemInCollection(collection, action.payload.itemUid); - + if (item && isItemARequest(item)) { if (!item.draft) { item.draft = cloneDeep(item); @@ -948,6 +950,10 @@ export const collectionsSlice = createSlice({ item.draft.request.body.binaryFile, (p) => p.uid !== action.payload.paramUid ); + + if (item.draft.request.body.binaryFile.length > 0) { + item.draft.request.body.binaryFile[0].selected = true; + } } } }, diff --git a/packages/bruno-app/src/utils/codegenerator/har.js b/packages/bruno-app/src/utils/codegenerator/har.js index 19e4ea4de..8514588ab 100644 --- a/packages/bruno-app/src/utils/codegenerator/har.js +++ b/packages/bruno-app/src/utils/codegenerator/har.js @@ -65,6 +65,23 @@ const createPostData = (body, type) => { switch (body.mode) { case 'formUrlEncoded': + return { + mimeType: contentType, + text: new URLSearchParams( + body[body.mode] + .filter((param) => param.enabled) + .reduce((acc, param) => { + acc[param.name] = param.value; + return acc; + }, {}) + ).toString(), + params: body[body.mode] + .filter((param) => param.enabled) + .map((param) => ({ + name: param.name, + value: param.value + })) + }; case 'multipartForm': return { mimeType: contentType, @@ -78,18 +95,13 @@ const createPostData = (body, type) => { }; case 'binaryFile': const binary = { - mimeType: 'application/octet-stream', - // mimeType: body[body.mode].filter((param) => param.enabled)[0].contentType, + mimeType: body[body.mode].filter((param) => param.enabled)[0].contentType, params: body[body.mode] - .filter((param) => param.enabled) + .filter((param) => param.selected) .map((param) => ({ - name: param.name, - value: param.value, - fileName: param.value + value: param.filePath, })) }; - - console.log('curl-binary', binary); return binary; default: return { @@ -100,10 +112,6 @@ const createPostData = (body, type) => { }; export const buildHarRequest = ({ request, headers, type }) => { - - console.log('buildHarRequest', request, headers, type); - - console.log('buildHarRequest-postData', createPostData(request.body, type)); return { method: request.method, url: encodeURI(request.url), diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 96e91b78a..db9a92503 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -275,11 +275,9 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {} return map(params, (param) => { return { uid: param.uid, - type: param.type, - name: param.name, - value: param.value, + filePath: param.filePath, contentType: param.contentType, - enabled: param.enabled + selected: param.selected } }); } @@ -666,7 +664,7 @@ export const humanizeRequestBodyMode = (mode) => { break; } case 'binaryFile': { - label = 'Binary File'; + label = 'File / Binary'; break; } case 'formUrlEncoded': { diff --git a/packages/bruno-app/src/utils/curl/curl-to-json.js b/packages/bruno-app/src/utils/curl/curl-to-json.js index 5a2c62022..7683b5cda 100644 --- a/packages/bruno-app/src/utils/curl/curl-to-json.js +++ b/packages/bruno-app/src/utils/curl/curl-to-json.js @@ -102,30 +102,24 @@ function getFilesString(request) { data.data = {}; - if (request.isDataBinary){ + if (request.isDataBinary) { + let filePath = ''; - let filePath = '' - - if(request.data.startsWith('@')){ + if (request.data.startsWith('@')) { filePath = request.data.slice(1); - }else{ + } else { filePath = request.data; } - const fileName = path.basename(filePath); - data.data = [ { - name: repr(fileName), - value: [repr(filePath)], - enabled: true, + filePath: repr(filePath), contentType: request.headers['Content-Type'], - type: 'binaryFile' + selected: true, } ]; return data; - } data.files = {}; @@ -190,13 +184,11 @@ const curlToJson = (curlCommand) => { if (request.query) { requestJson.queries = getQueries(request); - } - - else if (request.multipartUploads || request.isDataBinary) { + } else if (request.multipartUploads || request.isDataBinary) { Object.assign(requestJson, getFilesString(request)); } else if (typeof request.data === 'string' || typeof request.data === 'number') { Object.assign(requestJson, getDataString(request)); - } + } if (request.insecure) { requestJson.insecure = false; diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index c0391f4d6..5285ebd9b 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -54,14 +54,11 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection }); // browse directory for file - ipcMain.handle('renderer:browse-files', async (event, pathname, request, filters, properties) => { + ipcMain.handle('renderer:browse-files', async (_, filters, properties) => { try { - - const filePaths = await browseFiles(mainWindow, filters, properties); - - return filePaths; + return await browseFiles(mainWindow, filters, properties); } catch (error) { - return Promise.reject(error); + throw error; } }); diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 7495c94fa..7e06fd23c 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -583,7 +583,6 @@ const registerNetworkIpc = (mainWindow) => { try { request.signal = abortController.signal; - saveCancelToken(cancelTokenUid, abortController); await runPreRequest( @@ -614,7 +613,7 @@ const registerNetworkIpc = (mainWindow) => { url: request.url, method: request.method, headers: request.headers, - data: request.mode == 'binaryFile'? undefined: safeParseJSON(safeStringifyJSON(request.data)) , + data: request.mode == 'binaryFile'? "": safeParseJSON(safeStringifyJSON(request.data)) , timestamp: Date.now() }, collectionUid, diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 297033c6d..70d8017d1 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -1,4 +1,4 @@ -const { get, each, filter } = require('lodash'); +const { get, each, filter, find } = require('lodash'); const decomment = require('decomment'); const crypto = require('node:crypto'); const fs = require('node:fs/promises'); @@ -254,30 +254,25 @@ const prepareRequest = async (item, collection, abortController) => { } if (request.body.mode === 'binaryFile') { - if (!contentTypeDefined) { - axiosRequest.headers['content-type'] = 'application/octet-stream'; + axiosRequest.headers['content-type'] = 'application/octet-stream'; // Default headers for binary file uploads } - - if (request.body.binaryFile && request.body.binaryFile.length > 0) { - - axiosRequest.headers['content-type'] = request.body.binaryFile[0].contentType; - - let filePath = request.body.binaryFile[0].value[0]; - - if (filePath && filePath !== '') { - + + const binaryFile = find(request.body.binaryFile, (param) => param.selected); + if (binaryFile) { + let { filePath, contentType } = binaryFile; + + axiosRequest.headers['content-type'] = contentType; + if (filePath) { if (!path.isAbsolute(filePath)) { - filePath = path.join(collectionPath, filePath); } - - const file = await fs.readFile(filePath, abortController) - - axiosRequest.data = file - - if(axiosRequest.headers['content-type'].includes('application/json')) { - axiosRequest.data = JSON.parse(file) + + try { + const fileContent = await fs.readFile(filePath); + axiosRequest.data = fileContent; + } catch (error) { + console.error('Error reading file:', error); } } } diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index e7b0c5772..3b228036f 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -177,9 +177,9 @@ const multipartExtractContentType = (pair) => { const binaryFileExtractContentType = (pair) => { if (_.isString(pair.value)) { const match = pair.value.match(/^(.*?)\s*@contentType\((.*?)\)\s*$/); - if (match != null && match.length > 2) { - pair.value = match[1]; - pair.contentType = match[2]; + if (match && match.length > 2) { + pair.value = match[1].trim(); + pair.contentType = match[2].trim(); } else { pair.contentType = ''; } @@ -206,21 +206,25 @@ const mapPairListToKeyValPairsMultipart = (pairList = [], parseEnabled = true) = const mapPairListToKeyValPairsBinaryFile = (pairList = [], parseEnabled = true) => { const pairs = mapPairListToKeyValPairs(pairList, parseEnabled); - return pairs.map((pair) => { binaryFileExtractContentType(pair); if (pair.value.startsWith('@file(') && pair.value.endsWith(')')) { - let filestr = pair.value.replace(/^@file\(/, '').replace(/\)$/, ''); - pair.type = 'binaryFile'; - pair.value = filestr != '' ? filestr.split('|') : ['']; + let filePath = pair.value.replace(/^@file\(/, '').replace(/\)$/, ''); + pair.filePath = filePath; + pair.selected = pair.enabled + + // Remove pair.value as it only contains the file path reference + delete pair.value; + // Remove pair.name as it is auto-generated (e.g., file1, file2, file3, etc.) + delete pair.name; + delete pair.enabled; } return pair; }); }; - const concatArrays = (objValue, srcValue) => { if (_.isArray(objValue) && _.isArray(srcValue)) { return objValue.concat(srcValue); @@ -746,3 +750,4 @@ const parser = (input) => { }; module.exports = parser; + \ No newline at end of file diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index c4e2ba323..164ea6a35 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -2,8 +2,8 @@ const _ = require('lodash'); const { indentString } = require('../../v1/src/utils'); -const enabled = (items = []) => items.filter((item) => item.enabled); -const disabled = (items = []) => items.filter((item) => !item.enabled); +const enabled = (items = [], key = "enabled") => items.filter((item) => item[key]); +const disabled = (items = [], key = "enabled") => items.filter((item) => !item[key]); // remove the last line if two new lines are found const stripLastLine = (text) => { @@ -316,21 +316,19 @@ ${indentString(body.sparql)} if (body && body.binaryFile && body.binaryFile.length) { bru += `body:binary-file {`; - const binaryFiles = enabled(body.binaryFile).concat(disabled(body.binaryFile)); + const binaryFiles = enabled(body.binaryFile, "selected").concat(disabled(body.binaryFile, "selected")); if (binaryFiles.length) { bru += `\n${indentString( binaryFiles .map((item) => { - const enabled = item.enabled ? '' : '~'; + const selected = item.selected ? '' : '~'; const contentType = item.contentType && item.contentType !== '' ? ' @contentType(' + item.contentType + ')' : ''; - - if (item.type === 'binaryFile') { - let filestr = item.value[0] || ''; - const value = `@file(${filestr})`; - return `${enabled}${item.name}: ${value}${contentType}`; - } + const filePath = item.filePath || ''; + const value = `@file(${filePath})`; + const itemName = "file"; + return `${selected}${itemName}: ${value}${contentType}`; }) .join('\n') )}`; diff --git a/packages/bruno-lang/v2/tests/fixtures/request.bru b/packages/bruno-lang/v2/tests/fixtures/request.bru index 5f7183f34..59f37ac89 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.bru +++ b/packages/bruno-lang/v2/tests/fixtures/request.bru @@ -104,7 +104,8 @@ body:multipart-form { body:binary-file { file: @file(path/to/file.json) @contentType(application/json) - ~file2: @file(path/to/file2.json) @contentType(application/json) + file: @file(path/to/file.json) @contentType(application/json) + ~file: @file(path/to/file2.json) @contentType(application/json) } body:graphql { diff --git a/packages/bruno-lang/v2/tests/fixtures/request.json b/packages/bruno-lang/v2/tests/fixtures/request.json index ad7a45495..166040509 100644 --- a/packages/bruno-lang/v2/tests/fixtures/request.json +++ b/packages/bruno-lang/v2/tests/fixtures/request.json @@ -140,18 +140,19 @@ ], "binaryFile" : [ { - "name": "file", - "value": ["path/to/file.json"], - "enabled": true, - "type": "binaryFile", - "contentType": "application/json" + "filePath": "path/to/file.json", + "contentType": "application/json", + "selected": true }, { - "name": "file2", - "value": ["path/to/file2.json"], - "enabled": false, - "type": "binaryFile", - "contentType": "application/json" + "filePath": "path/to/file.json", + "contentType": "application/json", + "selected": true + }, + { + "filePath": "path/to/file2.json", + "contentType": "application/json", + "selected": false } ] }, diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 19d98afbb..fdf88b38c 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -77,11 +77,9 @@ const multipartFormSchema = Yup.object({ const binaryFileSchema = Yup.object({ uid: uidSchema, - type: Yup.string().oneOf(['binaryFile']).required('type is required'), - name: Yup.string().nullable(), - value: Yup.array().of(Yup.string().nullable()).nullable(), + filePath: Yup.string().nullable(), contentType: Yup.string().nullable(), - enabled: Yup.boolean() + selected: Yup.boolean() }) .noUnknown(true) .strict(); diff --git a/packages/bruno-tests/collection/echo/multiline/echo binary.bru b/packages/bruno-tests/collection/echo/multiline/echo binary.bru new file mode 100644 index 000000000..d11b30413 --- /dev/null +++ b/packages/bruno-tests/collection/echo/multiline/echo binary.bru @@ -0,0 +1,15 @@ +meta { + name: echo binary + type: http + seq: 1 +} + +post { + url: {{echo-host}} + body: binaryFile + auth: none +} + +body:binary-file { + file: @file(bruno.png) @contentType(image/png) +} diff --git a/packages/bruno-tests/src/echo/index.js b/packages/bruno-tests/src/echo/index.js index ba9b403ae..89a9208e0 100644 --- a/packages/bruno-tests/src/echo/index.js +++ b/packages/bruno-tests/src/echo/index.js @@ -19,6 +19,17 @@ router.post('/xml-raw', (req, res) => { return res.send(req.rawBody); }); +router.post('/bin', (req, res) => { + const rawBody = req.body; + + if (!rawBody || rawBody.length === 0) { + return res.status(400).send('No data received'); + } + + res.set('Content-Type', req.headers['content-type'] || 'application/octet-stream'); + res.send(rawBody); +}); + router.get('/bom-json-test', (req, res) => { const jsonData = { message: 'Hello!', diff --git a/packages/bruno-tests/src/index.js b/packages/bruno-tests/src/index.js index a09cb434b..a482fc128 100644 --- a/packages/bruno-tests/src/index.js +++ b/packages/bruno-tests/src/index.js @@ -10,6 +10,7 @@ const multipartRouter = require('./multipart'); const app = new express(); const port = process.env.PORT || 8080; +app.use(express.raw({type: '*/*', limit: '100mb'})); app.use(cors()); app.use(xmlParser()); app.use(bodyParser.text());
File
Content-Type
Enabled
+
File
+
+
Content-Type
+
+
Selected
+
- - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - collection={collection} - /> + + handleParamChange( + { + target: { + filePath: path + } + }, + param, + 'filePath' + ) + } + collection={collection} + /> { handleParamChange( { target: { - value: newValue + contentType: newValue } }, param, @@ -141,19 +132,19 @@ const Binary = ({ item, collection }) => { handleParamChange(e, param, 'enabled')} + onChange={(e) => handleParamChange(e, param, 'selected')} /> -
- +
+