Skip to content

feat(web): auto-add bookmark to list on selection#2629

Open
xingzihai wants to merge 7 commits intokarakeep-app:mainfrom
xingzihai:feat/auto-add-to-list-clean
Open

feat(web): auto-add bookmark to list on selection#2629
xingzihai wants to merge 7 commits intokarakeep-app:mainfrom
xingzihai:feat/auto-add-to-list-clean

Conversation

@xingzihai
Copy link
Copy Markdown
Contributor

Fixes #2604

Summary

Automatically add bookmark to the selected list when user clicks on a list item in the ManageListsModal.

Changes

  • BookmarkListSelector now triggers addToList when a list is selected
  • Improved UX: users don't need to click "Add" button separately
  • Added loading state and prevented duplicate submission

Testing

  • Tested locally with list selection
  • Verified bookmark is added correctly

Remove the 'Add' button from Manage Lists modal. When a user selects
a list from the dropdown, the bookmark is now automatically added to
that list, simplifying the user experience.

Users can still remove a bookmark from a list by clicking the X button
next to the list name.

Fixes karakeep-app#2604
…sModal

- Added isPending state from useAddBookmarkToList hook
- Added duplicate submission prevention in onChange handler
- Added disabled prop to BookmarkListSelector component
- Fix incorrect indentation of onSuccess and onError callbacks
- Add trailing newline at end of file
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a9da0ea3-eb02-4494-9033-76bbd4aba46a

📥 Commits

Reviewing files that changed from the base of the PR and between 3e555c2 and e13aac1.

📒 Files selected for processing (1)
  • apps/web/components/dashboard/bookmarks/ManageListsModal.tsx

Walkthrough

Removed the form/zod/react-hook-form submit flow from ManageListsModal; adding to a list now happens immediately via BookmarkListSelector.onChange. BookmarkListSelector gained a new disabled prop forwarded to its trigger button.

Changes

Cohort / File(s) Summary
Manage Lists Modal
apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
Removed react-hook-form/zod form wiring, Form/FormField scaffolding, submit handler and the type="submit" Add button. Selection now triggers addToList({ bookmarkId, listId }) directly from BookmarkListSelector.onChange; removed form.resetField("listId") calls. Dialog header title changed to t("actions.manage_lists"). List path lookup now uses allLists?.getPathById(list.id) with fallback to list.name. Footer actions reduced to Close and Archive; list item delete button includes aria-label={t("actions.remove_bookmark")}.
Bookmark List Selector
apps/web/components/dashboard/lists/BookmarkListSelector.tsx
Added disabled?: boolean prop (default false) and forwarded it to the selector trigger Button (disabled={disabled}) to control interactivity; selection/filtering and fetching logic unchanged.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing auto-add functionality when a bookmark is selected in a list, which aligns with the primary objective of the PR.
Description check ✅ Passed The description clearly explains the feature implementation, references the linked issue (#2604), and outlines the key changes and testing performed.
Linked Issues check ✅ Passed The PR successfully addresses issue #2604 by removing the explicit 'Add' button, implementing immediate bookmark addition on list selection, and maintaining the ability to remove lists afterward via delete controls.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked objective: removing form-based submission flow, enabling auto-add on selection, and improving accessibility with proper aria-labels. No extraneous modifications detected.

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


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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 27, 2026

Greptile Summary

This PR simplifies the "Manage Lists" modal by removing the react-hook-form/zod form wrapper and "Add" button, and instead fires addToList immediately when the user picks a list from BookmarkListSelector. A disabled prop is added to BookmarkListSelector to prevent re-opening the combobox while the mutation is in flight.\n\n- ManageListsModal: form, zodResolver, and the submit button are removed; onChange now calls addToList directly, and disabled={isAddingToListPending} blocks re-selection while the request is pending.\n- BookmarkListSelector: new optional disabled prop forwarded to the trigger Button.\n- Since value is no longer passed to BookmarkListSelector, the selector always displays the placeholder text — the selector effectively resets after each selection, which is the correct UX for an auto-add pattern.\n- No functional regressions found; two minor style nits remain (redundant in-flight guard and a missing trailing newline).

Confidence Score: 5/5

Safe to merge — no logic bugs or data-integrity concerns; only P2 style feedback remains.

All findings are P2 (missing newline and a harmless redundant guard). The core auto-add logic, the duplicate-submission prevention, and the disabled state handling are all correct. The removal of the form layer introduces no regressions.

No files require special attention.

Important Files Changed

Filename Overview
apps/web/components/dashboard/bookmarks/ManageListsModal.tsx Removed react-hook-form/zod wrapper and "Add" button; now calls addToList immediately when the user selects a list. Logic is correct, minor style nits only (missing newline, redundant guard).
apps/web/components/dashboard/lists/BookmarkListSelector.tsx Added optional disabled prop that gates the popover trigger button; clean, minimal change with no issues.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
Line: 183

Comment:
**Missing newline at end of file**

The file is missing a trailing newline. Most editors and linters expect a newline at the end of every text file (POSIX convention), and the diff explicitly shows `\ No newline at end of file`.

```suggestion
}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
Line: 142-149

Comment:
**Redundant in-flight guard**

The `if (!isAddingToListPending)` check inside `onChange` is already made unreachable by `disabled={isAddingToListPending}` on the trigger button — a disabled button won't open the popover, so `onChange` can't fire while the mutation is in flight. You can simplify to a direct call:

```suggestion
            onChange={(listId) => {
              addToList({
                bookmarkId: bookmarkId,
                listId: listId,
              });
            }}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "style: fix indentation in useAddBookmark..." | Re-trigger Greptile

),
};
}
} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Missing newline at end of file

The file is missing a trailing newline. Most editors and linters expect a newline at the end of every text file (POSIX convention), and the diff explicitly shows \ No newline at end of file.

Suggested change
}
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
Line: 183

Comment:
**Missing newline at end of file**

The file is missing a trailing newline. Most editors and linters expect a newline at the end of every text file (POSIX convention), and the diff explicitly shows `\ No newline at end of file`.

```suggestion
}
```

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +142 to +149
onChange={(listId) => {
if (!isAddingToListPending) {
addToList({
bookmarkId: bookmarkId,
listId: listId,
});
}
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Redundant in-flight guard

The if (!isAddingToListPending) check inside onChange is already made unreachable by disabled={isAddingToListPending} on the trigger button — a disabled button won't open the popover, so onChange can't fire while the mutation is in flight. You can simplify to a direct call:

Suggested change
onChange={(listId) => {
if (!isAddingToListPending) {
addToList({
bookmarkId: bookmarkId,
listId: listId,
});
}
}}
onChange={(listId) => {
addToList({
bookmarkId: bookmarkId,
listId: listId,
});
}}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
Line: 142-149

Comment:
**Redundant in-flight guard**

The `if (!isAddingToListPending)` check inside `onChange` is already made unreachable by `disabled={isAddingToListPending}` on the trigger button — a disabled button won't open the popover, so `onChange` can't fire while the mutation is in flight. You can simplify to a direct call:

```suggestion
            onChange={(listId) => {
              addToList({
                bookmarkId: bookmarkId,
                listId: listId,
              });
            }}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/components/dashboard/bookmarks/ManageListsModal.tsx`:
- Around line 139-152: The selection can be triggered while membership data is
still loading; update the ManageListsModal usage of BookmarkListSelector so
interactions are disabled during loading and the onChange guard also checks
loading. Specifically, change the disabled prop to combine isAddingToListPending
|| isLoading, and update the onChange callback to return early unless both
!isAddingToListPending and !isLoading before calling addToList(bookmarkId,
listId); keep references to BookmarkListSelector, hideBookmarkIds
(alreadyInList?.lists.map), onChange, isAddingToListPending, isLoading,
addToList, and bookmarkId so the fix is easy to locate.
- Around line 117-120: The code assumes allLists.getPathById(list.id) always
returns an array and directly calls .map(...), which will crash if it returns
undefined/null; update the render in ManageListsModal to first store the result
of allLists.getPathById(list.id) (or call it into a local variable), guard it
with a null check (e.g., if path is falsy render a safe fallback like list.name
or an empty string), and only call path.map(...) and .join(" / ") when path is
an array—this prevents crashes for stale/missing paths.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4058e129-f284-4a71-92d8-5d7f26364ff8

📥 Commits

Reviewing files that changed from the base of the PR and between 53a4598 and 227cb54.

📒 Files selected for processing (2)
  • apps/web/components/dashboard/bookmarks/ManageListsModal.tsx
  • apps/web/components/dashboard/lists/BookmarkListSelector.tsx

- Add trailing newline at end of file
- Remove redundant in-flight guard check (disabled prop handles it)
- Add guard for getPathById to prevent crash on stale cache
- Disable interactions while list membership data is loading
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/components/dashboard/bookmarks/ManageListsModal.tsx`:
- Around line 103-105: Replace the hardcoded modal title in
ManageListsModal.tsx: instead of <DialogTitle>Manage Lists</DialogTitle> call
the translation function used elsewhere (t) — e.g. <DialogTitle>{t("Manage
Lists")}</DialogTitle> (or use the existing i18n key you use for list headings,
like t("manageLists") if that key exists) so the DialogTitle uses localized
text; ensure t is in scope where DialogTitle is rendered.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b4160672-40de-4c88-804f-cd972a8d9093

📥 Commits

Reviewing files that changed from the base of the PR and between 227cb54 and 4a07721.

📒 Files selected for processing (1)
  • apps/web/components/dashboard/bookmarks/ManageListsModal.tsx

Copy link
Copy Markdown
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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/components/dashboard/bookmarks/ManageListsModal.tsx`:
- Around line 124-134: The ActionButton that renders the X icon is icon-only and
lacks an accessible name; add an aria-label (or equivalent sr-only text) to the
ActionButton in ManageListsModal so screen readers announce its purpose — e.g.,
set aria-label={`Remove bookmark from ${list.name}`} or a generic
aria-label="Remove bookmark" on the ActionButton that calls deleteFromList({
bookmarkId, listId: list.id }) to make the remove action accessible.
- Around line 109-121: The list rows are currently hidden because the whole UL
is gated on allLists; instead, render the rows unconditionally using
alreadyInList.lists and only use allLists when available to compute the display
path. Modify the render in ManageListsModal.tsx so that you iterate over
alreadyInList?.lists (or alreadyInList.lists) regardless of allLists, call
allLists?.getPathById(list.id) (optional chaining) to build the path if present,
and fall back to rendering list.name when getPathById returns undefined; keep
the existing remove control/handlers intact so they remain visible when the tree
query is empty.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b8b6565a-5b47-40ac-a8d2-0d1dca6a2e85

📥 Commits

Reviewing files that changed from the base of the PR and between 6d990af and 3e555c2.

📒 Files selected for processing (1)
  • apps/web/components/dashboard/bookmarks/ManageListsModal.tsx

- Add aria-label to remove button for accessibility (CodeRabbit comment 3006737430)
- Remove allLists gating to allow list.name fallback to render (CodeRabbit comment 3006737429)
- Use optional chaining for path lookup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete the 'Add' Button from Manage Lists

1 participant