Conversation
…all-redesign-start
…all-redesign-start
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
…all-redesign-add-empty-chat
📝 WalkthroughWalkthroughIntroduces a tabbed editor area with “Summary/Enhanced”, “Memos/Raw”, and “Transcript” tabs; adds TranscriptViewer, EnhancedNoteSubHeader, and LocalSearchBar with search/replace styling. Updates header chips styling and title autofocus. Refactors right panel to always show chat with dynamic quick actions and model info modal. Adds session activeTab state and TipTap search integration. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant EA as EditorArea
participant TH as TabHeader
participant SS as Session Store
participant EN as EnhancedNoteSubHeader
participant TV as TranscriptViewer
participant ED as Editor
U->>EA: Open note
EA->>TH: Render tabs
TH->>SS: Read activeTab / status
alt activeTab == transcript
EA->>TV: Mount TranscriptViewer(sessionId)
else activeTab == enhanced
EA->>ED: Render Enhanced content
EA->>EN: Render Enhanced sub-header
else activeTab == raw
EA->>ED: Render Raw editor/renderer
end
EN-->>EA: onEnhance({manual|template})
EA->>SS: Mark enhancing/progress
TH->>SS: Auto-switch to enhanced when enhancing/finished
sequenceDiagram
autonumber
actor U as User
participant LSB as LocalSearchBar
participant TER as TranscriptEditorRef
participant SAR as Search&Replace storage
U->>LSB: Open (Cmd/Ctrl+F)
LSB->>TER: commands.setSearchTerm(term)
TER->>SAR: Update results
SAR-->>LSB: {index,total}
U->>LSB: Next/Prev
LSB->>TER: nextSearchResult / previousSearchResult
TER->>SAR: Current index
SAR-->>LSB: index
U->>LSB: Replace / Replace All
LSB->>TER: replace / replaceAll
U->>LSB: Escape
LSB->>LSB: Clear + onClose
sequenceDiagram
autonumber
actor U as User
participant CI as ChatInput
participant MI as ChatModelInfoModal
participant W as Windows API
participant Nav as Navigation
U->>CI: Click model badge
CI->>MI: Open modal
U->>MI: Click "Choose"
MI->>W: windowShow({settings})
Note over MI: wait 800ms
MI->>Nav: emit navigate /app/settings?tab=ai-llm
MI->>MI: Close
sequenceDiagram
autonumber
participant CV as ChatView
participant ECS as EmptyChatState
participant DQA as getDynamicQuickActions
participant SES as Session/Env Services
CV->>ECS: Render(sessionId)
ECS->>DQA: fetch actions(sessionId)
DQA->>SES: read session, participants, LLM state
SES-->>DQA: context data
DQA-->>ECS: QuickAction[]
ECS-->>CV: Render buttons
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests
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. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop/src/components/search-bar.tsx (1)
57-82: Remove unused event handlers.The
handleInputChangeandhandleKeyDownfunctions are now dead code since the input field is disabled (line 146) and haspointer-events-none(line 145). These handlers will never fire, violating the coding guideline against unused functions.Apply this diff to remove the unused handlers:
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { - const value = e.target.value; - setSearchQuery(value); - setShowHistory(value === "" && isFocused); - }; - - const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { - switch (e.key) { - case "ArrowDown": - e.preventDefault(); - navigateResults("down"); - break; - case "ArrowUp": - e.preventDefault(); - navigateResults("up"); - break; - case "Enter": - e.preventDefault(); - selectResult(); - break; - case "Escape": - e.preventDefault(); - clearSearch(); - break; - } - }; -And remove their references from the input element:
<input ref={searchInputRef} type="text" value={searchQuery} - onChange={handleInputChange} - onKeyDown={handleKeyDown} onFocus={() => {
🧹 Nitpick comments (37)
apps/desktop/src/components/toolbar/bars/main-toolbar.tsx (2)
60-60: Verify redundant route checking is intentional.The
ShareButtonis conditionally rendered whenisNoteis true (line 60), which checks if the route matches/app/note/$id. However, examining theShareButtonimplementation inapps/desktop/src/components/toolbar/buttons/share-button.tsx(lines 27-30), it internally performs the same route check usinguseParamsand returnsnullif the param doesn't exist.This creates redundant checking:
- Outer:
{isNote && <ShareButton />}- Inner:
return param ? <ShareButtonInNote /> : nullIf this defensive double-check is intentional for clarity or future-proofing, no action needed. Otherwise, consider removing the outer
isNotecondition sinceShareButtonhandles the null case internally.If you prefer to simplify, you could apply this diff:
- {isNote && <ShareButton />} + <ShareButton />
62-62: Remove commented-out code.The commented-out
TranscriptPanelButtonshould be removed entirely rather than left as a comment. The component is no longer imported and cannot be uncommented without errors. Git history preserves the removal if needed later.Apply this diff:
{isNote && <ShareButton />} <ChatPanelButton /> - {/*<TranscriptPanelButton />*/} </>packages/ui/src/components/ui/command.tsx (1)
72-72: Simplify the excessive width value.The
w-[2000px]is an unusually large fixed width that will always be overridden bymax-w-[450px]. This appears to be unintentional or a leftover from experimentation.Consider simplifying to a more reasonable default width or removing the fixed width entirely:
- "w-[2000px] max-w-[450px]", + "w-full max-w-[450px]",This achieves the same visual result (450px max width) with clearer intent.
packages/tiptap/src/styles/transcript.css (1)
34-36: Review the white-space change and remove redundant properties.Two observations:
Behavior change: Switching from
white-space: normaltowhite-space: pre-wrapwill now preserve all whitespace and line breaks in the transcript content. This is a significant visual change—verify this is intentional for your transcript display use case.Redundant properties: Both
word-break: break-wordandoverflow-wrap: break-wordachieve the same word-wrapping behavior. Theword-break: break-wordproperty is deprecated;overflow-wrap: break-wordalone is sufficient.Apply this diff to remove the redundancy:
white-space: pre-wrap; - word-break: break-word; overflow-wrap: break-word;apps/desktop/src/styles/globals.css (1)
137-148: Consider using theme variables for search highlight colors.The search result styles use hardcoded color values (
#ffeb3b,#31e054). For better maintainability and theme consistency, consider using CSS custom properties or Tailwind theme tokens instead.Example refactor using CSS variables:
+:root { + --search-result-bg: #ffeb3b; + --search-result-current-bg: #31e054; +} + .search-result { - background-color: #ffeb3b; + background-color: var(--search-result-bg); border-radius: 2px; padding: 1px 0; } .search-result-current { - background-color: #31e054 !important; + background-color: var(--search-result-current-bg) !important; border-radius: 2px; padding: 1px 0; }apps/desktop/src/components/right-panel/index.tsx (1)
20-21: Consider removing commented code.The commented conditional render on Line 20 can be removed to keep the codebase clean, unless you intend to restore it soon.
Apply this diff if the conditional is no longer needed:
- {/*{(currentView === "transcript") ? <TranscriptView /> : <ChatView />}*/} <ChatView />apps/desktop/src/components/editor-area/note-header/tab-sub-header.tsx (2)
5-13: Unused prop:transcriptEditorRef.The
transcriptEditorRefprop is declared but only used in the commented-out transcript sub-header code (Line 35). Consider removing it if the transcript feature is not imminent, or add a TODO comment if it's planned for future work.Apply this diff if the prop is not needed yet:
interface TabSubHeaderProps { sessionId: string; onEnhance?: (params: { triggerType: "manual" | "template"; templateId?: string | null }) => void; isEnhancing?: boolean; - transcriptEditorRef?: TranscriptEditorRef | null; progress?: number; showProgress?: boolean; hashtags?: string[]; }
15-31: Unused prop:hashtags.The
hashtagsprop is accepted byTabSubHeaderbut is not forwarded toEnhancedNoteSubHeaderor used elsewhere. IfEnhancedNoteSubHeaderdoes not require hashtags, consider removing the prop fromTabSubHeaderProps.If
hashtagsis not needed, apply this diff:interface TabSubHeaderProps { sessionId: string; onEnhance?: (params: { triggerType: "manual" | "template"; templateId?: string | null }) => void; isEnhancing?: boolean; transcriptEditorRef?: TranscriptEditorRef | null; progress?: number; showProgress?: boolean; - hashtags?: string[]; }apps/desktop/src/components/right-panel/utils/dynamic-quickactions.ts (1)
213-281: Consider extractinglastActionlogic to reduce duplication.The
lastActiongeneration logic (Lines 214-226 and 249-261) is duplicated betweengeneratePostMeetingCustomWithToolsandgeneratePostMeetingHyprCloud. Extracting it into a helper function would improve maintainability.Example helper function:
function generateLastAction(hasParticipants: boolean, participants: any[]): QuickAction { return hasParticipants && participants.length > 0 ? { shownTitle: `Past conversations with ${participants[0].full_name}...`, actualPrompt: `Search my Hyprnote for all past conversations and meetings with ${ participants.map(p => p.full_name).join(", ") }`, eventName: "chat_dynamic_quickaction", } : { shownTitle: "Analyze related past meetings", actualPrompt: "Search my Hyprnote for related past meetings and show patterns or recurring topics", eventName: "chat_dynamic_quickaction", }; }Then replace the duplicated blocks with calls to
generateLastAction(hasParticipants, participants).apps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsx (1)
142-157: Remove commented-out code.The beta notice is commented out (lines 143-157) and appears to be dead code. Per the coding guidelines, unused code should be removed rather than commented out.
Apply this diff to remove the dead code:
- {/* Beta notice moved to bottom */} - { - /* <div className="mt-8 p-3 rounded-lg bg-neutral-50 border border-neutral-200 max-w-[280px]"> - <p className="text-xs text-neutral-600 text-left"> - <Trans> - Chat feature is in beta. For best results, we recommend you to use{" "} - <span - onClick={handleCustomEndpointsClick} - className="text-blue-600 hover:text-blue-800 cursor-pointer underline" - > - custom endpoints - </span> - . - </Trans> - </p> - </div> */ - }apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (3)
53-58: Verify the aggressive refetch interval for LLM connection.The
refetchInterval: 5000polls the LLM connection every 5 seconds. For a connection setting that typically changes infrequently, this may create unnecessary overhead and database/IPC calls.Consider increasing the interval to 30000 (30s) or using
refetchOnWindowFocus: truealone, unless the connection state is expected to change very frequently during active use.
60-65: Verify the aggressive refetch interval for custom LLM model.Similar to the LLM connection query,
refetchInterval: 5000polls every 5 seconds. Custom model settings are unlikely to change frequently.Consider increasing the interval to 30000 or removing it entirely, relying on
refetchOnWindowFocusor manual invalidation when settings change.
67-71: Verify the aggressive refetch interval for HyprCloud enabled state.The
refetchInterval: 5000polls every 5 seconds. The HyprCloud enabled state is a configuration setting that typically doesn't change during normal operation.Consider increasing the interval or removing it, relying instead on
refetchOnWindowFocusor manual cache invalidation when the user changes settings.apps/desktop/src/components/editor-area/local-search-bar.tsx (1)
84-95: Remove commented-out code.Per coding guidelines, comments should be minimal and explain "why" not "what". Commented-out code should be removed unless there's a specific reason to keep it for reference.
Apply this diff to remove the commented-out block:
- // Close on outside click - /* - useEffect(() => { - if (!isVisible) return; - const handleClickOutside = (event: MouseEvent) => { - if (containerRef.current && !containerRef.current.contains(event.target as Node)) { - handleClose(); - } - }; - document.addEventListener("mousedown", handleClickOutside); - return () => document.removeEventListener("mousedown", handleClickOutside); - }, [isVisible]); - */ -If this functionality is intentionally deferred for future implementation, consider opening an issue to track it instead of leaving commented code.
apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx (6)
85-93: Remove unnecessary try-catch block per coding guidelines.Per the coding guidelines: "Do not add any error handling. Keep the existing one." This try-catch adds error handling where none existed before. The
console.erroralso converts the failure into a silent no-op, which may hide genuine issues.Based on coding guidelines
Remove the try-catch and let errors propagate naturally:
const handleAddTemplate = async () => { setIsTemplateDropdownOpen(false); - try { - await windowsCommands.windowShow({ type: "settings" }); - await windowsCommands.windowNavigate({ type: "settings" }, "/app/settings?tab=templates"); - } catch (error) { - console.error("Failed to open settings/templates:", error); - } + await windowsCommands.windowShow({ type: "settings" }); + await windowsCommands.windowNavigate({ type: "settings" }, "/app/settings?tab=templates"); };
95-101: Remove commented-out code to improve maintainability.Commented-out code adds clutter and should be removed. Use version control to retrieve old code if needed.
Based on coding guidelines
- // Commented out share functionality - // const handleShareOpenChange = (newOpen: boolean) => { - // setIsShareDropdownOpen(newOpen); - // if (hasEnhancedNote) { - // handleOpenStateChange(newOpen); - // } - // };
147-169: Remove large commented-out JSX block.This commented-out share functionality spans 23 lines. Remove it to reduce clutter.
Based on coding guidelines
- { - /* Share button - <Popover open={isShareDropdownOpen} onOpenChange={handleShareOpenChange}> - <PopoverTrigger asChild> - <Button - variant="outline" - size="sm" - className="text-xs h-6 px-3 hover:bg-neutral-100" - > - <Share2 size={14} className="mr-1.5" /> - Share - </Button> - </PopoverTrigger> - <PopoverContent - className="w-80 p-3 focus:outline-none focus:ring-0 focus:ring-offset-0" - align="end" - sideOffset={4} - > - <SharePopoverContent /> - </PopoverContent> - </Popover> - */ - }
228-242: Remove commented-out chevron button code.Another block of commented-out code that should be removed.
Based on coding guidelines
- {/* Commented out separate chevron button */} - { - /* - <PopoverTrigger asChild> - <Button - variant="outline" - size="sm" - disabled={isEnhancing} - className="rounded-l-none px-1.5 h-[28px] border-l-0 hover:bg-neutral-100 disabled:opacity-100" - > - <ChevronDownIcon size={14} /> - </Button> - </PopoverTrigger> - */ - }
13-13: Unused import should be removed.The commented-out import
useShareLogicis not used and should be removed per coding guidelines.Based on coding guidelines
- // import { useShareLogic } from "../share-button-header";
36-37: Remove commented-out share logic.This commented code adds no value and should be removed.
Based on coding guidelines
- // Share functionality (currently commented out) - // const { hasEnhancedNote } = useShareLogic();apps/desktop/src/components/editor-area/floating-search-box.tsx (6)
21-34: Comment explains "what" rather than "why".The comment on line 21 states "NO useCallback, we want fresh ref every time" but doesn't explain why we want a fresh ref or what problem this solves. Comments should focus on "why" not "what" per coding guidelines.
Based on coding guidelines
Either remove the comment or explain the reasoning:
- // Get the editor - NO useCallback, we want fresh ref every time + // Access editor without memoization to ensure we read the latest ref valueOr simply remove it if the code is self-explanatory.
40-61: Remove unnecessary try-catch and explanatory comments.Lines 44-56 wrap commands in try-catch with
console.warn. Per coding guidelines, avoid adding error handling. The comments "Editor might not be ready yet, ignore" explain "what" not "why."Based on coding guidelines
Remove the try-catch and comments:
const debouncedSetSearchTerm = useDebouncedCallback( (value: string) => { const editor = getEditor(); if (editor && editor.commands) { - try { - editor.commands.setSearchTerm(value); - editor.commands.resetIndex(); - setTimeout(() => { - const storage = editor.storage?.searchAndReplace; - const results = storage?.results || []; - setResultCount(results.length); - setCurrentIndex((storage?.resultIndex ?? 0) + 1); - }, 100); - } catch (e) { - // Editor might not be ready yet, ignore - console.warn("Editor not ready for search:", e); - } + editor.commands.setSearchTerm(value); + editor.commands.resetIndex(); + setTimeout(() => { + const storage = editor.storage?.searchAndReplace; + const results = storage?.results || []; + setResultCount(results.length); + setCurrentIndex((storage?.resultIndex ?? 0) + 1); + }, 100); } }, - [], // Empty deps to prevent infinite re-creation + [], 300, );
67-76: Remove unnecessary try-catch block.Similar to previous comment, this try-catch adds error handling that silently swallows errors.
Based on coding guidelines
useEffect(() => { const editor = getEditor(); if (editor && editor.commands) { - try { - editor.commands.setReplaceTerm(replaceTerm); - } catch (e) { - // Editor might not be ready yet, ignore - } + editor.commands.setReplaceTerm(replaceTerm); } - }, [replaceTerm]); // Removed getEditor from deps + }, [replaceTerm]);
112-124: Remove try-catch block from scroll logic.Another unnecessary try-catch with a "what" comment.
Based on coding guidelines
const scrollCurrentResultIntoView = useCallback(() => { const editor = getEditor(); if (!editor) { return; } - try { - const editorElement = editor.view.dom; - const current = editorElement.querySelector(".search-result-current") as HTMLElement | null; - if (current) { - current.scrollIntoView({ - behavior: "smooth", - block: "center", - inline: "nearest", - }); - } - } catch (e) { - // Editor view not ready yet, ignore - } + const editorElement = editor.view.dom; + const current = editorElement.querySelector(".search-result-current") as HTMLElement | null; + if (current) { + current.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "nearest", + }); + } }, []);
218-228: Redundant wrapper div for search input.Lines 219-228 wrap the
Inputin adivthat only applies border/styling. TheInputcomponent can accept these classes directly, eliminating a DOM node.- <div className="flex items-center gap-1 bg-transparent border border-neutral-200 rounded px-2 py-1 flex-1"> - <Input - className="h-6 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-1 bg-transparent flex-1 text-sm" - value={searchTerm} - onChange={(e) => setSearchTerm(e.target.value)} - onKeyDown={handleKeyDown} - placeholder="Search..." - autoFocus - /> - </div> + <Input + className="h-6 border border-neutral-200 rounded px-2 py-1 focus-visible:ring-0 focus-visible:ring-offset-0 bg-transparent flex-1 text-sm" + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Search..." + autoFocus + />Verify the
Inputcomponent supports these classes without issues.
271-279: Redundant wrapper div for replace input.Same issue as the search input wrapper.
- <div className="flex items-center gap-1 bg-transparent border border-neutral-200 rounded px-2 py-1 flex-1"> - <Input - className="h-6 border-0 focus-visible:ring-0 focus-visible:ring-offset-0 px-1 bg-transparent flex-1 text-sm" - value={replaceTerm} - onChange={(e) => setReplaceTerm(e.target.value)} - onKeyDown={handleKeyDown} - placeholder="Replace..." - /> - </div> + <Input + className="h-6 border border-neutral-200 rounded px-2 py-1 focus-visible:ring-0 focus-visible:ring-offset-0 bg-transparent flex-1 text-sm" + value={replaceTerm} + onChange={(e) => setReplaceTerm(e.target.value)} + onKeyDown={handleKeyDown} + placeholder="Replace..." + />apps/desktop/src/components/editor-area/note-header/tab-header.tsx (7)
30-44: Comments explain "what" rather than "why".Comments on lines 30, 38, 41 describe what the code does rather than why it's structured this way. Per coding guidelines, prefer minimal comments focused on "why."
Based on coding guidelines
Consider removing or condensing these comments:
- // Check if this is a meeting session (has transcript or is currently recording) const hasTranscript = session.words && session.words.length > 0; const isCurrentlyRecording = ongoingSessionStatus === "running_active" && ongoingSessionId === sessionId; const isSessionInactive = ongoingSessionStatus === "inactive" || session.id !== ongoingSessionId; const hasEnhancedMemo = !!session?.enhanced_memo_html; const canEnhanceTranscript = hasTranscript && isSessionInactive; - // Keep the "meeting session" concept for overall tab visibility const isMeetingSession = hasTranscript || isCurrentlyRecording || isEnhancing; - // BUT use floating button logic for Enhanced tab visibility const isEnhancePending = useEnhancePendingState(sessionId); const shouldShowEnhancedTab = hasEnhancedMemo || isEnhancePending || canEnhanceTranscript; - - // Automatic tab switching logic following existing conventions
47-52: Comment on line 48 is verbose and explains "what".The comment describes the condition rather than explaining any non-obvious reasoning.
Based on coding guidelines
Remove or simplify:
useEffect(() => { - // When enhancement starts (immediately after recording ends) -> switch to enhanced note if (isEnhancePending || (ongoingSessionStatus === "inactive" && hasTranscript && shouldShowEnhancedTab)) { setActiveTab("enhanced"); } }, [isEnhancePending, ongoingSessionStatus, hasTranscript, shouldShowEnhancedTab, setActiveTab]);
54-59: Comment explains "what" not "why".Line 54 describes what the effect does.
Based on coding guidelines
- // Set default tab to 'raw' for blank notes (no meeting session) useEffect(() => { if (!isMeetingSession) { setActiveTab("raw"); } }, [isMeetingSession, setActiveTab]);
77-80: Comment is redundant with the code.Line 77 repeats what the return statement clearly shows.
Based on coding guidelines
- // Don't render tabs at all for blank notes (no meeting session) if (!isMeetingSession) { return null; }
84-131: Excessive inline JSX comments describing UI structure.Comments on lines 84, 88, 90, 118 describe what each section is (e.g., "Tab container", "Raw Note Tab"). These are redundant with the JSX structure itself.
Based on coding guidelines
Remove these comments:
<div className="relative"> - {/* Tab container */} <div className="bg-white"> <div className="flex px-8"> <div className="flex border-b border-neutral-100 w-full"> - {/* Raw Note Tab */} - - {/* Enhanced Note Tab - show when session ended OR transcript exists OR enhanced memo exists */} {shouldShowEnhancedTab && ( <button ... > Summary </button> )} <button ... > Memos </button> - {/* Transcript Tab - always show */} <button ... > Transcript {isCurrentlyRecording && <div className="w-2 h-2 bg-red-500 rounded-full animate-pulse" />} </button> </div> </div> </div> </div>
65-68: Nullish coalescing is unnecessary.Line 67 uses
isMeetingSession ?? false, butisMeetingSessionis already a boolean (derived from boolean expressions on lines 32-39). The?? falseis redundant.useImperativeHandle(ref, () => ({ - isVisible: isMeetingSession ?? false, + isVisible: isMeetingSession, }), [isMeetingSession]);
70-75: Redundant nullish coalescing in visibility notification.Same issue as above—
isMeetingSessionis already a boolean.useEffect(() => { if (onVisibilityChange) { - onVisibilityChange(isMeetingSession ?? false); + onVisibilityChange(isMeetingSession); } }, [isMeetingSession, onVisibilityChange]);apps/desktop/src/components/editor-area/index.tsx (4)
8-8: Remove commented code.Commented imports and logic should be removed rather than left in the codebase. Use version control to preserve history if needed.
Apply this diff to remove commented code:
-// import { useRightPanel } from "@/contexts/right-panel";- // const { isExpanded: isRightPanelExpanded, togglePanel: toggleRightPanel } = useRightPanel();- } else { - // comment out to turn off auto-open chat panel - - // if (!isRightPanelExpanded) { - // toggleRightPanel("chat"); - // } - } + }As per coding guidelines.
Also applies to: 133-133, 217-222
249-252: Simplify useMemo dependency array.The dependency array
[showRaw, showRaw ? rawContent : enhancedContent]is unnecessarily complex. While it works, listing all relevant dependencies is clearer and follows React best practices.Apply this diff:
const noteContent = useMemo( () => (showRaw ? rawContent : enhancedContent), - [showRaw, showRaw ? rawContent : enhancedContent], + [showRaw, rawContent, enhancedContent], );
312-329: Remove commented placeholder code.The commented date placeholder and MetadataModal code should be removed to keep the codebase clean.
Apply this diff:
- {/* Date placeholder - closer when search bar is visible */} - <div - className={cn([ - "flex justify-center pb-4 px-8", - isFloatingSearchVisible ? "pt-1" : "pt-1", // ← Less top padding when search bar is visible - ])} - > - { - /* - <MetadataModal sessionId={sessionId} hashtags={hashtags}> - <div className="cursor-pointer px-2 py-1"> - <span className="text-xs text-neutral-300 font-medium transition-colors"> - Today, December 19, 2024 - </span> - </div> - </MetadataModal> - */ - } - </div> -As per coding guidelines.
405-415: Remove commented FloatingButton code.Since the FloatingButton has been replaced by the new tab-based UI, the commented code should be removed to keep the codebase clean.
Apply this diff:
- { - /** - * FloatingSearchBox temporarily disabled in favor of LocalSearchBar - * <FloatingSearchBox - * key={activeTab} - * editorRef={activeTab === 'transcript' ? transcriptRef : editorRef} - * onClose={() => setIsFloatingSearchVisible(false)} - * isVisible={isFloatingSearchVisible} - * /> - */ - } -- { - /*<AnimatePresence> - <motion.div - className="absolute bottom-4 w-full flex justify-center items-center pointer-events-none z-10" - initial={{ y: 50, opacity: 0 }} - animate={{ y: 0, opacity: 1 }} - exit={{ y: 50, opacity: 0 }} - transition={{ duration: 0.2 }} - > - - <div className="pointer-events-auto"> - <FloatingButton - key={`floating-button-${sessionId}`} - handleEnhance={handleClickEnhance} - handleEnhanceWithTemplate={handleEnhanceWithTemplate} - templates={templatesQuery.data || []} - session={sessionStore.session} - isError={enhance.status === "error" && !isCancelled} - progress={progress} - showProgress={llmConnectionQuery.data?.type === "HyprLocal" && sessionId !== onboardingSessionId} - userId={userId} - /> - </div> - </motion.div> - </AnimatePresence>*/ - }As per coding guidelines.
Also applies to: 437-462
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/desktop/src/locales/en/messages.pois excluded by!**/*.poapps/desktop/src/locales/ko/messages.pois excluded by!**/*.po
📒 Files selected for processing (33)
apps/desktop/src/components/editor-area/floating-search-box.tsx(1 hunks)apps/desktop/src/components/editor-area/index.tsx(11 hunks)apps/desktop/src/components/editor-area/local-search-bar.tsx(1 hunks)apps/desktop/src/components/editor-area/metadata-modal.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/chips/event-chip.tsx(3 hunks)apps/desktop/src/components/editor-area/note-header/chips/index.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/chips/participants-chip.tsx(2 hunks)apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/index.tsx(5 hunks)apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/sub-headers/transcript-sub-header.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/tab-header.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/tab-sub-header.tsx(1 hunks)apps/desktop/src/components/editor-area/note-header/title-input.tsx(3 hunks)apps/desktop/src/components/editor-area/transcript-viewer.tsx(1 hunks)apps/desktop/src/components/pro-gate-modal/index.tsx(1 hunks)apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx(1 hunks)apps/desktop/src/components/right-panel/components/chat/chat-input.tsx(6 hunks)apps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsx(3 hunks)apps/desktop/src/components/right-panel/index.tsx(2 hunks)apps/desktop/src/components/right-panel/utils/dynamic-quickactions.ts(1 hunks)apps/desktop/src/components/right-panel/views/chat-view.tsx(1 hunks)apps/desktop/src/components/search-bar.tsx(2 hunks)apps/desktop/src/components/toolbar/bars/main-toolbar.tsx(2 hunks)apps/desktop/src/contexts/right-panel.tsx(1 hunks)apps/desktop/src/routes/app.note.$id.tsx(1 hunks)apps/desktop/src/styles/globals.css(1 hunks)packages/tiptap/src/editor/index.tsx(2 hunks)packages/tiptap/src/shared/extensions.ts(2 hunks)packages/tiptap/src/styles/transcript.css(1 hunks)packages/tiptap/src/transcript/index.tsx(1 hunks)packages/ui/src/components/ui/command.tsx(1 hunks)packages/utils/src/stores/session.ts(3 hunks)
🧰 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:
packages/tiptap/src/editor/index.tsxapps/desktop/src/components/pro-gate-modal/index.tsxapps/desktop/src/components/editor-area/note-header/chips/participants-chip.tsxpackages/ui/src/components/ui/command.tsxapps/desktop/src/components/editor-area/note-header/index.tsxapps/desktop/src/components/editor-area/note-header/chips/index.tsxapps/desktop/src/components/editor-area/note-header/tab-sub-header.tsxapps/desktop/src/components/editor-area/metadata-modal.tsxapps/desktop/src/components/right-panel/utils/dynamic-quickactions.tspackages/utils/src/stores/session.tsapps/desktop/src/routes/app.note.$id.tsxapps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsxapps/desktop/src/components/editor-area/note-header/title-input.tsxapps/desktop/src/components/right-panel/views/chat-view.tsxpackages/tiptap/src/shared/extensions.tsapps/desktop/src/components/right-panel/components/chat/chat-input.tsxapps/desktop/src/components/search-bar.tsxapps/desktop/src/components/editor-area/note-header/chips/event-chip.tsxapps/desktop/src/components/editor-area/index.tsxapps/desktop/src/components/editor-area/transcript-viewer.tsxapps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsxpackages/tiptap/src/transcript/index.tsxapps/desktop/src/components/editor-area/local-search-bar.tsxapps/desktop/src/components/editor-area/note-header/tab-header.tsxapps/desktop/src/components/editor-area/floating-search-box.tsxapps/desktop/src/components/right-panel/components/chat-model-info-modal.tsxapps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsxapps/desktop/src/contexts/right-panel.tsxapps/desktop/src/components/toolbar/bars/main-toolbar.tsxapps/desktop/src/components/editor-area/note-header/sub-headers/transcript-sub-header.tsxapps/desktop/src/components/right-panel/index.tsx
🧬 Code graph analysis (18)
apps/desktop/src/components/editor-area/note-header/index.tsx (3)
packages/utils/src/contexts/sessions.tsx (1)
useSession(49-74)apps/desktop/src/hooks/enhance-pending.ts (1)
useTitleGenerationPendingState(18-30)apps/desktop/src/components/editor-area/note-header/title-shimmer.tsx (1)
TitleShimmer(11-46)
apps/desktop/src/components/editor-area/note-header/tab-sub-header.tsx (3)
packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)packages/utils/src/contexts/sessions.tsx (1)
useSession(49-74)apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx (1)
EnhancedNoteSubHeader(23-299)
apps/desktop/src/components/editor-area/metadata-modal.tsx (3)
apps/desktop/src/components/editor-area/note-header/chips/event-chip.tsx (1)
EventChip(37-307)apps/desktop/src/components/editor-area/note-header/chips/participants-chip.tsx (1)
ParticipantsChip(53-113)apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx (1)
TagChip(20-77)
apps/desktop/src/components/right-panel/views/chat-view.tsx (5)
apps/desktop/src/components/right-panel/components/chat/floating-action-buttons.tsx (1)
FloatingActionButtons(19-67)apps/desktop/src/components/right-panel/components/chat/chat-history-view.tsx (1)
ChatHistoryView(17-89)apps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsx (1)
EmptyChatState(14-160)apps/desktop/src/components/right-panel/components/chat/chat-messages-view.tsx (1)
ChatMessagesView(45-136)apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (1)
ChatInput(34-540)
packages/tiptap/src/shared/extensions.ts (1)
packages/tiptap/src/transcript/extensions/search-and-replace.ts (1)
SearchAndReplace(229-381)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (1)
apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx (1)
ChatModelInfoModal(12-134)
apps/desktop/src/components/editor-area/note-header/chips/event-chip.tsx (1)
packages/utils/src/datetime.ts (1)
formatRelativeWithDay(88-132)
apps/desktop/src/components/editor-area/index.tsx (6)
packages/utils/src/contexts/sessions.tsx (1)
useSession(49-74)packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)apps/desktop/src/components/editor-area/note-header/tab-header.tsx (2)
TabHeaderRef(15-17)TabHeader(19-137)apps/desktop/src/components/editor-area/local-search-bar.tsx (1)
LocalSearchBar(15-290)apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx (1)
EnhancedNoteSubHeader(23-299)apps/desktop/src/components/editor-area/transcript-viewer.tsx (1)
TranscriptViewer(27-164)
apps/desktop/src/components/editor-area/transcript-viewer.tsx (5)
packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)apps/desktop/src/components/right-panel/hooks/useTranscript.ts (1)
useTranscript(8-91)apps/desktop/src/contexts/hypr.tsx (1)
useHypr(63-69)packages/utils/src/contexts/ongoing-session.tsx (1)
useOngoingSession(32-46)apps/desktop/src/components/editor-area/note-header/chips/participants-chip.tsx (1)
ParticipantsChipInner(115-130)
apps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsx (2)
apps/desktop/src/contexts/hypr.tsx (1)
useHypr(63-69)apps/desktop/src/components/right-panel/utils/dynamic-quickactions.ts (1)
getDynamicQuickActions(33-91)
apps/desktop/src/components/editor-area/local-search-bar.tsx (2)
packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)packages/ui/src/components/ui/button.tsx (1)
Button(37-89)
apps/desktop/src/components/editor-area/note-header/tab-header.tsx (5)
apps/desktop/src/components/editor-area/note-header/index.tsx (2)
TabHeaderRef(91-91)TabHeader(90-90)packages/utils/src/contexts/sessions.tsx (1)
useSession(49-74)packages/utils/src/contexts/ongoing-session.tsx (1)
useOngoingSession(32-46)apps/desktop/src/hooks/enhance-pending.ts (1)
useEnhancePendingState(4-16)packages/ui/src/lib/utils.ts (1)
cn(4-6)
apps/desktop/src/components/editor-area/floating-search-box.tsx (2)
packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)packages/ui/src/components/ui/button.tsx (1)
Button(37-89)
apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx (2)
packages/ui/src/components/ui/modal.tsx (4)
Modal(23-83)ModalBody(99-105)ModalTitle(130-136)ModalDescription(143-148)packages/ui/src/components/ui/button.tsx (1)
Button(37-89)
apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx (2)
packages/utils/src/contexts/ongoing-session.tsx (1)
useOngoingSession(32-46)apps/desktop/src/utils/template-service.ts (1)
TemplateService(5-66)
apps/desktop/src/components/toolbar/bars/main-toolbar.tsx (1)
apps/desktop/src/components/toolbar/buttons/share-button.tsx (1)
ShareButton(28-31)
apps/desktop/src/components/editor-area/note-header/sub-headers/transcript-sub-header.tsx (2)
packages/tiptap/src/transcript/index.tsx (1)
TranscriptEditorRef(33-41)packages/ui/src/components/ui/button.tsx (1)
Button(37-89)
apps/desktop/src/components/right-panel/index.tsx (2)
apps/desktop/src/contexts/right-panel.tsx (1)
useRightPanel(230-236)apps/desktop/src/components/right-panel/views/chat-view.tsx (1)
ChatView(24-349)
🪛 Biome (2.1.2)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx
[error] 401-401: This code will never be reached ...
... because this statement will return from the function beforehand
(lint/correctness/noUnreachable)
⏰ 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)
🔇 Additional comments (49)
apps/desktop/src/components/toolbar/bars/main-toolbar.tsx (1)
13-13: LGTM: Import correctly activated.The ShareButton import is now active and used at line 60, consistent with re-enabling the share functionality.
apps/desktop/src/components/pro-gate-modal/index.tsx (1)
38-51: Verify event-based window sync or annotate the 800ms delay.
- Confirm whether
@hypr/plugin-windowsprovides a lifecycle event (e.g. window-ready/show) to avoid an arbitrary 800ms timeout.- If no event exists, add a comment explaining why 800ms was chosen.
packages/tiptap/src/editor/index.tsx (1)
4-4: LGTM!The Document extension is correctly imported and added to the extensions array. This is a standard TipTap extension integration with no issues.
Also applies to: 36-36
apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx (1)
60-60: LGTM!The
text-neutral-500styling for the TagsIcon provides consistent neutral coloring.apps/desktop/src/components/editor-area/note-header/title-input.tsx (1)
2-2: LGTM! Clean autofocus implementation.The autofocus logic is correctly implemented with:
- Proper ref usage and focus call
- Correct useEffect dependencies
- Cleanup to prevent memory leaks from the timeout
The 200ms delay is a reasonable debounce to allow the component to settle before focusing.
Also applies to: 10-10, 19-19, 22-22, 38-46, 50-50
apps/desktop/src/components/editor-area/note-header/chips/event-chip.tsx (1)
112-113: LGTM! Consistent neutral styling applied.The text-neutral-500 color has been applied uniformly across all three rendering paths (onboarding, event with link, blank note), ensuring visual consistency throughout the chip display.
Also applies to: 148-152, 253-256
apps/desktop/src/components/editor-area/note-header/sub-headers/transcript-sub-header.tsx (1)
16-21: LGTM! Polling approach is appropriate for audio file existence check.The 2.5-second polling interval is reasonable for tracking audio file availability without excessive server load.
packages/tiptap/src/shared/extensions.ts (1)
10-10: LGTM! SearchAndReplace extension properly configured.The extension is correctly imported and configured with appropriate settings:
searchResultClassaligns with the CSS styling for search resultsdisableRegex: truesimplifies the search UX by disabling regex patternsAlso applies to: 93-96
apps/desktop/src/components/editor-area/note-header/chips/index.tsx (1)
50-50: LGTM! ShareChip intentionally removed.The ShareChip has been cleanly removed from the header chips, aligning with the broader UI redesign that shifts focus to tabbed editing and local search capabilities.
apps/desktop/src/components/search-bar.tsx (1)
121-121: LGTM! Search input correctly disabled for display-only mode.The input has been properly converted to display-only by adding
cursor-pointerto the container,pointer-events-noneto the input, and thedisabledattribute. This aligns with the new LocalSearchBar component handling actual search interactions.Also applies to: 145-146
apps/desktop/src/routes/app.note.$id.tsx (1)
164-164: LGTM - layout adjustment.The padding reduction from
pt-6topt-4aligns with the broader UI redesign for the tabbed editor layout.packages/tiptap/src/transcript/index.tsx (1)
185-187: LGTM - improved scroll container layout.The addition of
min-h-0on the scroll container (line 185) correctly prevents flex overflow issues, and the updated padding classes improve content spacing for the tabbed editor UI.apps/desktop/src/components/editor-area/note-header/chips/participants-chip.tsx (2)
102-103: LGTM - consistent color styling.The updated neutral color (
text-neutral-500) for both the icon and label improves visual consistency with the redesigned UI.
115-130: LGTM - intentional public export.Making
ParticipantsChipInnera public export enables reuse in other parts of the editor area components, aligning with the broader PR's modular UI redesign.apps/desktop/src/components/right-panel/index.tsx (1)
1-7: LGTM!Import and hook usage updated correctly. Removed
TranscriptViewimport andcurrentViewdestructuring align with the fixedChatViewrender path.apps/desktop/src/components/editor-area/note-header/index.tsx (4)
10-11: LGTM!
TabHeaderandTabSubHeaderimports are correctly wired and re-exported for external use.
27-33: LGTM!The
isNewNoteflag logic correctly identifies a fresh note by checking title, HTML content, and words. The conditions handle edge cases appropriately.
59-71: LGTM!Reduced padding and conditional
autoFocuslogic are correct. TheautoFocusprop is appropriately gated byisNewNoteandeditable.
89-91: LGTM!Public exports for
TabHeader,TabSubHeader, andTabHeaderRefare correctly defined and align with the multi-tab editor layout.apps/desktop/src/components/editor-area/note-header/tab-sub-header.tsx (1)
39-44: LGTM!The empty sub-header for the "raw" tab maintains consistent layout spacing, and returning
nullfor unmapped tabs is correct.apps/desktop/src/components/right-panel/utils/dynamic-quickactions.ts (4)
4-31: LGTM!The
QuickActioninterface andDEFAULT_ACTIONSare well-defined and provide a sensible fallback.
33-91: LGTM!The main logic correctly handles session state, participants, LLM connection, and strategy selection. Error handling appropriately falls back to
DEFAULT_ACTIONS.
93-182: LGTM!Pre-meeting helper functions are well-structured. The delegation pattern in
generatePreMeetingCustomNoToolsavoids duplication, and the participant-aware actions ingeneratePreMeetingHyprCloudare context-appropriate.
1-3: LGTM!Imports are clean and correctly scoped to the required plugin commands.
apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx (3)
1-10: LGTM!Imports and interface are clean and correctly defined.
29-31: LGTM!Early return when
isOpenis false prevents unnecessary rendering.
33-133: LGTM!Modal UI structure is correct. The custom backdrop and
showOverlay={false}prevent duplicate overlays, and the "Choose" button is appropriately accessible.packages/utils/src/stores/session.ts (2)
10-10: LGTM!The activeTab state field and setActiveTab action are properly typed with a union of three tab values. The addition is clean and follows the existing store pattern.
Also applies to: 17-17
47-60: Backward compatibility logic is correct.The setActiveTab implementation correctly maintains showRaw synchronization for "raw" and "enhanced" tabs while leaving it unchanged for "transcript". The comment on line 51 appropriately explains the reasoning.
apps/desktop/src/components/editor-area/metadata-modal.tsx (1)
28-34: Nice UX pattern for extended hover area.The negative margin trick (line 30:
p-4 -m-4) elegantly extends the hoverable area to prevent the popover from disappearing when the cursor moves between the trigger and popover. The arrow seamlessly connects the two elements.apps/desktop/src/components/right-panel/views/chat-view.tsx (2)
271-280: Verify the reserved height inconsistency.The reserved space for FloatingActionButtons differs between the history view (h-16 on line 273) and the main chat view (h-14 on line 301). This inconsistency could cause the floating buttons to be positioned differently or clipped.
Confirm whether this height difference is intentional (e.g., due to different button sizes or spacing requirements) or if both should use the same height for visual consistency.
Also applies to: 299-308
314-318: Good: sessionId prop enables dynamic quick actions.Passing sessionId to EmptyChatState allows it to fetch session-specific quick actions via getDynamicQuickActions, which improves the user experience by showing contextually relevant suggestions.
apps/desktop/src/components/right-panel/components/chat/empty-chat-state.tsx (2)
26-28: Dynamic quick actions implementation is correct.The useEffect properly fetches session-specific quick actions when sessionId changes, and the fallback to null ensures the function handles missing session IDs gracefully.
30-54: ResizeObserver pattern is correctly implemented.The responsive sizing logic with ResizeObserver is properly set up with cleanup, and the width-based thresholds (300, 400) provide good breakpoints for small/medium/large layouts.
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (3)
470-470: LGTM! Updated placeholder text improves UX clarity.The placeholder text now explicitly mentions the
@trigger for adding contexts, which helps guide users.
502-502: LGTM! Contextual placeholder during generation.The updated placeholder text clearly indicates how to add context while generating, improving the user experience.
507-514: LGTM! Model selector button integrates well.The model button with icon and dynamic label provides clear access to model information. The modal flow is properly wired with state management.
apps/desktop/src/components/editor-area/transcript-viewer.tsx (5)
34-49: Verify the polling interval approach for editor ref readiness.The component uses a 100ms interval to repeatedly check if the editor ref is set, which could trigger multiple unnecessary
onEditorRefChangecallbacks if the ref is set and unset during the component lifecycle.Consider tracking whether the notification has been sent to avoid duplicate callbacks:
useEffect(() => { + let notified = false; // Initial notification if (onEditorRefChange) { onEditorRefChange(editorRef.current); + if (editorRef.current?.editor) notified = true; } // Check if ref gets set later const checkInterval = setInterval(() => { - if (editorRef.current?.editor && onEditorRefChange) { + if (!notified && editorRef.current?.editor && onEditorRefChange) { onEditorRefChange(editorRef.current); + notified = true; clearInterval(checkInterval); } }, 100); return () => clearInterval(checkInterval); }, [onEditorRefChange]);Alternatively, consider using a callback ref pattern or the
refcallback form to be notified exactly when the ref is attached.
77-84: Verify the conditional logic for setting words in the editor.The condition
words && words.length > 0 && !isLiveensures words are only set when the transcript is not live. However, this effect depends onisAtBottomandisLive, which may cause the effect to run multiple times unnecessarily when those values change withoutwordschanging.Consider adding
wordsto a separate ref or using a more specific dependency array to avoid redundantsetWordscalls:useEffect(() => { if (words && words.length > 0 && !isLive) { editorRef.current?.setWords(words); if (isAtBottom && editorRef.current?.isNearBottom()) { editorRef.current?.scrollToBottom(); } } - }, [words, isAtBottom, isLive]); + }, [words, isLive]);The
isAtBottomcheck is only used for the scroll action, not for deciding whether to set words.
96-102: LGTM! Transcript update handler correctly persists changes.The
handleUpdatefunction fetches the current session and upserts the updated words, ensuring persistence of transcript edits.
114-150: LGTM! Live transcript rendering with auto-scroll is well implemented.The live view correctly displays final and partial words with visual distinction, and the "Go to bottom" button appears appropriately when the user scrolls up.
171-267: LGTM! Speaker selector provides robust speaker assignment UI.The memoized speaker selector with range options (current/all/fromHere) and participant integration provides a comprehensive speaker management experience. The conditional rendering based on session state and inactive status is appropriate.
apps/desktop/src/components/editor-area/local-search-bar.tsx (5)
44-60: Verify the hardcoded 100ms delay for reading search results.The
setTimeout(() => {...}, 100)delay is used to wait for the editor's storage to update after setting the search term. This hardcoded delay could be fragile if the editor update timing changes.Consider whether the TipTap SearchAndReplace extension provides a callback or event when results are computed, which would be more reliable than a fixed timeout. If not, document why the delay is necessary:
// Wait for editor storage to update after setSearchTerm setTimeout(() => { // ... }, 100);
125-147: Verify consistent use of hardcoded delays in navigation handlers.Both
handleNextandhandlePrevioususesetTimeout(() => {...}, 100)to read updated state from editor storage. This pattern is repeated multiple times throughout the file.If the 100ms delay is necessary due to TipTap's async update behavior, consider extracting it into a named constant at the top of the file to make the intent clear and enable easy adjustment:
const EDITOR_STORAGE_UPDATE_DELAY = 100; // ms to wait for editor storage updates // Then use it consistently: setTimeout(() => { // ... }, EDITOR_STORAGE_UPDATE_DELAY);
24-33: LGTM! Type-safe editor extraction with proper null handling.The
getEditorhelper correctly handles bothTranscriptEditorRefand nested editor shapes, with appropriate null checks.
189-205: LGTM! Comprehensive keyboard navigation support.The
handleEnterNavfunction properly handles Enter and F3 keys with Shift modifier for bidirectional navigation, providing a good keyboard-driven UX.
207-289: LGTM! Clean and accessible search/replace UI.The component renders a comprehensive search and replace interface with proper accessibility attributes (
aria-hidden), disabled states, and visual feedback for result counts and navigation.apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx (1)
67-67: Missing error handling for fetch call may cause silent failures.The fetch call to cancel the local LLM endpoint lacks error handling. Network failures or server errors will fail silently, leaving no trace for debugging.
Add error handling:
if (localLlmBaseUrl.data) { - fetch(`${localLlmBaseUrl.data}/cancel`, { method: "GET" }); + fetch(`${localLlmBaseUrl.data}/cancel`, { method: "GET" }).catch((error) => { + console.error("Failed to cancel local LLM:", error); + }); }Likely an incorrect or invalid review comment.
apps/desktop/src/components/editor-area/index.tsx (1)
384-401: SyncshowRawwithactiveTab
The Editor/Renderer toggle relies on bothactiveTabandshowRaw. Verify that switching tabs (e.g. to “enhanced” or “raw”) updatesshowRawaccordingly—via auseEffector in the session store—to prevent mismatched views.
apps/desktop/src/components/editor-area/floating-search-box.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/editor-area/floating-search-box.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/editor-area/floating-search-box.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx
Outdated
Show resolved
Hide resolved
apps/desktop/src/components/editor-area/note-header/sub-headers/enhanced-note-sub-header.tsx
Show resolved
Hide resolved
apps/desktop/src/components/editor-area/note-header/sub-headers/transcript-sub-header.tsx
Show resolved
Hide resolved
apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (1)
388-404: Verify unreachable code fix.A previous review flagged unreachable code in this function (duplicate return statement in the "HyprLocal" case). The current code structure appears correct with the switch statement returning "Local LLM" for "HyprLocal" and falling through to the default case properly. Please confirm the unreachable return statement has been removed.
🧹 Nitpick comments (1)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (1)
53-71: Consider increasing the refetch interval for configuration queries.The 5-second polling interval for LLM configuration queries may be aggressive, as these settings typically change infrequently. Consider increasing the interval (e.g., 30-60 seconds) or using event-driven updates when settings change.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx(1 hunks)apps/desktop/src/components/right-panel/components/chat/chat-input.tsx(6 hunks)apps/desktop/src/components/right-panel/index.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/desktop/src/components/editor-area/note-header/chips/tag-chip.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/desktop/src/components/right-panel/components/chat/chat-input.tsxapps/desktop/src/components/right-panel/index.tsx
🧬 Code graph analysis (2)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (1)
apps/desktop/src/components/right-panel/components/chat-model-info-modal.tsx (1)
ChatModelInfoModal(12-134)
apps/desktop/src/components/right-panel/index.tsx (2)
apps/desktop/src/contexts/right-panel.tsx (1)
useRightPanel(230-236)apps/desktop/src/components/right-panel/views/chat-view.tsx (1)
ChatView(24-349)
⏰ 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)
🔇 Additional comments (9)
apps/desktop/src/components/right-panel/components/chat/chat-input.tsx (6)
2-2: LGTM!The new imports (
BrainIcon,connectorCommands,ChatModelInfoModal) are all used in the file.Also applies to: 8-8, 15-15
50-50: LGTM!The
isModelModalOpenstate is properly initialized and used to control the modal.
408-421: LGTM!The entity badge UI is well-structured with proper conditional rendering, icon display, and text truncation.
506-513: LGTM!The model selection button is properly implemented with appropriate styling and state management.
532-536: LGTM!The modal integration follows the standard controlled component pattern with proper state management.
469-469: LGTM!The placeholder text updates provide clear guidance on the @ mention functionality. Minor note: "contexts" (line 469) vs "context" (line 501) is slightly inconsistent but acceptable.
Also applies to: 501-501
apps/desktop/src/components/right-panel/index.tsx (3)
20-20: LGTM: Simplified render logic.The unconditional rendering of
ChatViewaligns with the PR objective to refactor the right panel to always show chat. The removal of view-switching logic simplifies the component and is consistent with the broader redesign.
4-4: Verify TranscriptView usage with broad searchRun the following script to locate any remaining references to
TranscriptViewin the repository:#!/bin/bash echo "=== TranscriptView occurrences across repo ===" rg -n "TranscriptView" -C2 .
7-7: Ignore context API change suggestion. TheRightPanelContextstill exposescurrentView, and it’s valid for components to destructure only the values they use.Likely an incorrect or invalid review comment.
No description provided.