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 deployed across headers, params, vars, multipart files, and assertions with add-row, bulk edit, and drag-to-reorder.
    • New styled wrappers for editable tables and environment details for consistent UI.
  • Improvements

    • Centralized bulk-change handlers, memoized callbacks, enhanced editors (single/multi-line), validation, and improved file upload UX.
    • Bulk-set actions to replace entire collections (params/vars/assertions/headers).
  • 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 bespoke per-item tables with a new generic EditableTable component and adds bulk Redux actions to replace entire collections of params/vars/headers/assertions; multiple components now use EditableTable with 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 reusable EditableTable and themed StyledWrapper implementing configurable columns, per-cell editors, trailing empty-row behavior, optional checkboxes/delete, drag-and-drop reordering, row validation hook, and styling.
Collection Settings
packages/bruno-app/src/components/CollectionSettings/Headers/index.js, packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js
Replace custom header/var tables with EditableTable; introduce memoized handlers 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 UIs for EditableTable; add assertion operator parsing and unary-operator support; unify assertion updates via setRequestAssertions; support reorder via onReorder.
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/Multipart param UIs to EditableTable; centralize handlers (setQueryParams, setFormUrlEncodedParams, setMultipartFormParams), 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 editing with EditableTable; add getRowError validation, unified handleVarsChange, and reorder handling with setRequestVars/move actions.
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
Styling & Small UI tweaks
packages/bruno-app/src/components/*/StyledWrapper.js, packages/bruno-app/src/components/WorkspaceHome/index.js, other StyledWrapper changes
Multiple styling adjustments and small UI tweaks (checkbox alignment, tab font-weight, workspace icon sizing, multipart param button styles); some components refactored to import external StyledWrapper modules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on:
    • EditableTable empty-row lifecycle, UID generation, and onChange filtering to avoid duplicate/phantom rows.
    • onReorder payload format vs. existing move* Redux action expectations.
    • New bulk-set reducers in collections slice: UID preservation (uid || uuid()) and draft initialization.
    • Multipart file handling: path normalization, isWindowsOS handling, and relative-path conversion against collection directory.
    • Validation hooks (getRowError) and how errors surface in the EditableTable render.

Possibly related PRs

Suggested reviewers

  • lohit-bruno
  • bijin-bruno
  • helloanoop

Poem

✨ Rows converge into one shining frame,
Editors aligned, each cell knows its name.
UIDs kept tidy, bulk changes take flight,
Drag, edit, save — the UI hums just right.
A small refactor, but the workflow's bright.

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 doesn't clearly communicate the main change. While the PR does refactor table components, the title lacks specificity about what was improved or how. Consider a more descriptive title such as 'Refactor table editing with EditableTable component' or 'Consolidate table UIs using EditableTable for headers, params, and vars' to better convey the primary architectural change.
✅ 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.

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: 1

🧹 Nitpick comments (9)
packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (1)

60-64: Checkbox alignment tweak is a solid simplification

Centering via vertical-align: middle and resetting margin is cleaner and more predictable than positional nudging; this should align with the new table styling well.

If you later see browser-specific misalignment, consider also normalizing line-height on the checkbox container rather than the input itself, but it’s not necessary for this PR.

packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js (1)

99-99: Consider refactoring CSS variable to theme prop for consistency.

Line 99 uses a CSS variable for color, while the rest of the file uses theme props. Based on learnings, styled components should use theme props for colors.

Apply this diff for consistency:

-    color: var(--color-tab-inactive);
+    color: ${(props) => props.theme.tabs.inactive.color};

Note: Verify the correct theme path exists for inactive tab color.

packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js (1)

1-133: Theme usage and layout in StyledWrapper look solid.

The wrapper correctly uses props.theme for all colors/typography and mirrors the workspace rename/error patterns, so it should integrate cleanly with the existing UI. There is some duplication with WorkspaceHome/StyledWrapper (e.g., .inline-actions, .inline-action-btn, error tooltip), which could be factored into a shared helper later if this pattern spreads further.

packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (1)

21-27: Environment variables table styling aligns with EditableTable patterns.

Updating td padding/vertical-align, header color/font-size, and input/checkbox alignment makes this table visually consistent with the new EditableTable styles and keeps colors theme-driven. If more tables converge on this look, consider sharing more of this styling with the generic EditableTable StyledWrapper to avoid drift.

Also applies to: 41-45, 103-109, 119-126

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

12-52: Consolidate assertion operator helpers to avoid duplication.

unaryOperators, the full operators list inside parseAssertionOperator, and the operator options in AssertionOperator all encode essentially the same sets. Keeping these in one shared module (e.g., assertionOperators.js) would reduce drift when adding/removing operators and make tests easier to maintain.


142-147: EditableTable wiring for assertions looks appropriate; consider cleaning up the extra operator field.

Passing columns, rows={assertions || []}, defaultRow (with value: 'eq '), and reorderable/onReorder into EditableTable matches the intended API and should work well with drag-reorder and empty-row handling. The persisted operator is now encoded inside value ("operator value"), so the separate operator: 'eq' field in defaultRow appears unused; you might be able to drop or repurpose it to avoid confusion about the source of truth.

Also applies to: 150-157

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

36-79: Clarify or enforce the requirement for an isKeyField column.

rowsWithEmpty, isEmptyRow, isLastEmptyRow, and the final result filter all assume there is a column with isKeyField: true. If no such column exists, keyColumn is undefined, and the filter will effectively drop all rows when showAddRow is true. At minimum, it’s worth documenting that EditableTable requires exactly one key column; alternatively, you could add a runtime guard (e.g., console.warn or throwing in dev) when !columns.some(c => c.isKeyField).


81-116: Last empty row drops non-key edits; consider whether that UX is acceptable.

handleValueChange only promotes the last row into a “real” row when the key field changes from empty to non-empty. Edits to other columns on the last row are applied to updatedRows but then filtered out (the last row is removed from result and recreated from defaultRow on the next render). That means typing into a non-key field of the add-row is effectively discarded.

If you want to allow users to fill non-key fields first, you could:

  • Treat a row as “non-empty” when any of a configurable set of columns has data, or
  • Skip the i === updatedRows.length - 1 filter when !isEmptyRow(row) so partial edits on the last row are preserved.

As-is, it’s a reasonable tradeoff if the intended flow is “enter key column first,” but it’s worth confirming this matches UX expectations.


24-25: Remove unused dragStart state to reduce noise.

dragStart is set in handleDragStart and cleared in handleDragEnd, but never read. You can safely drop this state (and its setter) to avoid unnecessary state updates during drag-and-drop.

Also applies to: 132-136, 158-161

📜 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 5febefe and 50a84ce.

📒 Files selected for processing (11)
  • 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/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (2 hunks)
  • packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (2 hunks)
  • packages/bruno-app/src/components/RequestPane/Assertions/index.js (1 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js (1 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (4 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js (1 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js (1 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js (1 hunks)
  • packages/bruno-app/src/components/WorkspaceHome/index.js (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/components/EditableTable/StyledWrapper.js
🧰 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/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/EditableTable/index.js
  • packages/bruno-app/src/components/RequestPane/Assertions/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
🧠 Learnings (3)
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
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/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
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/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
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/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
  • packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
🧬 Code graph analysis (3)
packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js (1)
packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js (1)
  • StyledWrapper (3-133)
packages/bruno-app/src/components/EditableTable/index.js (3)
packages/bruno-app/src/components/FolderSettings/Headers/index.js (2)
  • defaultRow (76-80)
  • columns (38-74)
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/EditableTable/StyledWrapper.js (1)
  • StyledWrapper (3-144)
packages/bruno-app/src/components/RequestPane/Assertions/index.js (3)
packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js (8)
  • unaryOperators (78-91)
  • unaryOperators (117-130)
  • parseAssertionOperator (39-114)
  • parseAssertionOperator (146-146)
  • operators (47-76)
  • operator (93-93)
  • value (94-94)
  • isUnaryOperator (116-133)
packages/bruno-app/src/components/RequestPane/Assertions/AssertionOperator/index.js (1)
  • AssertionOperator (36-92)
packages/bruno-app/src/components/EditableTable/index.js (2)
  • isLastEmptyRow (76-79)
  • EditableTable (7-304)
🔇 Additional comments (7)
packages/bruno-app/src/components/WorkspaceHome/index.js (2)

222-223: LGTM! Header sizing refinement.

The reduction in text size (text-xltext-sm) and icon size (24 → 18) creates a more compact workspace header, consistent with the broader UI modernization described in the PR summary.


305-305: LGTM! Tab padding refinement.

The vertical padding adjustment (py-2pt-2 pb-1.5) subtly reduces tab height while maintaining consistent spacing with the updated header styling.

packages/bruno-app/src/components/GlobalEnvironments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (1)

10-15: Table cell vertical alignment change looks good

Using vertical-align: middle on td will help keep text and controls visually centered in rows and is consistent with the broader table cleanup. No issues.

packages/bruno-app/src/components/WorkspaceHome/StyledWrapper.js (1)

111-111: LGTM! Clean styling improvement.

Adding medium font-weight to active tabs improves visual hierarchy and user feedback.

packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js (2)

10-27: Vertical centering for table cells is a good improvement

Adding vertical-align: middle to the table cell rule will help keep header and body content visually aligned when rows get taller, without affecting logic or theming. Looks good as part of the broader table standardization.


60-64: Checkbox alignment tweak is appropriate and non-breaking

Centering the checkbox vertically and resetting its margin to 0 should remove the previous “off by a pixel” feel and align it better with adjacent text/controls inside the table cells. This is a safe, localized styling improvement.

packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js (1)

10-10: StyledWrapper import looks correct and consistent.

Import path and usage of the extracted StyledWrapper match the local file structure; no behavior concerns here.

Comment on lines +87 to 113
key: 'operator',
name: 'Operator',
width: '120px',
render: ({ row, rowIndex, isLastEmptyRow }) => {
const { operator } = parseAssertionOperator(row.value);
const assertionValue = parseAssertionOperator(row.value).value;

const handleOperatorChange = (newOperator) => {
const updatedAssertions = assertions.map((assertion, idx) => {
if (idx === rowIndex) {
return {
...assertion,
value: isUnaryOperator(newOperator) ? newOperator : `${newOperator} ${assertionValue}`
};
}
return assertion;
});
handleAssertionsChange(updatedAssertions);
};

return (
<AssertionOperator
operator={operator}
onChange={handleOperatorChange}
/>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use EditableTable’s onChange for operator updates and avoid indexing into assertions.

Right now, the Operator column:

  • Parses row.value twice
  • Rebuilds updatedAssertions from the external assertions array using rowIndex
  • Dispatches setRequestAssertions directly

This has a couple of downsides:

  • Changing the operator on the trailing “empty” row is effectively a no-op (there’s no corresponding entry in assertions), so the select will snap back to the default and the choice is lost.
  • It bypasses EditableTable’s onChange/handleValueChange machinery, which is what manages the empty row lifecycle and any future validation.

You can simplify and make this more robust by using the value and onChange provided by the column render, and parsing only once, e.g.:

-      render: ({ row, rowIndex, isLastEmptyRow }) => {
-        const { operator } = parseAssertionOperator(row.value);
-        const assertionValue = parseAssertionOperator(row.value).value;
-
-        const handleOperatorChange = (newOperator) => {
-          const updatedAssertions = assertions.map((assertion, idx) => {
-            if (idx === rowIndex) {
-              return {
-                ...assertion,
-                value: isUnaryOperator(newOperator) ? newOperator : `${newOperator} ${assertionValue}`
-              };
-            }
-            return assertion;
-          });
-          handleAssertionsChange(updatedAssertions);
-        };
+      render: ({ value, onChange }) => {
+        const { operator, value: assertionValue } = parseAssertionOperator(value);
+
+        const handleOperatorChange = (newOperator) => {
+          const nextValue = isUnaryOperator(newOperator)
+            ? newOperator
+            : `${newOperator} ${assertionValue}`;
+
+          onChange(nextValue);
+        };
-        return (
-          <AssertionOperator
-            operator={operator}
-            onChange={handleOperatorChange}
-          />
-        );
+        return (
+          <AssertionOperator
+            operator={operator}
+            onChange={handleOperatorChange}
+          />
+        );

This keeps all row mutation logic inside EditableTable, avoids relying on rowIndex/assertions, and fixes the “last empty row operator change is ignored” behavior.

Also applies to: 116-137

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