Skip to content

show spinner in tabs or left side bar items when note is being enhanced#2359

Merged
ComputelessComputer merged 1 commit intomainfrom
feat/tab-close-button
Dec 29, 2025
Merged

show spinner in tabs or left side bar items when note is being enhanced#2359
ComputelessComputer merged 1 commit intomainfrom
feat/tab-close-button

Conversation

@ComputelessComputer
Copy link
Collaborator

@ComputelessComputer ComputelessComputer commented Dec 17, 2025

show spinner in tabs or left side bar items when note is being enhanced


This is part 1 of 3 in a stack:

@netlify
Copy link

netlify bot commented Dec 17, 2025

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit ffeeeb7
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/69525bf84a1fca0008aa05c0

@netlify
Copy link

netlify bot commented Dec 17, 2025

Deploy Preview for hyprnote canceled.

Name Link
🔨 Latest commit ffeeeb7
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/69525bf8e649720008338f94

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

📝 Walkthrough

Walkthrough

Adds a read-only hook to detect when a session's enhanced notes are being generated and surfaces that state as a "finalizing" spinner in session tabs and timeline items by passing a new finalizing prop and adjusting rendering/layout to show a Spinner when appropriate.

Changes

Cohort / File(s) Change Summary
Enhanced notes status hook
apps/desktop/src/hooks/useEnhancedNotes.ts
Added export function useIsSessionEnhancing(sessionId: string): boolean which maps enhanced-note IDs to AI task IDs and returns true if any corresponding useAITask status is "generating".
Session tab wiring
apps/desktop/src/components/main/body/sessions/index.tsx
Imported useIsSessionEnhancing, derived isEnhancing, computed isFinalizing from sessionMode, combined into showSpinner, and passed finalizing={showSpinner} to TabItemBase.
Tab item rendering
apps/desktop/src/components/main/body/shared.tsx
Added finalizing?: boolean to TabItemBaseProps and finalizing = false default. When finalizing is true, render Spinner in the icon area; removed isEmptyTab prop and adjusted icon-area control flow.
Timeline item layout
apps/desktop/src/components/main/sidebar/timeline/item.tsx
Imported Spinner, useListener, and useIsSessionEnhancing. Computed sessionMode, isEnhancing, isFinalizing, and showSpinner. Reworked layout to conditionally show a left-aligned Spinner and adjusted title/timestamp stacking to allow truncation.

Sequence Diagram(s)

mermaid
sequenceDiagram
autonumber
participant SessionsIndex as SessionsIndex (render)
participant Hook as useIsSessionEnhancing
participant AITaskStore as useAITask / TaskStore
participant TabItem as TabItemBase / TimelineItem

SessionsIndex->>Hook: call useIsSessionEnhancing(sessionId)
Hook->>AITaskStore: derive task IDs -> query statuses
AITaskStore-->>Hook: return statuses (generating/...)
Hook-->>SessionsIndex: return isEnhancing (true/false)
SessionsIndex->>TabItem: pass finalizing={sessionMode==="finalizing" || isEnhancing}
TabItem->>TabItem: render icon area (Spinner if finalizing else prior visuals)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus review on: correctness of enhanced-note -> task ID mapping and status checks in useIsSessionEnhancing; consistent typing and default for new finalizing prop; UI layout/truncation and keyboard/accessibility when spinner is present.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description mentions a close button and finalizing state but doesn't align with the actual changes, which focus on displaying a spinner during session enhancement/finalization. Update the description to accurately reflect that the PR adds a finalizing spinner indicator to tabs and sidebar timeline items when sessions are enhancing or finalizing.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'feat/tab-close-button' is vague and doesn't clearly communicate the main changes; the PR actually adds a finalizing spinner state to tabs, not just a close button. Consider a more descriptive title that reflects the primary change, such as 'Add finalizing spinner state to tabs' or 'Display session enhancement status in tabs'.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/tab-close-button

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/desktop/src/components/main/body/sessions/index.tsx (1)

39-43: Consider extracting spinner state logic to a shared hook.

The pattern of computing isEnhancing, isFinalizing, and showSpinner is duplicated in timeline/item.tsx (lines 42-48). Extracting this to a reusable hook like useSessionSpinnerState(sessionId) would reduce duplication and improve maintainability.

Example implementation:

// In a shared hooks file
export function useSessionSpinnerState(sessionId: string | null) {
  const sessionMode = useListener((state) =>
    sessionId ? state.getSessionMode(sessionId) : "inactive"
  );
  const isEnhancing = useIsSessionEnhancing(sessionId ?? "");
  const isFinalizing = sessionMode === "finalizing";
  const showSpinner = isFinalizing || isEnhancing;
  
  return { isEnhancing, isFinalizing, showSpinner };
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d795e36 and 73a2372.

📒 Files selected for processing (4)
  • apps/desktop/src/components/main/body/sessions/index.tsx (2 hunks)
  • apps/desktop/src/components/main/body/shared.tsx (4 hunks)
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx (3 hunks)
  • apps/desktop/src/hooks/useEnhancedNotes.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/components/main/body/sessions/index.tsx
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props. Just inline them.
Never do manual state management for form/mutation. Use useForm from tanstack-form and useQuery/useMutation from tanstack-query for 99% cases.

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/components/main/body/sessions/index.tsx
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/components/main/body/sessions/index.tsx
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/components/main/body/sessions/index.tsx
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
🧬 Code graph analysis (4)
apps/desktop/src/hooks/useEnhancedNotes.ts (2)
apps/desktop/src/store/zustand/ai-task/task-configs/index.ts (1)
  • createTaskId (60-65)
apps/desktop/src/contexts/ai-task.tsx (1)
  • useAITask (49-60)
apps/desktop/src/components/main/body/shared.tsx (1)
extensions/shared/types/hypr-extension.d.ts (1)
  • Spinner (425-425)
apps/desktop/src/components/main/body/sessions/index.tsx (3)
apps/desktop/src/hooks/useEnhancedNotes.ts (1)
  • useIsSessionEnhancing (176-195)
apps/desktop/src/components/main/body/shared.tsx (1)
  • TabItemBase (38-162)
extensions/calendar/components/icons.tsx (1)
  • StickyNoteIcon (86-104)
apps/desktop/src/components/main/sidebar/timeline/item.tsx (3)
apps/desktop/src/contexts/listener.tsx (1)
  • useListener (37-49)
apps/desktop/src/hooks/useEnhancedNotes.ts (1)
  • useIsSessionEnhancing (176-195)
extensions/shared/types/hypr-extension.d.ts (1)
  • Spinner (425-425)
⏰ 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). (6)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
🔇 Additional comments (3)
apps/desktop/src/hooks/useEnhancedNotes.ts (1)

176-195: LGTM! Clean implementation of enhancement status check.

The function correctly aggregates AI task statuses for all enhanced notes in a session. The use of useMemo to derive task IDs is appropriate for performance, and the logic properly handles edge cases (null/empty arrays).

apps/desktop/src/components/main/body/shared.tsx (1)

110-112: LGTM! Clean conditional rendering for finalizing state.

The three-way conditional properly handles finalizing, active, and default icon states. The spinner provides clear visual feedback during enhancement operations.

apps/desktop/src/components/main/sidebar/timeline/item.tsx (1)

185-197: LGTM! Layout properly accommodates the loading spinner.

The horizontal flex layout with flex-shrink-0 on the spinner ensures proper spacing and alignment. The min-w-0 on the content container correctly enables text truncation when space is constrained.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/desktop/src/components/main/body/shared.tsx (1)

110-119: Consider: Close button behavior during finalization.

The current implementation allows users to close tabs while they're finalizing (close button appears on hover even when finalizing={true}). If this is intentional to give users control, the implementation is correct.

However, if finalization should prevent closing, you may want to conditionally disable the close button:

 <div
   className={cn([
     "absolute inset-0 flex items-center justify-center transition-opacity duration-200",
-    isHovered ? "opacity-100" : "opacity-0",
+    isHovered && !finalizing ? "opacity-100" : "opacity-0",
   ])}
 >
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73a2372 and c9ab57d.

📒 Files selected for processing (4)
  • apps/desktop/src/components/main/body/sessions/index.tsx (2 hunks)
  • apps/desktop/src/components/main/body/shared.tsx (4 hunks)
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx (3 hunks)
  • apps/desktop/src/hooks/useEnhancedNotes.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
  • apps/desktop/src/components/main/body/sessions/index.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/hooks/useEnhancedNotes.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props. Just inline them.
Never do manual state management for form/mutation. Use useForm from tanstack-form and useQuery/useMutation from tanstack-query for 99% cases.

Files:

  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/hooks/useEnhancedNotes.ts
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/hooks/useEnhancedNotes.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/body/shared.tsx
  • apps/desktop/src/hooks/useEnhancedNotes.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/hooks/useEnhancedNotes.ts
🧬 Code graph analysis (2)
apps/desktop/src/components/main/body/shared.tsx (1)
extensions/shared/types/hypr-extension.d.ts (1)
  • Spinner (425-425)
apps/desktop/src/hooks/useEnhancedNotes.ts (2)
apps/desktop/src/store/zustand/ai-task/task-configs/index.ts (1)
  • createTaskId (60-65)
apps/desktop/src/contexts/ai-task.tsx (1)
  • useAITask (49-60)
⏰ 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). (6)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
🔇 Additional comments (1)
apps/desktop/src/hooks/useEnhancedNotes.ts (1)

176-195: LGTM! Clean implementation of the enhancing state hook.

The hook correctly:

  • Retrieves enhanced note IDs for the session
  • Maps them to task IDs using the established pattern
  • Uses useMemo to optimize the task ID array computation
  • Leverages useAITask to check if any enhancement task is generating
  • Handles undefined enhancedNoteIds with the || [] fallback

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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/main/body/shared.tsx (1)

60-72: Critical: Undefined variable reference.

Line 61 references isEmptyTab, but this prop was removed in the refactoring. This will cause a ReferenceError at runtime and break the context menu functionality.

🔎 Proposed fix

If the isEmptyTab check is no longer needed, remove it:

  const contextMenu = !active
-    ? selected && !isEmptyTab
+    ? selected
      ? [{ id: "close-tab", text: "Close", action: handleCloseThis }]
      : [
          { id: "close-tab", text: "Close", action: handleCloseThis },

Alternatively, if different logic is needed based on the finalizing state or another condition, please clarify the intended behavior.

🧹 Nitpick comments (1)
apps/desktop/src/components/main/sidebar/timeline/item.tsx (1)

4-4: Remove unused import.

ContextMenuItem is imported but never used in this file.

🔎 Proposed fix
-import { ContextMenuItem } from "@hypr/ui/components/ui/context-menu";
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9ab57d and 0b187fb.

📒 Files selected for processing (2)
  • apps/desktop/src/components/main/body/shared.tsx (4 hunks)
  • apps/desktop/src/components/main/sidebar/timeline/item.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*

📄 CodeRabbit inference engine (AGENTS.md)

Format using dprint fmt from the root. Do not use cargo fmt.

Files:

  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
  • apps/desktop/src/components/main/body/shared.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props. Just inline them.
Never do manual state management for form/mutation. Use useForm from tanstack-form and useQuery/useMutation from tanstack-query for 99% cases.

Files:

  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
  • apps/desktop/src/components/main/body/shared.tsx
**/*.{ts,tsx,rs,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

By default, avoid writing comments at all. If you write one, it should be about 'Why', not 'What'.

Files:

  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
  • apps/desktop/src/components/main/body/shared.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: If there are many classNames with conditional logic, use cn (import from @hypr/utils). Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/sidebar/timeline/item.tsx
  • apps/desktop/src/components/main/body/shared.tsx
🧬 Code graph analysis (1)
apps/desktop/src/components/main/body/shared.tsx (1)
extensions/shared/types/hypr-extension.d.ts (1)
  • Spinner (425-425)
⏰ 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). (4)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
🔇 Additional comments (3)
apps/desktop/src/components/main/sidebar/timeline/item.tsx (1)

177-189: LGTM!

The layout refactoring correctly implements the spinner display with proper flex behaviors. The min-w-0 on the content wrapper enables text truncation within the flex container, and flex-shrink-0 prevents the spinner from being compressed.

apps/desktop/src/components/main/body/shared.tsx (2)

24-24: LGTM!

The prop rename from isEmptyTab to finalizing is clear and aligns well with the new functionality.

Also applies to: 42-42


114-123: LGTM!

The rendering logic correctly prioritizes the finalizing state over the active state, and the spinner size matches the icon container dimensions.

@github-project-automation github-project-automation bot moved this to Backlog in Product Dec 27, 2025
@ComputelessComputer ComputelessComputer moved this from Backlog to In review in Product Dec 27, 2025
@ComputelessComputer ComputelessComputer changed the title feat/tab-close-button show spinner in tabs or left side bar items when note is being enhanced Dec 27, 2025
@netlify
Copy link

netlify bot commented Dec 29, 2025

Deploy Preview for howto-fix-macos-audio-selection canceled.

Name Link
🔨 Latest commit ffeeeb7
🔍 Latest deploy log https://app.netlify.com/projects/howto-fix-macos-audio-selection/deploys/69525bf81311c00008692c39

@ComputelessComputer ComputelessComputer force-pushed the feat/tab-close-button branch 2 times, most recently from 5eea5fe to 24c2ef8 Compare December 29, 2025 10:42
@ComputelessComputer ComputelessComputer merged commit 6844f03 into main Dec 29, 2025
22 checks passed
@github-project-automation github-project-automation bot moved this from In review to Done in Product Dec 29, 2025
@ComputelessComputer ComputelessComputer deleted the feat/tab-close-button branch December 29, 2025 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant