Skip to content

refactor: improve performance for common use cases#307

Merged
vitonsky merged 99 commits into
masterfrom
306-improve-performance-for-common-use-cases
Jun 8, 2026
Merged

refactor: improve performance for common use cases#307
vitonsky merged 99 commits into
masterfrom
306-improve-performance-for-common-use-cases

Conversation

@vitonsky

@vitonsky vitonsky commented May 22, 2026

Copy link
Copy Markdown
Member

Closes #306, closes #297

  • Fix everything in footer
  • Sync themes
  • (optionally) Introduce light control view for a tags and mutted selects
  • Review performance after chakra-ui migration
    • Standard scenaroius with tabs
    • Suggests for tags
    • Footer

Changes

  • Migrated to Chakra v3
  • Tags tree is refactored. Now tree is aria compatible and virtualized
  • Vaults list is now aria compatible
  • Tuned theme colors
  • Tabs that has not been active is not rendered anymore Do not load inactive tabs #297

Side changes

  • Configured Hot Module Reloading
  • Configured run in browser (for development mode only)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added fuzzy search for tags using Fuse.js
    • Implemented hierarchical tags tree visualization
    • New ListBox component for improved list selections
    • Support for IndexedDB as storage backend
  • UI Improvements

    • Upgraded to Chakra UI v3 with modernized component APIs
    • Repositioned toast notifications to top-right corner
    • Enhanced dialog and menu components throughout the app
    • Improved theme system with better color token organization
  • Performance

    • Optimized component rendering with memoization
    • Improved note list virtualization and rendering efficiency
    • Enhanced selector memoization for Redux state

@vitonsky vitonsky linked an issue May 22, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@vitonsky, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 27 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5db45929-5cff-460d-a9ba-22e3efd11d62

📥 Commits

Reviewing files that changed from the base of the PR and between 1c12e3c and eb951a0.

📒 Files selected for processing (1)
  • packages/app/src/state/redux/vaults/hooks.ts
📝 Walkthrough

Walkthrough

The PR updates app build/runtime wiring, migrates theme and component APIs to Chakra v3 patterns, and rewires notes, tags, settings, and renderer storage/telemetry flows.

Changes

Chakra v3 migration and runtime updates

Layer / File(s) Summary
Build and renderer scaffolding
packages/app/package.json, packages/app/scripts/webpack/*, packages/app/src/electron/*, packages/app/src/windows/main/renderer.tsx
Adds a serve script, Chakra typegen, HMR settings, Electron guards, runtime storage selection, and shared toaster mounting.
Theme system and recipes
packages/app/src/components/theme/*, packages/app/src/components/ui/*, packages/app/src/components/*ListBox*, packages/app/src/features/*Dialog*, packages/app/src/features/*Menu*, packages/app/src/features/*RichEditor*
Converts theme config to recipe-based Chakra v3 structures and updates shared primitives, dialogs, menus, and rich text wrappers to the new API shapes.
Shared UI primitives and form controls
packages/app/src/components/*, packages/app/src/features/*/Settings/*, packages/app/src/features/App/VaultCreator/index.tsx, packages/app/src/features/App/VaultLoginForm/index.tsx, packages/app/src/features/NoteEditor/*
Reworks common buttons, switches, sliders, forms, preview cards, and editor controls to use Chakra v3 compound components and revised prop contracts.
Settings, dialogs, and app-shell controls
packages/app/src/features/App/Settings/*, packages/app/src/features/App/Workspace*, packages/app/src/hooks/useConfirmDialog.tsx, packages/app/src/features/WorkspaceModal/*
Migrates settings/workspace dialogs, selects, separators, and shell controls to compound Chakra components and updated layout props.
Main screen panels and notes list
packages/app/src/features/MainScreen/*, packages/app/src/features/App/ChooseVaultScreen.tsx, packages/app/src/features/App/Vault/*
Refactors the main screen, notes list, workspaces, tags, and vault panels to new layout primitives, selection hooks, and virtualized list rendering.
Notes, tags, and editor state model
packages/app/src/hooks/*, packages/app/src/state/redux/*, packages/app/src/utils/os/zoom.ts, packages/app/src/windows/about/About.tsx
Adds touched-note tracking, new selectors and helpers, updated settings/theme state, fallback runtime guards, and related selector tests.
Note editor and rich text refactor
packages/app/src/features/NoteEditor/*, packages/app/src/features/NotesContainer/*, packages/app/src/components/PropertiesForm.tsx, packages/app/src/components/TagEditor/index.tsx
Splits the note editor, rewires rich text rendering and dialog/menu surfaces, and updates note container tabs and context menus.
Context-menu fallbacks and auxiliary runtime utilities
packages/app/src/features/NotesContainer/NoteContextMenu/*, packages/app/src/hooks/useContextMenu.ts, packages/app/src/hooks/useShowNoteContextMenu.ts, packages/app/src/features/App/useGetAppUpdates.tsx, packages/app/src/features/App/index.tsx, packages/app/src/utils/dev.ts
Adds DOM context-menu support, shared toast usage, Electron detection, update toasts, and other runtime fallbacks.
  • Possibly related PRs
  • DeepinkApp/deepink#304: Shares the preview-tab flow that useTogglePreviewTabToRegularOnChange.ts now reads through store.getState().
  • DeepinkApp/deepink#243: Touches the same update-check notification flow now rewritten to use the shared toaster API.
  • DeepinkApp/deepink#217: Introduced WorkspaceServices; this PR extends it with notes-list synchronization.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐰 I hopped through themes and panels bright,
With recipes, toasts, and tabs in sight.
New lists and switches, sleek and neat,
Made this burrow fast on every beat.
Hop hop—Chakra stars tonight!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 306-improve-performance-for-common-use-cases

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
packages/app/src/features/NoteEditor/NoteVersions.tsx (1)

61-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix the shadowed noteId check in the history event listener.

The callback parameter shadows the component prop, so if (noteId !== noteId) is always false and the versions list refreshes for unrelated notes.

Proposed fix
 	useEffect(() => {
-		return eventBus.listen(WorkspaceEvents.NOTE_HISTORY_UPDATED, (noteId) => {
-			if (noteId !== noteId) return;
+		return eventBus.listen(
+			WorkspaceEvents.NOTE_HISTORY_UPDATED,
+			(updatedNoteId) => {
+				if (updatedNoteId !== noteId) return;
 			updateVersionsList();
-		});
+			},
+		);
 	}, [eventBus, updateVersionsList]);
🤖 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/app/src/features/NoteEditor/NoteVersions.tsx` around lines 61 - 63,
The listener passed to eventBus.listen for WorkspaceEvents.NOTE_HISTORY_UPDATED
shadows the component prop noteId (so if (noteId !== noteId) is wrong); rename
the callback parameter (e.g., updatedNoteId or incomingNoteId) and compare that
to the component prop noteId, e.g., if (updatedNoteId !== noteId) return; then
call updateVersionsList(); update the listener closure in NoteVersions.tsx (the
eventBus.listen callback) to use the new parameter name in the comparison.
🤖 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.

Outside diff comments:
In `@packages/app/src/features/NoteEditor/NoteVersions.tsx`:
- Around line 61-63: The listener passed to eventBus.listen for
WorkspaceEvents.NOTE_HISTORY_UPDATED shadows the component prop noteId (so if
(noteId !== noteId) is wrong); rename the callback parameter (e.g.,
updatedNoteId or incomingNoteId) and compare that to the component prop noteId,
e.g., if (updatedNoteId !== noteId) return; then call updateVersionsList();
update the listener closure in NoteVersions.tsx (the eventBus.listen callback)
to use the new parameter name in the comparison.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bfeed80-576a-4b2f-ac6f-f6956935a709

📥 Commits

Reviewing files that changed from the base of the PR and between 63f4448 and 60505ba.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (14)
  • packages/app/package.json
  • packages/app/src/components/ListBox/ListBox.theme.ts
  • packages/app/src/components/ListBox/ListBox.tsx
  • packages/app/src/components/NestedList/index.tsx
  • packages/app/src/components/PropertiesForm.tsx
  • packages/app/src/components/TagEditor/index.tsx
  • packages/app/src/components/theme/base.ts
  • packages/app/src/features/App/ChooseVaultScreen.tsx
  • packages/app/src/features/App/Settings/sections/WorkspaceSettings.tsx
  • packages/app/src/features/App/VaultCreator/index.tsx
  • packages/app/src/features/App/VaultLoginForm/index.tsx
  • packages/app/src/features/App/WelcomeScreen.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/features/NoteEditor/NoteVersions.tsx
💤 Files with no reviewable changes (1)
  • packages/app/src/components/NestedList/index.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/app/src/components/PropertiesForm.tsx
  • packages/app/src/features/App/Settings/sections/WorkspaceSettings.tsx
  • packages/app/src/components/TagEditor/index.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/features/App/VaultLoginForm/index.tsx
  • packages/app/src/features/App/VaultCreator/index.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
packages/app/src/features/NoteEditor/NoteMenu.tsx (1)

68-73: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Disable or remove non-functional menu items.

These menu items have no onSelect handler, making them appear interactive but do nothing when clicked. This creates a confusing user experience.

Consider one of these approaches:

  • Add disabled prop if these features are planned but not yet implemented
  • Remove the items entirely until they're ready
  • Add code comments explaining they're placeholders
♻️ Example: disabling placeholder items
-										<Menu.Item value="remindMe">
+										<Menu.Item value="remindMe" disabled>
 											<HStack>
 												<FaBell />
 												<Text>{t('note.menu.remindMe')}</Text>
 											</HStack>
 										</Menu.Item>

Apply the same pattern to backLinks, readonlyMode, spellcheck, passwordProtection, and disableSync.

Also applies to: 90-95, 96-101, 102-107, 121-128, 129-134

🤖 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/app/src/features/NoteEditor/NoteMenu.tsx` around lines 68 - 73,
Several Menu.Item entries (e.g., value="remindMe" and the other items referenced
as backLinks, readonlyMode, spellcheck, passwordProtection, disableSync) are
interactive but lack onSelect handlers; mark these placeholder items as
non-interactive by adding the disabled prop to each Menu.Item (or remove them if
you prefer), and add a short inline comment indicating they are placeholders
until implemented; update Menu.Item elements for remindMe, backLinks,
readonlyMode, spellcheck, passwordProtection, and disableSync accordingly so the
UI doesn’t present non-functional clickable options.
🤖 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.

Outside diff comments:
In `@packages/app/src/features/NoteEditor/NoteMenu.tsx`:
- Around line 68-73: Several Menu.Item entries (e.g., value="remindMe" and the
other items referenced as backLinks, readonlyMode, spellcheck,
passwordProtection, disableSync) are interactive but lack onSelect handlers;
mark these placeholder items as non-interactive by adding the disabled prop to
each Menu.Item (or remove them if you prefer), and add a short inline comment
indicating they are placeholders until implemented; update Menu.Item elements
for remindMe, backLinks, readonlyMode, spellcheck, passwordProtection, and
disableSync accordingly so the UI doesn’t present non-functional clickable
options.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 68d44e76-4dfe-44d6-b000-fa4b75bf3dac

📥 Commits

Reviewing files that changed from the base of the PR and between 60505ba and 6355883.

📒 Files selected for processing (11)
  • packages/app/src/components/theme/base.ts
  • packages/app/src/components/ui/toaster.tsx
  • packages/app/src/features/App/VaultLoginForm/index.tsx
  • packages/app/src/features/App/useGetAppUpdates.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
  • packages/app/src/features/MainScreen/TagsPanel/VirtualTagsList.tsx
  • packages/app/src/features/NoteEditor/EditorPanel/buttons/HeaderPicker.tsx
  • packages/app/src/features/NoteEditor/NoteMenu.tsx
  • packages/app/src/utils/dev.ts
  • packages/app/src/windows/main/renderer.tsx
✅ Files skipped from review due to trivial changes (1)
  • packages/app/src/utils/dev.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/app/src/features/App/VaultLoginForm/index.tsx
  • packages/app/src/components/ui/toaster.tsx
  • packages/app/src/features/MainScreen/TagsPanel/VirtualTagsList.tsx
  • packages/app/src/features/App/useGetAppUpdates.tsx
  • packages/app/src/windows/main/renderer.tsx
  • packages/app/src/features/NoteEditor/EditorPanel/buttons/HeaderPicker.tsx
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/components/theme/base.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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)
packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx (1)

47-52: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Drop modifier-based multi-select until this tree is actually controlled as multi-select.

activeTag makes this component single-select, and setSelectedItems immediately collapses any selection update back to one id/null. The ctrl/meta branch still calls item.toggleSelect(), so modifier-click asks headless-tree for multi-selection and then truncates it in the callback. That produces incorrect selection behavior in the tag list.

💡 Minimal fix
 			onClick: (e: MouseEvent) => {
-				if (e.ctrlKey || e.metaKey) {
-					item.toggleSelect();
-				} else {
-					tree.setSelectedItems([item.getItemMeta().itemId]);
-				}
+				tree.setSelectedItems([item.getItemMeta().itemId]);
 
 				item.setFocused();
 			},

Also applies to: 85-97

🤖 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/app/src/features/MainScreen/TagsPanel/TagsTree.tsx` around lines 47
- 52, The click handler currently tries to perform modifier-based multi-select
by calling item.toggleSelect() when e.ctrlKey/e.metaKey is set while the tree is
single-select via activeTag and tree.setSelectedItems(), causing selection
conflicts; remove the modifier-branch so the onClick always calls
tree.setSelectedItems([item.getItemMeta().itemId]) (and likewise remove or
change any identical logic around the other onClick at the 85-97 range) so
selection is consistently controlled by activeTag and multi-select toggling is
not attempted client-side.
🤖 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.

Outside diff comments:
In `@packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx`:
- Around line 47-52: The click handler currently tries to perform modifier-based
multi-select by calling item.toggleSelect() when e.ctrlKey/e.metaKey is set
while the tree is single-select via activeTag and tree.setSelectedItems(),
causing selection conflicts; remove the modifier-branch so the onClick always
calls tree.setSelectedItems([item.getItemMeta().itemId]) (and likewise remove or
change any identical logic around the other onClick at the 85-97 range) so
selection is consistently controlled by activeTag and multi-select toggling is
not attempted client-side.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e9ee50db-3380-4603-a0e7-0b8cee0794fe

📥 Commits

Reviewing files that changed from the base of the PR and between 6df3e89 and 1447d48.

📒 Files selected for processing (2)
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
  • packages/app/src/state/redux/vaults/selectors/tags/index.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (2)
packages/app/src/features/NotesContainer/NoteContextMenu/ElectronContextMenu.ts (1)

23-29: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Cancellation and selection events are mixed incorrectly.

null cancellation still triggers onClicked, and successful selection never triggers onClosed, which leaves close watchers uncleared in the caller path.

Suggested fix
 		}).then((action) => {
 			if (action === null) {
 				this.onClosed();
+				return;
 			}
-
-			this.onClicked(action as T);
+			this.onClicked(action as T);
+			this.onClosed();
 		});
🤖 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/app/src/features/NotesContainer/NoteContextMenu/ElectronContextMenu.ts`
around lines 23 - 29, The promise handler currently calls onClicked even when
action is null and never calls onClosed after a successful selection; change the
then((action) => { ... }) logic so that if action === null you call
this.onClosed() and return immediately, and if action !== null you first call
this.onClicked(action as T) and then call this.onClosed() to ensure close
watchers are cleared; update the handler surrounding the Promise returned in
ElectronContextMenu so both paths are handled explicitly.
packages/app/src/hooks/useShowNoteContextMenu.ts (1)

17-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Subscribe before open to avoid dropping immediate events.

Calling open first can miss onClose/onClick if the menu implementation emits synchronously (which the DOM path currently does).

Suggested fix
-			contextMenu.open(point);
-
 			const unsubscribeOnClick = contextMenu.onClick((action) => {
 				callback({ action, id });
 				unsubscribeOnClick();
 			});
 
 			const unsubscribeOnClose = contextMenu.onClose(() => {
 				unsubscribeOnClick();
 				unsubscribeOnClose();
 			});
+
+			contextMenu.open(point);
🤖 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/app/src/hooks/useShowNoteContextMenu.ts` around lines 17 - 27, The
current code calls contextMenu.open(point) before subscribing, which can drop
synchronous events; move the subscriptions for contextMenu.onClick and
contextMenu.onClose so they are created before calling contextMenu.open(point),
capture their unsubscribe functions (unsubscribeOnClick, unsubscribeOnClose),
then call contextMenu.open(point); ensure the onClick handler still invokes
callback({ action, id }) and calls unsubscribeOnClick(), and the onClose handler
calls both unsubscribeOnClick() and unsubscribeOnClose() to clean up.
♻️ Duplicate comments (1)
packages/app/src/features/NotesContainer/NoteContextMenu/DOMContextMenu.ts (1)

17-25: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

DOMContextMenu.open currently disables all menu actions.

open closes immediately and never emits onClicked, so note context-menu commands cannot run in non-Electron runtime.

🤖 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/app/src/features/NotesContainer/NoteContextMenu/DOMContextMenu.ts`
around lines 17 - 25, DOMContextMenu.open currently calls this.onClosed()
immediately which prevents the menu from rendering and stops any menu item click
events (onClicked) from firing; update DOMContextMenu.open to render the menu
DOM using this.menu and position it at {x,y} instead of closing, attach click
handlers to each menu item that call this.onClicked(item) and then call
this.onClosed() after selection or when clicking outside, and ensure existing
methods (onClosed, onClicked) are used for lifecycle rather than immediately
invoking onClosed on open so context-menu commands work in non-Electron
runtimes.
🤖 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/app/src/state/redux/vaults/hooks.ts`:
- Around line 17-20: useWorkspaceData currently returns a new plain object each
render which makes consumers like useWorkspaceActions (which depends on
[workspaceData]) re-create wrappers every time; update useWorkspaceData to
return a stable/memoized reference (e.g., useMemo) based on
useWorkspaceContext()'s vaultId and workspaceId so the returned object identity
only changes when those values change, ensuring useWorkspaceActions (and any
other consumers) do not rebuild unnecessarily.

---

Outside diff comments:
In
`@packages/app/src/features/NotesContainer/NoteContextMenu/ElectronContextMenu.ts`:
- Around line 23-29: The promise handler currently calls onClicked even when
action is null and never calls onClosed after a successful selection; change the
then((action) => { ... }) logic so that if action === null you call
this.onClosed() and return immediately, and if action !== null you first call
this.onClicked(action as T) and then call this.onClosed() to ensure close
watchers are cleared; update the handler surrounding the Promise returned in
ElectronContextMenu so both paths are handled explicitly.

In `@packages/app/src/hooks/useShowNoteContextMenu.ts`:
- Around line 17-27: The current code calls contextMenu.open(point) before
subscribing, which can drop synchronous events; move the subscriptions for
contextMenu.onClick and contextMenu.onClose so they are created before calling
contextMenu.open(point), capture their unsubscribe functions
(unsubscribeOnClick, unsubscribeOnClose), then call contextMenu.open(point);
ensure the onClick handler still invokes callback({ action, id }) and calls
unsubscribeOnClick(), and the onClose handler calls both unsubscribeOnClick()
and unsubscribeOnClose() to clean up.

---

Duplicate comments:
In `@packages/app/src/features/NotesContainer/NoteContextMenu/DOMContextMenu.ts`:
- Around line 17-25: DOMContextMenu.open currently calls this.onClosed()
immediately which prevents the menu from rendering and stops any menu item click
events (onClicked) from firing; update DOMContextMenu.open to render the menu
DOM using this.menu and position it at {x,y} instead of closing, attach click
handlers to each menu item that call this.onClicked(item) and then call
this.onClosed() after selection or when clicking outside, and ensure existing
methods (onClosed, onClicked) are used for lifecycle rather than immediately
invoking onClosed on open so context-menu commands work in non-Electron
runtimes.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8101e2cd-b488-42c0-8816-0307ff74bf2a

📥 Commits

Reviewing files that changed from the base of the PR and between 6df3e89 and 1c12e3c.

📒 Files selected for processing (19)
  • packages/app/src/components/AppToast.tsx
  • packages/app/src/components/CalmButton.tsx
  • packages/app/src/components/Features/Header/FeaturesHeader.tsx
  • packages/app/src/components/ListBox/ListBox.theme.ts
  • packages/app/src/components/WithFocusRedirect.tsx
  • packages/app/src/features/App/Settings/sections/ImportAndExport.tsx
  • packages/app/src/features/MainScreen/ActivityBar.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
  • packages/app/src/features/MainScreen/TagsPanel/VirtualTagsList.tsx
  • packages/app/src/features/MainScreen/TagsPanel/useMemoizedCallback.tsx
  • packages/app/src/features/NoteEditor/index.tsx
  • packages/app/src/features/NotesContainer/NoteContextMenu/DOMContextMenu.ts
  • packages/app/src/features/NotesContainer/NoteContextMenu/ElectronContextMenu.ts
  • packages/app/src/hooks/useContextMenu.ts
  • packages/app/src/hooks/useShowNoteContextMenu.ts
  • packages/app/src/state/redux/vaults/hooks.ts
  • packages/app/src/state/redux/vaults/selectors/tags/index.ts
  • packages/app/src/windows/main/renderer.tsx
💤 Files with no reviewable changes (5)
  • packages/app/src/components/CalmButton.tsx
  • packages/app/src/components/WithFocusRedirect.tsx
  • packages/app/src/components/ListBox/ListBox.theme.ts
  • packages/app/src/components/AppToast.tsx
  • packages/app/src/features/MainScreen/ActivityBar.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/app/src/features/MainScreen/TagsPanel/VirtualTagsList.tsx
  • packages/app/src/hooks/useContextMenu.ts
  • packages/app/src/features/App/Settings/sections/ImportAndExport.tsx
  • packages/app/src/components/Features/Header/FeaturesHeader.tsx
  • packages/app/src/windows/main/renderer.tsx
  • packages/app/src/features/MainScreen/TagsPanel/TagsTree.tsx
  • packages/app/src/features/MainScreen/NotesListPanel/index.tsx
  • packages/app/src/state/redux/vaults/selectors/tags/index.ts
  • packages/app/src/features/NoteEditor/index.tsx

Comment thread packages/app/src/state/redux/vaults/hooks.ts
@vitonsky vitonsky merged commit ddcef38 into master Jun 8, 2026
6 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 6, 2026
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.

Improve performance for common use cases Do not load inactive tabs

1 participant