Skip to content

refactor: remove auto-focus from newly created folders and consolidate navigation logic#195

Open
1shCha wants to merge 7 commits intomainfrom
sidebar_sv_fix
Open

refactor: remove auto-focus from newly created folders and consolidate navigation logic#195
1shCha wants to merge 7 commits intomainfrom
sidebar_sv_fix

Conversation

@1shCha
Copy link
Collaborator

@1shCha 1shCha commented Feb 11, 2026

Important

This PR introduces a double-panel mode for side-by-side item viewing, refactors navigation logic, and updates UI components to enhance user interaction and interface flexibility.

  • Behavior:
    • Introduces double-panel mode for side-by-side item viewing in DashboardContent and DashboardLayout.
    • Removes auto-focus from new folders in FolderCardComponent.
    • Updates navigation logic to emit created item IDs for reliable UI navigation.
  • UI Components:
    • Adds double-panel support in WorkspaceCard, WorkspaceContent, and WorkspaceGrid.
    • Updates WorkspaceHeader to handle double-panel mode with panel titles and close buttons.
    • Adjusts SelectionActionBar for responsive design.
  • State Management:
    • Adds double-panel state management in ui-store.ts with actions for opening, closing, and exiting double-panel mode.
    • Refactors use-reactive-navigation.ts to handle navigation after item creation without auto-selection.

This description was created by Ellipsis for 192ba5e. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Added a double‑panel mode to view two items side‑by‑side and "Open in Double Panel" actions across lists and context menus.
  • Bug Fixes

    • Removed automatic name‑editing/auto‑focus for new folders; renaming is user‑initiated.
    • Creation flows now emit created item IDs so the UI reliably navigates to new items.
    • Navigation no longer auto‑selects multiple items; modals are suppressed when double‑panel is active.
  • Style

    • More responsive, non‑shrinking selection action bar and adjusted split toggle labeling and spacing.

@vercel
Copy link

vercel bot commented Feb 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thinkex Ready Ready Preview, Comment Feb 12, 2026 3:45am

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed everything up to 02a5484 in 11 seconds. Click for details.
  • Reviewed 141 lines of code in 4 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_8T8GGLRcoX1Iw82R

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@ellipsis-dev ellipsis-dev bot changed the title small fixes for auto scroll on new items refactor: remove auto-focus from newly created folders and consolidate navigation logic Feb 11, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 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
📝 Walkthrough

Walkthrough

Adds a double-panel UI mode with store/state, dashboard and layout wiring, header/menu actions to open items in a left/right panel, modal rendering adjustments, navigation-only reactive navigation changes, and removal of automatic folder auto-focus/edit behavior.

Changes

Cohort / File(s) Summary
Double-panel UI state & store
src/lib/stores/ui-store.ts
Add doublePanelActive, secondPanelItemId, originalFolderId and actions to open/close/exit double-panel; integrate resets across UI flows.
Dashboard wiring & layout
src/app/dashboard/page.tsx, src/components/layout/DashboardLayout.tsx
Wire double-panel props into dashboard and layout; render two resizable panels (left/right) when active and forward panel content nodes.
Panel content & headers
src/components/workspace-canvas/ItemPanelContent.tsx, src/components/pdf/PdfPanelHeader.tsx
Add isDoublePanelMode prop, hide maximize/split controls in double-panel mode, and propagate flag to nested headers/content.
Workspace header & card/menu changes
src/components/workspace-canvas/WorkspaceHeader.tsx, src/components/workspace/SidebarCardList.tsx, src/components/workspace-canvas/WorkspaceCard.tsx
Render double-panel pills in header; emit created item IDs via onItemCreated; add “Open in Double Panel” actions in header/sidebar/context menus.
Workspace content/grid/section & folder behavior
src/components/workspace-canvas/WorkspaceContent.tsx, src/components/workspace-canvas/WorkspaceGrid.tsx, src/components/workspace-canvas/WorkspaceSection.tsx, src/components/workspace-canvas/FolderCard.tsx
Exclude second panel item from workspace grids, force grid remount on single-column toggle, navigate to created folders/items via reactive navigation hook, and remove automatic folder autofocus/editing.
Modal manager & modal selection changes
src/components/modals/ModalManager.tsx, src/components/modals/CardDetailModal.tsx, src/components/modals/PDFViewerModal.tsx
Prevent CardDetail/PDF modals rendering when double-panel active; switch to imperative reads of UI store on modal open for selection toggling (remove reactive subscription of selected ids).
Selection action bar & UI refinements
src/components/workspace-canvas/SelectionActionBar.tsx, src/components/workspace-canvas/ItemPanelContent.tsx
Adjust responsive sizing, prevent button/content shrinking, propagate double-panel mode to nested content, hide certain action buttons in double-panel mode.
Reactive navigation hook
src/hooks/ui/use-reactive-navigation.ts
Simplify handleCreatedItems to only set pending navigation id (remove auto-select of created items).
Small/UX tweaks
src/components/workspace-canvas/FolderCard.tsx, src/components/workspace-canvas/WorkspaceHeader.tsx
Remove local auto-focus state/behavior for new folders; adjust Split view label to "Split" and minor UI text/tooltip changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant WorkspaceHeader
  participant UIStore as UI Store
  participant DashboardLayout
  participant ItemPanel as Item Panel Content

  User->>WorkspaceHeader: choose "Open in Double Panel" / open item
  WorkspaceHeader->>UIStore: openDoublePanel(itemId)
  UIStore-->>WorkspaceHeader: set doublePanelActive, secondPanelItemId
  UIStore->>DashboardLayout: state update (doublePanelActive, secondPanelItemId, maximizedItemId)
  DashboardLayout->>ItemPanel: render left panel (secondPanelItemId) and right panel (maximizedItemId)
  ItemPanel-->>User: display two resizable panels (isDoublePanelMode = true)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • urjitc

Poem

"I hopped through code with nimble paws,
Two panes now bloom without a pause,
No auto-focus on new beds,
Just side-by-side bright reading spreads,
A double-view — hooray! 🐇✨"

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title describes removing auto-focus from folders and consolidating navigation logic, which aligns with FolderCard and use-reactive-navigation changes, but the majority of the changeset (estimated ~60-70% of lines changed) implements double-panel mode across multiple components—a significant feature not reflected in the title. Update the title to reflect both major changes: e.g., 'refactor: remove auto-focus from folders and add double-panel mode for side-by-side viewing' or focus the title on the most impactful change (double-panel) if that is the primary objective.
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch sidebar_sv_fix

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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
Contributor

greptile-apps bot commented Feb 11, 2026

Greptile Overview

Greptile Summary

This PR successfully implements a double-panel mode for viewing two items side-by-side, refactors navigation logic to use reactive patterns, and removes auto-focus behavior from newly created folders. The changes span 18 files with 572 additions and 172 deletions.

Key improvements:

  • Double-panel state management in ui-store.ts with openDoublePanel, closeDoublePanelLeft, closeDoublePanelRight, and exitDoublePanel actions
  • Refactored use-reactive-navigation.ts to wait for items to appear in state before navigating, solving race conditions
  • Fixed effect cleanup issues in CardDetailModal and PDFViewerModal by reading store actions imperatively via useUIStore.getState() to prevent stale closures
  • Removed auto-focus from FolderCard (line 403: autoFocus={false})
  • Added "Open in Double Panel" menu option in sidebar and workspace cards
  • Updated WorkspaceHeader to show panel title pills with close buttons in double-panel mode
  • ModalManager now skips rendering when doublePanelActive is true (DashboardLayout handles rendering)

Issues found:

  • SidebarCardList IIFE pattern runs on every render instead of only when needed (lines 191-195)
  • handleCreatedItems only navigates to first item when array has multiple items (line 18 in use-reactive-navigation.ts)

The implementation is well-structured with proper state tracking for auto-selected items (panelAutoSelectedCardIds) and folder restoration (originalFolderId).

Confidence Score: 4/5

  • Safe to merge with one logic issue that should be addressed
  • The PR implements a complex feature (double-panel mode) with proper state management and fixes previous issues with effect cleanups. The navigation refactoring is sound. One logic issue exists where the IIFE in SidebarCardList executes on every render, causing unnecessary work. The other issue (only navigating to first created item) is minor and unlikely to cause problems in practice.
  • Pay attention to src/components/workspace/SidebarCardList.tsx lines 191-195 and 395-399 (IIFE performance issue)

Important Files Changed

Filename Overview
src/lib/stores/ui-store.ts Adds comprehensive double-panel state management with openDoublePanel, closeDoublePanelLeft, closeDoublePanelRight, and exitDoublePanel actions. Properly manages secondPanelItemId, doublePanelActive, and originalFolderId state. Selection tracking with panelAutoSelectedCardIds works correctly.
src/hooks/ui/use-reactive-navigation.ts Refactors navigation hook to accept createdIds array and reactively navigate to newly created items when they appear in state. Clean implementation that solves race conditions.
src/components/workspace-canvas/WorkspaceSection.tsx Updates item creation handlers to call handleCreatedItems([itemId]) after creating notes, folders, and flashcards. Guards with if (itemId) check before navigation. Responsive SelectionActionBar using container width.
src/components/workspace-canvas/WorkspaceHeader.tsx Adds double-panel mode header UI with panel title pills and close buttons. Reads doublePanelActive, secondPanelItemId, and maximizedItemId from store. Calls store actions imperatively via useUIStore.getState().
src/components/modals/CardDetailModal.tsx Fixed effect cleanup by reading store actions imperatively via useUIStore.getState() in both setup and cleanup. Prevents stale closure issues with toggleCardSelection.
src/components/modals/PDFViewerModal.tsx Fixed effect cleanup by reading store actions imperatively via useUIStore.getState(). Removed unnecessary useShallow and useMemo for selection state.
src/app/dashboard/page.tsx Implements double-panel rendering with doublePanelLeftElement and doublePanelRightElement. Adds Escape key handler for exitDoublePanel. Properly flushes pending changes on panel close.
src/components/workspace/SidebarCardList.tsx Adds "Open in Double Panel" menu item for notes and PDFs when maximizedItemId exists and !doublePanelActive. Uses IIFE to read store state inline.

Sequence Diagram

sequenceDiagram
    participant User
    participant WorkspaceHeader
    participant UIStore
    participant DashboardLayout
    participant ItemPanelContent
    
    User->>WorkspaceHeader: Click "Create Note"
    WorkspaceHeader->>WorkspaceHeader: addItem("note")
    WorkspaceHeader->>WorkspaceHeader: handleCreatedItems([itemId])
    WorkspaceHeader->>UIStore: navigateToItem(itemId)
    Note over UIStore: No auto-selection
    
    User->>WorkspaceHeader: Open item (single click)
    WorkspaceHeader->>UIStore: openPanel(itemId, 'replace')
    UIStore->>UIStore: Set maximizedItemId
    UIStore->>UIStore: Auto-select item (panelAutoSelectedCardIds)
    UIStore-->>DashboardLayout: Render maximized item
    
    User->>WorkspaceHeader: Toggle split view
    WorkspaceHeader->>UIStore: toggleWorkspaceSplitView()
    UIStore->>UIStore: Set workspaceSplitViewActive = true
    UIStore-->>DashboardLayout: Render workspace + item panels
    
    User->>SidebarCardList: Click "Open in Double Panel"
    SidebarCardList->>UIStore: openDoublePanel(itemId)
    UIStore->>UIStore: Set doublePanelActive = true
    UIStore->>UIStore: Set secondPanelItemId
    UIStore->>UIStore: Auto-select second item
    UIStore-->>DashboardLayout: Render two items side-by-side
    DashboardLayout->>ItemPanelContent: Render left panel (secondPanelItemId)
    DashboardLayout->>ItemPanelContent: Render right panel (maximizedItemId)
    
    User->>WorkspaceHeader: Close left panel
    WorkspaceHeader->>UIStore: closeDoublePanelLeft()
    UIStore->>UIStore: Clear secondPanelItemId
    UIStore->>UIStore: Set doublePanelActive = false
    UIStore->>UIStore: Deselect left item if auto-selected
    UIStore-->>DashboardLayout: Revert to single panel
    
    User->>User: Press Escape
    User->>DashboardLayout: Escape key handler
    DashboardLayout->>UIStore: exitDoublePanel()
    UIStore->>UIStore: Clear all double-panel state
    UIStore->>UIStore: Restore originalFolderId
    UIStore->>UIStore: Deselect all auto-selected items
    UIStore-->>DashboardLayout: Return to folder view
Loading

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 4 files

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

onCreateFolder: () => { if (addItem) addItem("folder"); },
onCreateFolder: () => {
if (addItem) {
const itemId = addItem("folder");
Copy link
Contributor

Choose a reason for hiding this comment

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

Type mismatch: addItem in this component has type string | void (line 37 of WorkspaceGrid.tsx), but WorkspaceHeader.tsx declares it as returning string. The null check if (itemId) guards against void, but the types should be consistent across components.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 8ee8b13 in 17 seconds. Click for details.
  • Reviewed 35 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_3ArNRwxs367p6gtQ

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed d4ab59a in 13 seconds. Click for details.
  • Reviewed 158 lines of code in 4 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_QaTVa3Inxqh9Jt3v

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

7 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 35 to 55
// Auto-select card when modal opens (read selection state imperatively to avoid infinite loops)
useEffect(() => {
// Only run when modal is open and we have an item
if (!isOpen || !item?.id) return;

// Check if card was already selected at the time of opening
const wasAlreadySelected = selectedCardIds.has(item.id);
const wasAlreadySelected = useUIStore.getState().selectedCardIds.has(item.id);

// If not already selected, select it now (adds it to context)
if (!wasAlreadySelected) {
toggleCardSelection(item.id);

// Only deselect on cleanup if we were the ones who selected it
return () => {
toggleCardSelection(item.id);
};
}

// If it was already selected, don't change anything on cleanup
return undefined;
}, [isOpen, item?.id, selectedCardIds, toggleCardSelection]);
}, [isOpen, item?.id]); // eslint-disable-line react-hooks/exhaustive-deps

Copy link
Contributor

Choose a reason for hiding this comment

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

Effect cleanup may toggle wrong item

This effect uses toggleCardSelection but omits it from the dependency list (// eslint-disable-line react-hooks/exhaustive-deps). If the store/hook binding ever changes between open and cleanup (e.g., hot reload, provider changes), cleanup can call a stale toggleCardSelection reference.

Safer pattern here is to either include toggleCardSelection in deps or read the action from useUIStore.getState() inside the effect/cleanup so the same source is used throughout.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 11, 2026

Additional Comments (1)

src/components/workspace-canvas/WorkspaceSection.tsx
Undefined item IDs passed

addItem() is treated as always returning a string here, but elsewhere in this PR it’s handled as string | void (see the existing thread note). In this block you call handleCreatedItems([itemId]) even when itemId is undefined, which will flow into useReactiveNavigation and then into navigateToItem(pendingNavigationId), causing document.getElementById(item-${itemId}) lookups for item-undefined and incorrect navigation/highlighting.

This needs a guard (or type alignment) so handleCreatedItems only receives real IDs.

Also appears at: src/components/workspace-canvas/WorkspaceSection.tsx:512-515 and :662-666.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed da3926a in 27 seconds. Click for details.
  • Reviewed 114 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_lvx74Ez4iKHHwfkY

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 2f9bae5 in 16 seconds. Click for details.
  • Reviewed 762 lines of code in 10 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_H6oKPAixd8BL1Qir

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 11 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/components/workspace/SidebarCardList.tsx">

<violation number="1" location="src/components/workspace/SidebarCardList.tsx:193">
P2: The menu visibility uses `useUIStore.getState()` inside render, which won’t trigger re-renders when the UI store changes, so the "Open in Double Panel" option can get out of sync with the actual state. Use the zustand hook selector to subscribe to the relevant state instead.</violation>
</file>

<file name="src/components/workspace-canvas/WorkspaceCard.tsx">

<violation number="1" location="src/components/workspace-canvas/WorkspaceCard.tsx:1080">
P2: Using `useUIStore.getState()` inside the render means the menu visibility won’t update when split-view state changes, because `WorkspaceCard` is memoized on item props only. The “Open in Double Panel” option can become stale until an item prop changes. Subscribe to the store via the hook (or include these UI fields in the memoization logic) so UI state changes trigger re-render.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

)}
{/* Double Panel option - only for notes/PDFs when a panel is already open */}
{(item.type === 'note' || item.type === 'pdf') && (() => {
const uiState = useUIStore.getState();
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 11, 2026

Choose a reason for hiding this comment

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

P2: The menu visibility uses useUIStore.getState() inside render, which won’t trigger re-renders when the UI store changes, so the "Open in Double Panel" option can get out of sync with the actual state. Use the zustand hook selector to subscribe to the relevant state instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/workspace/SidebarCardList.tsx, line 193:

<comment>The menu visibility uses `useUIStore.getState()` inside render, which won’t trigger re-renders when the UI store changes, so the "Open in Double Panel" option can get out of sync with the actual state. Use the zustand hook selector to subscribe to the relevant state instead.</comment>

<file context>
@@ -188,6 +188,22 @@ function SidebarItemButton({ item, allItems, workspaceName, workspaceIcon, works
                             )}
+                            {/* Double Panel option - only for notes/PDFs when a panel is already open */}
+                            {(item.type === 'note' || item.type === 'pdf') && (() => {
+                                const uiState = useUIStore.getState();
+                                return uiState.maximizedItemId && uiState.maximizedItemId !== item.id && !uiState.doublePanelActive;
+                            })() && (
</file context>
Fix with Cubic

)
}
{/* Double Panel option - only for notes/PDFs when split view is active */}
{(item.type === 'note' || item.type === 'pdf') && (() => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Feb 11, 2026

Choose a reason for hiding this comment

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

P2: Using useUIStore.getState() inside the render means the menu visibility won’t update when split-view state changes, because WorkspaceCard is memoized on item props only. The “Open in Double Panel” option can become stale until an item prop changes. Subscribe to the store via the hook (or include these UI fields in the memoization logic) so UI state changes trigger re-render.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/workspace-canvas/WorkspaceCard.tsx, line 1080:

<comment>Using `useUIStore.getState()` inside the render means the menu visibility won’t update when split-view state changes, because `WorkspaceCard` is memoized on item props only. The “Open in Double Panel” option can become stale until an item prop changes. Subscribe to the store via the hook (or include these UI fields in the memoization logic) so UI state changes trigger re-render.</comment>

<file context>
@@ -1076,6 +1076,21 @@ function WorkspaceCard({
         )
         }
+        {/* Double Panel option - only for notes/PDFs when split view is active */}
+        {(item.type === 'note' || item.type === 'pdf') && (() => {
+          const state = useUIStore.getState();
+          return state.workspaceSplitViewActive && state.maximizedItemId && state.maximizedItemId !== item.id && !state.doublePanelActive;
</file context>
Fix with Cubic

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

17 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 650 to +654
onCreateNote: () => {
if (addItem) {
const itemId = addItem("note");
if (handleCreatedItems && itemId) {
handleCreatedItems([itemId]);
}
handleCreatedItems([itemId]);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Passing possibly undefined ID

addItem is typed to return string, but several call sites pass its return value directly into handleCreatedItems([itemId]) (e.g. note/folder/flashcard). If addItem ever returns undefined (as noted elsewhere in this PR), useReactiveNavigation will set pendingNavigationId to undefined and then call navigateToItem(undefined), which is a runtime bug. Either make addItem consistently return a string everywhere, or guard before calling handleCreatedItems.

Also appears at src/components/workspace-canvas/WorkspaceSection.tsx:656-670.

Comment on lines 44 to 62
// Auto-select card when modal opens (read selection state imperatively to avoid infinite loops)
useEffect(() => {
if (!isOpen || !item?.id) return;

// Check if card was already selected at the time of opening
const wasAlreadySelected = selectedCardIds.has(item.id);
const wasAlreadySelected = useUIStore.getState().selectedCardIds.has(item.id);

// If not already selected, select it now
if (!wasAlreadySelected) {
toggleCardSelection(item.id);

// Only deselect on cleanup if we were the ones who selected it
return () => {
toggleCardSelection(item.id);
};
}

return undefined;
}, [isOpen, item?.id]); // eslint-disable-line react-hooks/exhaustive-deps
Copy link
Contributor

Choose a reason for hiding this comment

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

Cleanup uses stale action

The effect reads toggleCardSelection but omits it from the dependency list and suppresses the lint rule ([isOpen, item?.id]). If the store action reference changes between mount and cleanup (e.g. hot reload or provider changes), cleanup can toggle the wrong selection state. To keep open/cleanup consistent, include toggleCardSelection in deps or read the action via useUIStore.getState() inside the effect/cleanup.

Also appears in src/components/modals/PDFViewerModal.tsx:35-54.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

17 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 188 to 206
Move to
</DropdownMenuItem>
)}
{/* Double Panel option - only for notes/PDFs when a panel is already open */}
{(item.type === 'note' || item.type === 'pdf') && (() => {
const uiState = useUIStore.getState();
return uiState.maximizedItemId && uiState.maximizedItemId !== item.id && !uiState.doublePanelActive;
})() && (
<DropdownMenuItem
onClick={(e) => {
e.stopPropagation();
setIsDropdownOpen(false);
useUIStore.getState().openDoublePanel(item.id);
}}
>
<Columns className="mr-2 h-4 w-4" />
Open in Double Panel
</DropdownMenuItem>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

Double panel opens from grid

The “Open in Double Panel” menu item here only checks maximizedItemId and !doublePanelActive. If a user has an item maximized in the modal (i.e. not in workspace split view), this action will still call openDoublePanel, which flips doublePanelActive on and makes DashboardLayout render two inline ItemPanelContents. That effectively forces double-panel mode from a modal-open state and bypasses the stated constraint “only when a panel is already open / split view is active”. This mismatch will produce confusing UI state transitions.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 11, 2026

Additional Comments (2)

src/lib/stores/ui-store.ts
setMaximizedItemId breaks selection

setMaximizedItemId removes the previously maximized card from selectedCardIds whenever workspaceSplitViewActive is true, but it does not check whether that card was auto-selected vs manually selected by the user (panelAutoSelectedCardIds). In split view, switching focus between items will therefore unexpectedly clear a user’s manual selection for the previously focused card. This is a behavior regression introduced by the new selection bookkeeping; the deselection should only apply to cards that were auto-selected by the panel.


src/components/workspace-canvas/WorkspaceHeader.tsx
Double-panel header can desync

In the if (doublePanelActive) branch, the header renders close buttons only if leftItem/rightItem are found in the items prop. However, the store can have doublePanelActive=true with missing item data (e.g. items list not yet loaded / item deleted), and then there’s no way to close/exist double panel from the header UI. Consider rendering the close buttons unconditionally (based on IDs) or falling back to an “Exit double panel” control when the items aren’t found.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed f96bfd2 in 15 seconds. Click for details.
  • Reviewed 58 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_U082AOt4il7yXiwO

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 70b7106 in 16 seconds. Click for details.
  • Reviewed 76 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_ZL7vumYBKopxDMLq

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

17 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 11, 2026

Additional Comments (1)

src/components/workspace-canvas/WorkspaceCanvasDropzone.tsx
Dead layout variable

let layout = undefined; is never read, and the function returns initialLayout directly when bestFrame is present. This unused variable indicates leftover/incomplete refactor; it should be removed to avoid confusion (and to prevent future edits mistakenly assuming layout is applied).

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 404fced in 23 seconds. Click for details.
  • Reviewed 13 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_UpA2Q6IntDq5ZP4P

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 11, 2026

Additional Comments (1)

src/lib/stores/ui-store.ts
Legacy modal close leaves double panel

setOpenModalItemId(null) no longer clears doublePanelActive/secondPanelItemId/originalFolderId (or workspaceSplitViewActive/activeFolderId). Any caller that still uses this legacy API to close the “modal item” can leave the app stuck in double-panel layout with no modal visible. This regression is introduced by the new double-panel state; fix by resetting the new fields (and any related panel state) in the id === null branch, similar to closeAllPanels/setMaximizedItemId(null).

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed b633239 in 22 seconds. Click for details.
  • Reviewed 15 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_3O1rMw80JhaKzulQ

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! 👍

Reviewed 192ba5e in 19 seconds. Click for details.
  • Reviewed 22 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 0 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.

Workflow ID: wflow_jRTsEd4Y5Cmafl2h

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 11, 2026

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

18 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile


// Set pending navigation to trigger in useEffect once item is available in state
if (createdIds.length > 0) {
setPendingNavigationId(createdIds[0]);
Copy link
Contributor

Choose a reason for hiding this comment

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

accepts array but only uses first item

handleCreatedItems takes an array but setPendingNavigationId(createdIds[0]) only navigates to the first item. If multiple items are created simultaneously, only the first receives navigation focus.

Suggested change
setPendingNavigationId(createdIds[0]);
setPendingNavigationId(createdIds[createdIds.length - 1]);

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 191 to 195
{/* Double Panel option - only for notes/PDFs when a panel is already open */}
{(item.type === 'note' || item.type === 'pdf') && (() => {
const uiState = useUIStore.getState();
return uiState.maximizedItemId && uiState.maximizedItemId !== item.id && !uiState.doublePanelActive;
})() && (
Copy link
Contributor

Choose a reason for hiding this comment

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

IIFE executes on every render

The condition (() => { const uiState = useUIStore.getState(); return uiState.maximizedItemId && ... })() runs on every component render, not just when the dropdown opens. Move the store read inside the onClick handler or use a proper hook selector.

Suggested change
{/* Double Panel option - only for notes/PDFs when a panel is already open */}
{(item.type === 'note' || item.type === 'pdf') && (() => {
const uiState = useUIStore.getState();
return uiState.maximizedItemId && uiState.maximizedItemId !== item.id && !uiState.doublePanelActive;
})() && (
{(item.type === 'note' || item.type === 'pdf') && (
<DropdownMenuItem
onClick={(e) => {
const uiState = useUIStore.getState();
if (!uiState.maximizedItemId || uiState.maximizedItemId === item.id || uiState.doublePanelActive) return;
e.stopPropagation();
setIsDropdownOpen(false);
uiState.openDoublePanel(item.id);
}}
>

Comment on lines 652 to 653
const itemId = addItem("note");
if (handleCreatedItems && itemId) {
handleCreatedItems([itemId]);
}
if (itemId) handleCreatedItems([itemId]);
Copy link
Contributor

Choose a reason for hiding this comment

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

properly guards against void return from addItem

The if (itemId) checks here correctly handle cases where addItem returns void, preventing handleCreatedItems([undefined]) from calling navigateToItem(undefined).

@1shCha
Copy link
Collaborator Author

1shCha commented Feb 12, 2026

@greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
9.4% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant