Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pr #2755 #3737

Draft
wants to merge 37 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
478fd4b
Started implementing raw file request body feature and added selectio…
zachary-berdell-elliott Jul 26, 2024
97bb560
Fixing import of RawFileParams component.
zachary-berdell-elliott Jul 27, 2024
0602373
Added logic to help with requests of raw files and got button for sel…
zachary-berdell-elliott Jul 28, 2024
b792f49
Added more logic for raw file and added rawFile to validation list so…
zachary-berdell-elliott Jul 29, 2024
145de02
Added rawFile to bruno-lang v1 files.
zachary-berdell-elliott Aug 3, 2024
b54b5ff
Added logic to select only one file.
zachary-berdell-elliott Aug 3, 2024
50482ee
Made changes so only one file can be selected in raw file upload.
zachary-berdell-elliott Aug 3, 2024
c81aded
Got file selection to work.
zachary-berdell-elliott Aug 3, 2024
e7976e9
Got request saving to work for faw files.
zachary-berdell-elliott Aug 4, 2024
f058fea
Making syntax corrections and checking tests.
zachary-berdell-elliott Aug 4, 2024
559e57d
Merge remote-tracking branch 'origin' into feature/add-raw-file-reque…
zachary-berdell-elliott Aug 4, 2024
ede35f4
Rolling back test changes.
zachary-berdell-elliott Aug 4, 2024
ca1f5b5
Made corrections so file is correctly found and uploaded.
zachary-berdell-elliott Aug 4, 2024
538b524
Made button for selecting a raw file bigger.
zachary-berdell-elliott Aug 4, 2024
069a038
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Aug 10, 2024
e7a1093
Merge remote-tracking branch 'origin' into feature/add-raw-file-reque…
zachary-berdell-elliott Aug 17, 2024
7b51739
Merge branch 'feature/add-raw-file-request-body-option' of https://gi…
zachary-berdell-elliott Aug 17, 2024
1a6a0b1
Changing to only use tailwind styles in RawFilePickerEditor to improv…
zachary-berdell-elliott Aug 17, 2024
1415e76
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Aug 24, 2024
a425c27
Update packages/bruno-app/src/components/RequestPane/RawFileParams/in…
zachary-berdell-elliott Aug 26, 2024
a573251
Update packages/bruno-app/src/components/RawFilePickerEditor/index.js
zachary-berdell-elliott Aug 26, 2024
d7b249f
Update packages/bruno-electron/src/utils/filesystem.js
zachary-berdell-elliott Aug 26, 2024
7757719
Update packages/bruno-app/src/components/RawFilePickerEditor/index.js
zachary-berdell-elliott Aug 26, 2024
cbf4e0b
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Sep 2, 2024
dad28f8
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Sep 5, 2024
88836ee
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Sep 6, 2024
a8e6fcf
Merge branch 'main' into feature/add-raw-file-request-body-option
zachary-berdell-elliott Sep 23, 2024
e58f54d
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Oct 1, 2024
d827150
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Oct 26, 2024
fda9b7b
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Nov 19, 2024
7787991
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-o…
zachary-berdell-elliott Nov 28, 2024
977274a
Merge branch 'main' into pr-2755
sanjaikumar-bruno Jan 2, 2025
54e3aa9
refactor: streamline file handling in RawFilePickerEditor and RawFile…
sanjaikumar-bruno Jan 3, 2025
d90f129
feat: enhance raw file handling and response in network IPC and tests
sanjaikumar-bruno Jan 6, 2025
cb5bdcd
Merge branch 'main' into improv-pr-2755
sanjaikumar-bruno Jan 6, 2025
413b4a8
feat: enhance file handling by adding asynchronous read and file size…
sanjaikumar-bruno Jan 6, 2025
6650850
feat: replace synchronous file read with stream-based reading for imp…
sanjaikumar-bruno Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions packages/bruno-app/src/components/RawFilePickerEditor/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import path from 'path';
import { useDispatch } from 'react-redux';
import { browseFile } from 'providers/ReduxStore/slices/collections/actions';
import { IconX } from '@tabler/icons';
import { isWindowsOS } from 'utils/common/platform';
import slash from 'utils/common/slash';

const RawFilePickerEditor = ({ value, onChange, collection }) => {
value = value || '';
const dispatch = useDispatch();
const separator = isWindowsOS() ? '\\' : '/';
const filename = value != '' ? value.split(separator).pop() : value;
const title = `- ${filename}`;

const browse = () => {
dispatch(browseFile())
.then((filePath) => {
const collectionDir = collection.pathname;

if (typeof filePath === 'string') {
filePath = filePath.startsWith(collectionDir)
? path.relative(slash(collectionDir), slash(filePath))
: filePath;

onChange(filePath);
}
})
.catch((error) => {
console.error(error);
});
};

const clear = () => {
onChange(null);
};

return filename.length > 0 ? (
<div className="btn btn-secondary px-1 font-normal w-full text-ellipsis overflow-x-hidden" title={title}>
<button className="align-middle" onClick={clear}>
<IconX size={18} />
</button>
&nbsp;
{filename}
</div>
) : (
<button className="btn btn-secondary px-1 w-full" onClick={browse}>
Select File
</button>
);
};

export default RawFilePickerEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import styled from 'styled-components';

const Wrapper = styled.div`
.btn {
padding: 2% 0%;
font-size: 125%;
}
`;

export default Wrapper;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
import RawFilePickerEditor from 'components/RawFilePickerEditor';
import { updateRequestBody } from 'providers/ReduxStore/slices/collections/index';

const RawFileParams = ({ item, collection }) => {
const dispatch = useDispatch();
const fileName = item.draft ? get(item, 'draft.request.body.rawFile') : get(item, 'request.body.rawFile') || [];

const handleFileChange = (e) => {
dispatch(
updateRequestBody({
content: e.target.rawFilePath,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};

return (
<StyledWrapper className="w-full">
<RawFilePickerEditor
value={fileName ? fileName : null}
onChange={(rawFilePath) =>
handleFileChange({
target: {
rawFilePath,
}
})
}
collection={collection}
/>
</StyledWrapper>
);
};
export default RawFileParams;
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ const RequestBodyMode = ({ item, collection }) => {
SPARQL
</div>
<div className="label-item font-medium">Other</div>
<div
className="dropdown-item"
onClick={() => {
dropdownTippyRef.current.hide();
onModeChange('rawFile');
}}
>
Raw File
</div>
<div
className="dropdown-item"
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import get from 'lodash/get';
import CodeEditor from 'components/CodeEditor';
import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams';
import MultipartFormParams from 'components/RequestPane/MultipartFormParams';
import RawFileParams from 'components/RequestPane/RawFileParams';
import { useDispatch, useSelector } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { updateRequestBody } from 'providers/ReduxStore/slices/collections';
Expand Down Expand Up @@ -69,6 +70,10 @@ const RequestBody = ({ item, collection }) => {
return <MultipartFormParams item={item} collection={collection} />;
}

if (bodyMode === 'rawFile') {
return <RawFileParams item={item} collection={collection} />;
}

return <StyledWrapper className="w-full">No Body</StyledWrapper>;
};
export default RequestBody;
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,8 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
xml: null,
sparql: null,
multipartForm: null,
formUrlEncoded: null
formUrlEncoded: null,
rawFile: null
},
auth: auth ?? {
mode: 'none'
Expand Down Expand Up @@ -1048,6 +1049,16 @@ export const browseFiles =
});
};

export const browseFile =
(filters = []) =>
(dispatch, getState) => {
const { ipcRenderer } = window;

return new Promise((resolve, reject) => {
ipcRenderer.invoke('renderer:browse-file', filters).then(resolve).catch(reject);
});
};

export const updateBrunoConfig = (brunoConfig, collectionUid) => (dispatch, getState) => {
const state = getState();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,10 @@ export const collectionsSlice = createSlice({
item.draft.request.body.multipartForm = action.payload.content;
break;
}
case 'rawFile': {
item.draft.request.body.rawFile = action.payload.content;
break;
}
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion packages/bruno-app/src/utils/collections/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
graphql: si.request.body.graphql,
sparql: si.request.body.sparql,
formUrlEncoded: copyFormUrlEncodedParams(si.request.body.formUrlEncoded),
multipartForm: copyMultipartFormParams(si.request.body.multipartForm)
multipartForm: copyMultipartFormParams(si.request.body.multipartForm),
rawFile: si.request.body.rawFile
},
script: si.request.script,
vars: si.request.vars,
Expand Down Expand Up @@ -652,6 +653,10 @@ export const humanizeRequestBodyMode = (mode) => {
label = 'Multipart Form';
break;
}
case 'rawFile': {
label = 'Raw File';
break;
}
}

return label;
Expand Down
10 changes: 10 additions & 0 deletions packages/bruno-cli/src/runner/prepare-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ const prepareRequest = (item = {}, collection = {}) => {
axiosRequest.data = enabledParams;
}

if(request.body.mode === 'rawFile') {
if (request.body.rawFile) {
axiosRequest.data = fs.readFileSync(request.body.rawFile);
fileLength = axiosRequest.data.length;
axiosRequest.headers['content-length'] = fileLength;
} else {
axiosRequest.data = null;
}
}

if (request.body.mode === 'graphql') {
const graphqlQuery = {
query: get(request, 'body.graphql.query'),
Expand Down
12 changes: 12 additions & 0 deletions packages/bruno-electron/src/ipc/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
isDirectory,
browseDirectory,
browseFiles,
browseFile,
createDirectory,
searchForBruFiles,
sanitizeDirectoryName,
Expand Down Expand Up @@ -64,6 +65,17 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
}
});

// browse directory for one file
ipcMain.handle('renderer:browse-file', async (event, pathname, request, filters) => {
try {
const filePath = await browseFile(mainWindow, filters);

return filePath;
} catch (error) {
return Promise.reject(error);
}
});

// create collection
ipcMain.handle(
'renderer:create-collection',
Expand Down
21 changes: 20 additions & 1 deletion packages/bruno-electron/src/ipc/network/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const { makeAxiosInstance } = require('./axios-instance');
const { addAwsV4Interceptor, resolveAwsV4Credentials } = require('./awsv4auth-helper');
const { addDigestInterceptor } = require('./digestauth-helper');
const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../../utils/proxy-util');
const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem');
const { chooseFileToSave, writeBinaryFile, writeFile, readFileStream, getFileSize } = require('../../utils/filesystem');
const { getCookieStringForUrl, addCookieToJar, getDomainsWithCookies } = require('../../utils/cookies');
const {
resolveOAuth2AuthorizationCodeAccessToken,
Expand All @@ -41,6 +41,8 @@ const FormData = require('form-data');
const { createFormData } = require('../../utils/form-data');
const { findItemInCollectionByPathname } = require('../../utils/collection');

const GENERIC_FILE_CONTENT_TYPE = "application/octet-stream";

const safeStringifyJSON = (data) => {
try {
return JSON.stringify(data);
Expand All @@ -49,6 +51,7 @@ const safeStringifyJSON = (data) => {
}
};


const safeParseJSON = (data) => {
try {
return JSON.parse(data);
Expand Down Expand Up @@ -452,6 +455,22 @@ const registerNetworkIpc = (mainWindow) => {
}
}

if (request.headers['content-type'] === GENERIC_FILE_CONTENT_TYPE) {
if (!(request.data instanceof Buffer)) {
const rawFilePath = request.data;

try {
request.data = await readFileStream(rawFilePath);
const newContentType = mime.lookup(rawFilePath) || GENERIC_FILE_CONTENT_TYPE;
const fileSize = await getFileSize(rawFilePath);

extend(request.headers, { 'content-type': newContentType, 'content-length': fileSize });
} catch (err) {
console.error(err);
}
}
}

return scriptResult;
};

Expand Down
13 changes: 13 additions & 0 deletions packages/bruno-electron/src/ipc/network/prepare-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ const decomment = require('decomment');
const crypto = require('node:crypto');
const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars } = require('../../utils/collection');
const { buildFormUrlEncodedPayload, createFormData } = require('../../utils/form-data');
const { readFile } = require('../../utils/filesystem');
const { lookup } = require("mime-types")

const GENERIC_FILE_CONTENT_TYPE = "application/octet-stream";


const setAuthHeaders = (axiosRequest, request, collectionRoot) => {
const collectionAuth = get(collectionRoot, 'request.auth');
Expand Down Expand Up @@ -252,6 +257,14 @@ const prepareRequest = (item, collection) => {
axiosRequest.data = enabledParams;
}

if(request.body.mode === 'rawFile') {
if (!contentTypeDefined){
axiosRequest.headers["content-type"] = GENERIC_FILE_CONTENT_TYPE;
};

axiosRequest.data = request.body.rawFile;
}

if (request.body.mode === 'graphql') {
const graphqlQuery = {
query: get(request, 'body.graphql.query'),
Expand Down
48 changes: 47 additions & 1 deletion packages/bruno-electron/src/utils/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,20 @@ const browseFiles = async (win, filters) => {
return filePaths.map((path) => normalizeAndResolvePath(path)).filter((path) => isFile(path));
};

const browseFile = async (win, filters) => {
const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openFile'],
filters
});

if (!filePaths || !filePaths[0]) {
return false;
}

const resolvedPath = normalizeAndResolvePath(filePaths[0]);
return isFile(resolvedPath) ? resolvedPath : false;
}

const chooseFileToSave = async (win, preferredFileName = '') => {
const { filePath } = await dialog.showSaveDialog(win, {
defaultPath: preferredFileName
Expand Down Expand Up @@ -211,6 +225,35 @@ const safeToRename = (oldPath, newPath) => {
}
};

const readFileStream = (path) => {
return new Promise((resolve, reject) => {
const stream = fs.createReadStream(path);
let data = '';

stream.on('data', chunk => {
data += chunk;
});

stream.on('end', () => {
resolve(data);
});

stream.on('error', err => {
console.error("Error while reading the file", err);
reject(err);
});
});
}

const getFileSize = async (path) => {
try {
return stats = (await fs.stat(path)).size
} catch (err) {
console.log("Error while trying to get the file size", err);
throw err;
}
}

module.exports = {
isValidPathname,
exists,
Expand All @@ -227,6 +270,7 @@ module.exports = {
createDirectory,
browseDirectory,
browseFiles,
browseFile,
chooseFileToSave,
searchForFiles,
searchForBruFiles,
Expand All @@ -235,5 +279,7 @@ module.exports = {
isWindowsOS,
safeToRename,
isValidFilename,
hasSubDirectories
hasSubDirectories,
readFileStream,
getFileSize
};
Loading
Loading