From 472b5452f73a1ffbc9af8f03cec749a5bfabd6ed Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Thu, 16 Jan 2025 20:06:53 +0530 Subject: [PATCH] =?UTF-8?q?Allow=20rearrangement=20of=20table=20items=20in?= =?UTF-8?q?=20params,=20body,=20vars,=20headers,=20etc=E2=80=A6=20(#3801)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow rearrangement of table items in params, body, vars, headers, and assert * updated drag function name --- .../Assertions/AssertionRow/index.js | 17 +- .../RequestPane/Assertions/StyledWrapper.js | 15 +- .../RequestPane/Assertions/index.js | 56 ++++-- .../FormUrlEncodedParams/StyledWrapper.js | 8 - .../RequestPane/FormUrlEncodedParams/index.js | 138 +++++++------ .../MultipartFormParams/StyledWrapper.js | 16 -- .../RequestPane/MultipartFormParams/index.js | 188 ++++++++++-------- .../RequestPane/QueryParams/index.js | 4 +- .../RequestHeaders/StyledWrapper.js | 8 - .../RequestPane/RequestHeaders/index.js | 41 ++-- .../Vars/VarsTable/StyledWrapper.js | 11 +- .../RequestPane/Vars/VarsTable/index.js | 64 +++--- .../ReduxStore/slices/collections/index.js | 124 ++++++++++++ 13 files changed, 413 insertions(+), 277 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js index ea94847808..e56e3c3986 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js @@ -146,19 +146,8 @@ const AssertionRow = ({ const { operator, value } = parseAssertionOperator(assertion.value); return ( - - - handleAssertionChange(e, assertion, 'name')} - /> - + <> + - + ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js index 14e21e1c60..efb860893c 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js @@ -4,6 +4,7 @@ const Wrapper = styled.div` table { width: 100%; border-collapse: collapse; + font-weight: 600; table-layout: fixed; thead, @@ -15,24 +16,15 @@ const Wrapper = styled.div` color: ${(props) => props.theme.table.thead.color}; font-size: 0.8125rem; user-select: none; - font-weight: 600; } td { padding: 6px 10px; - - &:nth-child(2) { - width: 130px; - } - - &:nth-child(4) { - width: 70px; } - select { + select { background-color: transparent; } } - } .btn-add-assertion { font-size: 0.8125rem; @@ -42,7 +34,8 @@ const Wrapper = styled.div` width: 100%; border: solid 1px transparent; outline: none !important; - background-color: inherit; + color: ${(props) => props.theme.table.input.color}; + background: transparent; &:focus { outline: none !important; diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/index.js b/packages/bruno-app/src/components/RequestPane/Assertions/index.js index 1805a632e1..7d173f3c5a 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/index.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/index.js @@ -6,6 +6,9 @@ import { addAssertion, updateAssertion, deleteAssertion } from 'providers/ReduxS import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import AssertionRow from './AssertionRow'; import StyledWrapper from './StyledWrapper'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; +import { moveAssertion } from 'providers/ReduxStore/slices/collections/index'; const Assertions = ({ item, collection }) => { const dispatch = useDispatch(); @@ -57,21 +60,43 @@ const Assertions = ({ item, collection }) => { ); }; + const handleAssertionDrag = ({ updateReorderedItem }) => { + dispatch( + moveAssertion({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - - - - - - +
ExprOperatorValue
+ {assertions && assertions.length ? assertions.map((assertion) => { - return ( + return ( + + { onSave={onSave} handleRun={handleRun} /> - ); - }) + + ); + }) : null} - -
+ handleAssertionChange(e, assertion, 'name')} + /> +
+ + diff --git a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js index f04a30be0f..517415935f 100644 --- a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js @@ -19,16 +19,8 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(3) { - width: 70px; } } - } .btn-add-param { font-size: 0.8125rem; diff --git a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js index 22de4735ba..c8eeda531f 100644 --- a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js +++ b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js @@ -7,11 +7,14 @@ import { useTheme } from 'providers/Theme'; import { addFormUrlEncodedParam, updateFormUrlEncodedParam, - deleteFormUrlEncodedParam + deleteFormUrlEncodedParam, + moveFormUrlEncodedParam } from 'providers/ReduxStore/slices/collections'; import MultiLineEditor from 'components/MultiLineEditor'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; +import ReorderTable from 'components/ReorderTable/index'; +import Table from 'components/Table/index'; const FormUrlEncodedParams = ({ item, collection }) => { const dispatch = useDispatch(); @@ -64,75 +67,84 @@ const FormUrlEncodedParams = ({ item, collection }) => { ); }; + const handleParamDrag = ({ updateReorderedItem }) => { + dispatch( + moveFormUrlEncodedParam({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - - - - - +
KeyValue
+ {params && params.length ? params.map((param, index) => { - return ( - - + + + - - - - ); - }) + + + + + ); + }) : null} - -
+ return ( +
+ handleParamChange(e, param, 'name')} + /> + + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'value' + ) + } + allowNewlines={true} + onRun={handleRun} + collection={collection} + item={item} + /> + +
handleParamChange(e, param, 'name')} - /> -
- - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - allowNewlines={true} - onRun={handleRun} - collection={collection} - item={item} + type="checkbox" + checked={param.enabled} + tabIndex="-1" + className="mr-3 mousetrap" + onChange={(e) => handleParamChange(e, param, 'enabled')} /> - -
- handleParamChange(e, param, 'enabled')} - /> - -
-
+ + diff --git a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js index 49c45f21dc..f7b6e5d132 100644 --- a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js @@ -19,23 +19,7 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(2) { - width: 45%; - } - - &:nth-child(3) { - width: 25%; - } - - &:nth-child(4) { - width: 70px; } - } } .btn-add-param { diff --git a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js index af23a645e6..790f7d5fa3 100644 --- a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js +++ b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js @@ -7,12 +7,15 @@ import { useTheme } from 'providers/Theme'; import { addMultipartFormParam, updateMultipartFormParam, - deleteMultipartFormParam + deleteMultipartFormParam, + moveMultipartFormParam } from 'providers/ReduxStore/slices/collections'; import MultiLineEditor from 'components/MultiLineEditor'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import FilePickerEditor from 'components/FilePickerEditor'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; const MultipartFormParams = ({ item, collection }) => { const dispatch = useDispatch(); @@ -82,80 +85,65 @@ const MultipartFormParams = ({ item, collection }) => { ); }; + const handleParamDrag = ({ updateReorderedItem }) => { + dispatch( + moveMultipartFormParam({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - - - - - - +
KeyValueContent-Type
+ {params && params.length ? params.map((param, index) => { - return ( - - + + - - + + - - - ); - }) + + + + + ); + }) : null} - -
- handleParamChange(e, param, 'name')} + return ( +
+ handleParamChange(e, param, 'name')} + /> + + {param.type === 'file' ? ( + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'value' + ) + } + collection={collection} /> - - {param.type === 'file' ? ( - - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - collection={collection} - /> - ) : ( - - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - onRun={handleRun} - allowNewlines={true} - collection={collection} - item={item} - /> - )} - + ) : ( handleParamChange( { @@ -164,33 +152,57 @@ const MultipartFormParams = ({ item, collection }) => { } }, param, - 'contentType' + 'value' ) } onRun={handleRun} + allowNewlines={true} collection={collection} + item={item} + /> + )} + + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'contentType' + ) + } + onRun={handleRun} + collection={collection} + /> + +
+ handleParamChange(e, param, 'enabled')} /> -
-
- handleParamChange(e, param, 'enabled')} - /> - -
-
+ +
diff --git a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js index efacc82885..c8ec78387f 100644 --- a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js @@ -19,16 +19,8 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(3) { - width: 70px; } } - } .btn-add-var { font-size: 0.8125rem; @@ -38,7 +30,8 @@ const Wrapper = styled.div` width: 100%; border: solid 1px transparent; outline: none !important; - background-color: inherit; + color: ${(props) => props.theme.table.input.color}; + background: transparent; &:focus { outline: none !important; diff --git a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js index 0f94f35bba..c073135d36 100644 --- a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js +++ b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js @@ -3,13 +3,15 @@ import cloneDeep from 'lodash/cloneDeep'; import { IconTrash } from '@tabler/icons'; import { useDispatch } from 'react-redux'; import { useTheme } from 'providers/Theme'; -import { addVar, updateVar, deleteVar } from 'providers/ReduxStore/slices/collections'; +import { addVar, updateVar, deleteVar, moveVar } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import SingleLineEditor from 'components/SingleLineEditor'; import InfoTip from 'components/InfoTip'; import StyledWrapper from './StyledWrapper'; import toast from 'react-hot-toast'; import { variableNameRegex } from 'utils/common/regex'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; const VarsTable = ({ item, collection, vars, varType }) => { const dispatch = useDispatch(); @@ -73,35 +75,41 @@ const VarsTable = ({ item, collection, vars, varType }) => { ); }; + const handleVarDrag = ({ updateReorderedItem }) => { + dispatch( + moveVar({ + type: varType, + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - {varType === 'request' ? ( - - ) : ( - - )} - - - - - {vars && vars.length +
Name -
- Value -
-
-
- Expr - -
-
+ Value + + ) : ( +
+ Expr + +
+ ), accessor: 'value', width: '46%' }, + { name: '', accessor: '', width: '14%' } + ]} + > + + {vars && vars.length ? vars.map((_var) => { return ( - - + -
+
{ ); }) : null} -
+ + 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 d4ad489218..7f40600f62 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -694,6 +694,28 @@ export const collectionsSlice = createSlice({ } } }, + moveRequestHeader: (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.headers; + + item.draft.request.headers = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addFormUrlEncodedParam: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -752,6 +774,28 @@ export const collectionsSlice = createSlice({ } } }, + moveFormUrlEncodedParam: (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.formUrlEncoded; + + item.draft.request.body.formUrlEncoded = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addMultipartFormParam: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -814,6 +858,28 @@ export const collectionsSlice = createSlice({ } } }, + 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); + }); + } + } + }, updateRequestAuthMode: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -1027,6 +1093,28 @@ export const collectionsSlice = createSlice({ } } }, + moveAssertion: (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.assertions; + + item.draft.request.assertions = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addVar: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); const type = action.payload.type; @@ -1121,6 +1209,37 @@ export const collectionsSlice = createSlice({ } } }, + moveVar: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + const type = action.payload.type; + + 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; + if(type == "request"){ + const params = item.draft.request.vars.req; + + item.draft.request.vars.req = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } else if (type === 'response') { + const params = item.draft.request.vars.res; + + item.draft.request.vars.res = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + } + }, updateCollectionAuthMode: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -1801,12 +1920,15 @@ export const { addRequestHeader, updateRequestHeader, deleteRequestHeader, + moveRequestHeader, addFormUrlEncodedParam, updateFormUrlEncodedParam, deleteFormUrlEncodedParam, + moveFormUrlEncodedParam, addMultipartFormParam, updateMultipartFormParam, deleteMultipartFormParam, + moveMultipartFormParam, updateRequestAuthMode, updateRequestBodyMode, updateRequestBody, @@ -1819,9 +1941,11 @@ export const { addAssertion, updateAssertion, deleteAssertion, + moveAssertion, addVar, updateVar, deleteVar, + moveVar, addFolderHeader, updateFolderHeader, deleteFolderHeader,