Skip to content

Conversation

@yujonglee
Copy link
Contributor

No description provided.

@yujonglee
Copy link
Contributor Author

@coderabbitai ignore

@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

Note

Reviews paused

Use the following commands to manage reviews:

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

Walkthrough

Introduces a new tabbed main content system with per-type tab items and contents (sessions, events, calendars, folders, humans), adds a new sidebar with timeline and profile sections, removes legacy main-area and left-sidebar modules, and updates routing/layout to use the new components and minor devtools positioning.

Changes

Cohort / File(s) Summary
Main Content: Tabs framework
apps/desktop2/src/components/main/body/index.tsx, apps/desktop2/src/components/main/body/shared.tsx
Adds MainContent rendering header/content per active tab; introduces TabItem type and TabItemBase UI with close/select handling and drag-reorder support.
Main Content: Tab items + content (sessions/events/calendars/folders/humans)
.../body/sessions.tsx, .../body/events.tsx, .../body/calendars.tsx, .../body/folders.tsx, .../body/humans.tsx
Adds per-type TabItem and TabContent implementations: note editor with title/raw MD; event viewer; calendar month grid with navigation and day events/sessions; folder explorer with top-level/specific views and breadcrumbs; simple human tab.
Sidebar: New structure
apps/desktop2/src/components/main/sidebar/index.tsx, .../sidebar/timeline.tsx, .../sidebar/profile.tsx
Introduces LeftSidebar composed of TimelineView (session list with open/openNew) and ProfileSection (expandable menu opening folders/calendars/settings). Includes toggle control.
Removal: Legacy main area and sidebar
apps/desktop2/src/components/main/left-sidebar.tsx, apps/desktop2/src/components/main/main-area.tsx
Deletes old LeftSidebar and MainArea implementations and their exports.
Routes/Layout updates
apps/desktop2/src/routes/app/main/_layout.index.tsx, apps/desktop2/src/routes/__root.tsx
Switches layout to new MainContent and LeftSidebar paths/components; adjusts devtools position to top-left.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant LeftSidebar as LeftSidebar
  participant Tabs as useTabs Store
  participant Main as MainContent
  participant Item as TabItem (per-type)
  participant Content as TabContent (per-type)

  User->>LeftSidebar: Click session in Timeline
  LeftSidebar->>Tabs: openCurrent({ type:"sessions", id })
  Tabs-->>Main: currentTab updated
  Main->>Item: Render tab header for type
  Main->>Content: Render content for type

  rect rgba(200,230,255,0.3)
  note right of Content: Calendar example
  User->>Content: Click Prev/Next/Today
  Content->>Tabs: openCurrent({ type:"calendars", month })
  Tabs-->>Main: currentTab updated
  Main->>Content: Re-render calendar month
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Profile as ProfileSection
  participant Tabs as useTabs Store

  User->>Profile: Expand menu
  User->>Profile: Click "Folders"
  Profile->>Tabs: openNew({ type:"folders", id: null })
  User->>Profile: Click "Calendar"
  Profile->>Tabs: openNew({ type:"calendars", month: current })
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Migration 1008 #1546 — Both touch calendar/day rendering and per-day event/session listing; likely overlaps with TabContentCalendar logic.
  • Calendar UI porting #1544 — Continues calendar UI porting and tab/type support that align with the new calendars tab here.
  • New bundle: left sidebar 3 tabs #1542 — Refactors/relocates sidebar and main-area components; closely related to the new sidebar and main body restructuring in this PR.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request lacks a description entirely, so there is no contextual information about the scope or intent of the code changes, which fails the requirement for a related description. Please add a concise description summarizing the objectives and key changes of this refactoring to provide context for reviewers.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly summarizes the primary change by indicating a refactoring of the main area, reflecting the removal of the old main-area module and introduction of new main/body and sidebar components, making it clear and directly related to the changeset.

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.

@yujonglee yujonglee merged commit b0121b4 into main Oct 9, 2025
5 checks passed
@yujonglee yujonglee deleted the refactor-main-area branch October 9, 2025 06:21
Copy link

@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: 3

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39674fa and fc715f0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • apps/desktop2/src/components/main/body/calendars.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/events.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/folders.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/humans.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/index.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/sessions.tsx (1 hunks)
  • apps/desktop2/src/components/main/body/shared.tsx (1 hunks)
  • apps/desktop2/src/components/main/left-sidebar.tsx (0 hunks)
  • apps/desktop2/src/components/main/main-area.tsx (0 hunks)
  • apps/desktop2/src/components/main/sidebar/index.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/profile.tsx (1 hunks)
  • apps/desktop2/src/components/main/sidebar/timeline.tsx (1 hunks)
  • apps/desktop2/src/routes/__root.tsx (1 hunks)
  • apps/desktop2/src/routes/app/main/_layout.index.tsx (2 hunks)
💤 Files with no reviewable changes (2)
  • apps/desktop2/src/components/main/main-area.tsx
  • apps/desktop2/src/components/main/left-sidebar.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,rs}

⚙️ CodeRabbit configuration file

**/*.{js,ts,tsx,rs}: 1. Do not add any error handling. Keep the existing one.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

Files:

  • apps/desktop2/src/components/main/body/events.tsx
  • apps/desktop2/src/components/main/body/humans.tsx
  • apps/desktop2/src/components/main/body/shared.tsx
  • apps/desktop2/src/components/main/body/index.tsx
  • apps/desktop2/src/components/main/sidebar/index.tsx
  • apps/desktop2/src/components/main/body/calendars.tsx
  • apps/desktop2/src/routes/app/main/_layout.index.tsx
  • apps/desktop2/src/components/main/sidebar/profile.tsx
  • apps/desktop2/src/components/main/sidebar/timeline.tsx
  • apps/desktop2/src/components/main/body/sessions.tsx
  • apps/desktop2/src/routes/__root.tsx
  • apps/desktop2/src/components/main/body/folders.tsx
🧬 Code graph analysis (10)
apps/desktop2/src/components/main/body/events.tsx (2)
apps/desktop2/src/components/main/body/shared.tsx (2)
  • TabItem (5-9)
  • TabItemBase (11-52)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • rowIdfromTab (117-135)
apps/desktop2/src/components/main/body/humans.tsx (1)
apps/desktop2/src/components/main/body/shared.tsx (2)
  • TabItem (5-9)
  • TabItemBase (11-52)
apps/desktop2/src/components/main/body/index.tsx (7)
apps/desktop2/src/store/zustand/tabs.ts (2)
  • useTabs (22-82)
  • uniqueIdfromTab (137-152)
apps/desktop2/src/components/main/body/shared.tsx (1)
  • TabItem (5-9)
apps/desktop2/src/components/main/body/sessions.tsx (2)
  • TabItemNote (11-23)
  • TabContentNote (25-75)
apps/desktop2/src/components/main/body/events.tsx (2)
  • TabItemEvent (7-19)
  • TabContentEvent (21-26)
apps/desktop2/src/components/main/body/calendars.tsx (2)
  • TabItemCalendar (10-20)
  • TabContentCalendar (22-60)
apps/desktop2/src/components/main/body/folders.tsx (2)
  • TabItemFolder (8-18)
  • TabContentFolder (50-62)
apps/desktop2/src/components/main/body/humans.tsx (2)
  • TabItemHuman (7-23)
  • TabContentHuman (25-31)
apps/desktop2/src/components/main/sidebar/index.tsx (4)
packages/utils/src/contexts/left-sidebar.tsx (1)
  • useLeftSidebar (42-48)
apps/desktop2/src/components/main/sidebar/timeline.tsx (1)
  • TimelineView (8-23)
apps/desktop2/src/components/main/sidebar/profile.tsx (1)
  • ProfileSection (8-97)
apps/desktop2/src/components/main/left-sidebar.tsx (1)
  • LeftSidebar (13-36)
apps/desktop2/src/components/main/body/calendars.tsx (3)
apps/desktop2/src/components/main/body/shared.tsx (2)
  • TabItem (5-9)
  • TabItemBase (11-52)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (22-82)
packages/ui/src/components/block/calendar-structure.tsx (1)
  • CalendarStructure (14-71)
apps/desktop2/src/routes/app/main/_layout.index.tsx (1)
apps/desktop2/src/components/main/body/index.tsx (1)
  • MainContent (12-25)
apps/desktop2/src/components/main/sidebar/profile.tsx (1)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (22-82)
apps/desktop2/src/components/main/sidebar/timeline.tsx (2)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (22-82)
apps/desktop2/src/components/interactive-button.tsx (1)
  • InteractiveButton (13-55)
apps/desktop2/src/components/main/body/sessions.tsx (3)
apps/desktop2/src/components/main/body/shared.tsx (2)
  • TabItem (5-9)
  • TabItemBase (11-52)
apps/desktop2/src/store/zustand/tabs.ts (2)
  • rowIdfromTab (117-135)
  • useTabs (22-82)
packages/ui/src/components/block/title-input.tsx (1)
  • TitleInput (12-59)
apps/desktop2/src/components/main/body/folders.tsx (2)
apps/desktop2/src/components/main/body/shared.tsx (2)
  • TabItem (5-9)
  • TabItemBase (11-52)
apps/desktop2/src/store/zustand/tabs.ts (1)
  • useTabs (22-82)
🪛 Biome (2.1.2)
apps/desktop2/src/components/main/body/calendars.tsx

[error] 27-27: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

apps/desktop2/src/components/main/body/folders.tsx

[error] 37-37: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ci (macos, macos-14)
  • GitHub Check: ci (windows, windows-latest)

Comment on lines +22 to +44
export function TabContentCalendar({ tab }: { tab: Tab }) {
if (tab.type !== "calendars") {
return null;
}

const { openCurrent } = useTabs();
const monthStart = startOfMonth(tab.month);
const monthEnd = endOfMonth(tab.month);
const days = eachDayOfInterval({ start: monthStart, end: monthEnd }).map((day) => format(day, "yyyy-MM-dd"));
const startDayOfWeek = getDay(monthStart);
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

const handlePreviousMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, -1) });
};

const handleNextMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, 1) });
};

const handleToday = () => {
openCurrent({ ...tab, month: new Date() });
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Move useTabs before the type guard to satisfy the Hooks rule.

useTabs() currently sits after an early return, so when tab.type isn’t "calendars" the hook is skipped. If React later renders the same component with a calendar tab, the hook order changes and state can corrupt (the lint warning you’ve probably seen). Pull the hook call above the guard.

-export function TabContentCalendar({ tab }: { tab: Tab }) {
-  if (tab.type !== "calendars") {
-    return null;
-  }
-
-  const { openCurrent } = useTabs();
+export function TabContentCalendar({ tab }: { tab: Tab }) {
+  const { openCurrent } = useTabs();
+
+  if (tab.type !== "calendars") {
+    return null;
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function TabContentCalendar({ tab }: { tab: Tab }) {
if (tab.type !== "calendars") {
return null;
}
const { openCurrent } = useTabs();
const monthStart = startOfMonth(tab.month);
const monthEnd = endOfMonth(tab.month);
const days = eachDayOfInterval({ start: monthStart, end: monthEnd }).map((day) => format(day, "yyyy-MM-dd"));
const startDayOfWeek = getDay(monthStart);
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const handlePreviousMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, -1) });
};
const handleNextMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, 1) });
};
const handleToday = () => {
openCurrent({ ...tab, month: new Date() });
};
export function TabContentCalendar({ tab }: { tab: Tab }) {
const { openCurrent } = useTabs();
if (tab.type !== "calendars") {
return null;
}
const monthStart = startOfMonth(tab.month);
const monthEnd = endOfMonth(tab.month);
const days = eachDayOfInterval({ start: monthStart, end: monthEnd }).map((day) =>
format(day, "yyyy-MM-dd")
);
const startDayOfWeek = getDay(monthStart);
const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const handlePreviousMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, -1) });
};
const handleNextMonth = () => {
openCurrent({ ...tab, month: addMonths(tab.month, 1) });
};
const handleToday = () => {
openCurrent({ ...tab, month: new Date() });
};
// ...rest of component
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 27-27: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

🤖 Prompt for AI Agents
In apps/desktop2/src/components/main/body/calendars.tsx around lines 22 to 44,
the call to useTabs() is after an early return guard for tab.type which violates
the Rules of Hooks; move the const { openCurrent } = useTabs(); call above the
if (tab.type !== "calendars") return null; so the hook is always invoked in the
same order, then keep the type guard and the rest of the month calculations and
handlers unchanged.

Comment on lines +33 to +47
if (tab.type !== "folders" || tab.id === null) {
return null;
}

const folderName = persisted.UI.useCell("folders", tab.id, "name", persisted.STORE_ID);

return (
<TabItemBase
icon={<FolderIcon className="w-4 h-4" />}
title={folderName ?? ""}
active={tab.active}
handleClose={() => handleClose(tab)}
handleSelect={() => handleSelect(tab)}
/>
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unconditional hook needed in TabItemFolderSpecific

persisted.UI.useCell is a hook, yet it only runs when the guard passes. That breaks the hooks contract (and Biome already errors), so lint will fail and future renders risk hook order mismatches. Please restructure so the hook lives in a component that’s always executed—e.g. delegate to an inner component that receives the narrowed folderId and calls the hook there.

-const TabItemFolderSpecific: TabItem = ({ tab, handleClose, handleSelect }) => {
-  if (tab.type !== "folders" || tab.id === null) {
-    return null;
-  }
-
-  const folderName = persisted.UI.useCell("folders", tab.id, "name", persisted.STORE_ID);
-
-  return (
-    <TabItemBase
-      icon={<FolderIcon className="w-4 h-4" />}
-      title={folderName ?? ""}
-      active={tab.active}
-      handleClose={() => handleClose(tab)}
-      handleSelect={() => handleSelect(tab)}
-    />
-  );
-};
+const TabItemFolderSpecific: TabItem = ({ tab, handleClose, handleSelect }) => {
+  if (tab.type !== "folders" || tab.id === null) {
+    return null;
+  }
+
+  return (
+    <TabItemFolderSpecificContent
+      tab={tab}
+      folderId={tab.id}
+      handleClose={handleClose}
+      handleSelect={handleSelect}
+    />
+  );
+};
+
+function TabItemFolderSpecificContent(
+  { tab, folderId, handleClose, handleSelect }: {
+    tab: Tab;
+    folderId: string;
+    handleClose: (tab: Tab) => void;
+    handleSelect: (tab: Tab) => void;
+  },
+) {
+  const folderName = persisted.UI.useCell("folders", folderId, "name", persisted.STORE_ID);
+
+  return (
+    <TabItemBase
+      icon={<FolderIcon className="w-4 h-4" />}
+      title={folderName ?? ""}
+      active={tab.active}
+      handleClose={() => handleClose(tab)}
+      handleSelect={() => handleSelect(tab)}
+    />
+  );
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (tab.type !== "folders" || tab.id === null) {
return null;
}
const folderName = persisted.UI.useCell("folders", tab.id, "name", persisted.STORE_ID);
return (
<TabItemBase
icon={<FolderIcon className="w-4 h-4" />}
title={folderName ?? ""}
active={tab.active}
handleClose={() => handleClose(tab)}
handleSelect={() => handleSelect(tab)}
/>
);
const TabItemFolderSpecific: TabItem = ({ tab, handleClose, handleSelect }) => {
if (tab.type !== "folders" || tab.id === null) {
return null;
}
return (
<TabItemFolderSpecificContent
tab={tab}
folderId={tab.id}
handleClose={handleClose}
handleSelect={handleSelect}
/>
);
};
function TabItemFolderSpecificContent(
{ tab, folderId, handleClose, handleSelect }: {
tab: Tab;
folderId: string;
handleClose: (tab: Tab) => void;
handleSelect: (tab: Tab) => void;
},
) {
const folderName = persisted.UI.useCell("folders", folderId, "name", persisted.STORE_ID);
return (
<TabItemBase
icon={<FolderIcon className="w-4 h-4" />}
title={folderName ?? ""}
active={tab.active}
handleClose={() => handleClose(tab)}
handleSelect={() => handleSelect(tab)}
/>
);
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 37-37: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

Comment on lines +27 to +142
const sessionRow = persisted.UI.useRow("sessions", sessionId, persisted.STORE_ID);

const handleEditTitle = persisted.UI.useSetRowCallback(
"sessions",
sessionId,
(input: string, _store) => ({ ...sessionRow, title: input }),
[sessionRow],
persisted.STORE_ID,
);

const handleEditRawMd = persisted.UI.useSetRowCallback(
"sessions",
sessionId,
(input: string, _store) => ({ ...sessionRow, raw_md: input }),
[sessionRow],
persisted.STORE_ID,
);

return (
<div className="flex flex-col gap-2 px-2 pt-2">
<TabContentNoteHeader sessionRow={sessionRow} />

<TitleInput
editable={true}
value={sessionRow.title ?? ""}
onChange={(e) => handleEditTitle(e.target.value)}
/>
<TabHeader
isEnhancing={false}
onVisibilityChange={() => {}}
currentTab="raw"
onTabChange={() => {}}
isCurrentlyRecording={false}
shouldShowTab={true}
shouldShowEnhancedTab={false}
/>
<NoteEditor
initialContent={sessionRow.raw_md ?? ""}
handleChange={(e) => handleEditRawMd(e)}
mentionConfig={{
trigger: "@",
handleSearch: async () => {
return [];
},
}}
/>
</div>
);
}

function TabContentNoteHeader({ sessionRow }: { sessionRow: ReturnType<typeof persisted.UI.useRow<"sessions">> }) {
return (
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
{sessionRow.folder_id && (
<TabContentNoteHeaderFolderChain
title={sessionRow.title ?? ""}
folderId={sessionRow.folder_id}
/>
)}
</div>

{sessionRow.event_id && <TabContentNoteHeaderEvent eventId={sessionRow.event_id} />}
</div>
);
}

function TabContentNoteHeaderFolderChain({ title, folderId }: { title: string; folderId: string }) {
const folderIds = persisted.UI.useLinkedRowIds(
"folderToParentFolder",
folderId,
persisted.STORE_ID,
);

if (!folderIds || folderIds.length === 0) {
return null;
}

const folderChain = [...folderIds].reverse();

return (
<div className="flex items-center gap-1 text-sm text-muted-foreground">
{folderChain.map((id, index) => (
<div key={id} className="flex items-center gap-1">
{index > 0 && <span>/</span>}
<TabContentNoteHeaderFolder folderId={id} />
</div>
))}
<div className="flex items-center gap-2">
<span>/</span>
<span className="truncate max-w-[80px]">{title}</span>
</div>
</div>
);
}

function TabContentNoteHeaderFolder({ folderId }: { folderId: string }) {
const folderName = persisted.UI.useCell("folders", folderId, "name", persisted.STORE_ID);
const { openNew } = useTabs();
const handleClick = useCallback(() => {
openNew({ type: "folders", id: folderId, active: true });
}, [openNew, folderId]);

return (
<button
className="text-gray-500 hover:text-gray-700"
onClick={handleClick}
>
{folderName}
</button>
);
}

function TabContentNoteHeaderEvent({ eventId }: { eventId: string }) {
const eventRow = persisted.UI.useRow("events", eventId, persisted.STORE_ID);
return <div>{eventRow.title}</div>;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against missing session/event rows to avoid crashes.

persisted.UI.useRow returns undefined when the backing row is missing or not yet hydrated (e.g., note deleted, data still loading). We immediately read from sessionRow and eventRow, so those cases will throw Cannot read properties of undefined and break the main area. Bail out early when either row is absent before touching their fields.

   const sessionRow = persisted.UI.useRow("sessions", sessionId, persisted.STORE_ID);
 
+  if (!sessionRow) {
+    return null;
+  }
@@
 function TabContentNoteHeaderEvent({ eventId }: { eventId: string }) {
   const eventRow = persisted.UI.useRow("events", eventId, persisted.STORE_ID);
-  return <div>{eventRow.title}</div>;
+  if (!eventRow) {
+    return null;
+  }
+  return <div>{eventRow.title}</div>;
 }
🤖 Prompt for AI Agents
In apps/desktop2/src/components/main/body/sessions.tsx around lines 27-142, add
guards to handle missing rows: check if sessionRow is undefined at the top of
the main component and return a safe fallback (null or a loading/empty state)
before reading sessionRow.title, raw_md, folder_id, or event_id; similarly, in
TabContentNoteHeaderEvent ensure eventRow is checked for undefined before
accessing eventRow.title and return null if absent; also ensure
TabContentNoteHeaderFolderChain handles a missing/empty folderIds (already
partly handled) but bail out early if folderIds is falsy; these changes will
prevent attempts to read properties on undefined and avoid crashes.

@coderabbitai
Copy link

coderabbitai bot commented Oct 9, 2025

✅ Actions performed

Reviews paused.

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.

2 participants