feat: support for sending url encoded params (resolves #11)

This commit is contained in:
Anoop M D 2022-10-03 00:41:25 +05:30
parent 7f0f496bb4
commit bd153bf849
8 changed files with 261 additions and 3 deletions

8
package-lock.json generated
View File

@ -7190,6 +7190,14 @@
"postcss-selector-parser": "^6.0.6"
}
},
"qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"requires": {
"side-channel": "^1.0.4"
}
},
"querystring-es3": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",

View File

@ -46,6 +46,7 @@
"mousetrap": "^1.6.5",
"nanoid": "^3.1.30",
"next": "12.0.4",
"qs": "^6.11.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-redux": "^7.2.6",

View File

@ -0,0 +1,45 @@
import styled from 'styled-components';
const Wrapper = styled.div`
table {
width: 100%;
border-collapse: collapse;
font-weight: 600;
thead, td {
border: 1px solid #efefef;
}
thead {
color: #616161;
font-size: 0.8125rem;
user-select: none;
}
td {
padding: 6px 10px;
}
}
.btn-add-param {
font-size: 0.8125rem;
}
input[type="text"] {
width: 100%;
border: solid 1px transparent;
outline: none !important;
&:focus{
outline: none !important;
border: solid 1px transparent;
}
}
input[type="checkbox"] {
cursor: pointer;
position: relative;
top: 1px;
}
`;
export default Wrapper;

View File

@ -0,0 +1,119 @@
import React from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
import { useDispatch } from 'react-redux';
import { addFormUrlEncodedParam, updateFormUrlEncodedParam, deleteFormUrlEncodedParam } from 'providers/ReduxStore/slices/collections';
import StyledWrapper from './StyledWrapper';
const FormUrlEncodedParams = ({item, collection}) => {
const dispatch = useDispatch();
const params = item.draft ? get(item, 'draft.request.body.formUrlEncoded') : get(item, 'request.body.formUrlEncoded');
const addParam = () => {
dispatch(addFormUrlEncodedParam({
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
const handleParamChange = (e, _param, type) => {
const param = cloneDeep(_param);
switch(type) {
case 'name' : {
param.name = e.target.value;
break;
}
case 'value' : {
param.value = e.target.value;
break;
}
case 'description' : {
param.description = e.target.value;
break;
}
case 'enabled' : {
param.enabled = e.target.checked;
break;
}
}
dispatch(updateFormUrlEncodedParam({
param: param,
itemUid: item.uid,
collectionUid: collection.uid
}));
};
const handleRemoveParams = (param) => {
dispatch(deleteFormUrlEncodedParam({
paramUid: param.uid,
itemUid: item.uid,
collectionUid: collection.uid
}));
};
return (
<StyledWrapper className="w-full">
<table>
<thead>
<tr>
<td>Key</td>
<td>Value</td>
<td>Description</td>
<td></td>
</tr>
</thead>
<tbody>
{params && params.length ? params.map((param, index) => {
return (
<tr key={param.uid}>
<td>
<input
type="text"
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
value={param.name}
className="mousetrap"
onChange={(e) => handleParamChange(e, param, 'name')}
/>
</td>
<td>
<input
type="text"
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
value={param.value}
className="mousetrap"
onChange={(e) => handleParamChange(e, param, 'value')}
/>
</td>
<td>
<input
type="text"
autoComplete="off" autoCorrect="off" autoCapitalize="off" spellCheck="false"
value={param.description}
className="mousetrap"
onChange={(e) => handleParamChange(e, param, 'description')}
/>
</td>
<td>
<div className="flex items-center">
<input
type="checkbox"
checked={param.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleParamChange(e, param, 'enabled')}
/>
<button onClick={() => handleRemoveParams(param)}>
<IconTrash strokeWidth={1.5} size={20}/>
</button>
</div>
</td>
</tr>
);
}) : null}
</tbody>
</table>
<button className="btn-add-param text-link pr-2 py-3 mt-2 select-none" onClick={addParam}>+ Add Param</button>
</StyledWrapper>
)
};
export default FormUrlEncodedParams;

View File

@ -1,6 +1,7 @@
import React from 'react';
import get from 'lodash/get';
import CodeEditor from 'components/CodeEditor';
import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams';
import { useDispatch } from 'react-redux';
import { updateRequestBody, sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections';
import StyledWrapper from './StyledWrapper';
@ -47,6 +48,10 @@ const RequestBody = ({item, collection}) => {
);
}
if(bodyMode === 'formUrlEncoded') {
return <FormUrlEncodedParams item={item} collection={collection}/>;
}
return(
<StyledWrapper className="w-full">
No Body

View File

@ -343,6 +343,61 @@ export const collectionsSlice = createSlice({
}
}
},
addFormUrlEncodedParam: (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.formUrlEncoded = item.draft.request.body.formUrlEncoded || [];
item.draft.request.body.formUrlEncoded.push({
uid: uuid(),
name: '',
value: '',
description: '',
enabled: true
});
}
}
},
updateFormUrlEncodedParam: (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);
}
const param = find(item.draft.request.body.formUrlEncoded, (p) => p.uid === action.payload.param.uid);
if(param) {
param.name = action.payload.param.name;
param.value = action.payload.param.value;
param.description = action.payload.param.description;
param.enabled = action.payload.param.enabled;
}
}
}
},
deleteFormUrlEncodedParam: (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.formUrlEncoded = filter(item.draft.request.body.formUrlEncoded, (p) => p.uid !== action.payload.paramUid);
}
}
},
updateRequestBodyMode: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@ -429,6 +484,9 @@ export const {
addRequestHeader,
updateRequestHeader,
deleteRequestHeader,
addFormUrlEncodedParam,
updateFormUrlEncodedParam,
deleteFormUrlEncodedParam,
updateRequestBodyMode,
updateRequestBody,
updateRequestMethod

View File

@ -128,6 +128,18 @@ export const transformCollectionToSaveToIdb = (collection, options = {}) => {
});
};
const copyFormUrlEncodedParams = (params = []) => {
return map(params, (param) => {
return {
uid: param.uid,
name: param.name,
value: param.value,
description: param.description,
enabled: param.enabled
}
});
};
const copyItems = (sourceItems, destItems) => {
each(sourceItems, (si) => {
const di = {
@ -151,7 +163,7 @@ export const transformCollectionToSaveToIdb = (collection, options = {}) => {
text: si.draft.request.body.text,
xml: si.draft.request.body.xml,
multipartForm: si.draft.request.body.multipartForm,
xmformUrlEncodedl: si.draft.request.body.formUrlEncoded
formUrlEncoded: copyFormUrlEncodedParams(si.draft.request.body.formUrlEncoded)
}
};
}
@ -168,7 +180,7 @@ export const transformCollectionToSaveToIdb = (collection, options = {}) => {
text: si.request.body.text,
xml: si.request.body.xml,
multipartForm: si.request.body.multipartForm,
xmformUrlEncodedl: si.request.body.formUrlEncoded
formUrlEncoded: copyFormUrlEncodedParams(si.request.body.formUrlEncoded)
}
}
};

View File

@ -1,4 +1,6 @@
import each from 'lodash/each';
import filter from 'lodash/filter';
import qs from 'qs';
import { rawRequest, gql } from 'graphql-request';
const sendNetworkRequest = async (item) => {
@ -58,8 +60,16 @@ const sendHttpRequest = async (request) => {
options.data = request.body.xml;
}
if(request.body.mode === 'formUrlEncoded') {
options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
const params = {};
const enabledParams = filter(request.body.formUrlEncoded, p => p.enabled);
each(enabledParams, (p) => params[p.name] = p.value);
options.data = qs.stringify(params);
}
console.log('>>> Sending Request');
console.log(request);
console.log(options);
ipcRenderer
.invoke('send-http-request', options)