Skip to content

feat(#304) Environments color 🎨 (#1053)#6970

Merged
sid-bruno merged 2 commits intomainfrom
feature/environment-color-extended
Jan 30, 2026
Merged

feat(#304) Environments color 🎨 (#1053)#6970
sid-bruno merged 2 commits intomainfrom
feature/environment-color-extended

Conversation

@sid-bruno
Copy link
Collaborator

@sid-bruno sid-bruno commented Jan 29, 2026

Extends #1053

Summary by CodeRabbit

Release Notes

  • New Features
    • Color picker functionality allows users to assign custom colors to environments for better organization and visual distinction.
    • Environment color badges now display next to each environment name in lists and selectors.
    • Color support extended to both collection-level and global environments.

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

@sid-bruno sid-bruno requested a review from helloanoop as a code owner January 29, 2026 10:52
Copilot AI review requested due to automatic review settings January 29, 2026 10:52
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 29, 2026

Walkthrough

This PR introduces environment color functionality to Bruno. It adds new UI components for color selection, updates Redux state management for environment colors (both collection and global), extends environment file parsing/serialization to support color metadata, adds IPC handlers for color persistence, and includes comprehensive tests validating the color picker feature.

Changes

Cohort / File(s) Summary
New Color UI Components
packages/bruno-app/src/components/ColorBadge/index.js, packages/bruno-app/src/components/ColorPicker/index.js, packages/bruno-app/src/components/ColorPicker/StyledWrapper.js, packages/bruno-app/src/components/ColorRange/index.js, packages/bruno-app/src/components/ColorRange/StyledWrapper.js
Introduces ColorBadge (circular color indicator), ColorPicker (dropdown with preset/custom color selection and slider), and ColorRangePicker (hue gradient slider) components with theme-aware styling.
Environment Selector UI Updates
packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js, packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js, packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js
Refactors EnvironmentSelector with TABS structure and EnvironmentBadge rendering; adds ColorBadge display in environment list; updates separator styling (color → background-color); introduces dropdown width calculation and centralized openEnvironmentSettingsTab helper.
Environment Settings UI Updates
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js, packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js, packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/StyledWrapper.js
Adds ColorBadge display and ColorPicker component in environment details; wires handleColorChange to dispatch updateEnvironmentColor action; adds gap spacing to environment items.
Global Environment Settings UI Updates
packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/EnvironmentDetails/index.js, packages/bruno-app/src/components/WorkspaceHome/WorkspaceEnvironments/EnvironmentList/StyledWrapper.js
Adds ColorBadge display and ColorPicker component in global environment details; wires handleColorChange to dispatch updateGlobalEnvironmentColor action; adds gap spacing.
Redux State Management (Collections)
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js, packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js
Introduces updateEnvironmentColor thunk action and _updateEnvironmentColor reducer; action validates collection/environment, clones collection, updates color, invokes IPC 'renderer:update-environment-color', and updates state.
Redux State Management (Global Environments)
packages/bruno-app/src/providers/ReduxStore/slices/global-environments.js
Introduces updateGlobalEnvironmentColor thunk action and _updateGlobalEnvironmentColor reducer; delegates to IPC 'renderer:update-global-environment-color' and updates global environment state on success.
IPC Handlers
packages/bruno-electron/src/ipc/collection.js, packages/bruno-electron/src/ipc/global-environments.js
Adds 'renderer:update-environment-color' and 'renderer:update-global-environment-color' IPC handlers to persist color changes to environment files via file system read/write/parse/stringify operations.
Electron Store/File System
packages/bruno-electron/src/store/global-environments.js, packages/bruno-electron/src/store/workspace-environments.js
Introduces updateGlobalEnvironmentColor and updateGlobalEnvironmentColorByPath methods to GlobalEnvironmentsStore and GlobalEnvironmentsManager for persisting color to global and workspace environment files.
Environment File Parsing & Serialization
packages/bruno-lang/v2/src/envToJson.js, packages/bruno-lang/v2/src/jsonToEnv.js, packages/bruno-filestore/src/formats/yml/parseEnvironment.ts, packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts
Extends BruEnvFile grammar to parse color: entries; updates jsonToEnv to serialize color blocks; modifies parseEnvironment and stringifyEnvironment to map color property to/from YAML representation.
Schema & Types
packages/bruno-schema/src/collections/index.js, packages/bruno-schema-types/src/collection/environment.ts
Adds optional color field to environmentSchema (Yup validation) and Environment TypeScript interface.
Tests
tests/environments/color-picker/color-picker.spec.ts, tests/environments/color-picker/collection/..., tests/environments/color-picker/init-user-data/...
Introduces comprehensive Playwright test suite validating color picker interactions (preset selection, custom color via slider, color removal, badge display) with test fixtures (collection config, global environments, preferences).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Environment UI
    participant Redux as Redux Store
    participant IPC as IPC Channel
    participant FS as File System
    
    User->>UI: Select/change environment color
    UI->>Redux: Dispatch updateEnvironmentColor(uid, color, collectionUid)
    Redux->>Redux: Clone collection, update color in state
    Redux->>IPC: renderer:update-environment-color(pathname, name, color)
    IPC->>FS: Read environment file
    FS-->>IPC: Current environment data
    IPC->>IPC: Parse, update color, stringify
    IPC->>FS: Write updated environment file
    FS-->>IPC: Write complete
    IPC-->>Redux: Success
    Redux->>UI: State updated, ColorBadge reflects new color
    UI-->>User: Color change visible in list
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

pr-feature

Suggested reviewers

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

Poem

🎨 Colors bloom where environments dwell,
From picker to picker, a prismatic spell,
Redux to IPC, persistence takes flight,
Each shade now saved, your configs aglow bright! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main feature being added: color support for environments, with a reference to the issue number.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/environment-color-extended

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.40.5)
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js

[]


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.

@github-actions
Copy link

github-actions bot commented Jan 29, 2026

CLI Test Results

  1 files  ±0  145 suites  ±0   55s ⏱️ +10s
242 tests ±0  242 ✅ ±0  0 💤 ±0  0 ❌ ±0 
310 runs  ±0  309 ✅ ±0  1 💤 ±0  0 ❌ ±0 

Results for commit a04ff3e. ± Comparison against base commit 214e143.

♻️ This comment has been updated with latest results.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Extends environment support by adding an optional color attribute, persisting it to env files, and surfacing it in the UI for faster environment recognition.

Changes:

  • Add color to the environment schema and env file (de)serialization (env.bru).
  • Introduce Redux plumbing + UI components/styles to view and update an environment’s color.
  • Add @uiw/react-color dependency to power the color picker.

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/bruno-schema/src/collections/index.js Extends environment schema to allow an optional color field.
packages/bruno-lang/v2/src/jsonToEnv.js Writes color: to env file output when present.
packages/bruno-lang/v2/src/envToJson.js Parses color: from env files into JSON representation.
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js Adds reducer to store environment color in Redux state.
packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js Adds thunk to persist environment color changes to disk and update store.
packages/bruno-app/src/components/RequestTabs/index.js Attempts to apply active environment color to request tabs container.
packages/bruno-app/src/components/RequestTabs/StyledWrapper.js Applies environment color as a visual indicator on request tabs.
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js Refactors environment list selection logic (currently introduces syntax issues).
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js Adds environment color picker to environment details view.
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentColor/index.js New color picker component that dispatches saveEnvironmentColor.
packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js Adds environment color styling to the selector trigger.
packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js Styles selector + dropdown items based on environment color.
packages/bruno-app/src/components/Environments/EnvironmentSelector/EnvironmentListContent/index.js Shows a colored icon next to each environment in the dropdown.
packages/bruno-app/package.json Adds @uiw/react-color dependency.
package-lock.json Locks new transitive dependencies for @uiw/react-color.
Comments suppressed due to low confidence (3)

packages/bruno-app/src/components/RequestTabs/index.js:47

  • Assignment to variable activeTab, which is declared constant.
  const activeTab = find(tabs, (t) => t.uid === activeTabUid);

packages/bruno-app/src/components/RequestTabs/index.js:48

  • Assignment to variable activeCollection, which is declared constant.
  const activeCollection = find(collections, (c) => c?.uid === activeTab?.collectionUid);

packages/bruno-app/src/components/RequestTabs/index.js:49

  • Assignment to variable collectionRequestTabs, which is declared constant.
  const collectionRequestTabs = filter(tabs, (t) => t.collectionUid === activeTab?.collectionUid);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Caution

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

⚠️ Outside diff range comments (4)
packages/bruno-lang/v2/src/envToJson.js (1)

15-47: Fix the color rule to prevent consuming subsequent blocks.

The color = "color:" any* rule will greedily match across newlines, consuming any following vars or secretvars blocks. Restrict it to the current line using the negative lookahead pattern.

Suggested fix
-  color = "color:" any*
+  color = "color:" (~nl any)*
packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js (1)

250-262: Critical: color is undefined in saveEnvironment reducer.

Line 259 assigns environment.color = color, but color is not destructured from action.payload at line 251. This references an undefined variable, which will set environment.color to undefined on every environment save, effectively clearing any previously set color.

Either add color to the destructured payload, or remove this line if color should be handled separately via saveEnvironmentColor.

🐛 Proposed fix - Option A: Add color to destructuring
     saveEnvironment: (state, action) => {
-      const { variables, environmentUid, collectionUid } = action.payload;
+      const { variables, environmentUid, collectionUid, color } = action.payload;
       const collection = findCollectionByUid(state.collections, collectionUid);

       if (collection) {
         const environment = findEnvironmentInCollection(collection, environmentUid);

         if (environment) {
           environment.variables = variables;
-          environment.color = color;
+          if (color !== undefined) {
+            environment.color = color;
+          }
         }
       }
     },
🐛 Proposed fix - Option B: Remove color assignment
         if (environment) {
           environment.variables = variables;
-          environment.color = color;
         }
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js (2)

16-32: Remove the duplicate EnvironmentList declaration at lines 16–26.

The first declaration with the old prop-based signature is incomplete and conflicts with the second declaration starting at line 29. Keep only the new declaration with the updated signature.

Suggested fix
-const EnvironmentList = ({
-  environments,
-  activeEnvironmentUid,
-  selectedEnvironment,
-  setSelectedEnvironment,
-  isModified,
-  setIsModified,
-  collection,
-  setShowExportModal
-}) => {
-  const dispatch = useDispatch();
-
-
 const EnvironmentList = ({ collection, isModified, setIsModified, onClose, setShowExportModal }) => {
   const { environments, activeEnvironmentUid } = collection;
   const [selectedEnvironment, setSelectedEnvironment] = useState(null);

67-72: Avoid reselecting by stale UID.
Line 72 calls setSelectedEnvironment() a second time with findItem(environments, selectedEnvironment.uid), which overrides the correct environment set in line 69. If selectedEnvironment.uid was deleted or renamed, findItem() returns undefined, causing the selection to briefly null out. Additionally, line 71 uses stale selectedEnvironment?.variables instead of the resolved environment's variables.

Use the resolved environment consistently throughout:

🛠️ Suggested fix
-      const hasSelectedEnvironmentChanged = !isEqual(selectedEnvironment, _selectedEnvironment);
-      if (hasSelectedEnvironmentChanged || selectedEnvironment.uid !== _selectedEnvironment?.uid) {
-        setSelectedEnvironment(_selectedEnvironment);
-      }
-      setOriginalEnvironmentVariables(selectedEnvironment?.variables||[]);
-      setSelectedEnvironment(findItem(environments, selectedEnvironment.uid));
+      const resolvedEnvironment = findItem(environments, _selectedEnvironment?.uid) || _selectedEnvironment;
+      const hasSelectedEnvironmentChanged = !isEqual(selectedEnvironment, resolvedEnvironment);
+      if (hasSelectedEnvironmentChanged || selectedEnvironment.uid !== resolvedEnvironment?.uid) {
+        setSelectedEnvironment(resolvedEnvironment);
+      }
+      setOriginalEnvironmentVariables(resolvedEnvironment?.variables || []);
🤖 Fix all issues with AI agents
In
`@packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js`:
- Around line 8-9: The background-color ternary is inverted and emits
"undefined" when props.color is present; update the background rule in
StyledWrapper.js to use the color when provided and fall back to transparent
(e.g., background-color: ${(props) => props.color ?? 'transparent'}), or
conditionally omit/unset the property if that's preferred, and keep the border
line using props.color ?? props.theme.dropdown.selectedColor as-is.

In
`@packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js`:
- Line 14: EnvironmentDetails currently destructures only { environment,
setIsModified, collection } but passes onClose down to <EnvironmentVariables>
which is undefined; fix by adding onClose to the component props (update the
destructuring in EnvironmentDetails to include onClose) and forward that prop to
EnvironmentVariables (or if the prop is unused, remove the onClose={onClose}
from the EnvironmentVariables invocation); refer to the EnvironmentDetails
component and the EnvironmentVariables usage to locate the change.

In `@packages/bruno-app/src/components/RequestTabs/index.js`:
- Around line 90-99: The code redeclares activeTab, activeCollection, and
collectionRequestTabs which shadows earlier declarations (breaking the useEffect
that depends on the originals); remove these duplicate declarations and reuse
the existing variables instead — either move the early-return check (the
"Something went wrong!" return) to run before the initial declarations or delete
the later const declarations and update the logic to reference the original
activeTab, activeCollection and collectionRequestTabs; ensure the lookup calls
(find(...), findEnvironmentInCollection(...), filter(...)) are performed only
once and that useEffect continues to depend on the original variables.

In `@packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js`:
- Around line 38-39: The code uses the pattern "something ?? reject(...)" which
does not stop execution, so add explicit guard clauses that return immediately
after calling reject to prevent using undefined collection/environment; locate
usages in this file (e.g., action creators referencing collection and
environment, including saveEnvironmentColor/_saveEnvironmentColor and
workspaceEnvUpdateEvent) and replace the inline nullish-rejects with checks like
"if (!collection) { return reject(new Error(...)) }" and similarly for
environment so the function exits early instead of continuing to operate on
undefined values.
🧹 Nitpick comments (2)
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js (1)

10-11: Import path issue and unused import.

  1. Line 10: The import path ../EnvironmentDetails/EnvironmentColor references the parent then re-enters EnvironmentDetails. Since this file is inside EnvironmentDetails/, use ./EnvironmentColor instead.
  2. Line 11: ToolHint is imported but never used.
♻️ Proposed fix
-import EnvironmentColor from '../EnvironmentDetails/EnvironmentColor';
-import ToolHint from 'components/ToolHint/index';
+import EnvironmentColor from './EnvironmentColor';
packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentColor/index.js (1)

11-19: Use strict equality for color comparison.

Line 13 uses == instead of ===. While unlikely to cause issues with hex strings, strict equality is safer and more explicit.

♻️ Proposed fix
   const onColorChange = useCallback(
     (color) => {
-      if (color == environment.color) return;
+      if (color === environment.color) return;
       dispatch(saveEnvironmentColor(color, environment.uid, collectionUid))
         .then(() => toast.success('Environment color changed successfully'))
         .catch(() => toast.error('An error occurred while changing the environment color'));
     },
     [dispatch, environment.uid, environment.color, collectionUid]
   );

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

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

🤖 Fix all issues with AI agents
In `@packages/bruno-app/src/components/ColorPicker/index.js`:
- Around line 95-149: The slider currently only commits changes on onMouseUp,
which misses keyboard and touch inputs; update the ColorRangePicker usage to
call the existing handleSliderEnd when pointer or keyboard interaction ends by
adding onPointerUp and onKeyUp props (in addition to keeping onMouseUp), so that
handleSliderChange updates state and handleSliderEnd is invoked for mouse,
pointer (touch/pen) and keyboard events; locate the ColorRangePicker element
near sliderPosition/customColor and wire onPointerUp={handleSliderEnd} and
onKeyUp={handleSliderEnd}.

In `@packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js`:
- Around line 27-31: The helper getEnvBackgroundColor currently appends "25" to
hex strings which breaks non-hex colors; import transparentize from 'polished'
and replace the concatenation with a polished call that produces the same visual
alpha for any color format (e.g., use transparentize(0.855, color) when color is
truthy, otherwise 'transparent') so getEnvBackgroundColor reliably returns a
transparentized color for rgb(), named colors, and hex alike.

In `@packages/bruno-electron/src/store/env-secrets.js`:
- Around line 121-135: Remove the unused method updateEnvironmentColor from the
env-secrets store: delete the updateEnvironmentColor(...) implementation in
packages/bruno-electron/src/store/env-secrets.js (the function that finds a
collection/environment and sets env.color then this.store.set('collections',
collections)), and ensure no other code relies on that symbol; if the method is
exported explicitly, remove it from the export list; run lint/tests/build to
confirm there are no remaining references to updateEnvironmentColor.
🧹 Nitpick comments (7)
tests/environments/color-picker/init-user-data/preferences.json (1)

1-6: Confirm the cross-directory collection reference is intentional.

This references global-env-config-selection/collection which is outside the color-picker test directory. Same observation as collection-security.json - if this is intentional reuse of an existing collection, consider adding a comment in the test spec clarifying this dependency.

packages/bruno-electron/src/store/global-environments.js (1)

166-173: Avoid redundant store writes when no change is needed.

If the environment isn’t found or the color is already the same, you can early-return to skip an unnecessary re-save.

♻️ Suggested tweak
  updateGlobalEnvironmentColor({ environmentUid, color }) {
    let globalEnvironments = this.getGlobalEnvironments();
    const environment = globalEnvironments.find((env) => env?.uid == environmentUid);
-   if (environment) {
-     environment.color = color;
-   }
-   this.setGlobalEnvironments(globalEnvironments);
+   if (!environment || environment.color === color) {
+     return;
+   }
+   environment.color = color;
+   this.setGlobalEnvironments(globalEnvironments);
  }
packages/bruno-app/src/components/ColorPicker/StyledWrapper.js (1)

1-5: Consider documenting why this wrapper exists if it’s intentionally empty.
A brief JSDoc (or inlining the wrapper where it’s used) would clarify intent and avoid a silent extra DOM layer.

As per coding guidelines, Add JSDoc comments to abstractions for additional details.

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

12-12: Minor: Guard against undefined className.

If className is not provided, the template literal produces "hue-slider undefined". Consider a fallback:

-        className={`hue-slider ${className}`}
+        className={`hue-slider ${className || ''}`}
tests/environments/color-picker/color-picker.spec.ts (2)

28-58: Consider wrapping logical sections in test.step for clearer reports.

Per coding guidelines, test.step improves report readability. For example:

test('should select a preset color for global environment', async ({ pageWithUserData: page }) => {
  await test.step('Open global environment configuration', async () => {
    await page.locator('#sidebar-collection-name').filter({ hasText: 'global-env-config-selection' }).click();
    await page.getByTestId('environment-selector-trigger').click();
    await page.getByTestId('env-tab-global').click();
    await page.getByText('Configure', { exact: true }).click();
  });
  
  await test.step('Select preset color', async () => {
    // ... color picker interactions
  });
  
  await test.step('Verify color badge', async () => {
    // ... assertions
  });
});

42-57: Repeated locators could be extracted to helper variables or a shared utility.

colorPickerTrigger, colorPickerDropdown, envTab, and activeEnvItem are duplicated across all tests. Extracting them to a helper object or using test.beforeEach would reduce repetition and improve maintainability. As per coding guidelines: "Prefer shared test utilities over copy-pasted setup code."

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

32-162: Add JSDoc for the new helpers and the component.
Several new abstractions (e.g., rgbToHex, interpolateColor, findClosestPosition, ColorPicker) are undocumented.

As per coding guidelines: Add JSDoc comments to abstractions for additional details.

MathieuDreano and others added 2 commits January 30, 2026 17:07
* associate environment to a color

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

use StyledWrapper

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

don't save anything for color if it is not set

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

use redux store instead of local state

remove logs

fix selectedEnvironment

cleanup

add bottom border on active tab

* associate environment to a color

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* move dependency to appropriate package.json

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* use border instead of background color

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* simplify onColorChange

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* add black, keep backgound on unselected color

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* fix conflicts

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

* associate environment to a color

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

use StyledWrapper

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

don't save anything for color if it is not set

Signed-off-by: mathieu <mathieu.dreano@gmail.com>

use redux store instead of local state

remove logs

fix selectedEnvironment

cleanup

add bottom border on active tab

# Conflicts:
#	packages/bruno-app/src/components/Environments/EnvironmentSelector/StyledWrapper.js
#	packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js
#	packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js
#	packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js
#	packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js
#	packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js

* Update packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentColor/index.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* unused selectedEnvironment prop in EnvironmentList

Signed-off-by: Mathieu D <mathieu.dreano@decathlon.com>

* RequestTab, avoid unnecessary call if undefined activeCollection

Signed-off-by: Mathieu D <mathieu.dreano@decathlon.com>

* use @uiw/reac-color instead of react-color

Signed-off-by: Mathieu D <mathieu.dreano@decathlon.com>

---------

Signed-off-by: mathieu <mathieu.dreano@gmail.com>
Signed-off-by: Mathieu D <mathieu.dreano@decathlon.com>
Co-authored-by: Mathieu D <mathieu.dreano@decathlon.com>
Co-authored-by: Anoop M D <anoop@usebruno.com>
Co-authored-by: Mathieu DREANO <122891400+mdreano@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@sid-bruno sid-bruno force-pushed the feature/environment-color-extended branch from 4f6e571 to a04ff3e Compare January 30, 2026 11:37
@sid-bruno sid-bruno merged commit eb5dc12 into main Jan 30, 2026
7 of 9 checks passed
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: 3

🤖 Fix all issues with AI agents
In `@packages/bruno-app/src/components/ColorPicker/index.js`:
- Around line 20-30: Update the JSDoc for the hexToRgb function to indicate
numeric channel values instead of strings: change the `@returns` annotation to
reflect {red:number, green:number, blue:number} so it matches the numeric math
usage and the actual return object (both from parseToRgb and the fallback
{red:0, green:0, blue:0}) in hexToRgb.
- Around line 82-105: The component initializes sliderPosition and customColor
only on mount, so add a useEffect inside ColorPicker that watches the color prop
and syncs state when it changes: if color is provided and not in PRESET_COLORS,
set sliderPosition to findClosestPosition(color), set customColor to color, and
update pendingColorRef.current to color; otherwise set sliderPosition to 0,
customColor to COLOR_RANGE_SEQUENCE[0], and pendingColorRef.current accordingly;
do not call onChange from this effect. This keeps the slider (sliderPosition),
customColor state, and pendingColorRef in sync with external prop updates
without altering existing handlers like handleSliderChange or handleSliderEnd.

In `@tests/environments/color-picker/collection/test-request.bru`:
- Around line 1-17: This collection file (meta name "test-request" containing
the test "should get 200 response") is unused by color-picker.spec.ts; either
delete tests/environments/color-picker/collection/test-request.bru (or the whole
collection folder) or move it under the fixtures/collection convention and/or
update color-picker.spec.ts to import/use the "test-request" collection (or
reference {{host}}/api/echo) so the spec actually exercises this collection;
ensure the chosen fix keeps the collection path consistent with other test
fixtures and that the test name "should get 200 response" remains accurate if
reused.
🧹 Nitpick comments (3)
packages/bruno-electron/src/store/global-environments.js (1)

166-173: Add JSDoc for the new public method.

✍️ Suggested JSDoc
+  /**
+   * Updates the color of a global environment.
+   * `@param` {{ environmentUid: string, color: string | null }} params
+   */
   updateGlobalEnvironmentColor({ environmentUid, color }) {
     let globalEnvironments = this.getGlobalEnvironments();
     const environment = globalEnvironments.find((env) => env?.uid == environmentUid);
     if (environment) {
       environment.color = color;
     }
     this.setGlobalEnvironments(globalEnvironments);
   }

As per coding guidelines: “Add JSDoc comments to abstractions for additional details.”

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

4-22: Add JSDoc for component props/behavior.

✍️ Suggested JSDoc
+/**
+ * Renders a circular color badge.
+ * `@param` {{ color?: string, size?: number|string, showEmptyBorder?: boolean }} props
+ */
 const ColorBadge = ({ color, size = 10, showEmptyBorder = true }) => {
   const sizeValue = typeof size === 'string' ? size : `${size}px`;
   const { theme } = useTheme();

As per coding guidelines: “Add JSDoc comments to abstractions for additional details.”

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

82-83: Add JSDoc for the exported ColorPicker component.

This is a public abstraction and would benefit from a brief props doc.

📚 Example JSDoc
+/**
+ * Color picker dropdown for preset and custom colors.
+ * `@param` {Object} props
+ * `@param` {string | null} props.color
+ * `@param` {(nextColor: string | null) => void} props.onChange
+ * `@param` {*} [props.icon]
+ */
 const ColorPicker = ({ color, onChange, icon }) => {
As per coding guidelines: Add JSDoc comments to abstractions for additional details.

Comment on lines +20 to +30
/**
* @param {string} hex
* @returns {red:string,green:string,blue:string}
*/
const hexToRgb = (hex) => {
try {
return parseToRgb(hex);
} catch (err) {
return { red: 0, green: 0, blue: 0 };
}
};
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

Fix JSDoc return types to match numeric channel usage.

The return object is used in numeric math, so the JSDoc should reflect numbers, not strings.

📝 Suggested JSDoc fix
- * `@returns` {red:string,green:string,blue:string}
+ * `@returns` {red:number,green:number,blue:number}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* @param {string} hex
* @returns {red:string,green:string,blue:string}
*/
const hexToRgb = (hex) => {
try {
return parseToRgb(hex);
} catch (err) {
return { red: 0, green: 0, blue: 0 };
}
};
/**
* `@param` {string} hex
* `@returns` {red:number,green:number,blue:number}
*/
const hexToRgb = (hex) => {
try {
return parseToRgb(hex);
} catch (err) {
return { red: 0, green: 0, blue: 0 };
}
};
🤖 Prompt for AI Agents
In `@packages/bruno-app/src/components/ColorPicker/index.js` around lines 20 - 30,
Update the JSDoc for the hexToRgb function to indicate numeric channel values
instead of strings: change the `@returns` annotation to reflect {red:number,
green:number, blue:number} so it matches the numeric math usage and the actual
return object (both from parseToRgb and the fallback {red:0, green:0, blue:0})
in hexToRgb.

Comment on lines +82 to +105
const ColorPicker = ({ color, onChange, icon }) => {
const [sliderPosition, setSliderPosition] = useState(() =>
color && !PRESET_COLORS.includes(color) ? findClosestPosition(color) : 0
);
const [customColor, setCustomColor] = useState(() =>
color && !PRESET_COLORS.includes(color) ? color : COLOR_RANGE_SEQUENCE[0]
);
const pendingColorRef = useRef(customColor);

const handleColorSelect = (selectedColor) => {
onChange(selectedColor);
};

const handleSliderChange = (e) => {
const newPosition = parseInt(e.target.value, 10);
setSliderPosition(newPosition);
const newColor = interpolateColor(newPosition);
setCustomColor(newColor);
pendingColorRef.current = newColor;
};

const handleSliderEnd = () => {
onChange(pendingColorRef.current);
};
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

🧩 Analysis chain

🏁 Script executed:

cat -n packages/bruno-app/src/components/ColorPicker/index.js

Repository: usebruno/bruno

Length of output: 6256


Add useEffect to sync slider and custom color state when the color prop changes.

The component initializes slider position and custom color only on mount, but doesn't respond to external color prop updates, causing the UI to lag behind parent-driven changes.

🔧 Add useEffect hook
   const [customColor, setCustomColor] = useState(() =>
     color && !PRESET_COLORS.includes(color) ? color : COLOR_RANGE_SEQUENCE[0]
   );
   const pendingColorRef = useRef(customColor);
+
+  useEffect(() => {
+    if (!color) {
+      const defaultColor = COLOR_RANGE_SEQUENCE[0];
+      setSliderPosition(0);
+      setCustomColor(defaultColor);
+      pendingColorRef.current = defaultColor;
+      return;
+    }
+
+    const nextPosition = findClosestPosition(color);
+    setSliderPosition(nextPosition);
+    setCustomColor(color);
+    pendingColorRef.current = color;
+  }, [color]);
🤖 Prompt for AI Agents
In `@packages/bruno-app/src/components/ColorPicker/index.js` around lines 82 -
105, The component initializes sliderPosition and customColor only on mount, so
add a useEffect inside ColorPicker that watches the color prop and syncs state
when it changes: if color is provided and not in PRESET_COLORS, set
sliderPosition to findClosestPosition(color), set customColor to color, and
update pendingColorRef.current to color; otherwise set sliderPosition to 0,
customColor to COLOR_RANGE_SEQUENCE[0], and pendingColorRef.current accordingly;
do not call onChange from this effect. This keeps the slider (sliderPosition),
customColor state, and pendingColorRef in sync with external prop updates
without altering existing handlers like handleSliderChange or handleSliderEnd.

Comment on lines +1 to +17
meta {
name: test-request
type: http
seq: 1
}

get {
url: {{host}}/api/echo
body: none
auth: none
}

tests {
test("should get 200 response", function() {
expect(res.getStatus()).to.equal(200);
});
}
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

🧩 Analysis chain

🏁 Script executed:

# Find all references to the environments/color-picker/collection path
rg "environments/color-picker/collection" -g "*.{ts,tsx,js,jsx,json}" -B 2 -A 2

Repository: usebruno/bruno

Length of output: 40


🏁 Script executed:

# Also check if there's already a fixtures/collection structure in the tests directory
fd -t d "fixtures" tests/ --exec sh -c 'echo "--- Directory: {} ---" && ls -la {} | head -20'

Repository: usebruno/bruno

Length of output: 10439


🏁 Script executed:

# Check if there are any other test files in the color-picker directory
fd -t f "\.spec\." tests/environments/color-picker/ 2>/dev/null || echo "No spec files found in color-picker"

Repository: usebruno/bruno

Length of output: 110


🏁 Script executed:

cat -n tests/environments/color-picker/color-picker.spec.ts

Repository: usebruno/bruno

Length of output: 7912


🏁 Script executed:

# Also check the directory structure of color-picker
tree tests/environments/color-picker/ -L 3

Repository: usebruno/bruno

Length of output: 308


🏁 Script executed:

# Check if the collection is referenced in init-user-data files
cat tests/environments/color-picker/init-user-data/*.json | grep -i "test-request\|color-picker.*collection" || echo "No references found in init-user-data"

Repository: usebruno/bruno

Length of output: 95


🏁 Script executed:

# Check for any other references to the collection directory
rg "color-picker" tests/environments/color-picker/ -g "*.json" -A 2 -B 2

Repository: usebruno/bruno

Length of output: 40


🏁 Script executed:

# Search broadly for how collections are loaded in the test infrastructure
grep -r "collection" tests/environments/color-picker/ --include="*.json" 2>/dev/null | head -20

Repository: usebruno/bruno

Length of output: 532


🏁 Script executed:

# Check if test-request.bru is referenced anywhere in the codebase
rg "test-request" tests/environments/color-picker/

Repository: usebruno/bruno

Length of output: 138


🏁 Script executed:

# Look at what collection is actually being used by the color-picker test
cat tests/environments/color-picker/init-user-data/collection-security.json

Repository: usebruno/bruno

Length of output: 253


🏁 Script executed:

# Check if the collection directory name or any part of it is referenced in test setup/config
grep -r "test-request" tests/ --include="*.ts" --include="*.js" 2>/dev/null | grep -v node_modules

Repository: usebruno/bruno

Length of output: 5240


🏁 Script executed:

# Double-check: verify the init-user-data for color-picker loads the global-env-config-selection collection
cat -n tests/environments/color-picker/init-user-data/preferences.json

Repository: usebruno/bruno

Length of output: 237


🏁 Script executed:

# Check if global-env-config-selection collection references or includes test-request.bru
find tests/environments/global-env-config-selection -type f -name "*.bru" -o -name "*.json" | xargs cat 2>/dev/null | grep -i "test-request" || echo "No references to test-request in global-env-config-selection"

Repository: usebruno/bruno

Length of output: 78


🏁 Script executed:

# List the contents of the actual collection being used
ls -la tests/environments/global-env-config-selection/collection/

Repository: usebruno/bruno

Length of output: 290


🏁 Script executed:

# Check if color-picker/collection is referenced as a dependency in global-env-config-selection
cat tests/environments/global-env-config-selection/collection/test-request.bru

Repository: usebruno/bruno

Length of output: 276


🏁 Script executed:

# Search for any imports or references between the two collections
grep -r "color-picker" tests/environments/global-env-config-selection/ 2>/dev/null || echo "No references found"

Repository: usebruno/bruno

Length of output: 77


🏁 Script executed:

# Check if the color-picker collection's bruno.json has any special configuration
cat tests/environments/color-picker/collection/bruno.json

Repository: usebruno/bruno

Length of output: 143


Remove the unused collection or clarify its purpose.

This collection is not referenced by color-picker.spec.ts, which instead uses global-env-config-selection. Either remove tests/environments/color-picker/collection/ entirely or update the test to use it. If it's intentionally part of the test setup, it should follow the convention of being nested under fixtures/collection.

🤖 Prompt for AI Agents
In `@tests/environments/color-picker/collection/test-request.bru` around lines 1 -
17, This collection file (meta name "test-request" containing the test "should
get 200 response") is unused by color-picker.spec.ts; either delete
tests/environments/color-picker/collection/test-request.bru (or the whole
collection folder) or move it under the fixtures/collection convention and/or
update color-picker.spec.ts to import/use the "test-request" collection (or
reference {{host}}/api/echo) so the spec actually exercises this collection;
ensure the chosen fix keeps the collection path consistent with other test
fixtures and that the test name "should get 200 response" remains accurate if
reused.

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.

4 participants