Skip to content

feat(environments): split variables and secrets into separate tabs#8191

Open
pooja-bruno wants to merge 6 commits into
usebruno:mainfrom
pooja-bruno:feat/env-variables-secrets-tabs
Open

feat(environments): split variables and secrets into separate tabs#8191
pooja-bruno wants to merge 6 commits into
usebruno:mainfrom
pooja-bruno:feat/env-variables-secrets-tabs

Conversation

@pooja-bruno

@pooja-bruno pooja-bruno commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

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

    • Variables and Secrets split into separate, tab-scoped views with independent save/reset/draft behavior.
    • Tab-aware search that only shows results for the active Variables or Secrets tab.
  • Improvements

    • Environment header actions and tabs redesigned with a unified search area and a Save action.
    • Tab selection and selected environment persist across views.
  • Bug Fixes

    • Trailing empty-row behavior, draft restoration, and save/reset now respect active tab.
  • Tests

    • End-to-end tests added to verify independent Variables vs Secrets behavior.

abhishek-bruno and others added 5 commits May 18, 2026 12:47
Remember and restore selected environment per tab by storing envUid in tabState (EnvironmentSettings, WorkspaceEnvironments) and dispatching updateTabState when selection changes. Ensure collection.activeEnvironmentUid is set in EnvironmentVariablesTable. Improve collections slice handling of environmentsDraft to reset only when switching environments and otherwise update variables in place. UI tweaks: increase DeleteEnvironment modal size to md and remove extra space before question mark, adjust StyledWrapper top margin from 12px to 16px. MenuDropdown/SubMenuItem: propagate selectedItemId and showTickMark, highlight submenu parent when a child is selected. Add .gstack to .gitignore.
Clean up .gitignore by removing the obsolete `.gstack` entry. This removes an unused ignore rule to reflect current repository files and tooling.
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Splits Environment Variables and Secrets into separate tabs: UI (ResponsiveTabs), Redux per‑tab state persistence, tab-scoped EnvironmentVariablesTable behavior (save/reset/filtering), layout/styling updates, and Playwright tests validating tab isolation across collection and global environments.

Changes

Variables/Secrets Tab Separation

Layer / File(s) Summary
EnvironmentVariablesTable tab-scoped core
packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
variableType prop and isSecretTab flag scope row ordering, memoization by variable.uid, form initialization caching with content equality, and save/reset handlers that validate/persist only the active tab's rows while preserving the other tab's draft state.
Redux tab state and environment selection
packages/bruno-app/src/providers/ReduxStore/slices/tabs.js, packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js, packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/index.js
Adds updateTabState to merge tabState; selected environment is derived from per-tab persisted envUid with fallback to global active environment or first environment; selection persists into Redux tab state.
EnvironmentSettings detail view tabs and actions
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js, packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/StyledWrapper.js
ResponsiveTabs with Variables/Secrets, search moved into tab rightContent with dynamic placeholder, header actions converted to ActionIcon, Save dispatches environment-save-all, and active tab passed as variableType to EnvironmentVariables.
WorkspaceEnvironments detail view tabs and state
packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
Mirrors EnvironmentSettings changes: Redux-driven tabs, tab rightContent search, ActionIcon header actions, Save event, and variableType threaded to EnvironmentVariables.
EnvironmentVariables component prop threading
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
Adds variableType prop (default 'variables') and forwards it to EnvironmentVariablesTable; updates sensitive-field warning text to instruct adding as a secret in the Secrets tab.
CSS layout restructuring and menu selection
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js, packages/bruno-app/src/ui/MenuDropdown/SubMenuItem/index.js, packages/bruno-app/src/ui/MenuDropdown/index.js
Styled-component nesting reflow to introduce .tabs-container and .env-search-container, border-right added to sections, spacing tweaks, and MenuDropdown now accepts/forwards selectedItemId and showTickMark.
DeleteEnvironment modal and messaging
packages/bruno-app/src/components/Environments/EnvironmentSettings/DeleteEnvironment/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/DeleteEnvironment/index.js
Modal size changed to md; confirmation text punctuation normalized to remove the space before ?.
Comprehensive test suite for tab separation
tests/environments/variable-secret-tabs/variable-secret-tabs.spec.ts, tests/utils/page/actions.ts
Playwright tests verify independent add/save/search/delete behavior between Variables and Secrets tabs for collection and global environments; new helpers addRowToActiveTab and deleteAllGlobalEnvironments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • usebruno/bruno#7287: Touches EnvironmentVariablesTable search/rendering and overlaps with table-level changes.
  • usebruno/bruno#6966: Adds search/filtering to EnvironmentVariablesTable; this PR scopes filtering by tab.
  • usebruno/bruno#6659: Earlier work adding searchQuery support to environment variables UI that this PR extends.

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • naman-bruno
  • bijin-bruno
  • sid-bruno

Poem

Tabs split the secrets from the regular names,
Redux keeps your place while you change the frames,
Save one side without erasing the other’s art,
Trailing rows sync their secret flag from the start. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: splitting environment variables and secrets into separate tabs, which is the core objective reflected across all file changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js (1)

28-55: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix .btn-action scoping and remove the extra closing brace.

.sidebar is closed before the first .btn-action, and there is an extra } afterward. This creates two competing root-level .btn-action rules (here and Line 130), making size/hitbox styling ambiguous.

Suggested fix
   .sidebar {
     width: 240px;
     min-width: 240px;
     display: flex;
     flex-direction: column;
-  }
-
-    .btn-action {
+    
+    .btn-action {
       display: flex;
       align-items: center;
       justify-content: center;
       width: 24px;
       height: 24px;
@@
       &:hover {
         background: ${(props) => props.theme.sidebar.collection.item.hoverBg};
         color: ${(props) => props.theme.text};
       }
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js`
around lines 28 - 55, The .btn-action rule is incorrectly scoped because
.sidebar is closed early and an extra closing brace remains; move the
.btn-action block so it is nested inside the .sidebar rule (remove the stray
closing brace that currently creates a second root-level .btn-action) and
consolidate/remove the duplicate root-level .btn-action definition to ensure
size/hitbox styles come only from the nested .sidebar .btn-action selector.
🧹 Nitpick comments (2)
tests/environments/variable-secret-tabs/variable-secret-tabs.spec.ts (1)

10-17: ⚡ Quick win

Consider data-testid for search button selector.

The search button is located via title attribute and the input via class selector .search-input. While functional, data-testid would be more stable for E2E tests.

🔍 Suggested improvement

Request the component team to add data-testids:

- await page.locator('.env-search-container button[title="Search"]').click();
- const input = page.locator('.search-input');
+ await page.getByTestId('env-search-button').click();
+ const input = page.getByTestId('env-search-input');
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/environments/variable-secret-tabs/variable-secret-tabs.spec.ts` around
lines 10 - 17, The test uses fragile selectors in searchEnv ('.search-input' and
'.env-search-container button[title="Search"]'); update the test to use stable
data-testid attributes instead (e.g., replace '.search-input' and the button
selector with 'data-testid' locators) and if those testids don't exist, ask the
component team to add them (for example data-testid="env-search-input" and
data-testid="env-search-button"), then change the locator calls in searchEnv to
use those data-testid values and keep the existing waitFor/fill logic intact.
packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js (1)

13-29: ⚡ Quick win

Extract this tab-scoped environment selection/persistence logic into a shared hook.

This block duplicates the same business logic already present in packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/index.js, which increases drift risk for fallback and persistence behavior.

As per coding guidelines: "MUST: Prefer custom hooks for business logic, data fetching, and side-effects in React".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js`
around lines 13 - 29, Extract the tab-scoped environment selection/persistence
logic (the useMemo computing selectedEnvironment and the setSelectedEnvironment
function that dispatches updateTabState using activeTabUid and env.uid) into a
shared custom hook (e.g., useTabEnvironment or useTabSelectedEnvironment) and
replace the inline logic in both EnvironmentSettings and WorkspaceEnvironments
with that hook; the hook should accept environments and collection (or their
minimal pieces) and return { selectedEnvironment, setSelectedEnvironment },
internally use useSelector to read activeTabUid and persistedEnvUid and dispatch
updateTabState, and preserve the existing fallback order (persistedEnvUid →
collection.activeEnvironmentUid → first environment) and no-op behavior when
activeTabUid or env.uid are missing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js`:
- Around line 202-251: Add stable Playwright selectors by adding data-testid
attributes to the new action and search controls: add data-testid props to the
three ActionIcon instances (the Rename, Copy and Delete buttons) and the Search
ActionIcon (used when isSearchExpanded is false), add data-testid to the search
input element (the input using searchInputRef) and to the clear search button
(the element with class "clear-search"); use descriptive keys like
data-testid="env-rename-btn", "env-copy-btn", "env-delete-btn",
"env-search-btn", "env-search-input", and "env-clear-search-btn" so tests can
reliably locate these controls (ensure ActionIcon forwards unknown props if
needed).

In
`@packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js`:
- Around line 204-253: Add stable Playwright selectors by adding data-testid
attributes to the new action icons and search controls: add data-testid values
on the ActionIcon usages (e.g. the Rename, Copy, Delete and Search icons) such
as data-testid="env-action-rename", "env-action-copy", "env-action-delete",
"env-action-search"; add data-testid="env-search-input" to the input element
rendered when isSearchExpanded is true (the element using searchInputRef and
value/searchQuery), and add data-testid="env-clear-search" to the clear button
that calls handleClearSearch; ensure these attributes are placed on the elements
inside the ResponsiveTabs rightContent so tests can target ActionIcon, the
search input and the clear button reliably.

---

Outside diff comments:
In
`@packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js`:
- Around line 28-55: The .btn-action rule is incorrectly scoped because .sidebar
is closed early and an extra closing brace remains; move the .btn-action block
so it is nested inside the .sidebar rule (remove the stray closing brace that
currently creates a second root-level .btn-action) and consolidate/remove the
duplicate root-level .btn-action definition to ensure size/hitbox styles come
only from the nested .sidebar .btn-action selector.

---

Nitpick comments:
In `@packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js`:
- Around line 13-29: Extract the tab-scoped environment selection/persistence
logic (the useMemo computing selectedEnvironment and the setSelectedEnvironment
function that dispatches updateTabState using activeTabUid and env.uid) into a
shared custom hook (e.g., useTabEnvironment or useTabSelectedEnvironment) and
replace the inline logic in both EnvironmentSettings and WorkspaceEnvironments
with that hook; the hook should accept environments and collection (or their
minimal pieces) and return { selectedEnvironment, setSelectedEnvironment },
internally use useSelector to read activeTabUid and persistedEnvUid and dispatch
updateTabState, and preserve the existing fallback order (persistedEnvUid →
collection.activeEnvironmentUid → first environment) and no-op behavior when
activeTabUid or env.uid are missing.

In `@tests/environments/variable-secret-tabs/variable-secret-tabs.spec.ts`:
- Around line 10-17: The test uses fragile selectors in searchEnv
('.search-input' and '.env-search-container button[title="Search"]'); update the
test to use stable data-testid attributes instead (e.g., replace '.search-input'
and the button selector with 'data-testid' locators) and if those testids don't
exist, ask the component team to add them (for example
data-testid="env-search-input" and data-testid="env-search-button"), then change
the locator calls in searchEnv to use those data-testid values and keep the
existing waitFor/fill logic intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 01332825-d840-47c0-a93f-2a768956c2dc

📥 Commits

Reviewing files that changed from the base of the PR and between b70bfb2 and 2d1f62b.

📒 Files selected for processing (19)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/DeleteEnvironment/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/DeleteEnvironment/index.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/EnvironmentVariables/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/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/ui/MenuDropdown/SubMenuItem/index.js
  • packages/bruno-app/src/ui/MenuDropdown/index.js
  • tests/environments/variable-secret-tabs/variable-secret-tabs.spec.ts
  • tests/utils/page/actions.ts

Comment on lines +202 to +251
<ActionIcon label="Rename" onClick={handleRenameClick}>
<IconEdit size={15} strokeWidth={1.5} />
</button>
<button onClick={() => setOpenCopyModal(true)} title="Copy">
</ActionIcon>
<ActionIcon label="Copy" onClick={() => setOpenCopyModal(true)}>
<IconCopy size={15} strokeWidth={1.5} />
</button>
<button onClick={() => setOpenDeleteModal(true)} title="Delete">
</ActionIcon>
<ActionIcon label="Delete" onClick={() => setOpenDeleteModal(true)} colorOnHover="danger">
<IconTrash size={15} strokeWidth={1.5} />
</button>
</ActionIcon>
</div>
</div>

<div className="tabs-container">
<ResponsiveTabs
tabs={TABS}
activeTab={activeTab}
onTabSelect={setActiveTab}
rightContent={(
<div ref={rightContentRef} className="env-search-container">
{isSearchExpanded ? (
<div className="search-input-wrapper">
<IconSearch size={14} strokeWidth={1.5} className="search-icon" />
<input
ref={searchInputRef}
type="text"
placeholder={activeTab === 'secrets' ? 'Search secrets...' : 'Search variables...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onBlur={handleSearchBlur}
className="search-input"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
/>
{searchQuery && (
<button
className="clear-search"
onClick={handleClearSearch}
onMouseDown={(e) => e.preventDefault()}
title="Clear search"
>
<IconX size={14} strokeWidth={1.5} />
</button>
)}
</div>
) : (
<ActionIcon label="Search" onClick={handleSearchIconClick}>
<IconSearch size={15} strokeWidth={1.5} />
</ActionIcon>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add stable Playwright selectors to the new actions and search controls.

The new testable controls introduced here (Rename/Copy/Delete/Search actions, search input, clear button) should expose data-testid to avoid brittle locator strategies.

Suggested update
-          <ActionIcon label="Rename" onClick={handleRenameClick}>
+          <ActionIcon data-testid="env-rename-action" label="Rename" onClick={handleRenameClick}>
             <IconEdit size={15} strokeWidth={1.5} />
           </ActionIcon>
-          <ActionIcon label="Copy" onClick={() => setOpenCopyModal(true)}>
+          <ActionIcon data-testid="env-copy-action" label="Copy" onClick={() => setOpenCopyModal(true)}>
             <IconCopy size={15} strokeWidth={1.5} />
           </ActionIcon>
-          <ActionIcon label="Delete" onClick={() => setOpenDeleteModal(true)} colorOnHover="danger">
+          <ActionIcon data-testid="env-delete-action" label="Delete" onClick={() => setOpenDeleteModal(true)} colorOnHover="danger">
             <IconTrash size={15} strokeWidth={1.5} />
           </ActionIcon>
...
-                  <input
+                  <input
+                    data-testid="env-tab-search-input"
                     ref={searchInputRef}
...
-                    <button
+                    <button
+                      data-testid="env-tab-search-clear"
                       className="clear-search"
...
-                <ActionIcon label="Search" onClick={handleSearchIconClick}>
+                <ActionIcon data-testid="env-search-action" label="Search" onClick={handleSearchIconClick}>
                   <IconSearch size={15} strokeWidth={1.5} />
                 </ActionIcon>

As per coding guidelines, "Add data-testid to testable elements for Playwright in React components".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js`
around lines 202 - 251, Add stable Playwright selectors by adding data-testid
attributes to the new action and search controls: add data-testid props to the
three ActionIcon instances (the Rename, Copy and Delete buttons) and the Search
ActionIcon (used when isSearchExpanded is false), add data-testid to the search
input element (the input using searchInputRef) and to the clear search button
(the element with class "clear-search"); use descriptive keys like
data-testid="env-rename-btn", "env-copy-btn", "env-delete-btn",
"env-search-btn", "env-search-input", and "env-clear-search-btn" so tests can
reliably locate these controls (ensure ActionIcon forwards unknown props if
needed).

Comment on lines +204 to +253
<ActionIcon label="Rename" onClick={handleRenameClick}>
<IconEdit size={15} strokeWidth={1.5} />
</button>
<button onClick={() => setOpenCopyModal(true)} title="Copy">
</ActionIcon>
<ActionIcon label="Copy" onClick={() => setOpenCopyModal(true)}>
<IconCopy size={15} strokeWidth={1.5} />
</button>
<button onClick={() => setOpenDeleteModal(true)} title="Delete">
</ActionIcon>
<ActionIcon label="Delete" onClick={() => setOpenDeleteModal(true)} colorOnHover="danger">
<IconTrash size={15} strokeWidth={1.5} />
</button>
</ActionIcon>
</div>
</div>

<div className="tabs-container">
<ResponsiveTabs
tabs={TABS}
activeTab={activeTab}
onTabSelect={setActiveTab}
rightContent={(
<div ref={rightContentRef} className="env-search-container">
{isSearchExpanded ? (
<div className="search-input-wrapper">
<IconSearch size={14} strokeWidth={1.5} className="search-icon" />
<input
ref={searchInputRef}
type="text"
placeholder={activeTab === 'secrets' ? 'Search secrets...' : 'Search variables...'}
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onBlur={handleSearchBlur}
className="search-input"
autoComplete="off"
autoCorrect="off"
autoCapitalize="off"
spellCheck="false"
/>
{searchQuery && (
<button
className="clear-search"
onClick={handleClearSearch}
onMouseDown={(e) => e.preventDefault()}
title="Clear search"
>
<IconX size={14} strokeWidth={1.5} />
</button>
)}
</div>
) : (
<ActionIcon label="Search" onClick={handleSearchIconClick}>
<IconSearch size={15} strokeWidth={1.5} />
</ActionIcon>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add stable Playwright selectors to the new actions and tab search controls.

The newly introduced controls here should include data-testid (actions/search input/clear) so tests don’t depend on icon or layout details.

As per coding guidelines, "Add data-testid to testable elements for Playwright in React components".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js`
around lines 204 - 253, Add stable Playwright selectors by adding data-testid
attributes to the new action icons and search controls: add data-testid values
on the ActionIcon usages (e.g. the Rename, Copy, Delete and Search icons) such
as data-testid="env-action-rename", "env-action-copy", "env-action-delete",
"env-action-search"; add data-testid="env-search-input" to the input element
rendered when isSearchExpanded is true (the element using searchInputRef and
value/searchQuery), and add data-testid="env-clear-search" to the clear button
that calls handleClearSearch; ensure these attributes are placed on the elements
inside the ResponsiveTabs rightContent so tests can target ActionIcon, the
search input and the clear button reliably.

@pooja-bruno pooja-bruno changed the title Feat/env variables secrets tabs feat(environments): split variables and secrets into separate tabs Jun 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/bruno-app/src/components/EnvironmentVariablesTable/index.js`:
- Around line 550-592: The comparison and reset must use the post-persistence
shape that blanks secret values: compute a normalizedPersisted =
persistedVariables.map(v => v.secret ? {...v, value: ''} : v) and use
JSON.stringify(normalizedPersisted.map(stripEnvVarUid)) when computing
hasChanges (instead of using raw persistedVariables), and pass
cloneDeep(normalizedPersisted) into onSave resolution and into formik.resetForm
(appending the new empty row) so the form state matches the persisted
environment shape; update references to persistedVariables ->
normalizedPersisted in hasChanges, onSave(...), and formik.resetForm(...) while
keeping orderVarsBySecret, stripEnvVarUid, savedValues, namedValues, onSave, and
formik.resetForm as the anchors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 66ec8711-c805-432e-b456-66120bc61c9b

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1f62b and fab3434.

📒 Files selected for processing (5)
  • packages/bruno-app/src/components/EnvironmentVariablesTable/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js
🚧 Files skipped from review as they are similar to previous changes (4)
  • 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/index.js
  • packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/StyledWrapper.js

Comment on lines +550 to +592
const persistedVariables = orderVarsBySecret(namedValues);

const hasChanges
= JSON.stringify(persistedVariables.map(stripEnvVarUid)) !== JSON.stringify(savedValues.map(stripEnvVarUid));
if (!hasChanges) {
toast.error('No changes to save');
return;
}

const hasValidationErrors = namedValues.some((variable) => {
if (!variable.name || variable.name.trim() === '') {
return true;
}
];
formik.resetForm({ values: resetValues });
setIsModified(false);
}, [environment.variables, setIsModified]);
if (!variableNameRegex.test(variable.name)) {
return true;
}
return false;
});

if (hasValidationErrors) {
toast.error('Please fix validation errors before saving');
return;
}

onSave(cloneDeep(persistedVariables))
.then(() => {
toast.success('Changes saved successfully');
onDraftClear();

formik.resetForm({
values: [
...persistedVariables,
{
uid: uuid(),
name: '',
value: '',
type: 'text',
secret: isSecretTab,
enabled: true
}
]
});
setIsModified(false);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize secret rows to the persisted shape before diffing and resetting.

stripEnvVarUid() includes value, but the environment persistence contract blanks secret values (value: ''). Here handleSaveAll() compares and then resetForm() with raw namedValues, so a successful save can leave the form holding the entered secret while environment.variables comes back blank. That makes the table dirty again immediately and keeps re-saving an unchanged secret payload. Compare/reset against the post-persistence shape instead of the raw Formik values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/src/components/EnvironmentVariablesTable/index.js` around
lines 550 - 592, The comparison and reset must use the post-persistence shape
that blanks secret values: compute a normalizedPersisted =
persistedVariables.map(v => v.secret ? {...v, value: ''} : v) and use
JSON.stringify(normalizedPersisted.map(stripEnvVarUid)) when computing
hasChanges (instead of using raw persistedVariables), and pass
cloneDeep(normalizedPersisted) into onSave resolution and into formik.resetForm
(appending the new empty row) so the form state matches the persisted
environment shape; update references to persistedVariables ->
normalizedPersisted in hasChanges, onSave(...), and formik.resetForm(...) while
keeping orderVarsBySecret, stripEnvVarUid, savedValues, namedValues, onSave, and
formik.resetForm as the anchors.

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.

2 participants