Skip to content

Commit 0bba66a

Browse files
feat: variable descriptions (usebruno#8269)
* feat: add description column to various tables and enhance UI interactions - Introduced a description column in Headers, VarsTable, and other components to allow multi-line descriptions. - Added toggle buttons to show/hide the description column in relevant tables. - Updated EditableTable component to support dynamic row addition with customizable labels. - Enhanced UI for better user experience with consistent button styles and spacing adjustments. * chore: resize fix handles * fix: restrict column check for last index * refactor: remove unwanted style and fix bottom padding of the last child in the table row * tests: improve testability and fix impacted locators * tests: fix locators for value fields * fix: improve newline handling in description prefix * fix: ts changes * chore: remove redundant code and fix description roundtrip * chore: remove redundant check * tests(bru-lang): tests for description and annotation * test: improve locators and tests * tests: descriptions * chore: re-add description setup * fix: re-add description cols * chore: fix the double click reset * fix: account for hidden sidebar in request pane width calculation * refactor: ui/ux fixes for data type toggle * chore: inline common deps into bruno-lang and bruno-schema * chore: tests * chore: fix ux for descriptions * fix: layout for environment vars table * fix: ensure correct row selection for multipart file upload in tests * feat: enhance UID assignment for request headers and variables in collections * chore: simplify * chore: update pkg * chore: abstract the e2e utils * chore: fix exports * tests: fix locators for datatype vars * fix: ux issue with secrets in environment table * tests: update locators for collection headers and vars descriptions * tests: update locators to use data attributes for datatype selectors * chore: update default css width for actions column * chore: remove tooltip for string type warnings * fix: reduce name widths * refactor: update annotation serialization to use single-quote delimiters for descriptions * refactor(tests): simplify description formatting in jsonToEnv tests * feat: add multiline description escaping and unescaping functions with tests * refactor: clean up imports and improve multiline text block handling * refactor: update locators to use new test IDs for environment variable editors * refactor: streamline header input handling and improve environment variable row access * refactor: update e2e-test job to support self-hosted runners * refactor: update E2E test runner configuration to include e2e and macOS environments --------- Co-authored-by: Pragadesh-45 <temporaryg7904@gmail.com>
1 parent 958ca49 commit 0bba66a

177 files changed

Lines changed: 6570 additions & 482 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package-lock.json

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bruno-app/src/components/CollectionSettings/Headers/index.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { saveCollectionSettings } from 'providers/ReduxStore/slices/collections/
77
import { updateTableColumnWidths } from 'providers/ReduxStore/slices/tabs';
88
import SingleLineEditor from 'components/SingleLineEditor';
99
import EditableTable from 'components/EditableTable';
10+
import { createDescriptionColumn } from 'components/EditableTable/descriptionColumn';
1011
import StyledWrapper from './StyledWrapper';
1112
import { headers as StandardHTTPHeaders } from 'know-your-http-well';
1213
import { MimeTypes } from 'utils/codemirror/autocompleteConstants';
@@ -65,13 +66,20 @@ const Headers = ({ collection }) => {
6566
return null;
6667
}, []);
6768

69+
const descriptionColumn = createDescriptionColumn({
70+
theme: storedTheme,
71+
onSave: handleSave,
72+
collection,
73+
nameFromRowIndex: true
74+
});
75+
6876
const columns = [
6977
{
7078
key: 'name',
7179
name: 'Name',
7280
isKeyField: true,
7381
placeholder: 'Name',
74-
width: '30%',
82+
width: '20%',
7583
render: ({ value, onChange }) => (
7684
<SingleLineEditor
7785
value={value || ''}
@@ -99,7 +107,8 @@ const Headers = ({ collection }) => {
99107
placeholder={!value ? 'Value' : ''}
100108
/>
101109
)
102-
}
110+
},
111+
descriptionColumn
103112
];
104113

105114
const defaultRow = {
@@ -131,6 +140,7 @@ const Headers = ({ collection }) => {
131140
</div>
132141
<EditableTable
133142
tableId="collection-headers"
143+
testId="collection-headers"
134144
columns={columns}
135145
rows={headers}
136146
onChange={handleHeadersChange}

packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import { updateTableColumnWidths } from 'providers/ReduxStore/slices/tabs';
66
import MultiLineEditor from 'components/MultiLineEditor';
77
import InfoTip from 'components/InfoTip';
88
import DataTypeSelector from 'components/DataTypeSelector';
9+
import VarValueCell from 'components/VarValueCell';
910
import { valueToString } from '@usebruno/common/utils';
1011
import EditableTable from 'components/EditableTable';
12+
import { createDescriptionColumn } from 'components/EditableTable/descriptionColumn';
1113
import StyledWrapper from './StyledWrapper';
1214
import toast from 'react-hot-toast';
1315
import { variableNameRegex } from 'utils/common/regex';
@@ -42,13 +44,20 @@ const VarsTable = ({ collection, vars, varType, initialScroll = 0 }) => {
4244
return null;
4345
}, []);
4446

47+
const descriptionColumn = createDescriptionColumn({
48+
theme: storedTheme,
49+
onSave,
50+
collection,
51+
nameFromRowIndex: true
52+
});
53+
4554
const columns = [
4655
{
4756
key: 'name',
4857
name: 'Name',
4958
isKeyField: true,
5059
placeholder: 'Name',
51-
width: '40%'
60+
width: '25%'
5261
},
5362
{
5463
key: 'value',
@@ -59,38 +68,43 @@ const VarsTable = ({ collection, vars, varType, initialScroll = 0 }) => {
5968
</div>
6069
),
6170
placeholder: varType === 'request' ? 'Value' : 'Expr',
62-
render: ({ row, value, onChange, isLastEmptyRow }) => (
63-
<div className="flex items-center w-full gap-2">
64-
<div className="flex-1 min-w-0">
71+
render: ({ row, value, onChange, isLastEmptyRow, rowIndex }) => (
72+
<VarValueCell
73+
editor={(
6574
<MultiLineEditor
6675
value={valueToString(value)}
76+
name={`${rowIndex}.value`}
6777
theme={storedTheme}
6878
onSave={onSave}
6979
onChange={onChange}
7080
collection={collection}
7181
placeholder={value == null || (typeof value === 'string' && value.trim() === '') ? (varType === 'request' ? 'Value' : 'Expr') : ''}
7282
/>
73-
</div>
74-
{/* DataTypes apply to literal values, not to the JS expression that produces a post-response value. */}
75-
{!isLastEmptyRow && varType === 'request' && (
76-
<DataTypeSelector
77-
variable={row}
78-
theme={storedTheme}
79-
collection={collection}
80-
onChange={(fields) => {
81-
const updated = (vars || []).map((v) => v.uid === row.uid ? { ...v, ...fields } : v);
82-
handleVarsChange(updated);
83-
}}
84-
/>
8583
)}
86-
</div>
84+
renderTypeSelector={!isLastEmptyRow && varType === 'request'
85+
? ({ compact }) => (
86+
<DataTypeSelector
87+
compact={compact}
88+
variable={row}
89+
theme={storedTheme}
90+
collection={collection}
91+
onChange={(fields) => {
92+
const updated = (vars || []).map((v) => v.uid === row.uid ? { ...v, ...fields } : v);
93+
handleVarsChange(updated);
94+
}}
95+
/>
96+
)
97+
: null}
98+
/>
8799
)
88-
}
100+
},
101+
descriptionColumn
89102
];
90103

91104
const defaultRow = {
92105
name: '',
93106
value: '',
107+
description: '',
94108
...(varType === 'response' ? { local: false } : {})
95109
};
96110

packages/bruno-app/src/components/DataTypeSelector/StyledWrapper.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ const StyledWrapper = styled.div`
1414
.caret-icon {
1515
opacity: 0.7;
1616
}
17+
18+
.type-icon {
19+
opacity: 0.7;
20+
flex-shrink: 0;
21+
}
1722
`;
1823

1924
export default StyledWrapper;

packages/bruno-app/src/components/DataTypeSelector/index.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
import React from 'react';
2-
import { IconAlertCircle, IconCaretDown } from '@tabler/icons';
2+
import {
3+
IconAlertCircle,
4+
IconBraces,
5+
IconCaretDown,
6+
IconNumbers,
7+
IconLetterT,
8+
IconToggleRight
9+
} from '@tabler/icons';
310
import { Tooltip } from 'react-tooltip';
411
import { BRUNO_VARIABLE_DATATYPES, parseValueByDataType, validateDataTypeValue } from '@usebruno/common/utils';
512
import MenuDropdown from 'ui/MenuDropdown';
613
import StyledWrapper from './StyledWrapper';
714

8-
const DataTypeSelector = ({ variable, onChange }) => {
15+
const TYPE_ICONS = {
16+
string: IconLetterT,
17+
number: IconNumbers,
18+
boolean: IconToggleRight,
19+
object: IconBraces
20+
};
21+
22+
const DataTypeSelector = ({ variable, onChange, compact = false }) => {
923
const selectedType = variable.dataType || 'string';
1024
const coercedValue = parseValueByDataType(variable.value, selectedType);
1125
const typeError = validateDataTypeValue(coercedValue, selectedType);
@@ -20,18 +34,29 @@ const DataTypeSelector = ({ variable, onChange }) => {
2034
onClick: () => handleTypeChange(type)
2135
}));
2236

37+
const TypeIcon = TYPE_ICONS[selectedType] || IconLetterT;
38+
2339
return (
2440
<StyledWrapper>
25-
<div className="flex items-center relative">
41+
<div className="flex items-center relative shrink-0">
2642
<MenuDropdown
2743
items={items}
2844
selectedItemId={selectedType}
2945
placement="bottom-end"
3046
showTickMark={true}
3147
appendTo={() => document.body}
48+
data-testid="datatype-selector-trigger"
3249
>
33-
<div className="flex items-center cursor-pointer select-none">
34-
<span className="type-label">{selectedType}</span>
50+
<div
51+
className="flex items-center cursor-pointer select-none"
52+
data-selected-type={selectedType}
53+
aria-label={`Data type: ${selectedType}`}
54+
>
55+
{compact ? (
56+
<TypeIcon className="type-icon" size={12} strokeWidth={2} />
57+
) : (
58+
<span className="type-label">{selectedType}</span>
59+
)}
3560
<IconCaretDown className="caret-icon ml-1" size={14} strokeWidth={2} />
3661
</div>
3762
</MenuDropdown>

packages/bruno-app/src/components/EditableTable/StyledWrapper.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,27 +107,53 @@ const StyledWrapper = styled.div`
107107
overflow: hidden;
108108
}
109109
110-
/* Handle CodeMirror editors overflow */
111-
.cm-editor {
110+
/* Single-line CodeMirror editors: clip overflow to one row */
111+
.single-line-editor .CodeMirror {
112112
max-width: 100%;
113113
height: 33px !important;
114114
max-height: 33px !important;
115115
116-
.cm-scroller {
116+
.CodeMirror-scroll {
117117
overflow: hidden !important;
118118
max-height: 33px;
119119
}
120120
121-
.cm-content {
121+
.CodeMirror-vscrollbar,
122+
.CodeMirror-hscrollbar,
123+
.CodeMirror-scrollbar-filler {
124+
display: none;
125+
}
126+
127+
.CodeMirror-lines {
122128
max-width: 100%;
123129
}
124130
125-
.cm-line {
131+
.CodeMirror-line {
126132
overflow: hidden;
127133
text-overflow: ellipsis;
128134
white-space: nowrap;
129135
}
130136
}
137+
138+
&:has(.multi-line-editor) {
139+
height: auto;
140+
max-height: none;
141+
overflow: visible;
142+
white-space: normal;
143+
text-overflow: clip;
144+
145+
> div:not(.drag-handle) {
146+
height: auto;
147+
max-height: none;
148+
overflow: visible;
149+
}
150+
}
151+
}
152+
153+
&:has(.multi-line-editor) {
154+
height: auto;
155+
max-height: calc(35px * 3);
156+
overflow: auto;
131157
}
132158
}
133159
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
import MultiLineEditor from 'components/MultiLineEditor';
3+
4+
export const createDescriptionColumn = ({
5+
theme,
6+
onSave,
7+
onRun,
8+
collection,
9+
item,
10+
nameFromRowIndex = false,
11+
onDescriptionChange
12+
}) => ({
13+
key: 'description',
14+
name: 'Description',
15+
placeholder: 'Description',
16+
width: '25%',
17+
render: ({ row, value, onChange, rowIndex }) => (
18+
<MultiLineEditor
19+
value={value || ''}
20+
theme={theme}
21+
onSave={onSave}
22+
onChange={
23+
onDescriptionChange
24+
? (newValue) => onDescriptionChange(newValue, { row, onChange })
25+
: onChange
26+
}
27+
{...(onRun ? { onRun } : {})}
28+
{...(collection ? { collection } : {})}
29+
{...(item ? { item } : {})}
30+
{...(nameFromRowIndex && rowIndex !== undefined ? { name: `${rowIndex}.description` } : {})}
31+
/>
32+
)
33+
});

packages/bruno-app/src/components/EditableTable/index.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,11 @@ const EditableTable = ({
380380
</td>
381381
))}
382382
{showDelete && (
383-
<td style={{ width: '60px' }}></td>
383+
<td
384+
id="delete-column-header"
385+
style={{ width: '57px' }}
386+
>
387+
</td>
384388
)}
385389
</tr>
386390
), [showCheckbox, checkboxLabel, columns, getColumnWidth, resizing, tableHeight, handleResizeStart, showDelete]);
@@ -426,7 +430,19 @@ const EditableTable = ({
426430
</td>
427431
))}
428432
{showDelete && (
429-
<td>
433+
<td ref={(node) => {
434+
if (!node) return;
435+
const width = node.scrollWidth;
436+
const parent = node.parentElement.parentElement.parentElement.querySelector('#delete-column-header');
437+
if (parent) {
438+
const parentWidth = parseInt(parent.style.width);
439+
const nextWidth = Math.max(parentWidth, width);
440+
if (nextWidth !== parentWidth) {
441+
parent.style.width = nextWidth + 'px';
442+
}
443+
}
444+
}}
445+
>
430446
{!isEmpty && (
431447
<button
432448
data-testid="column-delete"

packages/bruno-app/src/components/EnvironmentVariablesTable/StyledWrapper.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ const Wrapper = styled.div`
3232
width: 25px;
3333
border-right: none;
3434
}
35+
3536
&:nth-child(4) {
3637
width: 80px;
3738
}
39+
3840
&:nth-child(5) {
39-
width: 60px;
41+
width: 10%;
42+
}
43+
44+
&:nth-child(6) {
45+
width: 5%;
4046
}
4147
}
4248

0 commit comments

Comments
 (0)