Conversation
duckduckhero
commented
Oct 8, 2025
- extracted tab header (memos, summary, transcript) as a pure UI component
📝 WalkthroughWalkthroughRefactors TabHeader by removing ref-based logic in desktop, introducing a new shared UI TabHeader in packages/ui, and updating call sites to stop passing refs. Also removes the MetadataModal component and its public types. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Editor as EditorArea (Desktop)
participant TH as TabHeader (UI)
participant Parent as State/Store
User->>Editor: Open note / interact
Editor->>TH: Render TabHeader(props: shouldShowTab, shouldShowEnhancedTab, isEnhancing, currentTab, onTabChange, onVisibilityChange, isCurrentlyRecording)
TH->>Parent: onVisibilityChange(visible) [when shouldShowTab toggles]
alt isEnhancing true
TH->>Parent: onTabChange("enhanced")
else shouldShowTab false
TH->>Parent: onTabChange("raw")
TH-->>Editor: Render nothing
end
User->>TH: Click tab (Summary/Memos/Transcript)
TH->>Parent: onTabChange(nextTab)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/ui/src/components/block/tab-header.tsx (1)
37-42: Remove redundant nullish coalescing.Since
shouldShowTabis typed asboolean(not optional), the?? falseis unnecessary.Apply this diff:
// notify parent when visibility changes useEffect(() => { if (onVisibilityChange) { - onVisibilityChange(shouldShowTab ?? false); + onVisibilityChange(shouldShowTab); } }, [shouldShowTab, onVisibilityChange]);
📜 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 (5)
apps/desktop/src/components/editor-area/index.tsx(1 hunks)apps/desktop/src/components/editor-area/metadata-modal.tsx(0 hunks)apps/desktop/src/components/editor-area/note-header/index.tsx(0 hunks)apps/desktop/src/components/editor-area/note-header/tab-header.tsx(2 hunks)packages/ui/src/components/block/tab-header.tsx(1 hunks)
💤 Files with no reviewable changes (2)
- apps/desktop/src/components/editor-area/metadata-modal.tsx
- apps/desktop/src/components/editor-area/note-header/index.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/editor-area/index.tsxpackages/ui/src/components/block/tab-header.tsxapps/desktop/src/components/editor-area/note-header/tab-header.tsx
🧬 Code graph analysis (2)
packages/ui/src/components/block/tab-header.tsx (2)
apps/desktop/src/components/editor-area/note-header/tab-header.tsx (1)
TabHeader(14-53)packages/ui/src/lib/utils.ts (1)
cn(4-6)
apps/desktop/src/components/editor-area/note-header/tab-header.tsx (4)
packages/ui/src/components/block/tab-header.tsx (1)
TabHeader(14-108)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)
⏰ 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 (2)
apps/desktop/src/components/editor-area/index.tsx (1)
29-29: LGTM!The removal of
TabHeaderRefaligns with the refactor to use a pure UI component without ref exposure. The TabHeader usage at lines 336-343 remains unchanged and correctly passes props without refs.apps/desktop/src/components/editor-area/note-header/tab-header.tsx (1)
14-53: LGTM!The refactored component successfully separates concerns by:
- Acting as a smart container that computes visibility flags and recording state
- Delegating rendering to the pure UI component (
TabHeaderUI)- Maintaining clean prop drilling without ref exposure
The state derivations (lines 27-40) are logical, and the props mapping to
TabHeaderUI(lines 43-50) is complete and accurate.
| useEffect(() => { | ||
| // when enhancement starts (immediately after recording ends) -> switch to enhanced note | ||
| if (isEnhancing) { | ||
| onTabChange("enhanced"); | ||
| } | ||
| }, [isEnhancing]); |
There was a problem hiding this comment.
Add onTabChange to the dependency array.
The onTabChange callback is used inside the effect but missing from the dependency array, which could cause stale closures.
Apply this diff:
useEffect(() => {
// when enhancement starts (immediately after recording ends) -> switch to enhanced note
if (isEnhancing) {
onTabChange("enhanced");
}
- }, [isEnhancing]);
+ }, [isEnhancing, onTabChange]);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| // when enhancement starts (immediately after recording ends) -> switch to enhanced note | |
| if (isEnhancing) { | |
| onTabChange("enhanced"); | |
| } | |
| }, [isEnhancing]); | |
| useEffect(() => { | |
| // when enhancement starts (immediately after recording ends) -> switch to enhanced note | |
| if (isEnhancing) { | |
| onTabChange("enhanced"); | |
| } | |
| }, [isEnhancing, onTabChange]); |
🤖 Prompt for AI Agents
In packages/ui/src/components/block/tab-header.tsx around lines 23 to 28, the
useEffect references the onTabChange callback but does not include it in the
dependency array, which can lead to stale closures; update the effect's
dependency array to include onTabChange (i.e., [isEnhancing, onTabChange]) so
the effect sees the latest callback, or if onTabChange is intentionally stable,
ensure it is memoized (useCallback) or document why it's safe to omit before
keeping it out of the deps.
| <button | ||
| onClick={() => onTabChange("raw")} | ||
| className={cn( | ||
| "relative py-2 text-xs font-medium transition-all duration-200 border-b-2 -mb-px flex items-center gap-1.5", | ||
| shouldShowEnhancedTab ? "pl-3 px-4" : "pl-1 px-2", | ||
| currentTab === "raw" | ||
| ? "text-neutral-900 border-neutral-900" | ||
| : "text-neutral-600 border-transparent hover:text-neutral-800", | ||
| )} | ||
| > | ||
| Memos | ||
| </button> |
There was a problem hiding this comment.
Consider consistent padding to prevent layout shift.
The dynamic padding on the "Memos" button based on shouldShowEnhancedTab causes the button to shift position when the Enhanced tab appears or disappears, creating a jarring visual experience.
If this is intentional for design reasons, consider adding a CSS transition to smooth the shift. Otherwise, use consistent padding:
<button
onClick={() => onTabChange("raw")}
className={cn(
"relative py-2 text-xs font-medium transition-all duration-200 border-b-2 -mb-px flex items-center gap-1.5",
- shouldShowEnhancedTab ? "pl-3 px-4" : "pl-1 px-2",
+ "pl-3 px-4",
currentTab === "raw"
? "text-neutral-900 border-neutral-900"
: "text-neutral-600 border-transparent hover:text-neutral-800",
)}
>
Memos
</button>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| onClick={() => onTabChange("raw")} | |
| className={cn( | |
| "relative py-2 text-xs font-medium transition-all duration-200 border-b-2 -mb-px flex items-center gap-1.5", | |
| shouldShowEnhancedTab ? "pl-3 px-4" : "pl-1 px-2", | |
| currentTab === "raw" | |
| ? "text-neutral-900 border-neutral-900" | |
| : "text-neutral-600 border-transparent hover:text-neutral-800", | |
| )} | |
| > | |
| Memos | |
| </button> | |
| <button | |
| onClick={() => onTabChange("raw")} | |
| className={cn( | |
| "relative py-2 text-xs font-medium transition-all duration-200 border-b-2 -mb-px flex items-center gap-1.5", | |
| "pl-3 px-4", | |
| currentTab === "raw" | |
| ? "text-neutral-900 border-neutral-900" | |
| : "text-neutral-600 border-transparent hover:text-neutral-800", | |
| )} | |
| > | |
| Memos | |
| </button> |
🤖 Prompt for AI Agents
In packages/ui/src/components/block/tab-header.tsx around lines 72 to 83, the
"Memos" button uses conditional padding based on shouldShowEnhancedTab which
causes layout shift when the Enhanced tab appears or disappears; make the
padding consistent (choose one padding set for both states) to prevent shifting,
or if the design requires the change, add a CSS transition on padding or
transform to smooth the shift (apply a stable padding value and optionally
animate the change) so the button position does not jump when tabs toggle.