mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-21 15:33:11 +01:00
Now based on the request type appropriate views are shown. (#3340)
* Now based on the request type appropriate views are shown. Co-authored-by: Anoop M D <anoop.md1421@gmail.com>
This commit is contained in:
parent
1cb0d4e191
commit
412a0ed078
@ -39,6 +39,14 @@ const StyledWrapper = styled.div`
|
|||||||
textarea.curl-command {
|
textarea.curl-command {
|
||||||
min-height: 150px;
|
min-height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
padding: 0.2rem 0.6rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useRef, useEffect, useCallback } from 'react';
|
import React, { useRef, useEffect, useCallback, forwardRef, useState } from 'react';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
@ -12,6 +12,8 @@ import HttpMethodSelector from 'components/RequestPane/QueryUrl/HttpMethodSelect
|
|||||||
import { getDefaultRequestPaneTab } from 'utils/collections';
|
import { getDefaultRequestPaneTab } from 'utils/collections';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import { getRequestFromCurlCommand } from 'utils/curl';
|
import { getRequestFromCurlCommand } from 'utils/curl';
|
||||||
|
import Dropdown from 'components/Dropdown';
|
||||||
|
import { IconCaretDown } from '@tabler/icons';
|
||||||
|
|
||||||
const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -19,6 +21,39 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
|||||||
const {
|
const {
|
||||||
brunoConfig: { presets: collectionPresets = {} }
|
brunoConfig: { presets: collectionPresets = {} }
|
||||||
} = collection;
|
} = collection;
|
||||||
|
const [curlRequestTypeDetected, setCurlRequestTypeDetected] = useState(null);
|
||||||
|
|
||||||
|
const dropdownTippyRef = useRef();
|
||||||
|
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
|
||||||
|
|
||||||
|
const Icon = forwardRef((props, ref) => {
|
||||||
|
return (
|
||||||
|
<div ref={ref} className="flex items-center justify-end auth-type-label select-none">
|
||||||
|
{curlRequestTypeDetected === 'http-request' ? "HTTP" : "GraphQL"}
|
||||||
|
<IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// This function analyzes a given cURL command string and determines whether the request is a GraphQL or HTTP request.
|
||||||
|
const identifyCurlRequestType = (url, headers, body) => {
|
||||||
|
if (url.endsWith('/graphql')) {
|
||||||
|
setCurlRequestTypeDetected('graphql-request');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type')?.value;
|
||||||
|
if (contentType && contentType.includes('application/graphql')) {
|
||||||
|
setCurlRequestTypeDetected('graphql-request');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurlRequestTypeDetected('http-request');
|
||||||
|
};
|
||||||
|
|
||||||
|
const curlRequestTypeChange = (type) => {
|
||||||
|
setCurlRequestTypeDetected(type);
|
||||||
|
};
|
||||||
|
|
||||||
const getRequestType = (collectionPresets) => {
|
const getRequestType = (collectionPresets) => {
|
||||||
if (!collectionPresets || !collectionPresets.requestType) {
|
if (!collectionPresets || !collectionPresets.requestType) {
|
||||||
@ -99,11 +134,11 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
|||||||
})
|
})
|
||||||
.catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request'));
|
.catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request'));
|
||||||
} else if (values.requestType === 'from-curl') {
|
} else if (values.requestType === 'from-curl') {
|
||||||
const request = getRequestFromCurlCommand(values.curlCommand);
|
const request = getRequestFromCurlCommand(values.curlCommand, curlRequestTypeDetected);
|
||||||
dispatch(
|
dispatch(
|
||||||
newHttpRequest({
|
newHttpRequest({
|
||||||
requestName: values.requestName,
|
requestName: values.requestName,
|
||||||
requestType: 'http-request',
|
requestType: curlRequestTypeDetected,
|
||||||
requestUrl: request.url,
|
requestUrl: request.url,
|
||||||
requestMethod: request.method,
|
requestMethod: request.method,
|
||||||
collectionUid: collection.uid,
|
collectionUid: collection.uid,
|
||||||
@ -158,6 +193,12 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
|||||||
formik.setFieldValue('requestType', 'from-curl');
|
formik.setFieldValue('requestType', 'from-curl');
|
||||||
formik.setFieldValue('curlCommand', pastedData);
|
formik.setFieldValue('curlCommand', pastedData);
|
||||||
|
|
||||||
|
// Identify the request type
|
||||||
|
const request = getRequestFromCurlCommand(pastedData);
|
||||||
|
if (request) {
|
||||||
|
identifyCurlRequestType(request.url, request.headers, request.body);
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent the default paste behavior to avoid pasting into the textarea
|
// Prevent the default paste behavior to avoid pasting into the textarea
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
@ -165,6 +206,18 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
|||||||
[formik]
|
[formik]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleCurlCommandChange = (event) => {
|
||||||
|
formik.handleChange(event);
|
||||||
|
|
||||||
|
if (event.target.name === 'curlCommand') {
|
||||||
|
const curlCommand = event.target.value;
|
||||||
|
const request = getRequestFromCurlCommand(curlCommand);
|
||||||
|
if (request) {
|
||||||
|
identifyCurlRequestType(request.url, request.headers, request.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<Modal size="md" title="New Request" confirmText="Create" handleConfirm={onSubmit} handleCancel={onClose}>
|
<Modal size="md" title="New Request" confirmText="Create" handleConfirm={onSubmit} handleCancel={onClose}>
|
||||||
@ -279,15 +332,37 @@ const NewRequest = ({ collection, item, isEphemeral, onClose }) => {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<label htmlFor="request-url" className="block font-semibold">
|
<div className="flex justify-between">
|
||||||
cURL Command
|
<label htmlFor="request-url" className="block font-semibold">
|
||||||
</label>
|
cURL Command
|
||||||
|
</label>
|
||||||
|
<Dropdown className="dropdown" onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
|
||||||
|
<div
|
||||||
|
className="dropdown-item"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
curlRequestTypeChange('http-request');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
HTTP
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="dropdown-item"
|
||||||
|
onClick={() => {
|
||||||
|
dropdownTippyRef.current.hide();
|
||||||
|
curlRequestTypeChange('graphql-request');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
GraphQL
|
||||||
|
</div>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
<textarea
|
<textarea
|
||||||
name="curlCommand"
|
name="curlCommand"
|
||||||
placeholder="Enter cURL request here.."
|
placeholder="Enter cURL request here.."
|
||||||
className="block textbox w-full mt-4 curl-command"
|
className="block textbox w-full mt-4 curl-command"
|
||||||
value={formik.values.curlCommand}
|
value={formik.values.curlCommand}
|
||||||
onChange={formik.handleChange}
|
onChange={handleCurlCommandChange}
|
||||||
></textarea>
|
></textarea>
|
||||||
{formik.touched.curlCommand && formik.errors.curlCommand ? (
|
{formik.touched.curlCommand && formik.errors.curlCommand ? (
|
||||||
<div className="text-red-500">{formik.errors.curlCommand}</div>
|
<div className="text-red-500">{formik.errors.curlCommand}</div>
|
||||||
|
@ -19,16 +19,23 @@ const createContentType = (mode) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a list of enabled headers for the request, ensuring no duplicate content-type headers.
|
||||||
|
*
|
||||||
|
* @param {Object} request - The request object.
|
||||||
|
* @param {Object[]} headers - The array of header objects, each containing name, value, and enabled properties.
|
||||||
|
* @returns {Object[]} - An array of enabled headers with normalized names and values.
|
||||||
|
*/
|
||||||
const createHeaders = (request, headers) => {
|
const createHeaders = (request, headers) => {
|
||||||
const enabledHeaders = headers
|
const enabledHeaders = headers
|
||||||
.filter((header) => header.enabled)
|
.filter((header) => header.enabled)
|
||||||
.map((header) => ({
|
.map((header) => ({
|
||||||
name: header.name,
|
name: header.name.toLowerCase(),
|
||||||
value: header.value
|
value: header.value
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const contentType = createContentType(request.body?.mode);
|
const contentType = createContentType(request.body?.mode);
|
||||||
if (contentType !== '') {
|
if (contentType !== '' && !enabledHeaders.some((header) => header.name === 'content-type')) {
|
||||||
enabledHeaders.push({ name: 'content-type', value: contentType });
|
enabledHeaders.push({ name: 'content-type', value: contentType });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,12 @@ function getQueries(request) {
|
|||||||
return queries;
|
return queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts request data to a string based on its content type.
|
||||||
|
*
|
||||||
|
* @param {Object} request - The request object containing data and headers.
|
||||||
|
* @returns {Object} An object containing the data string.
|
||||||
|
*/
|
||||||
function getDataString(request) {
|
function getDataString(request) {
|
||||||
if (typeof request.data === 'number') {
|
if (typeof request.data === 'number') {
|
||||||
request.data = request.data.toString();
|
request.data = request.data.toString();
|
||||||
@ -44,7 +50,13 @@ function getDataString(request) {
|
|||||||
const contentType = getContentType(request.headers);
|
const contentType = getContentType(request.headers);
|
||||||
|
|
||||||
if (contentType && contentType.includes('application/json')) {
|
if (contentType && contentType.includes('application/json')) {
|
||||||
return { data: request.data.toString() };
|
try {
|
||||||
|
const parsedData = JSON.parse(request.data);
|
||||||
|
return { data: JSON.stringify(parsedData) };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to parse JSON data:', error);
|
||||||
|
return { data: request.data.toString() };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedQueryString = querystring.parse(request.data, { sort: false });
|
const parsedQueryString = querystring.parse(request.data, { sort: false });
|
||||||
|
@ -2,7 +2,7 @@ import { forOwn } from 'lodash';
|
|||||||
import { convertToCodeMirrorJson } from 'utils/common';
|
import { convertToCodeMirrorJson } from 'utils/common';
|
||||||
import curlToJson from './curl-to-json';
|
import curlToJson from './curl-to-json';
|
||||||
|
|
||||||
export const getRequestFromCurlCommand = (curlCommand) => {
|
export const getRequestFromCurlCommand = (curlCommand, requestType = 'http-request') => {
|
||||||
const parseFormData = (parsedBody) => {
|
const parseFormData = (parsedBody) => {
|
||||||
const formData = [];
|
const formData = [];
|
||||||
forOwn(parsedBody, (value, key) => {
|
forOwn(parsedBody, (value, key) => {
|
||||||
@ -12,6 +12,22 @@ export const getRequestFromCurlCommand = (curlCommand) => {
|
|||||||
return formData;
|
return formData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parseGraphQL = (text) => {
|
||||||
|
try {
|
||||||
|
const graphql = JSON.parse(text);
|
||||||
|
|
||||||
|
return {
|
||||||
|
query: graphql.query,
|
||||||
|
variables: JSON.stringify(graphql.variables, null, 2)
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
query: '',
|
||||||
|
variables: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!curlCommand || typeof curlCommand !== 'string' || curlCommand.length === 0) {
|
if (!curlCommand || typeof curlCommand !== 'string' || curlCommand.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -24,6 +40,8 @@ export const getRequestFromCurlCommand = (curlCommand) => {
|
|||||||
Object.keys(parsedHeaders).map((key) => ({ name: key, value: parsedHeaders[key], enabled: true }));
|
Object.keys(parsedHeaders).map((key) => ({ name: key, value: parsedHeaders[key], enabled: true }));
|
||||||
|
|
||||||
const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type')?.value;
|
const contentType = headers?.find((h) => h.name.toLowerCase() === 'content-type')?.value;
|
||||||
|
const parsedBody = request.data;
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
mode: 'none',
|
mode: 'none',
|
||||||
json: null,
|
json: null,
|
||||||
@ -31,11 +49,15 @@ export const getRequestFromCurlCommand = (curlCommand) => {
|
|||||||
xml: null,
|
xml: null,
|
||||||
sparql: null,
|
sparql: null,
|
||||||
multipartForm: null,
|
multipartForm: null,
|
||||||
formUrlEncoded: null
|
formUrlEncoded: null,
|
||||||
|
graphql: null
|
||||||
};
|
};
|
||||||
const parsedBody = request.data;
|
|
||||||
if (parsedBody && contentType && typeof contentType === 'string') {
|
if (parsedBody && contentType && typeof contentType === 'string') {
|
||||||
if (contentType.includes('application/json')) {
|
if (requestType === 'graphql-request' && (contentType.includes('application/json') || contentType.includes('application/graphql'))) {
|
||||||
|
body.mode = 'graphql';
|
||||||
|
body.graphql = parseGraphQL(parsedBody);
|
||||||
|
} else if (contentType.includes('application/json')) {
|
||||||
body.mode = 'json';
|
body.mode = 'json';
|
||||||
body.json = convertToCodeMirrorJson(parsedBody);
|
body.json = convertToCodeMirrorJson(parsedBody);
|
||||||
} else if (contentType.includes('text/xml')) {
|
} else if (contentType.includes('text/xml')) {
|
||||||
|
Loading…
Reference in New Issue
Block a user