add: bulk edit for collection and folder header (#5279)

This commit is contained in:
Pooja
2025-08-08 19:44:47 +05:30
committed by GitHub
parent f1f1c1fe5b
commit 84cca6f92b
3 changed files with 112 additions and 10 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
@@ -7,19 +7,30 @@ import { useTheme } from 'providers/Theme';
import {
addCollectionHeader,
updateCollectionHeader,
deleteCollectionHeader
deleteCollectionHeader,
setCollectionHeaders
} from 'providers/ReduxStore/slices/collections';
import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
import SingleLineEditor from 'components/SingleLineEditor';
import StyledWrapper from './StyledWrapper';
import { headers as StandardHTTPHeaders } from 'know-your-http-well';
import { MimeTypes } from 'utils/codemirror/autocompleteConstants';
import BulkEditor from 'components/BulkEditor/index';
const headerAutoCompleteList = StandardHTTPHeaders.map((e) => e.header);
const Headers = ({ collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const headers = get(collection, 'root.request.headers', []);
const [isBulkEditMode, setIsBulkEditMode] = useState(false);
const toggleBulkEditMode = () => {
setIsBulkEditMode(!isBulkEditMode);
};
const handleBulkHeadersChange = (newHeaders) => {
dispatch(setCollectionHeaders({ collectionUid: collection.uid, headers: newHeaders }));
};
const addHeader = () => {
dispatch(
@@ -63,6 +74,22 @@ const Headers = ({ collection }) => {
);
};
if (isBulkEditMode) {
return (
<StyledWrapper className="h-full w-full">
<div className="text-xs mb-4 text-muted">
Add request headers that will be sent with every request in this collection.
</div>
<BulkEditor
params={headers}
onChange={handleBulkHeadersChange}
onToggle={toggleBulkEditMode}
onSave={handleSave}
/>
</StyledWrapper>
);
}
return (
<StyledWrapper className="h-full w-full">
<div className="text-xs mb-4 text-muted">
@@ -141,9 +168,14 @@ const Headers = ({ collection }) => {
: null}
</tbody>
</table>
<button className="btn-add-header text-link pr-2 py-3 mt-2 select-none" onClick={addHeader}>
+ Add Header
</button>
<div className="flex justify-between mt-2">
<button className="btn-add-header text-link pr-2 py-3 select-none" onClick={addHeader}>
+ Add Header
</button>
<button className="text-link select-none" onClick={toggleBulkEditMode}>
Bulk Edit
</button>
</div>
<div className="mt-6">
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>

View File

@@ -1,21 +1,31 @@
import React from 'react';
import React, { useState } from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { addFolderHeader, updateFolderHeader, deleteFolderHeader } from 'providers/ReduxStore/slices/collections';
import { addFolderHeader, updateFolderHeader, deleteFolderHeader, setFolderHeaders } from 'providers/ReduxStore/slices/collections';
import { saveFolderRoot } from 'providers/ReduxStore/slices/collections/actions';
import SingleLineEditor from 'components/SingleLineEditor';
import StyledWrapper from './StyledWrapper';
import { headers as StandardHTTPHeaders } from 'know-your-http-well';
import { MimeTypes } from 'utils/codemirror/autocompleteConstants';
import BulkEditor from 'components/BulkEditor/index';
const headerAutoCompleteList = StandardHTTPHeaders.map((e) => e.header);
const Headers = ({ collection, folder }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const headers = get(folder, 'root.request.headers', []);
const [isBulkEditMode, setIsBulkEditMode] = useState(false);
const toggleBulkEditMode = () => {
setIsBulkEditMode(!isBulkEditMode);
};
const handleBulkHeadersChange = (newHeaders) => {
dispatch(setFolderHeaders({ collectionUid: collection.uid, folderUid: folder.uid, headers: newHeaders }));
};
const addHeader = () => {
dispatch(
@@ -62,6 +72,22 @@ const Headers = ({ collection, folder }) => {
);
};
if (isBulkEditMode) {
return (
<StyledWrapper className="w-full">
<div className="text-xs mb-4 text-muted">
Request headers that will be sent with every request inside this folder.
</div>
<BulkEditor
params={headers}
onChange={handleBulkHeadersChange}
onToggle={toggleBulkEditMode}
onSave={handleSave}
/>
</StyledWrapper>
);
}
return (
<StyledWrapper className="w-full">
<div className="text-xs mb-4 text-muted">
@@ -141,9 +167,14 @@ const Headers = ({ collection, folder }) => {
: null}
</tbody>
</table>
<button className="btn-add-header text-link pr-2 py-3 mt-2 select-none" onClick={addHeader}>
+ Add Header
</button>
<div className="flex justify-between mt-2">
<button className="btn-add-header text-link pr-2 py-3 select-none" onClick={addHeader}>
+ Add Header
</button>
<button className="text-link select-none" onClick={toggleBulkEditMode}>
Bulk Edit
</button>
</div>
<div className="mt-6">
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>

View File

@@ -873,6 +873,43 @@ export const collectionsSlice = createSlice({
enabled: enabled
}));
},
setCollectionHeaders: (state, action) => {
const { collectionUid, headers } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (!collection) {
return;
}
collection.root.request.headers = map(headers, ({name = '', value = '', enabled = true}) => ({
uid: uuid(),
name: name,
value: value,
description: '',
enabled: enabled
}));
},
setFolderHeaders: (state, action) => {
const { collectionUid, folderUid, headers } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
if (!collection) {
return;
}
const folder = findItemInCollection(collection, folderUid);
if (!folder || !isItemAFolder(folder)) {
return;
}
folder.root.request.headers = map(headers, ({name = '', value = '', enabled = true}) => ({
uid: uuid(),
name: name,
value: value,
description: '',
enabled: enabled
}));
},
addFormUrlEncodedParam: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
@@ -2472,6 +2509,8 @@ export const {
deleteRequestHeader,
moveRequestHeader,
setRequestHeaders,
setCollectionHeaders,
setFolderHeaders,
addFormUrlEncodedParam,
updateFormUrlEncodedParam,
deleteFormUrlEncodedParam,