Skip to content

feat(app): add "Ignore Folder" sidebar context menu item (closes #1890)#8398

Open
justadityaraj wants to merge 1 commit into
usebruno:mainfrom
justadityaraj:feat/ignore-folder-menu-item
Open

feat(app): add "Ignore Folder" sidebar context menu item (closes #1890)#8398
justadityaraj wants to merge 1 commit into
usebruno:mainfrom
justadityaraj:feat/ignore-folder-menu-item

Conversation

@justadityaraj

@justadityaraj justadityaraj commented Jun 27, 2026

Copy link
Copy Markdown

Description

Adds an Ignore Folder item to the folder context menu in the sidebar, closing #1890.

Today the only way to add a folder to a collection's ignore list is to hand-edit bruno.json. This adds a right-click action that does it from the UI:

  • Right-click a folder → Ignore Folder
  • The folder's collection-relative path is appended to brunoConfig.ignore and persisted to bruno.json
  • The folder is removed from the sidebar immediately; bruno.json keeps it ignored on subsequent loads

The path is stored with forward slashes so the value stays portable when bruno.json is committed and shared across operating systems.

How it works

  • getCollectionRelativePath(collectionPathname, itemPathname) derives the portable relative path
  • addPathToIgnoreList(brunoConfig, relativePath) returns a new config with the path added (immutable, dedupes)
  • The menu handler dispatches the existing updateBrunoConfig thunk to persist, then deleteItem to drop the folder from the tree

Tests

Added utils/collections/ignore.spec.js covering relative-path derivation (nested paths, Windows separators, trailing slashes, root/empty inputs) and ignore-list merging (append, create, dedupe, empty paths, immutability). 11 assertions, all passing.

Notes

  • Only shown for folders.
  • Reuses existing persistence (updateBrunoConfig) and tree-removal (deleteItem) machinery; no watcher changes.

Summary by CodeRabbit

  • New Features

    • Added an Ignore Folder action to the folder menu in the sidebar.
    • Ignored folders are now added to the app’s ignore list and removed from view immediately.
  • Bug Fixes

    • Improved path handling for folders, including nested paths, trailing slashes, and Windows-style separators.
    • Prevents duplicate ignore entries and avoids changes when no valid path is available.
  • Tests

    • Added coverage for ignore-path handling and ignore-list updates.

Folders can now be added to a collection's ignore list from the sidebar
context menu instead of hand-editing bruno.json. The folder's
collection-relative path (stored with forward slashes so it stays
portable across operating systems) is written to brunoConfig.ignore via
the existing updateBrunoConfig flow, and the folder is removed from the
sidebar immediately.

Adds getCollectionRelativePath and addPathToIgnoreList helpers with unit
tests covering nested paths, Windows separators, trailing slashes, and
ignore-list dedupe/immutability.

Closes usebruno#1890
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Adds an "Ignore Folder" context menu action to the sidebar's CollectionItem. Two new utility functions (getCollectionRelativePath, addPathToIgnoreList) handle path normalization and config mutation. The handler updates brunoConfig and removes the folder from the UI. Tests cover both utilities.

Changes

Ignore Folder Feature

Layer / File(s) Summary
Ignore path utilities and tests
packages/bruno-app/src/utils/collections/ignore.js, packages/bruno-app/src/utils/collections/ignore.spec.js
New file exports getCollectionRelativePath (POSIX normalization, relative path derivation) and addPathToIgnoreList (immutable config update); full Jest suite covers edge cases, Windows paths, duplicates, and immutability.
Sidebar CollectionItem wiring
packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
Imports updateBrunoConfig, deleteItem, IconEyeOff; adds handleIgnoreFolder that computes relative path, updates config, dispatches delete, and shows toasts; extends folder context menu with the new entry.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • bijin-bruno

🗂️ A folder once seen, now gone from sight,
With a click it fades into the night.
brunoConfig quietly updated in place,
The sidebar refreshed with elegant grace.
IconEyeOff winks — out of mind, out of space! 👁️‍🗨️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding an Ignore Folder context menu action in the app sidebar.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

Inline comments:
In
`@packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js`:
- Around line 347-352: The Ignore Folder flow in CollectionItem should not reuse
the Delete action path, because dispatch(deleteItem(...)) triggers
renderer:delete-item and can physically remove the folder instead of only hiding
it. Update the post-update cleanup in CollectionItem to use the same UI-removal
path as an ignore action, and make sure the call matches the deleteItem thunk
signature only if you keep that helper; otherwise switch to a dedicated
non-destructive tree-removal action after updateBrunoConfig succeeds.
- Around line 346-347: The update is rebuilding from a stale collection config
because CollectionItem reads collection?.brunoConfig directly before calling
updateBrunoConfig(). Fix it by using the latest config source in this flow, such
as deriving from the current ignore state or from the result of the previous
update, and ensure addPathToIgnoreList() always merges into the most recent
brunoConfig before dispatching updateBrunoConfig(). This should be adjusted in
the CollectionItem logic where the ignore action is triggered so consecutive
folder ignores cannot overwrite earlier changes.

In `@packages/bruno-app/src/utils/collections/ignore.js`:
- Around line 10-23: The fallback in getCollectionRelativePath is returning a
normalized absolute target path when itemPathname is not actually under the
collection root. Update the function so it only returns a relative suffix when
target equals root or starts with root/, and otherwise returns an empty string.
Keep the path normalization in toPosix, but avoid persisting any
non-collection-relative value into brunoConfig.ignore.

In `@packages/bruno-app/src/utils/collections/ignore.spec.js`:
- Around line 3-28: The getCollectionRelativePath test suite is missing
regression coverage for paths that cannot be derived relative to the collection
root. Add cases in ignore.spec.js for a non-descendant item path and for a
case-only mismatch between the collection root and item path, asserting that
getCollectionRelativePath returns an empty string in both scenarios. Use the
existing getCollectionRelativePath helper to keep the new tests aligned with the
current path-normalization behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 120fcfd0-9eae-4694-816f-4f84269d529a

📥 Commits

Reviewing files that changed from the base of the PR and between 87f7426 and fe86d29.

📒 Files selected for processing (3)
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js
  • packages/bruno-app/src/utils/collections/ignore.js
  • packages/bruno-app/src/utils/collections/ignore.spec.js

Comment on lines +346 to +347
const brunoConfig = addPathToIgnoreList(collection?.brunoConfig, relativePath);
dispatch(updateBrunoConfig(brunoConfig, collectionUid))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

This merge starts from stale brunoConfig.

Line 346 reads collection?.brunoConfig from Redux, but updateBrunoConfig() only persists over IPC and does not update that state slice. Ignoring folder B right after folder A in the same session will rebuild from the pre-change config and can drop A from bruno.json.

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

In
`@packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js`
around lines 346 - 347, The update is rebuilding from a stale collection config
because CollectionItem reads collection?.brunoConfig directly before calling
updateBrunoConfig(). Fix it by using the latest config source in this flow, such
as deriving from the current ignore state or from the result of the previous
update, and ensure addPathToIgnoreList() always merges into the most recent
brunoConfig before dispatching updateBrunoConfig(). This should be adjusted in
the CollectionItem logic where the ignore action is triggered so consecutive
folder ignores cannot overwrite earlier changes.

Comment on lines +347 to +352
dispatch(updateBrunoConfig(brunoConfig, collectionUid))
.then(() => {
// Remove the folder from the sidebar immediately; bruno.json keeps it
// ignored on subsequent loads.
dispatch(deleteItem({ itemUid: item.uid, collectionUid }));
toast.success(`Ignored folder: ${relativePath}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Don't use deleteItem to hide an ignored folder.

Line 351 dispatches the same thunk used by the Delete action, and that thunk invokes renderer:delete-item for the folder path. So once the call shape is corrected, Ignore Folder will physically delete the directory instead of just removing it from the tree. The current invocation is also passing { itemUid, collectionUid } even though the thunk signature is (itemUid, collectionUid), so the UI-removal step already rejects today.

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

In
`@packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js`
around lines 347 - 352, The Ignore Folder flow in CollectionItem should not
reuse the Delete action path, because dispatch(deleteItem(...)) triggers
renderer:delete-item and can physically remove the folder instead of only hiding
it. Update the post-update cleanup in CollectionItem to use the same UI-removal
path as an ignore action, and make sure the call matches the deleteItem thunk
signature only if you keep that helper; otherwise switch to a dedicated
non-destructive tree-removal action after updateBrunoConfig succeeds.

Comment on lines +10 to +23
export const getCollectionRelativePath = (collectionPathname, itemPathname) => {
if (!collectionPathname || !itemPathname) return '';

const toPosix = (p) => p.replace(/\\/g, '/').replace(/\/+$/, '');
const root = toPosix(collectionPathname);
const target = toPosix(itemPathname);

if (target === root) return '';
if (target.startsWith(`${root}/`)) {
return target.slice(root.length + 1);
}

return target;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Return '' when the path is not actually collection-relative.

Line 22 currently falls back to the normalized absolute target path. If itemPathname is outside the collection root, or only differs by case on a case-insensitive filesystem, this writes a machine-specific absolute path into brunoConfig.ignore even though the helper contract says unresolved paths should return ''. The config reader/writer carries ignore entries through as-is, so this would persist a non-portable value into bruno.json. As per path instructions, "Ensure that all code is OS-agnostic" and "Never assume case-sensitive or case-insensitive filesystems."

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

In `@packages/bruno-app/src/utils/collections/ignore.js` around lines 10 - 23, The
fallback in getCollectionRelativePath is returning a normalized absolute target
path when itemPathname is not actually under the collection root. Update the
function so it only returns a relative suffix when target equals root or starts
with root/, and otherwise returns an empty string. Keep the path normalization
in toPosix, but avoid persisting any non-collection-relative value into
brunoConfig.ignore.

Source: Path instructions

Comment on lines +3 to +28
describe('getCollectionRelativePath', () => {
it('returns the folder path relative to the collection root', () => {
expect(getCollectionRelativePath('/home/adi/my-collection', '/home/adi/my-collection/auth')).toBe('auth');
});

it('returns nested folder paths with forward slashes', () => {
expect(getCollectionRelativePath('/home/adi/my-collection', '/home/adi/my-collection/v1/users')).toBe('v1/users');
});

it('normalizes windows-style separators to forward slashes', () => {
expect(getCollectionRelativePath('C:\\Users\\adi\\coll', 'C:\\Users\\adi\\coll\\auth\\login')).toBe('auth/login');
});

it('tolerates a trailing slash on the collection path', () => {
expect(getCollectionRelativePath('/home/adi/coll/', '/home/adi/coll/auth')).toBe('auth');
});

it('returns an empty string when the item is the collection root', () => {
expect(getCollectionRelativePath('/home/adi/coll', '/home/adi/coll')).toBe('');
});

it('returns an empty string when inputs are missing', () => {
expect(getCollectionRelativePath('', '/home/adi/coll/auth')).toBe('');
expect(getCollectionRelativePath('/home/adi/coll', '')).toBe('');
});
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a regression for non-descendant and case-mismatch inputs.

The helper is documented to return '' when a relative path cannot be derived, but this suite never exercises an item outside the collection root or a case-only root/item mismatch. That leaves the portability edge case unprotected. As per coding guidelines, "Cover both the 'happy path' and the realistically problematic paths." As per path instructions, "Never assume case-sensitive or case-insensitive filesystems."

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

In `@packages/bruno-app/src/utils/collections/ignore.spec.js` around lines 3 - 28,
The getCollectionRelativePath test suite is missing regression coverage for
paths that cannot be derived relative to the collection root. Add cases in
ignore.spec.js for a non-descendant item path and for a case-only mismatch
between the collection root and item path, asserting that
getCollectionRelativePath returns an empty string in both scenarios. Use the
existing getCollectionRelativePath helper to keep the new tests aligned with the
current path-normalization behavior.

Sources: Coding guidelines, Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant