Skip to content

feat: preferences as tab#6786

Merged
sid-bruno merged 2 commits intousebruno:mainfrom
Pragadesh-45:feat/preferences-as-tab
Jan 21, 2026
Merged

feat: preferences as tab#6786
sid-bruno merged 2 commits intousebruno:mainfrom
Pragadesh-45:feat/preferences-as-tab

Conversation

@Pragadesh-45
Copy link
Contributor

@Pragadesh-45 Pragadesh-45 commented Jan 12, 2026

Description

This PR implements the logic of changing the preference modal to a tab behavior

JIRA

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.

Summary by CodeRabbit

  • New Features

    • Preferences can now be accessed as a workspace tab alongside Overview and Environments.
    • Added preferences tab support in request panels.
  • UI Improvements

    • Enhanced styling for preferences interface, including text links and form elements.
    • Refined keybindings table layout and spacing.
  • Bug Fixes

    • Improved null safety checks and early returns to prevent errors with missing data.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

Walkthrough

This PR converts the Preferences panel from a modal-based component with prop-driven closing logic into a tab-based component integrated with Redux state management. The preferences UI now activates through the tab system, removes close handlers from child components, and manages active tab selection via Redux actions rather than local state.

Changes

Cohort / File(s) Summary
Preferences Components – Styling packages/bruno-app/src/components/Preferences/StyledWrapper.js
Preferences Components – Font & General packages/bruno-app/src/components/Preferences/Display/Font/index.js, packages/bruno-app/src/components/Preferences/General/index.js
Preferences Components – Main & Settings packages/bruno-app/src/components/Preferences/index.js, packages/bruno-app/src/components/Preferences/General/StyledWrapper.js, packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js, packages/bruno-app/src/components/Preferences/ProxySettings/index.js
Tab System Integration packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js, packages/bruno-app/src/components/RequestTabs/RequestTab/index.js, packages/bruno-app/src/components/RequestTabs/index.js, packages/bruno-app/src/components/RequestTabPanel/index.js, packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js, packages/bruno-app/src/components/WorkspaceTabs/index.js
Redux State Management packages/bruno-app/src/providers/ReduxStore/slices/app.js, packages/bruno-app/src/providers/ReduxStore/slices/tabs.js, packages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.js
Event Handlers & IPC packages/bruno-app/src/components/StatusBar/index.js, packages/bruno-app/src/providers/App/useIpcEvents.js, packages/bruno-app/src/providers/Hotkeys/index.js
Page & Home Rendering packages/bruno-app/src/pages/Bruno/index.js, packages/bruno-app/src/components/WorkspaceHome/index.js
Utilities & Minor Fixes packages/bruno-app/src/utils/collections/index.js, packages/bruno-app/src/components/Table/StyledWrapper.js

Sequence Diagram

sequenceDiagram
    participant User
    participant StatusBar/Hotkeys
    participant Redux Store
    participant Preferences Tab
    participant Workspace Tabs

    User ->> StatusBar/Hotkeys: Click Preferences Icon
    
    alt On Home/Manage/NoActiveTab + Has Workspace
        StatusBar/Hotkeys ->> Redux Store: dispatch setActiveWorkspaceTab({type: 'preferences'})
        Redux Store ->> Workspace Tabs: Update activeWorkspaceTabUid
    else Otherwise
        StatusBar/Hotkeys ->> Redux Store: dispatch addTab({type: 'preferences', ...})
        Redux Store ->> Redux Store: Check nonReplaceableTabTypes
        alt Tab Already Exists
            Redux Store ->> Workspace Tabs: Activate existing tab
        else Create New
            Redux Store ->> Workspace Tabs: Create & activate new tab
        end
    end
    
    Workspace Tabs ->> Preferences Tab: Render (Redux-driven state)
    Preferences Tab ->> Redux Store: dispatch updateActivePreferencesTab({tab: 'general'|...})
    Redux Store ->> Preferences Tab: Update activePreferencesTab
    Preferences Tab ->> User: Display selected preferences section
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #6456: Modifies the setActiveWorkspaceTab infrastructure and workspaceTabs slice that this PR builds upon for preferences tab activation.
  • PR #6520: Changes Preferences component prop passing (removing close handlers) and tab rendering in the same Preferences UI that this PR refactors into Redux-driven tabs.
  • PR #6407: Converts modal-based UIs to tab-based UIs using the same tab management patterns (addTab, nonReplaceableTabTypes) applied here.

Suggested reviewers

  • bijin-bruno
  • helloanoop
  • lohit-bruno

Poem

🎯 Modal's gone, tabs take the stage,
Redux writes each preference page,
No more props to close and retreat,
Tab-driven prefs, the flow's complete! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: preferences as tab' directly and clearly summarizes the main architectural change in this PR: converting preferences from a modal dialog to a tab-based interface.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

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

Caution

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

⚠️ Outside diff range comments (6)
packages/bruno-app/src/components/Preferences/ProxySettings/index.js (1)

19-19: Remove debug console.log.

This appears to be leftover debug code that should be removed before merge.

Proposed fix
-  console.log(preferences);
packages/bruno-app/src/components/Preferences/index.js (1)

39-69: Add a default case to getTabPanel.

If activePreferencesTab state contains an unexpected value (e.g., from a previous session or corrupted state), the function returns undefined, rendering nothing without feedback.

🔧 Proposed fix
       case 'support': {
         return <Support />;
       }
+
+      default: {
+        return <General />;
+      }
     }
packages/bruno-app/src/themes/dark/dark-pastel.js (1)

627-660: Missing app.kbd block.

Same issue as dark-monochrome.js — the app.kbd styling block is present in light themes but missing here. This creates an inconsistency across themes.

Suggested addition
     collection: {
       toolbar: {
         // ... existing content
       }
-    }
+    },
+    kbd: {
+      bg: colors.GRAY_2,
+      color: colors.TEXT,
+      border: colors.GRAY_4
+    }
   }
 };
packages/bruno-app/src/themes/dark/dark-monochrome.js (1)

608-642: Add missing app.kbd block to match other themes.

The app.kbd styling is defined in the theme schema and present in all other dark and light theme variants, but absent from dark-monochrome.js. This will cause inconsistency if the UI relies on theme.app.kbd.

Suggested addition
     collection: {
       toolbar: {
         // ... existing content
       }
-    }
+    },
+    kbd: {
+      bg: colors.GRAY_2,
+      color: colors.TEXT,
+      border: colors.GRAY_3
+    }
   }
 };

Note: dark-pastel.js has the same issue and should also be updated.

packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)

621-654: Missing kbd property.

The schema requires kbd (either at root or under app depending on final decision). This theme is missing the kbd styling block, which will cause validation failures.

Add the kbd property with appropriate Catppuccin Frappé colors:

Suggested addition
         }
       }
-    }
+    },
+    kbd: {
+      bg: colors.SURFACE0,
+      color: colors.TEXT,
+      border: colors.SURFACE1
+    }
   }
 };
packages/bruno-app/src/themes/dark/catppuccin-mocha.js (1)

621-654: Missing kbd property.

Same issue as catppuccin-frappe.js — this theme needs the kbd styling block to pass schema validation.

Suggested addition
         }
       }
-    }
+    },
+    kbd: {
+      bg: colors.SURFACE0,
+      color: colors.TEXT,
+      border: colors.SURFACE1
+    }
   }
 };
🤖 Fix all issues with AI agents
In @packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js:
- Line 46: The CSS shorthand for border-bottom in StyledWrapper.js is using
color first then width and style, which is invalid; update the declaration in
the styled component (the line with "border-bottom: ${(props) =>
props.theme.table.input.border} 1.44px solid;") to use the correct order width
style color (e.g., "1.44px solid ${(props) => props.theme.table.input.border}")
so the border shorthand reads as width, style, then color.

In @packages/bruno-app/src/components/RequestTabs/RequestTab/index.js:
- Line 153: The component is importing state.app.preferences into a local
variable named preferences via useSelector but never uses it; remove the unused
selector call by deleting the const preferences = useSelector((state) =>
state.app.preferences); line in the RequestTab component (look for useSelector
and the preferences variable in RequestTab/index.js) to eliminate the dead
variable and any unnecessary import or dependency it introduced.

In @packages/bruno-app/src/components/StatusBar/index.js:
- Line 13: The import list includes an unused symbol focusWorkspaceTab; remove
focusWorkspaceTab from the import statement that currently reads import {
focusWorkspaceTab, setActiveWorkspaceTab } from
'providers/ReduxStore/slices/workspaceTabs' (or, if you intended to use
focusWorkspaceTab, add the missing usage where appropriate); update the import
to only include setActiveWorkspaceTab and run the linter to confirm no other
unused imports remain.

In @packages/bruno-app/src/providers/App/useIpcEvents.js:
- Around line 10-13: Remove the unused import focusWorkspaceTab from the import
list in useIpcEvents.js (the import that currently reads import {
focusWorkspaceTab, setActiveWorkspaceTab } from
'providers/ReduxStore/slices/workspaceTabs') so only setActiveWorkspaceTab is
imported, or if focusWorkspaceTab is actually needed, call it where appropriate;
this eliminates the unused-symbol lint error referencing focusWorkspaceTab.

In @packages/bruno-app/src/themes/dark/vscode.js:
- Around line 660-665: The kbd theme object is currently nested under the app
key but the schema (schema/oss.js) requires kbd at the root level; move the kbd
definition out of the app object in dark/vscode.js so it is a top-level export
(matching the root-level kbd shape used in light/vscode.js), remove the nested
kbd from app, and ensure any references expecting the root kbd (e.g., consumers
of the exported theme) continue to work with the moved property.

In @packages/bruno-app/src/themes/schema/oss.js:
- Around line 1187-1204: The schema currently defines "kbd" at the root level
and includes "kbd" in the root required array, but theme implementations place
it under "app.kbd", causing validation failures; to fix, move the "kbd" schema
object into the "app" object's properties (so it becomes app.properties.kbd /
accessible as app.kbd) and remove "kbd" from the root required array (or if you
choose the alternative, update every theme to expose kbd at the root and add
required keys there), ensuring the "app" schema's required/ additionalProperties
remain consistent with the nested kbd definition.
🧹 Nitpick comments (11)
packages/bruno-app/src/utils/collections/index.js (1)

117-124: Good defensive guard, minor return value inconsistency.

The null/undefined check is a sensible addition to prevent TypeError when collection or collection.items is missing. This aligns well with the PR's goal of handling cases where collections may be undefined.

One minor note: this explicitly returns null, while findItem (via lodash find) returns undefined when no match is found. Both are falsy, so typical if (!result) checks work fine, but callers using strict equality (=== undefined) could miss the null case.

Consider returning undefined for consistency, or verify that all call sites use loose checks.

Optional: return undefined for consistency
 export const findItemInCollection = (collection, itemUid) => {
   if (!collection || !collection.items) {
-    return null;
+    return undefined;
   }
   let flattenedItems = flattenItems(collection.items);

   return findItem(flattenedItems, itemUid);
 };
packages/bruno-app/src/components/RequestTabPanel/index.js (1)

182-185: Stale TODO comment.

The TODO on line 183 says "Add a preferences tab panel to the request tab panel" but the code on line 184 already does exactly that. Remove or update this comment.

🧹 Suggested fix
   if (focusedTab.type === 'preferences') {
-    // TODO: Add a preferences tab panel to the request tab panel
     return <Preferences />;
   }
packages/bruno-app/src/components/WorkspaceTabs/index.js (1)

10-14: Approve with a note on duplication.

The PERMANENT_TABS constant here duplicates the permanentTabs array in switchWorkspace action (workspaces/actions.js). Consider extracting this to a shared constant to avoid drift if tabs are added/removed in the future.

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

37-51: Duplicated logic with useIpcEvents.js.

The handlePreferencesClick logic is nearly identical to the main:open-preferences handler in useIpcEvents.js (lines 248-268). Consider extracting this into a shared thunk or utility to avoid divergence.

Additionally, if activeWorkspaceUid is falsy when on special pages (home/manage workspace/api spec), the click does nothing silently—user gets no feedback.

♻️ Suggested approach

Extract shared logic into a Redux thunk:

// In a slice or actions file
export const openPreferencesTab = () => (dispatch, getState) => {
  const state = getState();
  const { showHomePage, showManageWorkspacePage, showApiSpecPage } = state.app;
  const activeWorkspaceUid = state.workspaces?.activeWorkspaceUid;
  const tabs = state.tabs?.tabs;
  const activeTabUid = state.tabs?.activeTabUid;
  const activeTab = tabs?.find((t) => t.uid === activeTabUid);

  if (showHomePage || showManageWorkspacePage || showApiSpecPage || !activeTabUid) {
    if (activeWorkspaceUid) {
      dispatch(setActiveWorkspaceTab({ workspaceUid: activeWorkspaceUid, type: 'preferences' }));
    }
  } else {
    dispatch(addTab({
      type: 'preferences',
      uid: activeTab?.collectionUid ? `${activeTab.collectionUid}-preferences` : 'preferences',
      collectionUid: activeTab?.collectionUid
    }));
  }
};
packages/bruno-app/src/components/Preferences/index.js (1)

74-102: ARIA tab pattern is incomplete.

The tabs have role="tab" and the panel has aria-labelledby={${tab}-tab}, but the tab elements lack the corresponding id attributes, aria-selected, and tabindex for proper keyboard navigation.

♿ Accessibility improvement
-          <div className={getTabClassname('general')} role="tab" onClick={() => setTab('general')}>
+          <div
+            className={getTabClassname('general')}
+            role="tab"
+            id="general-tab"
+            aria-selected={tab === 'general'}
+            tabIndex={tab === 'general' ? 0 : -1}
+            onClick={() => setTab('general')}
+          >

Apply similar changes to all tab elements.

packages/bruno-app/src/providers/App/useIpcEvents.js (2)

345-345: Effect dependency on isElectron function reference.

isElectron is a function import, so the reference never changes. However, using a function in the dependency array is misleading. The early return already guards non-Electron contexts, so an empty array would be clearer.

♻️ Proposed fix
-  }, [isElectron]);
+  }, []);

248-268: Duplicated preferences tab logic.

This handler mirrors handlePreferencesClick in StatusBar/index.js. As noted there, consider extracting to a shared thunk to maintain a single source of truth.

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

143-150: Empty reducer case with explanatory comment.

The closeTabs case has no implementation—just a multi-line comment explaining why. If no state changes are needed, remove the case entirely. The comment could live in a code comment outside the switch or in documentation.

♻️ Proposed fix
       .addCase(focusTab, (state) => {
         state.showHomePage = false;
         state.showApiSpecPage = false;
         state.showManageWorkspacePage = false;
-      })
-      .addCase(closeTabs, (state, action) => {
-        // We don't have access to the tabs state here easily to check if it's empty
-        // but the RequestTabPanel handles showing WorkspaceHome if tabs are empty.
-        // However, to ensure logic in StatusBar and useIpcEvents works correctly,
-        // we should probably let the UI handle switching to showHomePage if needed,
-        // or just rely on !activeTabUid check which I added.
       });
packages/bruno-app/src/themes/light/light-pastel.js (1)

655-661: Minor inconsistency: Hardcoded color value.

The kbd.bg uses '#f3f3f3' while other properties reference palette colors. Consider using colors.GRAY_2 (#f0ebe4) or adding a dedicated constant if this specific shade is intentional.

Suggested change
     kbd: {
-      bg: '#f3f3f3',
+      bg: colors.GRAY_2,
       color: colors.TEXT,
       border: colors.GRAY_3
     }
packages/bruno-app/src/themes/light/light-monochrome.js (1)

638-644: Consider using palette constant.

The hardcoded '#f3f3f3' matches colors.GRAY_2 in this theme's palette. Using the constant would improve maintainability.

Suggested change
     kbd: {
-      bg: '#f3f3f3',
+      bg: colors.GRAY_2,
       color: colors.TEXT,
       border: colors.GRAY_4
     }
packages/bruno-app/src/themes/dark/nord.js (1)

657-663: Consider using a Nord palette color for kbd background.

The border and color properties correctly reference Nord constants, but bg: '#3f3f3f' is a hardcoded value that doesn't match any Nord color. Consider using colors.NORD1 or colors.NORD2 for palette consistency.

Suggested fix
     kbd: {
-      bg: '#3f3f3f',
+      bg: colors.NORD2,
       color: colors.TEXT,
       border: colors.NORD2
     }
📜 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 59ff9bd and f9bc0b1.

📒 Files selected for processing (37)
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/components/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/utils/collections/index.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/utils/collections/index.js
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/components/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/components/StatusBar/index.js
🧠 Learnings (6)
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.

Applied to files:

  • packages/bruno-app/src/utils/collections/index.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/components/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/components/StatusBar/index.js
📚 Learning: 2026-01-09T18:25:14.640Z
Learnt from: kanakkholwal
Repo: usebruno/bruno PR: 6767
File: packages/bruno-app/src/components/ResponseExample/index.js:221-226
Timestamp: 2026-01-09T18:25:14.640Z
Learning: In the Bruno Electron renderer code (packages/bruno-app), assume window.ipcRenderer is always available and skip existence checks. Do not guard for ipcRenderer in this Electron context; use window.ipcRenderer directly (e.g., window.ipcRenderer.send(...), window.ipcRenderer.on(...)). If there are non-Electron contexts (such as test environments or non-Electron builds), add guards or mocks to avoid runtime errors there, but for the intended Electron renderer files, this pattern should be applied broadly within packages/bruno-app.

Applied to files:

  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/components/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/components/StatusBar/index.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/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/Keybindings/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 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/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/Keybindings/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/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
🧬 Code graph analysis (16)
packages/bruno-app/src/pages/Bruno/index.js (7)
packages/bruno-app/src/components/StatusBar/index.js (2)
  • showHomePage (21-21)
  • activeTabUid (25-25)
packages/bruno-app/src/components/RequestTabPanel/index.js (1)
  • activeTabUid (51-51)
packages/bruno-app/src/components/RequestTabs/index.js (1)
  • activeTabUid (26-26)
packages/bruno-app/src/components/WorkspaceHome/index.js (1)
  • activeTabUid (22-22)
packages/bruno-app/src/components/WorkspaceTabs/index.js (1)
  • activeTabUid (24-24)
packages/bruno-app/src/components/RequestPane/WSRequestPane/index.js (1)
  • activeTabUid (20-20)
packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js (1)
  • activeTabUid (26-26)
packages/bruno-app/src/themes/dark/dark-pastel.js (1)
packages/bruno-app/src/themes/dark/dark-monochrome.js (1)
  • colors (3-39)
packages/bruno-app/src/components/RequestTabs/index.js (1)
packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js (1)
  • CollectionToolBar (12-81)
packages/bruno-app/src/themes/light/vscode.js (1)
packages/bruno-app/src/themes/dark/vscode.js (1)
  • colors (6-62)
packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js (4)
packages/bruno-app/src/components/RequestTabPanel/index.js (1)
  • collection (81-81)
packages/bruno-app/src/utils/collections/index.js (5)
  • collection (590-590)
  • collection (1178-1178)
  • collection (1180-1180)
  • collection (1615-1615)
  • collection (1625-1625)
packages/bruno-electron/src/ipc/network/index.js (1)
  • collection (145-145)
packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js (1)
  • collection (68-68)
packages/bruno-app/src/themes/dark/catppuccin-mocha.js (2)
packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/dark/catppuccin-macchiato.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/dark/dark.js (1)
packages/bruno-app/src/themes/light/light.js (2)
  • palette (2-56)
  • palette (2-56)
packages/bruno-app/src/themes/dark/catppuccin-macchiato.js (2)
packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/dark/catppuccin-mocha.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/dark/dark-monochrome.js (2)
packages/bruno-app/src/themes/dark/dark.js (1)
  • colors (88-93)
packages/bruno-app/src/themes/light/light-monochrome.js (1)
  • colors (3-40)
packages/bruno-app/src/providers/App/useIpcEvents.js (2)
packages/bruno-app/src/providers/ReduxStore/index.js (2)
  • store (26-40)
  • store (26-40)
packages/bruno-app/src/providers/ReduxStore/slices/tabs.js (3)
  • tabs (215-215)
  • activeTab (169-169)
  • activeTab (176-176)
packages/bruno-app/src/components/WorkspaceHome/index.js (1)
packages/bruno-app/src/components/Preferences/index.js (1)
  • Preferences (25-115)
packages/bruno-app/src/themes/dark/catppuccin-frappe.js (2)
packages/bruno-app/src/themes/dark/catppuccin-mocha.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/light/catppuccin-latte.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/light/light-monochrome.js (1)
packages/bruno-app/src/themes/light/vscode.js (1)
  • colors (5-61)
packages/bruno-app/src/themes/dark/vscode.js (3)
packages/bruno-app/src/themes/dark/dark-monochrome.js (1)
  • colors (3-39)
packages/bruno-app/src/themes/dark/dark.js (1)
  • colors (88-93)
packages/bruno-app/src/themes/light/vscode.js (1)
  • colors (5-61)
packages/bruno-app/src/themes/light/catppuccin-latte.js (2)
packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)
  • colors (6-52)
packages/bruno-app/src/themes/dark/catppuccin-mocha.js (1)
  • colors (6-52)
packages/bruno-app/src/components/RequestTabPanel/index.js (8)
packages/bruno-app/src/components/RequestPane/WSRequestPane/index.js (1)
  • focusedTab (24-24)
packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js (1)
  • focusedTab (103-103)
packages/bruno-app/src/components/ResponsePane/index.js (1)
  • focusedTab (42-42)
packages/bruno-app/src/components/RequestPane/GraphQLRequestPane/index.js (1)
  • focusedTab (55-55)
packages/bruno-app/src/components/RequestPane/HttpRequestPane/index.js (1)
  • focusedTab (55-55)
packages/bruno-app/src/hooks/useTabPaneBoundaries/index.js (1)
  • focusedTab (11-11)
packages/bruno-app/src/components/Environments/GlobalEnvironmentSettings/index.js (1)
  • GlobalEnvironmentSettings (4-6)
packages/bruno-app/src/components/Preferences/index.js (1)
  • Preferences (25-115)
⏰ 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 - Linux
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - macOS
🔇 Additional comments (41)
packages/bruno-app/src/components/Preferences/Display/Font/index.js (1)

9-9: LGTM — close prop correctly removed for tab-based preferences.

Removing the modal-specific close prop aligns with the refactor from modal to tab behavior. The component now self-manages state via Redux without needing a close callback.

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

26-31: The code is correct as written. All 13 theme files consistently define table.thead.bg, and the fallback || 'transparent' provides defensive access. Optional chaining is unnecessary and inconsistent with how the codebase accesses theme properties elsewhere.

Likely an incorrect or invalid review comment.

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

15-17: Good defensive guard.

The early return prevents downstream access errors when collection is undefined. This aligns with similar patterns elsewhere in the codebase (e.g., RequestTabPanel, CollectionItem).

Minor: Line 54 uses collection?.name but the guard above already ensures collection is truthy—optional chaining is now redundant there.

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

294-300: Checkbox component usage looks correct.

The inverted checked state and onChange handler logic properly maps the UI state to the underlying config.auth.disabled field.

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

5-41: Styling updates look good.

Table width reduction, padding adjustments, background-color with fallback, and opacity changes are well-structured and use theme props appropriately per coding standards.

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

10-10: Clean integration of Preferences tab.

The import and switch case follow the existing pattern for workspace tab content. The Preferences component is correctly rendered without props since it manages state internally via Redux.

Also applies to: 161-162

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

6-20: Styling additions follow project conventions.

Uses theme props for colors and consistent rem units for font sizing. The .text-link class and form label styling align with the broader Preferences UI refresh.

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

2-11: LGTM!

Clean extension of the icon mapping for the new preferences tab type. Follows the existing pattern consistently.

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

36-36: LGTM!

Import correctly added for the Preferences component.


174-176: LGTM!

Early return for missing tab state is appropriate. The generic error message is fine for this edge case.

packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js (1)

268-274: LGTM!

The preferences tab is correctly added to the permanent tabs during workspace initialization. This aligns with the PERMANENT_TABS constant in WorkspaceTabs/index.js.

packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js (1)

64-71: LGTM!

The new preferences case follows the established pattern for special tabs. Icon and styling are consistent with other tab types.

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

47-47: LGTM - Defensive optional chaining for collection-less tabs.

Good safeguard for tabs like 'preferences' that don't have an associated collection.


119-119: LGTM - Proper guard for CollectionToolBar rendering.

Correctly prevents rendering CollectionToolBar when activeCollection is undefined (e.g., for preferences tabs). This aligns with the early return in CollectionToolBar/index.js at line 14.

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

176-176: LGTM - 'preferences' added to special tab types.

Correctly integrates the preferences tab into the existing special tab rendering logic.

packages/bruno-app/src/pages/Bruno/index.js (1)

126-127: LGTM - Fallback to WorkspaceHome when no active tab.

Good catch ensuring the home page displays when all tabs are closed (!activeTabUid), complementing the new tab-based preferences system.

packages/bruno-app/src/components/Preferences/StyledWrapper.js (3)

29-36: LGTM - Theme-consistent active tab styling.

Using theme.tabs.secondary.active.bg aligns the preferences tab styling with the application's tab system. Based on coding standards, using the theme prop for colors is correct.


40-45: LGTM - Flexible layout for tab-based UI.

Replacing fixed max-height with flex-grow: 1 properly adapts the preferences panel to fill available space within the tab container.


53-70: LGTM - Reusable textbox styling.

Clean, theme-aware input styling with proper focus and disabled states. Follows the project convention of using styled-components for color theming.

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

24-30: LGTM - 'preferences' added to non-replaceable tab types.

This prevents duplicate preferences tabs. Preferences can be either workspace-scoped (no collectionUid) or collection-scoped (collectionUid: activeTab?.collectionUid). The tabTypeAlreadyExists logic correctly handles both cases—matching on collectionUid equality whether it's undefined or a specific collection ID.

packages/bruno-app/src/components/Preferences/General/index.js (2)

8-8: LGTM! Clean migration to Checkbox component and removal of close prop.

The component signature update and Checkbox integration align well with the modal-to-tab refactor. The custom Checkbox component is consistently applied across all form fields.

Also applies to: 15-15


243-249: Disabled logic for keepDefaultCaCertificates is correct.

The checkbox is properly disabled when customCaCertificate.enabled is false OR customCaCertificate.filePath is falsy, ensuring users can only toggle this option when a custom CA certificate is actively configured.

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

99-101: LGTM! Clean addition of activePreferencesTab state management.

The new reducer and initial state cleanly support the modal-to-tab transition.

packages/bruno-app/src/themes/light/catppuccin-latte.js (2)

431-434: LGTM!

The thead.bg addition using colors.MANTLE is consistent with the Catppuccin Latte palette and aligns with similar changes in other theme files.


651-657: LGTM!

The app.kbd block properly styles keyboard-like UI elements using the theme's surface colors. Values are well-chosen for the light theme aesthetic.

packages/bruno-app/src/themes/light/light-pastel.js (1)

435-438: LGTM!

The thead.bg using colors.GRAY_1 fits the Light Pastel theme's warm grayscale palette.

packages/bruno-app/src/themes/dark/dark-monochrome.js (1)

421-424: LGTM!

The thead.bg addition using colors.GRAY_1 is correct for the monochrome dark theme.

packages/bruno-app/src/themes/light/light-monochrome.js (1)

419-422: LGTM!

The thead.bg properly uses colors.GRAY_1 for the monochrome light theme header background.

packages/bruno-app/src/themes/dark/dark-pastel.js (1)

438-441: LGTM!

The thead.bg using colors.GRAY_1 fits the Nebula theme's deep plum palette.

packages/bruno-app/src/themes/light/vscode.js (2)

440-442: LGTM!

The addition of bg: colors.GRAY_1 for the table header is consistent with the theme's color palette and aligns with the schema extension for table.thead.bg.


659-664: No action needed — kbd is correctly positioned at the top level.

The kbd object is a sibling of app, not nested within it. Line 659 closes the app block with },, and kbd begins on line 660 at the same indentation level. This matches the schema definition in oss.js (line 1188), where kbd is also defined as a top-level property. All theme files follow this consistent structure.

Likely an incorrect or invalid review comment.

packages/bruno-app/src/themes/schema/oss.js (1)

726-730: LGTM!

Good decision to keep bg optional in the required array. This maintains backward compatibility for themes that don't define a header background.

packages/bruno-app/src/themes/dark/vscode.js (1)

441-442: LGTM!

Table header background using colors.GRAY_2 is appropriate for the dark VS Code theme.

packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)

435-436: LGTM!

Using colors.MANTLE for the table header background is consistent with the Catppuccin Frappé palette.

packages/bruno-app/src/themes/dark/catppuccin-mocha.js (1)

435-436: LGTM!

Using colors.MANTLE for the table header background maintains consistency with other Catppuccin themes.

packages/bruno-app/src/themes/dark/catppuccin-macchiato.js (1)

434-437: LGTM on the thead background addition.

The bg: colors.MANTLE properly uses the theme's palette constant and aligns with other theme files.

However, this file appears to be missing the app.kbd styling block that was added to dark.js, light.js, and nord.js in this PR. Please verify if app.kbd should also be added here for consistency.

packages/bruno-app/src/themes/dark/dark.js (2)

464-474: LGTM on the table thead styling.

The hardcoded #292929 provides appropriate contrast for the dark theme header background.


685-691: LGTM on the kbd styling block.

The app.kbd addition properly uses palette references for color and border while providing a suitable background for keyboard-style UI elements.

packages/bruno-app/src/themes/light/light.js (2)

453-463: LGTM on the table thead styling.

The #f8f9fa is a clean light gray that works well for table headers in the light theme.


674-680: LGTM on the kbd styling block.

Consistent structure with the dark theme, using palette references appropriately.

packages/bruno-app/src/themes/dark/nord.js (1)

435-445: LGTM on the table thead styling.

Good use of colors.NORD1 to maintain consistency with the Nord palette.

const hasFolderDraft = tab.type === 'folder-settings' && folder?.draft;
const hasEnvironmentDraft = tab.type === 'environment-settings' && collection?.environmentsDraft;
const globalEnvironmentDraft = useSelector((state) => state.globalEnvironments.globalEnvironmentDraft);
const preferences = useSelector((state) => state.app.preferences);
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

Unused Redux selector - preferences is never referenced.

The preferences variable is selected from the store but not used anywhere in this component. Remove it to avoid confusion.

🧹 Proposed fix
-  const preferences = useSelector((state) => state.app.preferences);
📝 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
const preferences = useSelector((state) => state.app.preferences);
🤖 Prompt for AI Agents
In @packages/bruno-app/src/components/RequestTabs/RequestTab/index.js at line
153, The component is importing state.app.preferences into a local variable
named preferences via useSelector but never uses it; remove the unused selector
call by deleting the const preferences = useSelector((state) =>
state.app.preferences); line in the RequestTab component (look for useSelector
and the preferences variable in RequestTab/index.js) to eliminate the dead
variable and any unnecessary import or dependency it introduced.

Comment on lines 660 to 665
},
kbd: {
bg: '#3f3f3f',
color: colors.TEXT,
border: colors.BORDER
}
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 | 🟠 Major

Same schema location issue as the light theme.

kbd is nested under app, but the schema expects it at the root level. See comments on light/vscode.js and schema/oss.js for details.

🤖 Prompt for AI Agents
In @packages/bruno-app/src/themes/dark/vscode.js around lines 660 - 665, The kbd
theme object is currently nested under the app key but the schema
(schema/oss.js) requires kbd at the root level; move the kbd definition out of
the app object in dark/vscode.js so it is a top-level export (matching the
root-level kbd shape used in light/vscode.js), remove the nested kbd from app,
and ensure any references expecting the root kbd (e.g., consumers of the
exported theme) continue to work with the moved property.

Comment on lines +1187 to +1204
},
kbd: {
type: 'object',
properties: {
bg: { type: 'string' },
color: { type: 'string' },
border: { type: 'string' }
},
required: ['bg', 'color', 'border'],
additionalProperties: false
}
},
required: [
'mode', 'brand', 'text', 'textLink', 'draftColor', 'bg', 'primary', 'accents', 'background', 'status', 'overlay', 'font', 'shadow', 'border', 'colors', 'input',
'sidebar', 'dropdown', 'workspace', 'request',
'requestTabPanel', 'notifications', 'modal', 'button', 'button2', 'tabs',
'requestTabs', 'codemirror', 'table', 'plainGrid', 'scrollbar', 'dragAndDrop',
'infoTip', 'statusBar', 'console', 'grpc', 'deprecationWarning', 'examples', 'app'
'infoTip', 'statusBar', 'console', 'grpc', 'deprecationWarning', 'examples', 'app', 'kbd'
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 | 🟠 Major

Schema structure mismatch with theme implementations.

Two issues:

  1. Location: kbd is defined at the root level here, but theme files (e.g., light/vscode.js, dark/vscode.js) place it under app.kbd. This will fail validation.

  2. Required constraint: Adding kbd to the root required array will break themes that don't implement it (e.g., catppuccin-frappe.js, catppuccin-mocha.js in this PR).

Consider either:

  • Moving kbd inside the app schema definition, or
  • Updating all theme files to place kbd at the root level and ensure all themes implement it.
🤖 Prompt for AI Agents
In @packages/bruno-app/src/themes/schema/oss.js around lines 1187 - 1204, The
schema currently defines "kbd" at the root level and includes "kbd" in the root
required array, but theme implementations place it under "app.kbd", causing
validation failures; to fix, move the "kbd" schema object into the "app"
object's properties (so it becomes app.properties.kbd / accessible as app.kbd)
and remove "kbd" from the root required array (or if you choose the alternative,
update every theme to expose kbd at the root and add required keys there),
ensuring the "app" schema's required/ additionalProperties remain consistent
with the nested kbd definition.

@Pragadesh-45 Pragadesh-45 force-pushed the feat/preferences-as-tab branch from 8894b69 to d12cc2b Compare January 14, 2026 10:10
@Pragadesh-45 Pragadesh-45 marked this pull request as ready for review January 14, 2026 14:03
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

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/Preferences/General/index.js (1)

128-128: Bug: toast.error will never execute.

console.log() returns undefined, so the && short-circuits and toast.error('Failed to update preferences') is never called.

Proposed fix
-      .catch((err) => console.log(err) && toast.error('Failed to update preferences'));
+      .catch((err) => {
+        console.log(err);
+        toast.error('Failed to update preferences');
+      });
🤖 Fix all issues with AI agents
In `@packages/bruno-app/src/components/RequestTabPanel/index.js`:
- Around line 35-36: Remove the unused import of WorkspaceHome: delete the
"import WorkspaceHome from 'components/WorkspaceHome';" line at the top of the
file (it is no longer referenced after the fallback was simplified at the
render/fallback block). Verify there are no remaining references to
WorkspaceHome in this component (e.g., in the render/fallback logic) and keep
only the used "Preferences" import.
🧹 Nitpick comments (6)
packages/bruno-app/src/providers/App/useIpcEvents.js (1)

247-268: Logic duplicates StatusBar's handlePreferencesClick.

This branching logic mirrors the handler in StatusBar/index.js. Consider extracting to a shared utility or thunk action to maintain consistency and reduce duplication if this pattern grows.

Same edge case applies: no action when activeWorkspaceUid is falsy on the home page.

💡 Potential refactor: shared action creator
// In a shared location, e.g., slices/tabs.js or a new utils file
export const openPreferencesTab = () => (dispatch, getState) => {
  const state = getState();
  const activeWorkspaceUid = state.workspaces?.activeWorkspaceUid;
  const { showHomePage, showManageWorkspacePage, showApiSpecPage } = state.app;
  const tabs = state.tabs?.tabs;
  const activeTabUid = state.tabs?.activeTabUid;
  const activeTab = tabs?.find((t) => t.uid === activeTabUid);

  if (showHomePage || showManageWorkspacePage || showApiSpecPage || !activeTabUid) {
    if (activeWorkspaceUid) {
      dispatch(setActiveWorkspaceTab({ workspaceUid: activeWorkspaceUid, type: 'preferences' }));
    }
  } else {
    dispatch(
      addTab({
        type: 'preferences',
        uid: activeTab?.collectionUid ? `${activeTab.collectionUid}-preferences` : 'preferences',
        collectionUid: activeTab?.collectionUid
      })
    );
  }
};

Then both StatusBar and useIpcEvents can simply dispatch(openPreferencesTab()).

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

58-63: Consider adding a brief comment explaining the +1 tolerance.

The 1-pixel buffer likely prevents false overflow detection from sub-pixel rounding. A short comment would clarify intent for future maintainers.

💡 Suggested comment
 const checkOverflow = () => {
   if (tabsRef.current && scrollContainerRef.current) {
+    // +1 tolerance to avoid false positives from sub-pixel rounding
     const hasOverflow = tabsRef.current.scrollWidth > scrollContainerRef.current.clientWidth + 1;
     setShowChevrons(hasOverflow);
   }
 };
packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js (1)

54-54: Optional chaining is now redundant.

With the early return on lines 15-17, collection?.name can safely be collection.name. Minor cleanup opportunity.

💡 Suggested fix
-          <span className="ml-2 mr-4 font-medium">{collection?.name}</span>
+          <span className="ml-2 mr-4 font-medium">{collection.name}</span>
packages/bruno-app/src/components/Preferences/index.js (2)

39-69: Add a default case to getTabPanel.

The switch statement has no default case. If an unexpected tab value is passed, this returns undefined which renders nothing without feedback.

Proposed fix
       case 'support': {
         return <Support />;
       }
+
+      default: {
+        return <General />;
+      }
     }
   };

74-102: Incomplete ARIA attributes on tab elements.

Tab elements are missing id, aria-selected, and tabIndex attributes required for full accessibility compliance. The aria-labelledby on the tabpanel (line 108) references ${tab}-tab, but no tab has a matching id.

Example fix for one tab
-          <div className={getTabClassname('general')} role="tab" onClick={() => setTab('general')}>
+          <div
+            id="general-tab"
+            className={getTabClassname('general')}
+            role="tab"
+            aria-selected={tab === 'general'}
+            tabIndex={tab === 'general' ? 0 : -1}
+            onClick={() => setTab('general')}
+          >
             <IconSettings size={16} strokeWidth={1.5} />
             General
           </div>

Apply similar changes to all tab elements.

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

174-176: Generic error message is not user-friendly.

"An error occurred!" provides no actionable context. Consider a more descriptive message or fallback behavior.

Suggested improvement
   if (!activeTabUid || !focusedTab) {
-    return <div className="pb-4 px-4">An error occurred!</div>;
+    return <div className="pb-4 px-4">No active tab selected. Please select or open a tab.</div>;
   }
📜 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 f9bc0b1 and e091ab3.

📒 Files selected for processing (38)
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/components/Preferences/General/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/components/Preferences/index.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/providers/Hotkeys/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/utils/collections/index.js
🚧 Files skipped from review as they are similar to previous changes (25)
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/themes/light/light-pastel.js
  • packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
  • packages/bruno-app/src/themes/light/light-monochrome.js
  • packages/bruno-app/src/themes/light/catppuccin-latte.js
  • packages/bruno-app/src/themes/dark/catppuccin-mocha.js
  • packages/bruno-app/src/components/Preferences/StyledWrapper.js
  • packages/bruno-app/src/themes/schema/oss.js
  • packages/bruno-app/src/components/Preferences/Display/Font/index.js
  • packages/bruno-app/src/themes/dark/catppuccin-macchiato.js
  • packages/bruno-app/src/components/WorkspaceHome/index.js
  • packages/bruno-app/src/providers/ReduxStore/slices/app.js
  • packages/bruno-app/src/themes/dark/nord.js
  • packages/bruno-app/src/components/Preferences/ProxySettings/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
  • packages/bruno-app/src/components/RequestTabs/index.js
  • packages/bruno-app/src/themes/dark/vscode.js
  • packages/bruno-app/src/themes/dark/catppuccin-frappe.js
  • packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
  • packages/bruno-app/src/themes/dark/dark-pastel.js
  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-app/src/themes/light/vscode.js
  • packages/bruno-app/src/components/Table/StyledWrapper.js
  • packages/bruno-app/src/themes/light/light.js
  • packages/bruno-app/src/components/Preferences/General/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/WorkspaceTabs/index.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/Hotkeys/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/components/Preferences/index.js
🧠 Learnings (3)
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/Hotkeys/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/components/Preferences/index.js
📚 Learning: 2026-01-09T18:25:14.640Z
Learnt from: kanakkholwal
Repo: usebruno/bruno PR: 6767
File: packages/bruno-app/src/components/ResponseExample/index.js:221-226
Timestamp: 2026-01-09T18:25:14.640Z
Learning: In the Bruno Electron renderer code (packages/bruno-app), assume window.ipcRenderer is always available and skip existence checks. Do not guard for ipcRenderer in this Electron context; use window.ipcRenderer directly (e.g., window.ipcRenderer.send(...), window.ipcRenderer.on(...)). If there are non-Electron contexts (such as test environments or non-Electron builds), add guards or mocks to avoid runtime errors there, but for the intended Electron renderer files, this pattern should be applied broadly within packages/bruno-app.

Applied to files:

  • packages/bruno-app/src/components/WorkspaceTabs/index.js
  • packages/bruno-app/src/themes/dark/dark.js
  • packages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.js
  • packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
  • packages/bruno-app/src/providers/App/useIpcEvents.js
  • packages/bruno-app/src/components/RequestTabPanel/index.js
  • packages/bruno-app/src/pages/Bruno/index.js
  • packages/bruno-app/src/components/StatusBar/index.js
  • packages/bruno-app/src/themes/dark/dark-monochrome.js
  • packages/bruno-app/src/providers/Hotkeys/index.js
  • packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js
  • packages/bruno-app/src/components/Preferences/General/index.js
  • packages/bruno-app/src/components/Preferences/index.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 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/Preferences/index.js
🧬 Code graph analysis (3)
packages/bruno-app/src/pages/Bruno/index.js (7)
packages/bruno-app/src/components/StatusBar/index.js (2)
  • showHomePage (21-21)
  • activeTabUid (25-25)
packages/bruno-app/src/components/RequestTabs/index.js (1)
  • activeTabUid (26-26)
packages/bruno-app/src/components/WorkspaceTabs/index.js (1)
  • activeTabUid (23-23)
packages/bruno-app/src/components/RequestTabPanel/index.js (1)
  • activeTabUid (51-51)
packages/bruno-app/src/components/WorkspaceHome/index.js (1)
  • activeTabUid (22-22)
packages/bruno-app/src/components/ResponsePane/WsResponsePane/index.js (1)
  • activeTabUid (25-25)
packages/bruno-app/src/components/RequestPane/WSRequestPane/index.js (1)
  • activeTabUid (20-20)
packages/bruno-app/src/components/StatusBar/index.js (6)
packages/bruno-app/src/components/RequestTabs/RequestTab/index.js (1)
  • dispatch (28-28)
packages/bruno-app/src/components/Devtools/Console/index.js (1)
  • useSelector (287-287)
packages/bruno-app/src/components/Devtools/Console/RequestDetailsPanel/index.js (2)
  • useSelector (158-158)
  • activeTab (160-160)
packages/bruno-app/src/pages/Bruno/index.js (4)
  • showHomePage (60-60)
  • showManageWorkspacePage (62-62)
  • showApiSpecPage (61-61)
  • activeTabUid (57-57)
packages/bruno-app/src/components/WorkspaceTabs/index.js (2)
  • tabs (22-22)
  • activeTabUid (23-23)
packages/bruno-app/src/providers/ReduxStore/slices/tabs.js (3)
  • tabs (215-215)
  • activeTab (169-169)
  • activeTab (176-176)
packages/bruno-app/src/themes/dark/dark-monochrome.js (2)
packages/bruno-app/src/themes/dark/dark.js (1)
  • colors (88-93)
packages/bruno-app/src/themes/light/light-monochrome.js (1)
  • colors (3-40)
🔇 Additional comments (18)
packages/bruno-app/src/themes/dark/dark.js (1)

464-474: LGTM!

Clean addition of the thead.bg property. The color value #292929 is consistent with the dark theme palette and provides appropriate contrast for table headers.

packages/bruno-app/src/themes/dark/dark-monochrome.js (1)

419-429: LGTM!

Good use of colors.GRAY_1 constant rather than a hardcoded value. This maintains consistency with the rest of this theme file and improves maintainability.

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

167-176: Clean centralization of tab labels.

Good approach using a lookup map for tab labels. This is more maintainable than scattered conditionals and makes adding future tab types trivial.

packages/bruno-app/src/components/StatusBar/index.js (4)

3-14: Imports look correct.

All imports are used in the component. The previously flagged unused focusWorkspaceTab has been removed.


20-26: Selectors are well-structured.

Selector pattern is consistent with the rest of the codebase. Deriving activeTab via find() is appropriate here.


37-51: Edge case: no-op when no active workspace on home page.

When showHomePage is true but activeWorkspaceUid is falsy, clicking preferences silently does nothing. Confirm this is the intended UX—users might expect feedback or the button to be disabled in this state.


84-84: Handler wired correctly.

packages/bruno-app/src/providers/App/useIpcEvents.js (3)

7-12: Imports are correct and complete.

The previously flagged unused focusWorkspaceTab has been removed.


34-44: Good refactor using useStore() hook.

Much cleaner than accessing window.__store__ directly. This aligns with React-Redux best practices.


135-136: Consistent store access pattern.

All window.__store__.getState() calls properly migrated to store.getState().

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

7-11: LGTM!

Clean extension of the TAB_ICONS mapping to support the new preferences tab type. The IconSettings icon is a sensible choice for preferences.

packages/bruno-app/src/pages/Bruno/index.js (1)

126-128: LGTM!

The expanded condition ensures WorkspaceHome renders as a fallback when no request tab is active. This correctly supports the new tab-based preferences workflow where the workspace home displays workspace-level tabs.

packages/bruno-app/src/providers/Hotkeys/index.js (1)

177-193: Logic is sound, but verify edge case behavior.

The branching correctly prioritizes closing workspace tabs when on the home page. One edge case: if showHomePage is true but activeWorkspaceTabUid is falsy, and activeTabUid exists, neither branch executes. Confirm this "no-op" is intended.

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

15-17: LGTM!

Good defensive guard clause. Correctly placed after the useDispatch hook to maintain React's rules of hooks.

packages/bruno-app/src/components/Preferences/General/index.js (2)

8-8: LGTM on Checkbox migration.

The migration from native <input type="checkbox"> to the custom Checkbox component is consistent and well-applied across all form fields. Props (id, name, checked, onChange, disabled) are correctly passed.

Also applies to: 180-185


15-15: Signature change aligns with tab-based architecture.

Removing the close prop is correct since the Preferences component is now rendered as a tab rather than a modal.

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

25-31: Redux integration looks good.

Clean implementation of Redux-driven tab state management with useSelector and dispatch.

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

182-185: TODO comment suggests incomplete implementation.

The comment indicates this feature may not be finalized. Confirm if this is intentional or should be addressed before merge.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 35 to +36
import WorkspaceHome from 'components/WorkspaceHome';
import Preferences from 'components/Preferences';
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:

#!/bin/bash
# Check if WorkspaceHome is used anywhere in RequestTabPanel/index.js
rg -n "WorkspaceHome" packages/bruno-app/src/components/RequestTabPanel/index.js

Repository: usebruno/bruno

Length of output: 114


Remove unused WorkspaceHome import.

The import at line 35 is not used anywhere in this file. With the fallback at line 175 changed to a simple error message, this import is dead code and should be removed.

🤖 Prompt for AI Agents
In `@packages/bruno-app/src/components/RequestTabPanel/index.js` around lines 35 -
36, Remove the unused import of WorkspaceHome: delete the "import WorkspaceHome
from 'components/WorkspaceHome';" line at the top of the file (it is no longer
referenced after the fallback was simplified at the render/fallback block).
Verify there are no remaining references to WorkspaceHome in this component
(e.g., in the render/fallback logic) and keep only the used "Preferences"
import.

sid-bruno
sid-bruno previously approved these changes Jan 21, 2026
sid-bruno
sid-bruno previously approved these changes Jan 21, 2026
refactor: remove preferences tab from permanent tabs and update tab label handling

fix: comment

Co-authored-by: Sid <siddharth@usebruno.com>
@Pragadesh-45 Pragadesh-45 force-pushed the feat/preferences-as-tab branch from 6c469f0 to 3e72478 Compare January 21, 2026 12:21
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

🤖 Fix all issues with AI agents
In `@packages/bruno-app/src/providers/ReduxStore/slices/app.js`:
- Line 4: Remove the unused import closeTabs from the import statement that
currently reads "import { addTab, focusTab, closeTabs } from './tabs';" in the
app slice; update the import to only import the used symbols (addTab, focusTab)
so there are no unused imports (reference: closeTabs, addTab, focusTab).
🧹 Nitpick comments (3)
packages/bruno-app/src/themes/dark/dark.js (1)

464-474: LGTM!

The addition of bg: '#292929' aligns with the broader theme update and matches the existing examples.urlBar.bg and examples.table.thead.bg values in this file, ensuring visual consistency.

Optional: Consider extracting #292929 into the palette or colors object (e.g., colors.GRAY_DARK) since it's reused in multiple places (lines 468, 640, 644). This would centralize the value for easier future adjustments.

packages/bruno-app/src/utils/collections/index.js (1)

117-124: Good defensive guard; consider consistency across similar functions.

The null check prevents runtime errors when collection is falsy or lacks an items array—solid addition.

Two minor observations:

  1. Return value inconsistency: This now returns null for invalid input but undefined when the item isn't found (via lodash find). Both are falsy, so unlikely to break callers, but worth noting.

  2. Similar functions lack this guard: findItemInCollectionByPathname, findItemInCollectionByItemUid, findParentItemInCollectionByPathname, and findParentItemInCollection all access collection.items directly without a guard.

♻️ Optional: Add consistent guards to sibling functions
 export const findItemInCollectionByPathname = (collection, pathname) => {
+  if (!collection || !collection.items) {
+    return null;
+  }
   let flattenedItems = flattenItems(collection.items);

   return findItemByPathname(flattenedItems, pathname);
 };

 export const findItemInCollectionByItemUid = (collection, itemUid) => {
+  if (!collection || !collection.items) {
+    return null;
+  }
   let flattenedItems = flattenItems(collection.items);
   return findItem(flattenedItems, itemUid);
 };

 export const findParentItemInCollectionByPathname = (collection, pathname) => {
+  if (!collection || !collection.items) {
+    return null;
+  }
   let flattenedItems = flattenItems(collection.items);

   return find(flattenedItems, (item) => {
     return item.items && find(item.items, (i) => i.pathname === pathname);
   });
 };

 export const findParentItemInCollection = (collection, itemUid) => {
+  if (!collection || !collection.items) {
+    return null;
+  }
   let flattenedItems = flattenItems(collection.items);

   return find(flattenedItems, (item) => {
     return item.items && find(item.items, (i) => i.uid === itemUid);
   });
 };
packages/bruno-app/src/components/Preferences/index.js (1)

74-102: Incomplete ARIA tab pattern.

The tabs have role="tab" but are missing attributes needed for screen reader compatibility:

  • id attribute (e.g., id="general-tab") — the panel references aria-labelledby={tab}-tab but there's no matching id
  • aria-selected to indicate active state
  • tabindex for keyboard navigation
♻️ Example fix for one tab
-          <div className={getTabClassname('general')} role="tab" onClick={() => setTab('general')}>
+          <div
+            className={getTabClassname('general')}
+            role="tab"
+            id="general-tab"
+            aria-selected={tab === 'general'}
+            tabIndex={tab === 'general' ? 0 : -1}
+            onClick={() => setTab('general')}
+          >

Apply similar pattern to all tabs.

@Pragadesh-45 Pragadesh-45 force-pushed the feat/preferences-as-tab branch from 5f8e2c5 to 01f435a Compare January 21, 2026 12:49
@sid-bruno sid-bruno merged commit 67c1d39 into usebruno:main Jan 21, 2026
7 of 8 checks passed
FraCata00 pushed a commit to FraCata00/bruno that referenced this pull request Feb 9, 2026
* feat: preferences as tab

refactor: remove preferences tab from permanent tabs and update tab label handling

fix: comment

Co-authored-by: Sid <siddharth@usebruno.com>

* refactor: replace Checkbox component with native input elements in Preferences and ProxySettings

---------

Co-authored-by: Sid <siddharth@usebruno.com>
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