Perf: improve rendering performance of Notes with big number of Notes#357
Perf: improve rendering performance of Notes with big number of Notes#357
Conversation
✅ Deploy Preview for graypaper-reader ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughReplaces direct NotesContext usage with a new hook Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as UI (NoteManager / Components)
participant Hook as useNoteManagerNotes
participant NotesCtx as NotesContext
participant CodeSync as CodeSyncContext
participant Cache as Metadata Cache
UI->>Hook: mount / render — request notes + readiness
Hook->>NotesCtx: read notes, activeNotes, handlers, notesReady
loop each note
Hook->>Cache: lookup metadata by note.key
alt cache miss
Hook->>CodeSync: getSectionTitles(selectionStart)
CodeSync-->>Hook: sectionTitle, subSectionTitle
Hook->>Cache: store metadata for note.key
else cache hit
Cache-->>Hook: metadata
end
end
Hook-->>UI: return INotesMangerNote[] (noteObject + metadata), notesReady, sectionTitlesLoaded, handlers
UI->>Hook: user triggers add/update/delete
Hook->>NotesCtx: forward add/update/delete
NotesCtx-->>Hook: confirmation/update
Hook-->>UI: updated notes state
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
🧰 Additional context used📓 Path-based instructions (4)src/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{js,jsx,ts,tsx}⚙️ CodeRabbit configuration file
Files:
🧠 Learnings (2)📓 Common learnings📚 Learning: 2025-12-28T13:25:05.152ZApplied to files:
⏰ 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). (1)
🔇 Additional comments (3)
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. Comment |
Visual Regression Test Report ✅ PassedGithub run id: 20560209608 🔗 Artifacts: Download |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
src/components/NoteManager/useNoteManagerNotes.ts (1)
67-74: Remove unusedcacheByKeyfield.Line 73 sets a
cacheByKeyfield onnoteManagerNote, but this field is not part of theINotesMangerNotetype definition and is never read anywhere in the codebase. This appears to be dead code or an incomplete implementation.🔎 Proposed fix
const noteManagerNote = { noteObject: note, metadata: { sectionTitle: sectionTitles.sectionTitle, subSectionTitle: sectionTitles.subSectionTitle, }, - cacheByKey: new Set<string>(notes.map((note) => note.key)), };src/components/NoteManager/components/Note.tsx (1)
46-64: Create a new object before passing toonEditNoterather than mutating state directly.Line 60 mutates the
noteDirtystate object directly withnoteDirty.content = contentbefore passing it toonEditNote. While the callback is synchronous and works correctly, directly mutating state objects violates React best practices. Instead, create a new object:const updatedNote = { ...noteDirty, content }; onEditNote(note, updatedNote);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NoteLayout.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx}: Feature folders should keep components, hooks, and styles together insrc/
Prefer hooks over Higher-Order Components (HOCs)
Colocate helper functions with their consumer components
Use PascalCase for component names
Favor semantic wrappers over long Tailwind utility class strings; complement Tailwind with@fluffylabs/shared-uicomponents
Files:
src/components/NoteManager/useNoteManagerNotes.tssrc/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript as the primary language with functional React components
Use camelCase for function and variable names
Use SCREAMING_SNAKE_CASE for constants
Files:
src/components/NoteManager/useNoteManagerNotes.tssrc/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use 2-space indentation
Files:
src/components/NoteManager/useNoteManagerNotes.tssrc/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
**/*.{js,jsx,ts,tsx}
⚙️ CodeRabbit configuration file
When reviewing Tailwind CSS classes, ensure they follow Tailwind 4.x conventions and suggest modern 4.x alternatives for deprecated patterns.
Files:
src/components/NoteManager/useNoteManagerNotes.tssrc/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: FluffyLabs/graypaper-reader PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-26T10:17:47.372Z
Learning: Write imperative, present-tense commit subject lines under 72 characters with helpful scopes (e.g., `feat(notes): add label filter`)
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
📚 Learning: 2025-12-28T13:25:05.152Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 355
File: src/components/NoteManager/components/NoteLayout.tsx:39-39
Timestamp: 2025-12-28T13:25:05.152Z
Learning: In Tailwind CSS 4.x, max-h-68 is a valid utility that sets max-height: 17rem (272px) and is part of the extended spacing scale. When reviewing TSX files, verify components use this class consistently and that tailwind.config.js includes the 68 spacing key in the extended spacing scale if you rely on it.
Applied to files:
src/components/NoteManager/components/NewNote.tsxsrc/components/NoteManager/components/NoteContext.tsxsrc/components/NoteManager/components/NotesList.tsxsrc/components/NoteManager/components/Note.tsxsrc/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/components/NoteLink.tsxsrc/components/NoteManager/components/NoteLayout.tsx
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Tailwind CSS v4 is used; avoid non-default width utilities like border-b-1 unless configured. Prefer border-b (1px) or border-b-[1px]. File context: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/components/NoteLink.tsx
🧬 Code graph analysis (6)
src/components/NoteManager/useNoteManagerNotes.ts (4)
src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)src/components/NotesProvider/NotesProvider.tsx (2)
NotesContext(18-18)INotesContext(20-40)src/components/CodeSyncProvider/CodeSyncProvider.tsx (2)
CodeSyncContext(31-31)ICodeSyncContext(11-22)src/hooks/useLatestCallback.ts (1)
useLatestCallback(4-8)
src/components/NoteManager/components/NotesList.tsx (1)
src/components/NoteManager/useNoteManagerNotes.ts (1)
INotesMangerNote(7-13)
src/components/NoteManager/components/Note.tsx (4)
src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)src/utils/validateMath.ts (1)
validateMath(3-14)src/components/NoteManager/components/NoteLink.tsx (1)
NoteLink(7-60)src/components/NoteManager/components/NoteLayout.tsx (1)
NoteLayout(63-70)
src/components/NoteManager/NoteManager.tsx (7)
src/components/NoteManager/useNoteManagerNotes.ts (1)
useNoteManagerNotes(15-99)src/components/SelectionProvider/SelectionProvider.tsx (2)
SelectionContext(35-35)ISelectionContext(21-29)shared/links-metadata/src/types.ts (1)
ISynctexBlockId(1-4)src/hooks/useLatestCallback.ts (1)
useLatestCallback(4-8)src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)src/components/NotesProvider/types/StorageNote.ts (1)
IStorageNote(5-5)src/components/NotesProvider/utils/areSelectionsEqual.ts (1)
areSelectionsEqual(8-13)
src/components/NoteManager/components/NoteLink.tsx (1)
src/components/NoteManager/components/NoteContext.tsx (1)
useNoteContext(26-32)
src/components/NoteManager/components/NoteLayout.tsx (4)
src/components/NoteManager/components/NoteLink.tsx (1)
NoteLink(7-60)src/components/NoteManager/components/NoteContext.tsx (1)
useNoteContext(26-32)src/components/NoteManager/components/SimpleComponents/Textarea.tsx (1)
NoteSimpleTextarea(6-10)src/components/NoteManager/components/SimpleComponents/index.ts (1)
NoteSimpleTextarea(2-2)
⏰ 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). (1)
- GitHub Check: visual-tests
🔇 Additional comments (10)
src/components/NoteManager/components/NoteContext.tsx (1)
1-1: LGTM! Clean context refactor.The removal of
ChangeEventand addition ofsectionTitlescorrectly reflects the architectural shift from onChange-based content tracking to centralized section title management.Also applies to: 21-21
src/components/NoteManager/components/NoteLink.tsx (1)
7-9: LGTM! Effective performance optimization.The refactor to accept
showTooltipand useuseId()for unique tooltip IDs is well-executed. Conditionally rendering theTooltipcomponent only when needed will improve performance with large numbers of notes.Also applies to: 27-30, 57-57
src/components/NoteManager/components/NoteLayout.tsx (1)
36-36: LGTM! Consistent refactor to uncontrolled textarea pattern.The changes correctly implement the shift from onChange-based content tracking to ref-based reading:
- Line 36:
showTooltip={true}ensures tooltip is always rendered when editing- Line 46: Removal of
handleNoteContentChangealigns with context updates- Line 60:
defaultValuewith props spreading maintains keyboard handlers while eliminating controlled stateAlso applies to: 46-46, 60-60
src/components/NoteManager/components/NewNote.tsx (2)
32-64: LGTM! Proper ref-based content reading with validation.The refactor correctly:
- Reads content from
textAreaRef.current?.valueat save time (line 32)- Adds empty content validation after trimming (lines 55-58)
- Updates
noteDirty.contentbefore callingonEditNote(line 60)This approach is cleaner than maintaining controlled state and aligns with the PR's architecture.
159-159: LGTM! Appropriate default for new notes.The empty
sectionTitlesconstant is correct for new notes that don't yet have a finalized location.src/components/NoteManager/components/NotesList.tsx (1)
16-16: LGTM! Correct adaptation to new note structure.The component properly:
- Updates the prop type to
INotesMangerNote[](line 16)- Accesses
note.noteObjectfor active state checks (lines 33-34)- Passes
note.metadataassectionTitlesto child components (line 42)The data flow is correct and consistent with the architectural changes.
Also applies to: 33-46
src/components/NoteManager/NoteManager.tsx (2)
31-39: LGTM! Hook integration and readiness gating implemented correctly.The changes properly:
- Replace direct
NotesContextusage withuseNoteManagerNoteshook (lines 31-39)- Clear selection on delete for better UX (line 47)
- Combine readiness checks for both notes and section titles (line 126)
- Access
note.noteObjectfor active checks (line 124)The readiness gating ensures UI doesn't render until all data is available.
Also applies to: 44-50, 124-126
52-58: Critical: Mutation occurs before handler can validate or reject the update.Line 54 mutates
note.original.contentbeforelatestUpdateNote.current()is called. However,handleUpdateNotein NotesProvider has an early return on line 160 if the note's source is Remote—the mutation will persist even though the update is refused, creating state inconsistency.Move the mutation inside the handler after validation succeeds, or validate the note source before mutating.
src/components/NoteManager/components/Note.tsx (2)
234-240: LGTM! Proper state management and performance optimization.The changes correctly implement:
- State reset when note becomes inactive (lines 234-240) prevents stale hover/focus/dropdown state
- Tooltip optimization with
showTooltip={isHovered}(line 269) aligns with performance goals- Ref wiring to textarea (line 284) enables ref-based content reading
Also applies to: 269-269, 284-284
23-23: LGTM! CorrectsectionTitlespropagation.The
sectionTitlesprop is properly:
- Added to the component's type signature (line 23)
- Accepted as a parameter (line 30)
- Passed through to the layout context (line 173)
- Included in the dependency array (line 190)
This enables downstream components like
NoteLinkto access section titles from context.Also applies to: 30-30, 173-173, 190-190
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/NoteManager/components/NewNote.tsx (1)
181-206: Error handling for async section title fetching is optional but recommended.The
CodeSyncContextis always provided at the app root level (App.tsx), so the type assertion is safe in practice. However, the async calls togetSectionTitleAtSynctexBlockandgetSubsectionTitleAtSynctexBlocklack error handling, which could cause unhandled promise rejections if the underlyingtexStore.getTexAsLinesfails.Consider wrapping the async operations in a try-catch block as defensive programming:
useEffect(() => { let cancelled = false; (async () => { if (selectionStart && selectionEnd) { + try { const newSectionTitle = (await getSectionTitleAtSynctexBlock(selectionStart)) ?? ""; const newSubSectionTitle = (await getSubsectionTitleAtSynctexBlock(selectionStart)) ?? ""; if (cancelled) return; setSectionTitles({ sectionTitle: newSectionTitle, subSectionTitle: newSubSectionTitle, }); + } catch (error) { + console.error("Failed to fetch section titles:", error); + if (cancelled) return; + setSectionTitles({ + sectionTitle: "", + subSectionTitle: "", + }); + } } })(); return () => { cancelled = true; }; }, [selectionStart, selectionEnd, getSectionTitleAtSynctexBlock, getSubsectionTitleAtSynctexBlock]);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/NoteManager/components/NewNote.tsx
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx}: Feature folders should keep components, hooks, and styles together insrc/
Prefer hooks over Higher-Order Components (HOCs)
Colocate helper functions with their consumer components
Use PascalCase for component names
Favor semantic wrappers over long Tailwind utility class strings; complement Tailwind with@fluffylabs/shared-uicomponents
Files:
src/components/NoteManager/components/NewNote.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript as the primary language with functional React components
Use camelCase for function and variable names
Use SCREAMING_SNAKE_CASE for constants
Files:
src/components/NoteManager/components/NewNote.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use 2-space indentation
Files:
src/components/NoteManager/components/NewNote.tsx
**/*.{js,jsx,ts,tsx}
⚙️ CodeRabbit configuration file
When reviewing Tailwind CSS classes, ensure they follow Tailwind 4.x conventions and suggest modern 4.x alternatives for deprecated patterns.
Files:
src/components/NoteManager/components/NewNote.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/components/NewNote.tsx
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/components/NewNote.tsx
📚 Learning: 2025-12-28T13:25:05.152Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 355
File: src/components/NoteManager/components/NoteLayout.tsx:39-39
Timestamp: 2025-12-28T13:25:05.152Z
Learning: In Tailwind CSS 4.x, max-h-68 is a valid utility that sets max-height: 17rem (272px) and is part of the extended spacing scale. When reviewing TSX files, verify components use this class consistently and that tailwind.config.js includes the 68 spacing key in the extended spacing scale if you rely on it.
Applied to files:
src/components/NoteManager/components/NewNote.tsx
🧬 Code graph analysis (1)
src/components/NoteManager/components/NewNote.tsx (4)
src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)shared/links-metadata/src/types.ts (1)
ISynctexBlockId(1-4)src/components/CodeSyncProvider/CodeSyncProvider.tsx (2)
CodeSyncContext(31-31)ICodeSyncContext(11-22)src/components/NoteManager/components/NoteContext.tsx (1)
ISingleNoteContext(6-22)
⏰ 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). (1)
- GitHub Check: visual-tests
🔇 Additional comments (3)
src/components/NoteManager/components/NewNote.tsx (3)
32-46: LGTM! Clean ref-based content reading pattern.The refactor from state-based to ref-based content access is well-executed. The validation flow properly checks for both math validation errors and empty content before saving.
66-72: Good addition of focus management.The
handleSelectionChangecallback ensures the textarea receives focus when the selection changes, improving the user experience.
149-149: Content field intentionally empty in dummy object.The
contentfield is now always an empty string since content is read directly from the textarea ref on save. This is consistent with the ref-based approach and the dependency array correctly excludesnoteContent.Also applies to: 157-157
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/components/NoteManager/useNoteManagerNotes.ts (2)
7-13: Typo in type name:INotesMangerNoteshould beINotesManagerNote.The type is missing an 'a' in "Manager". Since this is exported and used in other files, consider fixing for consistency and discoverability.
🔎 Proposed fix
-export type INotesMangerNote = { +export type INotesManagerNote = { noteObject: IDecoratedNote; metadata: { sectionTitle: string; subSectionTitle: string; }; };
15-22: Consider adding null guards for context consumption.The type assertions (
as INotesContextandas ICodeSyncContext) assume the contexts are never null. If this hook is ever used outside the provider tree, it will fail silently. Adding a runtime check or using a custom hook that throws on missing context would improve robustness.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx}: Feature folders should keep components, hooks, and styles together insrc/
Prefer hooks over Higher-Order Components (HOCs)
Colocate helper functions with their consumer components
Use PascalCase for component names
Favor semantic wrappers over long Tailwind utility class strings; complement Tailwind with@fluffylabs/shared-uicomponents
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript as the primary language with functional React components
Use camelCase for function and variable names
Use SCREAMING_SNAKE_CASE for constants
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use 2-space indentation
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{js,jsx,ts,tsx}
⚙️ CodeRabbit configuration file
When reviewing Tailwind CSS classes, ensure they follow Tailwind 4.x conventions and suggest modern 4.x alternatives for deprecated patterns.
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
📚 Learning: 2025-12-28T13:25:05.152Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 355
File: src/components/NoteManager/components/NoteLayout.tsx:39-39
Timestamp: 2025-12-28T13:25:05.152Z
Learning: In Tailwind CSS 4.x, max-h-68 is a valid utility that sets max-height: 17rem (272px) and is part of the extended spacing scale. When reviewing TSX files, verify components use this class consistently and that tailwind.config.js includes the 68 spacing key in the extended spacing scale if you rely on it.
Applied to files:
src/components/NoteManager/NoteManager.tsx
🧬 Code graph analysis (2)
src/components/NoteManager/NoteManager.tsx (5)
src/components/SelectionProvider/SelectionProvider.tsx (2)
SelectionContext(35-35)ISelectionContext(21-29)src/hooks/useLatestCallback.ts (1)
useLatestCallback(4-8)src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)src/components/NotesProvider/types/StorageNote.ts (1)
IStorageNote(5-5)src/components/NotesProvider/utils/areSelectionsEqual.ts (1)
areSelectionsEqual(8-13)
src/components/NoteManager/useNoteManagerNotes.ts (4)
src/components/NotesProvider/types/DecoratedNote.ts (1)
IDecoratedNote(4-19)src/components/NotesProvider/NotesProvider.tsx (2)
NotesContext(18-18)INotesContext(20-40)src/components/CodeSyncProvider/CodeSyncProvider.tsx (2)
CodeSyncContext(31-31)ICodeSyncContext(11-22)src/hooks/useLatestCallback.ts (1)
useLatestCallback(4-8)
⏰ 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). (1)
- GitHub Check: visual-tests
🔇 Additional comments (6)
src/components/NoteManager/useNoteManagerNotes.ts (2)
48-102: LGTM!The async effect with cancellation pattern is well-implemented. The cache-first approach with parallel fetching via
Promise.allis good for performance. The cancellation guard at line 80 correctly prevents state updates after unmount.
116-132: LGTM!Clean helper function with parallel fetching and appropriate null coalescing for fallback values.
src/components/NoteManager/NoteManager.tsx (4)
31-39: LGTM!Clean destructuring from the new
useNoteManagerNoteshook. The integration properly replaces direct context consumption with the composed hook.
95-96: LGTM!Good use of ref pattern to keep
memoizedHandleSelectNotestable while accessing freshlocationParamsandsetLocationParamsvalues. This avoids unnecessary re-renders of child components.
134-172: LGTM!The render logic properly gates UI based on
readyAndLoadedstate. The skeleton/no-notes message conditions are mutually exclusive and correct. The opacity and pointer-events styling provides clear visual feedback during loading.
128-132: LGTM!Simple effect to reset the temporary new-note state once notes are fully loaded. The dependency on
readyAndLoadedis correct.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/components/NoteManager/useNoteManagerNotes.ts (1)
7-13: Fix typo in exported type name.The type name
INotesMangerNotehas a typo (missing 'a'). It should beINotesManagerNotefor consistency with the file and hook name.🔎 Proposed fix
-export type INotesMangerNote = { +export type INotesManagerNote = { noteObject: IDecoratedNote; metadata: { sectionTitle: string; subSectionTitle: string; }; };Then update all references in this file and consumers (e.g.,
NoteManager.tsx,NotesList.tsx).
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (8)
tools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-note-activation-dark-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-note-activation-light-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-note-edit-dark-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-note-edit-light-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-opening-dropdown-dark-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-after-opening-dropdown-light-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-initial-dark-mode-linux.pngis excluded by!**/*.pngtools/snapshot-tests/tests/basic-snapshots.spec.ts-snapshots/notes-tab-initial-light-mode-linux.pngis excluded by!**/*.png
📒 Files selected for processing (2)
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
src/**/*.{ts,tsx}: Feature folders should keep components, hooks, and styles together insrc/
Prefer hooks over Higher-Order Components (HOCs)
Colocate helper functions with their consumer components
Use PascalCase for component names
Favor semantic wrappers over long Tailwind utility class strings; complement Tailwind with@fluffylabs/shared-uicomponents
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use TypeScript as the primary language with functional React components
Use camelCase for function and variable names
Use SCREAMING_SNAKE_CASE for constants
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use 2-space indentation
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
**/*.{js,jsx,ts,tsx}
⚙️ CodeRabbit configuration file
When reviewing Tailwind CSS classes, ensure they follow Tailwind 4.x conventions and suggest modern 4.x alternatives for deprecated patterns.
Files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 357
File: src/components/NoteManager/NoteManager.tsx:52-58
Timestamp: 2025-12-28T21:09:55.992Z
Learning: In `src/components/NoteManager/NoteManager.tsx`, the direct mutation of `note.original.content` in `memoizedHandleUpdateNote` before calling `updateNote` is intentional and used for optimistic UI updates.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 357
File: src/components/NoteManager/NoteManager.tsx:52-58
Timestamp: 2025-12-28T21:10:25.396Z
Learning: In src/components/NoteManager/NoteManager.tsx, direct mutation of `note.original.content` before calling `updateNote` is intentional for optimistic UI updates. This pattern is documented with an explicit comment in the code.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
📚 Learning: 2025-12-28T21:10:25.396Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 357
File: src/components/NoteManager/NoteManager.tsx:52-58
Timestamp: 2025-12-28T21:10:25.396Z
Learning: In src/components/NoteManager/NoteManager.tsx, direct mutation of `note.original.content` before calling `updateNote` is intentional for optimistic UI updates. This pattern is documented with an explicit comment in the code.
Applied to files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
📚 Learning: 2025-12-28T21:09:55.992Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 357
File: src/components/NoteManager/NoteManager.tsx:52-58
Timestamp: 2025-12-28T21:09:55.992Z
Learning: In src/components/NoteManager/NoteManager.tsx, note.original.content is mutated directly within memoizedHandleUpdateNote before updateNote is called to support optimistic UI updates. This is intentional for this component; during reviews, don't flag this as an improper mutation. Ensure the mutation is isolated, safe, and revertible, and consider documenting the rationale in code comments.
Applied to files:
src/components/NoteManager/NoteManager.tsx
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: This repo targets React 19+; prefer passing refs as a normal prop to function components and avoid React.forwardRef in new code. File context: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
📚 Learning: 2025-10-22T20:36:10.440Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 330
File: src/components/Outline/OutlineLink.tsx:17-21
Timestamp: 2025-10-22T20:36:10.440Z
Learning: Project targets React 19+; prefer passing refs as a regular prop in function components and avoid React.forwardRef in new code. File: src/components/Outline/OutlineLink.tsx.
Applied to files:
src/components/NoteManager/NoteManager.tsxsrc/components/NoteManager/useNoteManagerNotes.ts
📚 Learning: 2025-12-28T13:25:05.152Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 355
File: src/components/NoteManager/components/NoteLayout.tsx:39-39
Timestamp: 2025-12-28T13:25:05.152Z
Learning: In Tailwind CSS 4.x, max-h-68 is a valid utility that sets max-height: 17rem (272px) and is part of the extended spacing scale. When reviewing TSX files, verify components use this class consistently and that tailwind.config.js includes the 68 spacing key in the extended spacing scale if you rely on it.
Applied to files:
src/components/NoteManager/NoteManager.tsx
📚 Learning: 2025-12-28T21:09:55.992Z
Learnt from: chmurson
Repo: FluffyLabs/graypaper-reader PR: 357
File: src/components/NoteManager/NoteManager.tsx:52-58
Timestamp: 2025-12-28T21:09:55.992Z
Learning: In `src/components/NoteManager/NoteManager.tsx`, the direct mutation of `note.original.content` in `memoizedHandleUpdateNote` before calling `updateNote` is intentional and used for optimistic UI updates.
Applied to files:
src/components/NoteManager/useNoteManagerNotes.ts
⏰ 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). (1)
- GitHub Check: visual-tests
🔇 Additional comments (6)
src/components/NoteManager/useNoteManagerNotes.ts (2)
30-43: LGTM! Cache invalidation on mutations is correct.Both
updateNoteanddeleteNoteproperly invalidate cache entries before delegating to upstream handlers, ensuring metadata stays in sync with note changes.
115-131: LGTM! Efficient concurrent metadata fetching.The helper correctly fetches section and subsection titles in parallel and handles null values appropriately.
src/components/NoteManager/NoteManager.tsx (4)
31-39: LGTM! Clean hook integration.The migration from direct
NotesContextusage touseNoteManagerNotesis well-structured, and all necessary values are properly destructured.
44-50: LGTM! Correct delegation to hook's delete handler.The delete flow properly delegates to the hook's
deleteNote(which handles cache invalidation) and clears the selection. Dependencies are correct.
96-123: LGTM! Smart use of ref to stabilize callback.The
locationRefpattern correctly stabilizesmemoizedHandleSelectNoteby avoidinglocationParamsandsetLocationParamsin its dependency array, while ensuring the callback always reads current values.
125-174: LGTM! Rendering logic correctly handles dual loading states.The
readyAndLoadedcheck appropriately gates rendering on bothnotesReadyandsectionTitlesLoaded, preventing premature empty states and correctly managing skeleton display. TheisActiveNotescheck correctly accessesnote.noteObjectgiven the new data structure.
What?
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.