Skip to content

Conversation

@naman-bruno
Copy link
Collaborator

@naman-bruno naman-bruno commented Dec 6, 2025

Description

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • New Features

    • Unified EditableTable used across headers, params, vars, multipart files, and assertions with add-row, bulk edit and drag‑to‑reorder support.
    • Bulk replace actions to apply entire sets of params/vars/assertions/headers at once.
  • Improvements

    • Consolidated change handlers and memoized callbacks for more stable, faster UI updates.
    • Improved inline editors, validation hooks, and file-handling UX.
  • Bug Fixes

    • Preserve existing item identifiers when reapplying or importing entries.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 6, 2025

Walkthrough

Replaces many manual table UIs with a new, generic EditableTable component and adds six bulk Redux actions (setFormUrlEncodedParams, setMultipartFormParams, setFolderVars, setCollectionVars, setRequestAssertions, setRequestVars). Multiple components now use EditableTable and centralized onChange handlers instead of per-item actions.

Changes

Cohort / File(s) Summary
EditableTable Component
packages/bruno-app/src/components/EditableTable/index.js, packages/bruno-app/src/components/EditableTable/StyledWrapper.js
New EditableTable component and themed StyledWrapper providing configurable columns, per-cell editors, trailing empty-row behavior, optional checkboxes/delete, drag-and-drop reordering, row validation hooks, and comprehensive styling.
Collection Settings
packages/bruno-app/src/components/CollectionSettings/Headers/index.js, packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js
Replace bespoke header/var tables with EditableTable; introduce memoized handleHeadersChange/handleVarsChange that dispatch bulk setCollectionHeaders/setCollectionVars; remove per-item add/update/delete handlers and legacy UI.
Folder Settings
packages/bruno-app/src/components/FolderSettings/Headers/index.js, packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js
Migrate folder header and var editing to EditableTable; unify updates via setFolderHeaders/setFolderVars and remove old per-item mutation logic.
Request Pane — Headers & Assertions
packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js, packages/bruno-app/src/components/RequestPane/Assertions/index.js
Swap manual header/assertion tables for EditableTable; add assertion operator parsing, unary-operator handling, unified handleAssertionsChange, and reorder support wired to Redux move actions.
Request Pane — Parameters
packages/bruno-app/src/components/RequestPane/QueryParams/index.js, packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js, packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js, packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js
Consolidate Query, Path, Form-URL-Encoded, and Multipart param UIs to EditableTable; centralize handlers (handleParamsChange/handleParamDrag), add multipart file browse/clear and path normalization, remove Table/ReorderTable and per-item actions.
Request Pane — Variables
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js
Replace inline request var management with EditableTable; add getRowError validation, unified handleVarsChange, and reorder handling via moveVar and onReorder.
Redux Store (collections slice)
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
Add bulk-set reducers/actions: setFormUrlEncodedParams, setMultipartFormParams, setFolderVars, setCollectionVars, setRequestAssertions, setRequestVars; preserve provided UIDs (uid

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Pay extra attention to:
    • EditableTable empty-row lifecycle, UID generation, and onChange filtering (avoid duplicate empty rows).
    • Reorder behavior and onReorder payloads vs. existing move* Redux actions.
    • New bulk-set reducers: UID preservation logic and draft initialization.
    • Multipart file path normalization (isWindowsOS, relative path conversion) and file-list handling.

Possibly related PRs

Suggested reviewers

  • lohit-bruno
  • bijin-bruno
  • helloanoop

Poem

✨ A table once many, now single and bright,
Rows that can wander, reorder, and write.
Handlers consolidated, UIDs kept in line,
Bulk actions arrive — the state now in rhyme.
Edit, drag, save — one flow, shining fine.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Improve tables design' is vague and generic, lacking specificity about the actual changes implemented in the changeset. Consider a more descriptive title that captures the main architectural change, such as 'Refactor table components to use EditableTable' or 'Consolidate table editing with unified EditableTable component'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (12)
packages/bruno-app/src/components/EditableTable/StyledWrapper.js (1)

22-44: Excessive !important declarations.

Multiple !important rules in thead styling (lines 23, 25, 26, 31, 35, 36) suggest possible specificity conflicts. Consider reviewing CSS cascade to reduce reliance on !important, which can make future maintenance harder.

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

32-60: Consider memoizing the columns array.

The columns array contains render functions that depend on storedTheme, onSave, collection, and varType. It's recreated each render. Wrapping with useMemo would prevent unnecessary re-renders in EditableTable.

-  const columns = [
+  const columns = useMemo(() => [
     {
       key: 'name',
       ...
     },
     {
       key: 'value',
       ...
     }
-  ];
+  ], [storedTheme, onSave, collection, varType]);
packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js (1)

45-84: Consider memoizing columns.

Similar to VarsTable, the columns array with render functions is recreated each render. Memoizing with useMemo would optimize re-renders.

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

34-69: Consider memoizing columns.

Same optimization opportunity as other EditableTable usages in this PR.


98-103: Consider adding reorderable support for consistency.

RequestHeaders component includes reorderable={true} with drag support, but this collection-level Headers component doesn't. If header ordering matters at the collection level, consider adding the same capability.

       <EditableTable
         columns={columns}
         rows={headers}
         onChange={handleHeadersChange}
         defaultRow={defaultRow}
+        reorderable={true}
+        onReorder={handleHeaderDrag}
       />
packages/bruno-app/src/components/RequestPane/Assertions/index.js (1)

86-108: Unused parameters in render function.

The value and isLastEmptyRow parameters are destructured but never used in the operator column's render function.

-      render: ({ row, value, onChange, isLastEmptyRow }) => {
+      render: ({ row, onChange }) => {
packages/bruno-app/src/components/RequestPane/QueryParams/index.js (1)

167-179: No-op onChange for path params is intentional but worth documenting.

The onChange={() => {}} is correct here since path param value changes are handled via handlePathParamChange in the column render function, and the table doesn't allow adding/deleting rows. Consider adding a brief comment to clarify this isn't an oversight.

         {pathParams && pathParams.length > 0 ? (
           <EditableTable
             columns={pathColumns}
             rows={pathParams}
-            onChange={() => {}}
+            onChange={() => {}} // Path param changes handled via render callback
             defaultRow={{}}
             showCheckbox={false}
             showDelete={false}
             showAddRow={false}
           />
packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (1)

76-84: Unused onChange parameter in handleValueChange.

The onChange parameter is passed but never used since the function dispatches directly via handleParamsChange.

-  const handleValueChange = useCallback((row, newValue, onChange) => {
+  const handleValueChange = useCallback((row, newValue) => {

Also update the call site at line 144:

-                onChange={(newValue) => handleValueChange(row, newValue, onChange)}
+                onChange={(newValue) => handleValueChange(row, newValue)}
packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js (1)

66-70: Missing enabled field in defaultRow.

The EditableTable component defaults checkboxKey to 'enabled', but defaultRow doesn't include it. This could cause inconsistent state when new rows are created. The Redux reducer setFormUrlEncodedParams defaults enabled to true, so it works, but adding it here improves clarity.

 const defaultRow = {
   name: '',
   value: '',
-  description: ''
+  description: '',
+  enabled: true
 };
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (1)

79-83: Missing enabled field in defaultRow.

Same issue as FormUrlEncodedParams - defaultRow should include enabled: true for consistency with the EditableTable checkbox behavior.

 const defaultRow = {
   name: '',
   value: '',
+  enabled: true,
   ...(varType === 'response' ? { local: false } : {})
 };
packages/bruno-app/src/components/EditableTable/index.js (2)

108-116: Filter logic could exclude valid rows with falsy key values.

The condition keyVal && (typeof keyVal !== 'string' || keyVal.trim() !== '') filters out rows where keyVal is any falsy value (0, false, empty string). If a numeric key field could legitimately be 0, this would incorrectly filter it out.

Given the current usage context (string-based keys like "name"), this is unlikely to cause issues, but worth noting for future use cases.

-const result = updatedRows.filter((row, i) => {
-  if (showAddRow && i === updatedRows.length - 1) return false;
-  if (!showAddRow) return true;
-  const keyVal = keyColumn ? (keyColumn.getValue ? keyColumn.getValue(row) : row[keyColumn.key]) : '';
-  return keyVal && (typeof keyVal !== 'string' || keyVal.trim() !== '');
-});
+const result = updatedRows.filter((row, i) => {
+  if (showAddRow && i === updatedRows.length - 1) return false;
+  if (!showAddRow) return true;
+  const keyVal = keyColumn ? (keyColumn.getValue ? keyColumn.getValue(row) : row[keyColumn.key]) : '';
+  if (keyVal === null || keyVal === undefined) return false;
+  if (typeof keyVal === 'string') return keyVal.trim() !== '';
+  return true;
+});

26-34: createEmptyRow spreads defaultRow after setting checkboxKey.

If defaultRow contains a property matching checkboxKey (typically enabled), it will override the [checkboxKey]: true set on line 31. This is likely fine if defaultRow always sets enabled: true, but could cause unexpected behavior if a consumer passes enabled: false in defaultRow.

Consider spreading defaultRow first to allow explicit override:

 const createEmptyRow = useCallback(() => {
   const newUid = uuid();
   emptyRowUidRef.current = newUid;
   return {
+    ...defaultRow,
     uid: newUid,
-    [checkboxKey]: true,
-    ...defaultRow
+    [checkboxKey]: true
   };
 }, [defaultRow, checkboxKey]);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a8d787 and 379b6b9.

📒 Files selected for processing (14)
  • packages/bruno-app/src/components/CollectionSettings/Headers/index.js (4 hunks)
  • packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js (1 hunks)
  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js (1 hunks)
  • packages/bruno-app/src/components/EditableTable/index.js (1 hunks)
  • packages/bruno-app/src/components/FolderSettings/Headers/index.js (4 hunks)
  • packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/Assertions/index.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/QueryParams/index.js (4 hunks)
  • packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js (3 hunks)
  • packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (1 hunks)
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (13 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js
  • packages/bruno-app/src/components/EditableTable/index.js
  • packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js
  • packages/bruno-app/src/components/CollectionSettings/Headers/index.js
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js
  • packages/bruno-app/src/components/RequestPane/Assertions/index.js
  • packages/bruno-app/src/components/RequestPane/QueryParams/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
  • packages/bruno-app/src/components/FolderSettings/Headers/index.js
  • packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js
  • packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js
  • packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js
  • packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js
🧠 Learnings (3)
📚 Learning: 2025-12-05T20:31:32.975Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:32.975Z
Learning: Applies to **/*.{jsx,tsx} : Styled Components are used as wrappers to define both self and children components style; Tailwind classes are used specifically for layout based styles

Applied to files:

  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:32.975Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:32.975Z
Learning: Applies to **/*.{jsx,tsx} : Styled Component CSS might also change layout but Tailwind classes shouldn't define colors

Applied to files:

  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:32.975Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:32.975Z
Learning: Applies to **/*.{jsx,tsx} : Use styled component's theme prop to manage CSS colors and not CSS variables when in the context of a styled component or any React component using the styled component

Applied to files:

  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js
🧬 Code graph analysis (6)
packages/bruno-app/src/components/EditableTable/index.js (1)
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (3)
  • defaultRow (79-83)
  • columns (47-77)
  • getRowError (38-45)
packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js (5)
packages/bruno-app/src/components/RequestPane/QueryParams/index.js (2)
  • dispatch (18-18)
  • onSave (26-26)
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (4)
  • dispatch (14-14)
  • columns (47-77)
  • onSave (17-17)
  • defaultRow (79-83)
packages/bruno-app/src/components/EditableTable/index.js (2)
  • isLastEmptyRow (76-79)
  • EditableTable (7-304)
packages/bruno-app/src/utils/codemirror/autocompleteConstants.js (2)
  • MimeTypes (1-56)
  • MimeTypes (1-56)
packages/bruno-app/src/components/BulkEditor/index.js (1)
  • BulkEditor (7-38)
packages/bruno-app/src/components/CollectionSettings/Headers/index.js (3)
packages/bruno-app/src/components/FolderSettings/Headers/index.js (8)
  • headerAutoCompleteList (14-14)
  • Headers (16-121)
  • dispatch (17-17)
  • headers (19-21)
  • handleHeadersChange (28-34)
  • handleSave (36-36)
  • columns (38-74)
  • defaultRow (76-80)
packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js (2)
  • saveCollectionSettings (2203-2242)
  • saveCollectionSettings (2203-2242)
packages/bruno-app/src/components/EditableTable/index.js (1)
  • EditableTable (7-304)
packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js (5)
packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js (8)
  • VarsTable (13-85)
  • dispatch (14-14)
  • useTheme (15-15)
  • onSave (17-17)
  • handleVarsChange (19-26)
  • getRowError (28-35)
  • columns (37-66)
  • defaultRow (68-72)
packages/bruno-app/src/components/CollectionSettings/Headers/index.js (4)
  • dispatch (17-17)
  • useTheme (18-18)
  • columns (34-69)
  • defaultRow (71-75)
packages/bruno-js/src/bru.js (1)
  • variableNameRegex (7-7)
packages/bruno-app/src/components/EditableTable/index.js (1)
  • EditableTable (7-304)
packages/bruno-app/src/components/EditableTable/StyledWrapper.js (1)
  • StyledWrapper (3-137)
packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js (2)
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (5)
  • dispatch (14-14)
  • onSave (17-17)
  • handleRun (18-18)
  • columns (47-77)
  • defaultRow (79-83)
packages/bruno-app/src/components/EditableTable/index.js (2)
  • isLastEmptyRow (76-79)
  • EditableTable (7-304)
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (2)
packages/bruno-js/src/bru.js (1)
  • variableNameRegex (7-7)
packages/bruno-app/src/components/EditableTable/index.js (2)
  • isLastEmptyRow (76-79)
  • EditableTable (7-304)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: Unit Tests
  • GitHub Check: CLI Tests
  • GitHub Check: SSL Tests - Linux
  • GitHub Check: SSL Tests - macOS
🔇 Additional comments (22)
packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js (2)

62-66: Clean conditional property spread.

Good use of the spread operator for conditionally adding local property based on varType.


68-78: LGTM - Clean EditableTable integration.

Proper wiring of columns, rows, onChange, defaultRow, and getRowError to the EditableTable component. Aligns well with the pattern used in related files.

packages/bruno-app/src/components/RequestPane/RequestHeaders/index.js (3)

25-39: Well-structured memoized handlers.

Both handleHeadersChange and handleHeaderDrag are properly memoized with correct dependency arrays. Clean separation of concerns between bulk updates and reordering.


106-121: LGTM - Clean EditableTable with reorder support.

Proper integration of EditableTable with reorderable={true} and onReorder handler. The defensive headers || [] fallback is a good safeguard.


86-90: Verify description field usage in headers data model.

The defaultRow includes a description field, but confirm whether the columns array defines a column for it. If not displayed in the UI, verify this field is intentionally preserved for API data consistency or backend persistence, and check if it's included in header payloads sent to the server.

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

19-21: LGTM - Clean conditional header retrieval.

Proper use of optional chaining with collection.draft?.root to determine the correct headers source.


28-30: Well-memoized change handler.

Proper use of useCallback with correct dependencies for handleHeadersChange.

packages/bruno-app/src/components/RequestPane/Assertions/index.js (2)

110-134: LGTM on value column rendering logic.

The conditional rendering for unary operators (disabled input) vs binary operators (SingleLineEditor) is clean and handles the operator parsing correctly.


137-141: operator key in defaultRow may be unused.

The defaultRow includes an operator key, but columns only defines name and value as column keys. If EditableTable only processes columns by their key, this property won't be set on new rows. Verify whether operator is needed here or if it's vestigial from a prior implementation.

packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js (2)

28-35: Validation only checks name field, as expected.

The getRowError properly validates only the name field and allows empty names (for new rows). Clean implementation.


37-66: LGTM on columns configuration.

The conditional column header with InfoTip for non-request var types is a nice UX touch. The MultiLineEditor integration looks correct.

packages/bruno-app/src/components/FolderSettings/Headers/index.js (3)

76-80: description field in defaultRow has no corresponding column.

The defaultRow includes a description key, but there's no column defined for it. Verify if EditableTable preserves extra properties from defaultRow when creating new rows, or if this is dead configuration.


45-55: Good: Header name sanitization.

Stripping \r\n from header names (line 50) prevents invalid multi-line header names. Solid defensive coding.


103-108: LGTM on EditableTable integration.

The component correctly passes headers as rows and uses the centralized handleHeadersChange for updates.

packages/bruno-app/src/components/RequestPane/QueryParams/index.js (2)

101-112: Path param value changes bypass the generic onChange prop.

The handlePathParamChange is called directly in the render function (line 106). This works but creates a subtle inconsistency with how query params are handled. The current approach is acceptable since path params are read-only except for values.


29-36: LGTM on query params handler.

Correctly adds type: 'query' to all params before dispatching. This ensures the type is preserved through bulk updates.

packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (2)

86-99: LGTM on getFileName helper.

Good handling of null/empty arrays, platform-specific path separators, and multiple file count display.


114-163: Well-structured conditional rendering for file vs text values.

The value cell properly handles file display with clear button, text editing with MultiLineEditor, and conditionally shows the upload button. Clean separation of concerns.

packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js (1)

1-84: LGTM overall - clean migration to EditableTable.

The migration from legacy table components to the unified EditableTable is well-structured. The useCallback hooks properly stabilize dependencies, and the Redux integration via setFormUrlEncodedParams and moveFormUrlEncodedParam is correct.

packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (1)

38-45: Validation callback is well implemented.

The getRowError callback correctly validates variable names using variableNameRegex, returns null for empty names (allowing placeholder rows), and provides a clear error message. Good use of useCallback with empty deps since no external state is referenced.

packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (1)

1297-1315: New bulk set actions are well-structured.

The setFormUrlEncodedParams, setRequestAssertions, setRequestVars, setFolderVars, and setCollectionVars reducers follow a consistent pattern: validate inputs, create draft if needed, and map with UID preservation. Good defensive defaults throughout.

Also applies to: 1749-1767, 1883-1907, 2214-2236, 2448-2471

packages/bruno-app/src/components/EditableTable/index.js (1)

1-304: Well-designed reusable component.

The EditableTable component provides good encapsulation of common table behaviors: row management, checkbox toggling, drag-and-drop reordering, and cell rendering. The use of useMemo and useCallback optimizes re-renders appropriately. The empty row management logic handles edge cases like stale UIDs.

@naman-bruno naman-bruno changed the title init Improve tables design Dec 6, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (1)

1401-1420: setMultipartFormParams missing description field in mapping.

This was flagged in a previous review and appears unaddressed. Other form param actions (e.g., setFormUrlEncodedParams at line 1311) include description. This could cause data loss:

-item.draft.request.body.multipartForm = map(params, ({ uid, name = '', value = '', contentType = '', type = 'text', enabled = true }) => ({
+item.draft.request.body.multipartForm = map(params, ({ uid, name = '', value = '', contentType = '', type = 'text', description = '', enabled = true }) => ({
   uid: uid || uuid(),
   name,
   value,
   contentType,
   type,
+  description,
   enabled
 }));
🧹 Nitpick comments (3)
packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (2)

69-77: Potential stale closure on params in handleClearFile.

Same pattern as the fixed handleBrowseFiles - if the user makes changes before this callback runs, params could be outdated. Consider reading fresh state from item:

 const handleClearFile = useCallback((row) => {
+  const currentParams = item.draft
+    ? get(item, 'draft.request.body.multipartForm')
+    : get(item, 'request.body.multipartForm');
-  const updatedParams = params.map((p) => {
+  const updatedParams = (currentParams || []).map((p) => {
     if (p.uid === row.uid) {
       return { ...p, type: 'text', value: '' };
     }
     return p;
   });
   handleParamsChange(updatedParams);
-}, [params, handleParamsChange]);
+}, [item, handleParamsChange]);

79-87: Same stale closure concern and unused onChange parameter.

The params closure risk applies here too. Additionally, onChange is passed but never used - remove it to avoid confusion:

-const handleValueChange = useCallback((row, newValue, onChange) => {
-  const updatedParams = params.map((p) => {
+const handleValueChange = useCallback((row, newValue) => {
+  const currentParams = item.draft
+    ? get(item, 'draft.request.body.multipartForm')
+    : get(item, 'request.body.multipartForm');
+  const updatedParams = (currentParams || []).map((p) => {
     if (p.uid === row.uid) {
       return { ...p, type: 'text', value: newValue };
     }
     return p;
   });
   handleParamsChange(updatedParams);
-}, [params, handleParamsChange]);
+}, [item, handleParamsChange]);

Update the caller at line 147 accordingly:

-onChange={(newValue) => handleValueChange(row, newValue, onChange)}
+onChange={(newValue) => handleValueChange(row, newValue)}
packages/bruno-app/src/components/EditableTable/index.js (1)

81-116: Consider simplifying the filter logic.

The filtering at lines 108-113 is complex. It filters out empty rows to pass to onChange, but the conditions are hard to follow. Consider extracting to a named function for clarity:

const filterEmptyTrailingRows = (rows) => {
  const keyColumn = columns.find((col) => col.isKeyField);
  return rows.filter((row, i) => {
    if (showAddRow && i === rows.length - 1) return false;
    if (!keyColumn) return true;
    const keyVal = keyColumn.getValue ? keyColumn.getValue(row) : row[keyColumn.key];
    return keyVal && (typeof keyVal !== 'string' || keyVal.trim() !== '');
  });
};
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 379b6b9 and 5febefe.

📒 Files selected for processing (3)
  • packages/bruno-app/src/components/EditableTable/index.js (1 hunks)
  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (1 hunks)
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (13 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
  • packages/bruno-app/src/components/EditableTable/index.js
🧬 Code graph analysis (2)
packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (2)
packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js (2)
  • browseFiles (2195-2201)
  • browseFiles (2195-2201)
packages/bruno-app/src/utils/common/platform.js (2)
  • isWindowsOS (22-27)
  • isWindowsOS (22-27)
packages/bruno-app/src/components/EditableTable/index.js (1)
packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js (2)
  • columns (47-77)
  • getRowError (38-45)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: CLI Tests
  • GitHub Check: Unit Tests
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: SSL Tests - Linux
🔇 Additional comments (14)
packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js (2)

89-102: LGTM!

getFileName handles both single and multiple files correctly, with proper Windows/Unix path separator detection. Edge cases (null, empty array, empty strings) are well covered.


104-185: Clean column configuration and EditableTable integration.

The columns setup with custom render functions for file handling is well-structured. The conditional rendering for file display vs. text editor is clear.

Also applies to: 187-206

packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (6)

1300-1318: LGTM!

setFormUrlEncodedParams correctly maps all fields including description and preserves UIDs when provided.


1752-1770: LGTM!

setRequestAssertions correctly includes the operator field and follows the established pattern.


1886-1910: LGTM!

setRequestVars correctly handles the conditional local field for response-type variables.


2217-2239: LGTM!

setFolderVars properly initializes folder.draft from folder.root and handles both request/response types.


2451-2474: LGTM!

setCollectionVars follows the same consistent pattern as other bulk-set actions.


1231-1240: LGTM!

setFolderHeaders now correctly initializes folder.draft before modifying headers, addressing the previous review concern about bypassing the draft workflow.

packages/bruno-app/src/components/EditableTable/index.js (6)

7-20: Well-designed prop interface.

Good defaults and clear prop names. The flexibility to customize checkbox behavior, deletion, and reordering makes this component reusable across the codebase.


36-66: Solid trailing empty row management.

The logic correctly handles edge cases: empty initial state, preventing duplicate empty rows, and maintaining UID stability. The check at line 57 prevents UID collisions if a row somehow matches the empty row UID.


144-156: Drag-drop reorder excludes trailing empty row correctly.

Good handling at line 148 to slice off the empty row before reordering. The updateReorderedItem callback shape aligns with the Redux actions expecting UID arrays.


193-208: Error tooltip implementation looks correct.

Using data-tooltip-id on the anchor and id on the Tooltip follows react-tooltip v5+ API. The error is only shown for non-empty rows.


251-280: Drag handle visibility tied to hover state.

The conditional rendering based on hoveredRow === rowIndex means the grip icon only appears on hover. This is good UX but note: if users need visual affordance that rows are reorderable, consider showing a subtle indicator always.


236-298: Solid row rendering with conditional drag behavior.

The canDrag check properly prevents dragging empty rows and respects the reorderable prop. Event handlers are correctly conditionally applied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant