Skip to content

feat: add manual save toggle for browser extension#2693

Merged
MohamedBassem merged 4 commits intokarakeep-app:mainfrom
keslerm:feat/bookmark-autosave-toggle
Apr 20, 2026
Merged

feat: add manual save toggle for browser extension#2693
MohamedBassem merged 4 commits intokarakeep-app:mainfrom
keslerm:feat/bookmark-autosave-toggle

Conversation

@keslerm
Copy link
Copy Markdown
Contributor

@keslerm keslerm commented Apr 11, 2026

I tried to keep this intentionally light only including the options that can be saved on the initial create bookmark call (no tags/lists) but could add those as well.

Fixes #2692

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Adds new autoSave setting (default true), an "Auto-save on open" toggle to OptionsPage, and refactors SavePage to wait for settings, introduce pendingBookmark and hasCheckedRequest, and either auto-create bookmarks or show a confirmation/editor when auto-save is disabled.

Changes

Cohort / File(s) Summary
Settings Configuration
apps/browser-extension/src/utils/settings.ts
Adds autoSave: boolean to the Zod settings schema with default true and updates DEFAULT_SETTINGS.
Options UI
apps/browser-extension/src/OptionsPage.tsx
Inserts "Auto-save on open" Switch bound to settings.autoSave, updates settings via setSettings on toggle, and adds helper text; placed between <hr /> dividers near Server Address.
Save flow / SavePage
apps/browser-extension/src/SavePage.tsx
Defers loading bookmark request until plugin settings are available; introduces pendingBookmark and hasCheckedRequest; replaces previous runSave with loadBookmarkRequest reading session storage or deriving from active tab; auto-creates bookmark when settings.autoSave is true, otherwise renders confirmation/editor UI with notes and manual "Save Bookmark" action; tracks request validation completion explicitly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 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 'feat: add manual save toggle for browser extension' clearly summarizes the main change—adding a toggle to enable manual saving instead of auto-save—which aligns with the changeset's modifications across OptionsPage, SavePage, and settings.
Description check ✅ Passed The description mentions keeping changes minimal to initial bookmark creation options and references the fixed issue #2692, which relates to the manual save toggle feature implemented in the changeset.
Linked Issues check ✅ Passed The PR fully addresses issue #2692 requirements: it adds a user-controllable autoSave option in settings [settings.ts], provides UI toggle in OptionsPage, and implements manual confirmation/save flow when auto-save is disabled [SavePage].
Out of Scope Changes check ✅ Passed All changes are within scope: the autoSave setting, OptionsPage toggle UI, and SavePage confirmation flow directly support the manual save toggle feature requested in issue #2692 without introducing unrelated modifications.

✏️ 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 Apr 11, 2026

Greptile Summary

This PR adds an "Auto-save on open" toggle to the browser extension. When disabled, the extension shows a confirmation panel (with editable title and notes fields) before saving, instead of immediately creating the bookmark on popup open. The implementation correctly separates settings loading from bookmark request loading using two useEffect hooks, and the state machine logic is sound.

Confidence Score: 5/5

Safe to merge; all findings are P2 style/UX suggestions that don't affect correctness.

Both open findings are minor: a cosmetic truncation bug and a missing cancel button. The core state logic (two-effect split, idle-state guard, settings schema) is correct and the feature works as described.

apps/browser-extension/src/SavePage.tsx — text truncation and cancel-button UX

Important Files Changed

Filename Overview
apps/browser-extension/src/SavePage.tsx Adds manual-save confirmation UI and splits the original single useEffect into two (load request + auto-save trigger); logic is correct but has a minor text-truncation issue and a missing cancel button in the confirmation panel.
apps/browser-extension/src/OptionsPage.tsx Adds the Auto-save toggle switch following the same pattern as the existing Show count badge / Use badge cache switches — clean and consistent.
apps/browser-extension/src/utils/settings.ts Adds autoSave: z.boolean().default(true) to the zod schema and DEFAULT_SETTINGS; straightforward and consistent with existing fields.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/browser-extension/src/SavePage.tsx
Line: 174-177

Comment:
**Trailing ellipsis appended unconditionally**

`"..."` is always concatenated even when `pendingBookmark.text` is shorter than 150 characters, producing output like `"short text..."`. Use conditional logic or the built-in CSS `truncate` approach.

```suggestion
              <p className="text-muted-foreground text-xs">
                {pendingBookmark.text.length > 150
                  ? pendingBookmark.text.substring(0, 150) + "..."
                  : pendingBookmark.text}
              </p>
```

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/browser-extension/src/SavePage.tsx
Line: 209-212

Comment:
**No way to dismiss the confirmation UI**

The manual-save panel has only a "Save Bookmark" button. Users who opened the extension by accident, or who change their mind, have no cancel path short of closing the popup. A "Cancel" / "Dismiss" button would complete the confirmation UX.

```suggestion
            <div className="flex gap-2">
              <Button variant="outline" onClick={() => window.close()} className="w-full">
                Cancel
              </Button>
              <Button onClick={handleManualSave} className="w-full">
                Save Bookmark
              </Button>
            </div>
```

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

Reviews (1): Last reviewed commit: "feat: add manual save toggle for browser..." | Re-trigger Greptile

Comment thread apps/browser-extension/src/SavePage.tsx
Comment on lines +209 to +212
</div>
<Button onClick={handleManualSave} className="w-full">
Save Bookmark
</Button>
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 No way to dismiss the confirmation UI

The manual-save panel has only a "Save Bookmark" button. Users who opened the extension by accident, or who change their mind, have no cancel path short of closing the popup. A "Cancel" / "Dismiss" button would complete the confirmation UX.

Suggested change
</div>
<Button onClick={handleManualSave} className="w-full">
Save Bookmark
</Button>
<div className="flex gap-2">
<Button variant="outline" onClick={() => window.close()} className="w-full">
Cancel
</Button>
<Button onClick={handleManualSave} className="w-full">
Save Bookmark
</Button>
</div>
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/browser-extension/src/SavePage.tsx
Line: 209-212

Comment:
**No way to dismiss the confirmation UI**

The manual-save panel has only a "Save Bookmark" button. Users who opened the extension by accident, or who change their mind, have no cancel path short of closing the popup. A "Cancel" / "Dismiss" button would complete the confirmation UX.

```suggestion
            <div className="flex gap-2">
              <Button variant="outline" onClick={() => window.close()} className="w-full">
                Cancel
              </Button>
              <Button onClick={handleManualSave} className="w-full">
                Save Bookmark
              </Button>
            </div>
```

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

🧹 Nitpick comments (1)
apps/browser-extension/src/SavePage.tsx (1)

23-23: Confusing variable rename from hook.

The hook returns isPending: isInit, where isInit is false initially and becomes true after settings load. Renaming it to isSettingsLoaded makes the usage at line 102 (if (!isSettingsLoaded) return;) read correctly, but the original isPending name in the hook is misleading—it actually means "isInitialized", not "is currently pending".

Consider renaming the property in usePluginSettings from isPending to isLoaded or isInitialized to avoid confusion for future maintainers.

♻️ Suggested hook return value rename in settings.ts
-  return { settings, setSettings, isPending: isInit };
+  return { settings, setSettings, isLoaded: isInit };

Then in SavePage:

-  const { settings, isPending: isSettingsLoaded } = usePluginSettings();
+  const { settings, isLoaded: isSettingsLoaded } = usePluginSettings();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/browser-extension/src/SavePage.tsx` at line 23, Rename the hook return
property to reflect its semantics: update usePluginSettings to return isLoaded
or isInitialized instead of isPending (where the hook currently maps isInit ->
isPending), and update all call sites like SavePage that destructure
usePluginSettings (currently using isSettingsLoaded) to use the new name
consistently; specifically change the property in the hook implementation in
settings.ts (the place that defines isInit) and replace occurrences of isPending
in consumers (e.g., the destructure in SavePage that now reads const { settings,
isPending: isSettingsLoaded } = usePluginSettings()) so they destructure the new
name or keep their local alias (e.g., const { settings, isLoaded:
isSettingsLoaded } = usePluginSettings()) to retain existing usage semantics.
🤖 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/browser-extension/src/SavePage.tsx`:
- Around line 174-178: The UI always appends "..." to pendingBookmark.text even
when shorter than 150 chars; update the render in SavePage.tsx (the
pendingBookmark and BookmarkTypes.TEXT branch) to conditionally append the
ellipsis only when pendingBookmark.text.length > 150, e.g., render the truncated
substring when length > 150 and the full text otherwise so users aren't misled.

---

Nitpick comments:
In `@apps/browser-extension/src/SavePage.tsx`:
- Line 23: Rename the hook return property to reflect its semantics: update
usePluginSettings to return isLoaded or isInitialized instead of isPending
(where the hook currently maps isInit -> isPending), and update all call sites
like SavePage that destructure usePluginSettings (currently using
isSettingsLoaded) to use the new name consistently; specifically change the
property in the hook implementation in settings.ts (the place that defines
isInit) and replace occurrences of isPending in consumers (e.g., the destructure
in SavePage that now reads const { settings, isPending: isSettingsLoaded } =
usePluginSettings()) so they destructure the new name or keep their local alias
(e.g., const { settings, isLoaded: isSettingsLoaded } = usePluginSettings()) to
retain existing usage semantics.
🪄 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: db560b7f-6234-4e76-8696-8335ab1d3e88

📥 Commits

Reviewing files that changed from the base of the PR and between 700359e and ff55f38.

📒 Files selected for processing (3)
  • apps/browser-extension/src/OptionsPage.tsx
  • apps/browser-extension/src/SavePage.tsx
  • apps/browser-extension/src/utils/settings.ts

Comment thread apps/browser-extension/src/SavePage.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.

Caution

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

⚠️ Outside diff range comments (1)
apps/browser-extension/src/SavePage.tsx (1)

57-66: ⚠️ Potential issue | 🟡 Minor

Unhandled parse exception may crash the component.

zNewBookmarkRequestSchema.parse(req) at line 65 throws if the stored request is malformed or corrupted. This would result in an unhandled promise rejection, potentially leaving users with a broken popup.

🛡️ Proposed fix to handle parse failure gracefully
     async function getNewBookmarkRequestFromBackgroundScriptIfAny(): Promise<ZNewBookmarkRequest | null> {
       const { [NEW_BOOKMARK_REQUEST_KEY_NAME]: req } =
         await chrome.storage.session.get(NEW_BOOKMARK_REQUEST_KEY_NAME);
       if (!req) {
         return null;
       }
       // Delete the request immediately to avoid issues with lingering values
       await chrome.storage.session.remove(NEW_BOOKMARK_REQUEST_KEY_NAME);
-      return zNewBookmarkRequestSchema.parse(req);
+      const parsed = zNewBookmarkRequestSchema.safeParse(req);
+      if (!parsed.success) {
+        console.warn("Invalid bookmark request in session storage:", parsed.error);
+        return null;
+      }
+      return parsed.data;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/browser-extension/src/SavePage.tsx` around lines 57 - 66, The call to
zNewBookmarkRequestSchema.parse(req) inside
getNewBookmarkRequestFromBackgroundScriptIfAny can throw on malformed data; wrap
the parse in a try/catch inside that function, catch parsing errors, log or
report the error (e.g., via console.error or a telemetry/processLogger), and
return null so the component won't crash; keep the existing removal of
NEW_BOOKMARK_REQUEST_KEY_NAME and ensure the function returns null on parse
failure instead of letting the exception bubble.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/browser-extension/src/SavePage.tsx`:
- Around line 57-66: The call to zNewBookmarkRequestSchema.parse(req) inside
getNewBookmarkRequestFromBackgroundScriptIfAny can throw on malformed data; wrap
the parse in a try/catch inside that function, catch parsing errors, log or
report the error (e.g., via console.error or a telemetry/processLogger), and
return null so the component won't crash; keep the existing removal of
NEW_BOOKMARK_REQUEST_KEY_NAME and ensure the function returns null on parse
failure instead of letting the exception bubble.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e944873f-3a08-45fa-b7cc-c59539ac320d

📥 Commits

Reviewing files that changed from the base of the PR and between ff55f38 and c2f1cad.

📒 Files selected for processing (1)
  • apps/browser-extension/src/SavePage.tsx

@MohamedBassem MohamedBassem merged commit c397501 into karakeep-app:main Apr 20, 2026
5 of 6 checks passed
@MohamedBassem
Copy link
Copy Markdown
Collaborator

Thank you!

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.

feat: Add option to disable auto saving of bookmarks in browser extensions

2 participants