mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-27 22:54:07 +00:00
fix: refactor response examples to use MenuDropdown and Editable components (#6382)
* feat: use common dropdown component * fix: update example ui to match v3 * fix: test cases, bugs * fix: review comments * fix: review comments * fix: review * fix: file body/binary table within response examples * fix: file name, close btn not visible issue * fix: unnessary transition for three dots * fix: install missing deps in bruno-app * update example url when param is updated * empty commit * chore: update package-lock.json --------- Co-authored-by: Bijin A B <bijin@usebruno.com>
This commit is contained in:
@@ -43,13 +43,17 @@ const StyledWrapper = styled.div`
|
||||
tbody {
|
||||
tr {
|
||||
border-bottom: 1px solid ${(props) => props.theme.table.border};
|
||||
|
||||
&:hover {
|
||||
background: ${(props) => props.theme.plainGrid.hoverBg};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Override styles for EditableTable to prevent uppercase transformation and ensure proper spacing */
|
||||
/* The .table-container is from EditableTable component */
|
||||
.table-container table thead td {
|
||||
text-transform: none !important;
|
||||
letter-spacing: normal !important;
|
||||
padding: 8px 10px !important;
|
||||
}
|
||||
|
||||
|
||||
tr {
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import React, { useState, useMemo, useCallback } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { IconTrash } from '@tabler/icons';
|
||||
import { useTheme } from 'providers/Theme';
|
||||
import get from 'lodash/get';
|
||||
import { addResponseExampleParam, updateResponseExampleParam, deleteResponseExampleParam, moveResponseExampleParam, setResponseExampleParams } from 'providers/ReduxStore/slices/collections';
|
||||
import Table from 'components/Table-v2';
|
||||
import ReorderTable from 'components/ReorderTable';
|
||||
import { moveResponseExampleParam, setResponseExampleParams } from 'providers/ReduxStore/slices/collections';
|
||||
import EditableTable from 'components/EditableTable';
|
||||
import SingleLineEditor from 'components/SingleLineEditor';
|
||||
import BulkEditor from 'components/BulkEditor';
|
||||
import Checkbox from 'components/Checkbox';
|
||||
import InfoTip from 'components/InfoTip';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
@@ -26,61 +23,22 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
const queryParams = params.filter((param) => param.type === 'query');
|
||||
const pathParams = params.filter((param) => param.type === 'path');
|
||||
|
||||
const handleAddQueryParam = () => {
|
||||
const handleQueryParamsChange = useCallback((updatedQueryParams) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(addResponseExampleParam({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid
|
||||
}));
|
||||
};
|
||||
|
||||
const handleQueryParamChange = (e, data, key) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedParam = { ...data };
|
||||
switch (key) {
|
||||
case 'name': {
|
||||
updatedParam.name = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'value': {
|
||||
updatedParam.value = e.target.value;
|
||||
break;
|
||||
}
|
||||
case 'enabled': {
|
||||
updatedParam.enabled = e.target.checked;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(updateResponseExampleParam({
|
||||
// Merge updated query params with path params
|
||||
const allParams = [...updatedQueryParams, ...pathParams];
|
||||
dispatch(setResponseExampleParams({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid,
|
||||
param: updatedParam
|
||||
params: allParams
|
||||
}));
|
||||
};
|
||||
}, [editMode, dispatch, item.uid, collection.uid, exampleUid, pathParams]);
|
||||
|
||||
const handleRemoveQueryParam = (param) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(deleteResponseExampleParam({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid,
|
||||
paramUid: param.uid
|
||||
}));
|
||||
};
|
||||
|
||||
const handleQueryParamDrag = ({ updateReorderedItem }) => {
|
||||
const handleQueryParamDrag = useCallback(({ updateReorderedItem }) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
@@ -91,7 +49,22 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
exampleUid: exampleUid,
|
||||
updateReorderedItem
|
||||
}));
|
||||
};
|
||||
}, [editMode, dispatch, item.uid, collection.uid, exampleUid]);
|
||||
|
||||
const handlePathParamsChange = useCallback((updatedPathParams) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge updated path params with query params
|
||||
const allParams = [...queryParams, ...updatedPathParams];
|
||||
dispatch(setResponseExampleParams({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid,
|
||||
params: allParams
|
||||
}));
|
||||
}, [editMode, dispatch, item.uid, collection.uid, exampleUid, queryParams]);
|
||||
|
||||
const toggleBulkEditMode = () => {
|
||||
setIsBulkEditMode(!isBulkEditMode);
|
||||
@@ -102,27 +75,13 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge bulk edited query params with path params
|
||||
const allParams = [...newParams, ...pathParams];
|
||||
dispatch(setResponseExampleParams({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid,
|
||||
params: newParams
|
||||
}));
|
||||
};
|
||||
|
||||
const handlePathParamChange = (e, data) => {
|
||||
if (!editMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedParam = { ...data };
|
||||
updatedParam.value = e.target.value;
|
||||
|
||||
dispatch(updateResponseExampleParam({
|
||||
itemUid: item.uid,
|
||||
collectionUid: collection.uid,
|
||||
exampleUid: exampleUid,
|
||||
param: updatedParam
|
||||
params: allParams
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -138,6 +97,86 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const queryColumns = [
|
||||
{
|
||||
key: 'name',
|
||||
name: 'Name',
|
||||
isKeyField: true,
|
||||
placeholder: 'Name',
|
||||
width: '40%',
|
||||
readOnly: !editMode,
|
||||
render: ({ row, value, onChange, isLastEmptyRow }) => (
|
||||
<SingleLineEditor
|
||||
value={value || ''}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={onChange}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
placeholder={isLastEmptyRow ? 'Name' : ''}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
name: 'Value',
|
||||
placeholder: 'Value',
|
||||
width: '60%',
|
||||
readOnly: !editMode,
|
||||
render: ({ row, value, onChange, isLastEmptyRow }) => (
|
||||
<SingleLineEditor
|
||||
value={value || ''}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={onChange}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
placeholder={isLastEmptyRow ? 'Value' : ''}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const pathColumns = [
|
||||
{
|
||||
key: 'name',
|
||||
name: 'Name',
|
||||
readOnly: true,
|
||||
width: '40%'
|
||||
},
|
||||
{
|
||||
key: 'value',
|
||||
name: 'Value',
|
||||
placeholder: 'Value',
|
||||
width: '60%',
|
||||
readOnly: !editMode,
|
||||
render: ({ row, value, onChange, isLastEmptyRow }) => (
|
||||
<SingleLineEditor
|
||||
value={value || ''}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={onChange}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
placeholder={isLastEmptyRow ? 'Value' : ''}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const defaultQueryRow = {
|
||||
name: '',
|
||||
value: '',
|
||||
enabled: true,
|
||||
type: 'query'
|
||||
};
|
||||
|
||||
if (queryParams.length === 0 && pathParams.length === 0 && !editMode) {
|
||||
return null;
|
||||
}
|
||||
@@ -145,69 +184,17 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
return (
|
||||
<StyledWrapper className="w-full mt-4">
|
||||
<div className="mb-1 title text-xs font-bold">Query parameters</div>
|
||||
<Table
|
||||
headers={[
|
||||
{ name: 'Name', accessor: 'name', width: '40%' },
|
||||
{ name: 'Value', accessor: 'value', width: '60%' }
|
||||
]}
|
||||
>
|
||||
<ReorderTable updateReorderedItem={handleQueryParamDrag}>
|
||||
{queryParams && queryParams.length
|
||||
? queryParams.map((param, index) => (
|
||||
<tr key={param.uid} data-uid={param.uid}>
|
||||
<td className="flex relative">
|
||||
<div className="flex items-center justify-center mr-3">
|
||||
<Checkbox
|
||||
checked={param.enabled !== false}
|
||||
disabled={!editMode}
|
||||
onChange={(e) => handleQueryParamChange(e, param, 'enabled')}
|
||||
dataTestId={`query-param-checkbox-${index}`}
|
||||
/>
|
||||
</div>
|
||||
<SingleLineEditor
|
||||
value={param.name || ''}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={(newValue) => handleQueryParamChange({ target: { value: newValue } }, param, 'name')}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex items-center justify-center pl-4">
|
||||
<SingleLineEditor
|
||||
value={param.value || ''}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={(newValue) => handleQueryParamChange({ target: { value: newValue } }, param, 'value')}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
/>
|
||||
{editMode && (
|
||||
<button tabIndex="-1" onClick={() => handleRemoveQueryParam(param)} className="delete-button">
|
||||
<IconTrash strokeWidth={1.5} size={16} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
: null}
|
||||
</ReorderTable>
|
||||
</Table>
|
||||
|
||||
<EditableTable
|
||||
columns={queryColumns}
|
||||
rows={queryParams || []}
|
||||
onChange={handleQueryParamsChange}
|
||||
defaultRow={defaultQueryRow}
|
||||
reorderable={editMode}
|
||||
onReorder={handleQueryParamDrag}
|
||||
showAddRow={editMode}
|
||||
/>
|
||||
{editMode && (
|
||||
<div className="flex justify-between mt-2">
|
||||
<button
|
||||
className="btn-action text-link pr-2 py-3 select-none"
|
||||
onClick={handleAddQueryParam}
|
||||
>
|
||||
+ Add Param
|
||||
</button>
|
||||
<div className="flex justify-end mt-2">
|
||||
<button
|
||||
className="btn-action text-link select-none"
|
||||
onClick={toggleBulkEditMode}
|
||||
@@ -231,37 +218,16 @@ const ResponseExampleParams = ({ editMode, item, collection, exampleUid }) => {
|
||||
</div>
|
||||
</InfoTip>
|
||||
</div>
|
||||
<Table
|
||||
headers={[
|
||||
{ name: 'Name', accessor: 'name', width: '40%' },
|
||||
{ name: 'Value', accessor: 'value', width: '60%' }
|
||||
]}
|
||||
>
|
||||
{pathParams && pathParams.length
|
||||
? pathParams.map((path, index) => {
|
||||
return (
|
||||
<tr key={index} data-uid={path.uid}>
|
||||
<td>
|
||||
{path.name}
|
||||
</td>
|
||||
<td>
|
||||
<SingleLineEditor
|
||||
value={path.value}
|
||||
theme={storedTheme}
|
||||
onSave={() => {}}
|
||||
onChange={(newValue) => handlePathParamChange({ target: { value: newValue } }, path)}
|
||||
onRun={() => {}}
|
||||
collection={collection}
|
||||
variablesAutocomplete={true}
|
||||
readOnly={!editMode}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</Table>
|
||||
{pathParams.length === 0 && <div className="title pr-2 py-3 mt-2 text-xs">No path parameters defined</div>}
|
||||
<EditableTable
|
||||
columns={pathColumns}
|
||||
rows={pathParams}
|
||||
onChange={handlePathParamsChange}
|
||||
defaultRow={{}}
|
||||
showCheckbox={false}
|
||||
showDelete={false}
|
||||
showAddRow={false}
|
||||
reorderable={false}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user