Conversation
WalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this comment.
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 debugconsole.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 togetTabPanel.If
activePreferencesTabstate contains an unexpected value (e.g., from a previous session or corrupted state), the function returnsundefined, 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: Missingapp.kbdblock.Same issue as
dark-monochrome.js— theapp.kbdstyling 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 missingapp.kbdblock to match other themes.The
app.kbdstyling is defined in the theme schema and present in all other dark and light theme variants, but absent fromdark-monochrome.js. This will cause inconsistency if the UI relies ontheme.app.kbd.Suggested addition
collection: { toolbar: { // ... existing content } - } + }, + kbd: { + bg: colors.GRAY_2, + color: colors.TEXT, + border: colors.GRAY_3 + } } };Note:
dark-pastel.jshas the same issue and should also be updated.packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)
621-654: Missingkbdproperty.The schema requires
kbd(either at root or underappdepending on final decision). This theme is missing thekbdstyling block, which will cause validation failures.Add the
kbdproperty 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: Missingkbdproperty.Same issue as
catppuccin-frappe.js— this theme needs thekbdstyling 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
TypeErrorwhencollectionorcollection.itemsis missing. This aligns well with the PR's goal of handling cases where collections may be undefined.One minor note: this explicitly returns
null, whilefindItem(via lodashfind) returnsundefinedwhen no match is found. Both are falsy, so typicalif (!result)checks work fine, but callers using strict equality (=== undefined) could miss thenullcase.Consider returning
undefinedfor 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_TABSconstant here duplicates thepermanentTabsarray inswitchWorkspaceaction (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 withuseIpcEvents.js.The
handlePreferencesClicklogic is nearly identical to themain:open-preferenceshandler inuseIpcEvents.js(lines 248-268). Consider extracting this into a shared thunk or utility to avoid divergence.Additionally, if
activeWorkspaceUidis 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 hasaria-labelledby={${tab}-tab}, but the tab elements lack the correspondingidattributes,aria-selected, andtabindexfor 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 onisElectronfunction reference.
isElectronis 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
handlePreferencesClickinStatusBar/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
closeTabscase 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.bguses'#f3f3f3'while other properties reference palette colors. Consider usingcolors.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'matchescolors.GRAY_2in 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
borderandcolorproperties correctly reference Nord constants, butbg: '#3f3f3f'is a hardcoded value that doesn't match any Nord color. Consider usingcolors.NORD1orcolors.NORD2for 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
📒 Files selected for processing (37)
packages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/General/StyledWrapper.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.jspackages/bruno-app/src/components/RequestTabs/RequestTab/index.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/StatusBar/index.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/WorkspaceHome/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/WorkspaceTabs/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/providers/ReduxStore/slices/app.jspackages/bruno-app/src/providers/ReduxStore/slices/tabs.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.jspackages/bruno-app/src/themes/dark/catppuccin-frappe.jspackages/bruno-app/src/themes/dark/catppuccin-macchiato.jspackages/bruno-app/src/themes/dark/catppuccin-mocha.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/themes/dark/dark-pastel.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/themes/dark/nord.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/themes/light/catppuccin-latte.jspackages/bruno-app/src/themes/light/light-monochrome.jspackages/bruno-app/src/themes/light/light-pastel.jspackages/bruno-app/src/themes/light/light.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/themes/schema/oss.jspackages/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()notfunc ()
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.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/themes/dark/dark-pastel.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.jspackages/bruno-app/src/components/WorkspaceTabs/index.jspackages/bruno-app/src/components/Preferences/General/StyledWrapper.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/themes/dark/catppuccin-mocha.jspackages/bruno-app/src/themes/light/light-pastel.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/themes/dark/catppuccin-macchiato.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/WorkspaceHome/index.jspackages/bruno-app/src/themes/dark/catppuccin-frappe.jspackages/bruno-app/src/themes/light/light-monochrome.jspackages/bruno-app/src/components/RequestTabs/RequestTab/index.jspackages/bruno-app/src/providers/ReduxStore/slices/tabs.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/themes/light/catppuccin-latte.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/themes/schema/oss.jspackages/bruno-app/src/themes/dark/nord.jspackages/bruno-app/src/themes/light/light.jspackages/bruno-app/src/providers/ReduxStore/slices/app.jspackages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.jspackages/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.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/themes/dark/dark-pastel.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.jspackages/bruno-app/src/components/WorkspaceTabs/index.jspackages/bruno-app/src/components/Preferences/General/StyledWrapper.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/themes/dark/catppuccin-mocha.jspackages/bruno-app/src/themes/light/light-pastel.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/themes/dark/catppuccin-macchiato.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/WorkspaceHome/index.jspackages/bruno-app/src/themes/dark/catppuccin-frappe.jspackages/bruno-app/src/themes/light/light-monochrome.jspackages/bruno-app/src/components/RequestTabs/RequestTab/index.jspackages/bruno-app/src/providers/ReduxStore/slices/tabs.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/themes/light/catppuccin-latte.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/themes/schema/oss.jspackages/bruno-app/src/themes/dark/nord.jspackages/bruno-app/src/themes/light/light.jspackages/bruno-app/src/providers/ReduxStore/slices/app.jspackages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.jspackages/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.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/themes/dark/dark-pastel.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.jspackages/bruno-app/src/components/WorkspaceTabs/index.jspackages/bruno-app/src/components/Preferences/General/StyledWrapper.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/themes/dark/catppuccin-mocha.jspackages/bruno-app/src/themes/light/light-pastel.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/themes/dark/catppuccin-macchiato.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/WorkspaceHome/index.jspackages/bruno-app/src/themes/dark/catppuccin-frappe.jspackages/bruno-app/src/themes/light/light-monochrome.jspackages/bruno-app/src/components/RequestTabs/RequestTab/index.jspackages/bruno-app/src/providers/ReduxStore/slices/tabs.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/themes/light/catppuccin-latte.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/themes/schema/oss.jspackages/bruno-app/src/themes/dark/nord.jspackages/bruno-app/src/themes/light/light.jspackages/bruno-app/src/providers/ReduxStore/slices/app.jspackages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.jspackages/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.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/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.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/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.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/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 —closeprop correctly removed for tab-based preferences.Removing the modal-specific
closeprop 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 definetable.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
collectionis undefined. This aligns with similar patterns elsewhere in the codebase (e.g.,RequestTabPanel,CollectionItem).Minor: Line 54 uses
collection?.namebut the guard above already ensurescollectionis 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
checkedstate andonChangehandler logic properly maps the UI state to the underlyingconfig.auth.disabledfield.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-linkclass 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
preferencestab 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
preferencestab is correctly added to the permanent tabs during workspace initialization. This aligns with thePERMANENT_TABSconstant inWorkspaceTabs/index.js.packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js (1)
64-71: LGTM!The new
preferencescase 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
activeCollectionis undefined (e.g., for preferences tabs). This aligns with the early return inCollectionToolBar/index.jsat 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.bgaligns 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: 1properly 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). ThetabTypeAlreadyExistslogic correctly handles both cases—matching oncollectionUidequality whether it'sundefinedor 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.enabledis false ORcustomCaCertificate.filePathis 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 ofactivePreferencesTabstate 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.bgaddition usingcolors.MANTLEis consistent with the Catppuccin Latte palette and aligns with similar changes in other theme files.
651-657: LGTM!The
app.kbdblock 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.bgusingcolors.GRAY_1fits the Light Pastel theme's warm grayscale palette.packages/bruno-app/src/themes/dark/dark-monochrome.js (1)
421-424: LGTM!The
thead.bgaddition usingcolors.GRAY_1is correct for the monochrome dark theme.packages/bruno-app/src/themes/light/light-monochrome.js (1)
419-422: LGTM!The
thead.bgproperly usescolors.GRAY_1for the monochrome light theme header background.packages/bruno-app/src/themes/dark/dark-pastel.js (1)
438-441: LGTM!The
thead.bgusingcolors.GRAY_1fits 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_1for the table header is consistent with the theme's color palette and aligns with the schema extension fortable.thead.bg.
659-664: No action needed —kbdis correctly positioned at the top level.The
kbdobject is a sibling ofapp, not nested within it. Line 659 closes theappblock with},, andkbdbegins on line 660 at the same indentation level. This matches the schema definition inoss.js(line 1188), wherekbdis 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
bgoptional in therequiredarray. 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_2is appropriate for the dark VS Code theme.packages/bruno-app/src/themes/dark/catppuccin-frappe.js (1)
435-436: LGTM!Using
colors.MANTLEfor 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.MANTLEfor 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.MANTLEproperly uses the theme's palette constant and aligns with other theme files.However, this file appears to be missing the
app.kbdstyling block that was added todark.js,light.js, andnord.jsin this PR. Please verify ifapp.kbdshould 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
#292929provides appropriate contrast for the dark theme header background.
685-691: LGTM on the kbd styling block.The
app.kbdaddition properly uses palette references forcolorandborderwhile 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
#f8f9fais 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.NORD1to maintain consistency with the Nord palette.
packages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.js
Outdated
Show resolved
Hide resolved
| 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); |
There was a problem hiding this comment.
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.
| 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.
| }, | ||
| kbd: { | ||
| bg: '#3f3f3f', | ||
| color: colors.TEXT, | ||
| border: colors.BORDER | ||
| } |
There was a problem hiding this comment.
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.
| }, | ||
| 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' |
There was a problem hiding this comment.
Schema structure mismatch with theme implementations.
Two issues:
-
Location:
kbdis defined at the root level here, but theme files (e.g.,light/vscode.js,dark/vscode.js) place it underapp.kbd. This will fail validation. -
Required constraint: Adding
kbdto the rootrequiredarray will break themes that don't implement it (e.g.,catppuccin-frappe.js,catppuccin-mocha.jsin this PR).
Consider either:
- Moving
kbdinside theappschema definition, or - Updating all theme files to place
kbdat 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.
8894b69 to
d12cc2b
Compare
There was a problem hiding this comment.
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.errorwill never execute.
console.log()returnsundefined, so the&&short-circuits andtoast.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'shandlePreferencesClick.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
activeWorkspaceUidis 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?.namecan safely becollection.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 togetTabPanel.The switch statement has no default case. If an unexpected
tabvalue is passed, this returnsundefinedwhich 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, andtabIndexattributes required for full accessibility compliance. Thearia-labelledbyon the tabpanel (line 108) references${tab}-tab, but no tab has a matchingid.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
📒 Files selected for processing (38)
packages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/General/StyledWrapper.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/components/Preferences/Keybindings/StyledWrapper.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/Preferences/index.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.jspackages/bruno-app/src/components/RequestTabs/RequestTab/index.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/StatusBar/index.jspackages/bruno-app/src/components/Table/StyledWrapper.jspackages/bruno-app/src/components/WorkspaceHome/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/WorkspaceTabs/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/providers/Hotkeys/index.jspackages/bruno-app/src/providers/ReduxStore/slices/app.jspackages/bruno-app/src/providers/ReduxStore/slices/tabs.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.jspackages/bruno-app/src/themes/dark/catppuccin-frappe.jspackages/bruno-app/src/themes/dark/catppuccin-macchiato.jspackages/bruno-app/src/themes/dark/catppuccin-mocha.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/themes/dark/dark-pastel.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/themes/dark/nord.jspackages/bruno-app/src/themes/dark/vscode.jspackages/bruno-app/src/themes/light/catppuccin-latte.jspackages/bruno-app/src/themes/light/light-monochrome.jspackages/bruno-app/src/themes/light/light-pastel.jspackages/bruno-app/src/themes/light/light.jspackages/bruno-app/src/themes/light/vscode.jspackages/bruno-app/src/themes/schema/oss.jspackages/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()notfunc ()
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.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/components/StatusBar/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/Hotkeys/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/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.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/components/StatusBar/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/Hotkeys/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/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.jspackages/bruno-app/src/themes/dark/dark.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaceTabs.jspackages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.jspackages/bruno-app/src/providers/App/useIpcEvents.jspackages/bruno-app/src/components/RequestTabPanel/index.jspackages/bruno-app/src/pages/Bruno/index.jspackages/bruno-app/src/components/StatusBar/index.jspackages/bruno-app/src/themes/dark/dark-monochrome.jspackages/bruno-app/src/providers/Hotkeys/index.jspackages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/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.bgproperty. The color value#292929is 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_1constant 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
focusWorkspaceTabhas been removed.
20-26: Selectors are well-structured.Selector pattern is consistent with the rest of the codebase. Deriving
activeTabviafind()is appropriate here.
37-51: Edge case: no-op when no active workspace on home page.When
showHomePageis true butactiveWorkspaceUidis 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
focusWorkspaceTabhas been removed.
34-44: Good refactor usinguseStore()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 tostore.getState().packages/bruno-app/src/components/WorkspaceTabs/WorkspaceTab/index.js (1)
7-11: LGTM!Clean extension of the
TAB_ICONSmapping to support the new preferences tab type. TheIconSettingsicon is a sensible choice for preferences.packages/bruno-app/src/pages/Bruno/index.js (1)
126-128: LGTM!The expanded condition ensures
WorkspaceHomerenders 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
showHomePageis true butactiveWorkspaceTabUidis falsy, andactiveTabUidexists, 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
useDispatchhook 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 customCheckboxcomponent 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
closeprop 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
useSelectoranddispatch.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.
| import WorkspaceHome from 'components/WorkspaceHome'; | ||
| import Preferences from 'components/Preferences'; |
There was a problem hiding this comment.
🧩 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.jsRepository: 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.
refactor: remove preferences tab from permanent tabs and update tab label handling fix: comment Co-authored-by: Sid <siddharth@usebruno.com>
6c469f0 to
3e72478
Compare
There was a problem hiding this comment.
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 existingexamples.urlBar.bgandexamples.table.thead.bgvalues in this file, ensuring visual consistency.Optional: Consider extracting
#292929into thepaletteorcolorsobject (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
collectionis falsy or lacks anitemsarray—solid addition.Two minor observations:
Return value inconsistency: This now returns
nullfor invalid input butundefinedwhen the item isn't found (via lodashfind). Both are falsy, so unlikely to break callers, but worth noting.Similar functions lack this guard:
findItemInCollectionByPathname,findItemInCollectionByItemUid,findParentItemInCollectionByPathname, andfindParentItemInCollectionall accesscollection.itemsdirectly 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:
idattribute (e.g.,id="general-tab") — the panel referencesaria-labelledby={tab}-tabbut there's no matching idaria-selectedto indicate active statetabindexfor 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.
…eferences and ProxySettings
5f8e2c5 to
01f435a
Compare
* 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>
Description
This PR implements the logic of changing the preference modal to a tab behavior
JIRA
Contribution Checklist:
Summary by CodeRabbit
New Features
UI Improvements
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.