Skip to content

Conversation

@ameer2468
Copy link
Contributor

@ameer2468 ameer2468 commented Oct 7, 2025

Summary by CodeRabbit

  • New Features

    • Organization-wide Cap settings UI, per-cap/video Settings dialog, owner controls to save per-video overrides, and SummaryChapters component.
    • Server-side save for org/video settings; transcription can now be marked SKIPPED when disabled.
  • Improvements

    • Feature flags now consistently disable summaries, captions, chapters, comments, and reactions across dashboard, share page, sidebar, players, and comments UI.
    • Debounced auto-save with per-key toasts, layout/timing tweaks, and improved hydration handling.
  • Chores

    • Dependency updates and minor styling adjustments.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Warning

Rate limit exceeded

@ameer2468 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 734029f and 86a13ec.

📒 Files selected for processing (1)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/SharedCaps.tsx (1 hunks)

Walkthrough

Adds organization- and per-video feature-flag settings across DB, server actions, transcription job, dashboard data/context, UI surfaces (organization and per-cap settings, share/player/sidebar/tabs), and component/type updates including a new transcription status "SKIPPED".

Changes

Cohort / File(s) Summary
Database schema & migrations
packages/database/schema.ts, packages/database/migrations/meta/_journal.json
Add JSON settings columns to organizations and videos; add "SKIPPED" to transcriptionStatus; append migration journal entry.
Server actions: settings
apps/web/actions/organization/settings.ts, apps/web/actions/videos/settings.ts
New server actions updateOrganizationSettings and updateVideoSettings: auth, validation, update settings JSON in DB, and revalidate dashboard path.
Transcription flow & status
apps/web/lib/transcribe.ts, apps/web/actions/videos/get-status.ts, packages/web-domain/src/Video.ts, packages/web-api-contract-effect/src/index.ts
Load org/video settings in transcribe job; skip transcription when disableTranscript is set and mark status SKIPPED; add SKIPPED to types and dev-mode short-circuits.
Dashboard data & context
apps/web/app/(org)/dashboard/dashboard-data.ts, apps/web/app/(org)/dashboard/Contexts.tsx, apps/web/app/(org)/dashboard/layout.tsx
Select and expose organizationSettings; add to dashboard data return shape and provide via DashboardContext / DashboardContexts props.
Organization settings UI
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx, apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
New CapSettingsCard: grid of toggles, pro gating, interdependent toggles, debounced autosave via updateOrganizationSettings, per-key toasts and error handling; inserted into Organization settings page.
Caps page & cap-level settings
apps/web/app/(org)/dashboard/caps/page.tsx, apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx, apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx, apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx, apps/web/app/(org)/dashboard/caps/Caps.tsx
Include videos.settings in queries; add per-cap SettingsDialog (owner-only gear), forward settings props, move Download into dropdown, suppress hydration warnings on menu triggers, adjust layout for settings UI.
Share page, players & sidebar
apps/web/app/s/[videoId]/page.tsx, apps/web/app/s/[videoId]/Share.tsx, apps/web/app/s/[videoId]/_components/ShareVideo.tsx, apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx, apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx, apps/web/app/s/[videoId]/_components/Toolbar.tsx, apps/web/app/s/[videoId]/_components/Sidebar.tsx, apps/web/app/s/[videoId]/_components/SummaryChapters.tsx, apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
Thread orgSettings/videoSettings into page/data; add disable flags (captions/chapters/comments/reactions/transcript); conditional rendering in players, toolbar, sidebar and tabs; add SummaryChapters and formatTimeMinutes util; update many props/signatures.
Activity/comments tab updates
apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx, .../Comments.tsx, .../EmptyState.tsx
Propagate commentsDisabled; show disabled EmptyState (icon/text) and hide/disable comment input when comments are disabled; EmptyState now prop-driven.
Settings dialog & related components
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
New SettingsDialog component for per-cap settings with local state, interdependent toggle logic, pro gating, save flow calling updateVideoSettings, loading state and toasts.
Misc UI & small edits
apps/web/app/(org)/dashboard/_components/MobileTab.tsx, apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx, apps/web/app/(site)/Navbar.tsx, packages/ui/src/components/Switch.tsx, apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
Small className/spacing tweaks, add suppressHydrationWarning/"use client" directives, adjust Switch disabled styling.
AI metadata cleanup
apps/web/actions/videos/generate-ai-metadata.ts
Remove unused minutesElapsed variable.
Package updates
apps/web/package.json, package.json
Bump @radix-ui/react-slot; add devDependency prettier.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant WC as Web Client
  participant SA as Server Action
  participant DB as Database

  U->>WC: toggle org/video setting
  WC->>SA: call updateOrganizationSettings/updateVideoSettings
  SA->>DB: auth check, update settings JSON
  DB-->>SA: success
  SA-->>WC: { success: true }
  WC->>WC: revalidatePath("/dashboard/caps")
Loading
sequenceDiagram
  autonumber
  participant Job as Transcribe Job
  participant DB as Database

  Job->>DB: Load video + org settings
  DB-->>Job: { orgSettings, video.settings }
  alt disableTranscript (org or video)
    Job->>DB: Update video.transcriptionStatus = "SKIPPED"
    DB-->>Job: OK
    Job-->>Job: return skipped result
  else enabled
    Job->>DB: Update transcriptionStatus = "PROCESSING"
    Job->>Job: transcribeAudio (dev-mode may short-circuit)
    Job->>DB: Save transcript & update status COMPLETE/ERROR
  end
Loading
sequenceDiagram
  autonumber
  participant Page as Share Page
  participant Ctx as Dashboard Context
  participant UI as Player/Sidebar/Toolbar

  Page->>Ctx: fetch orgSettings + videoSettings
  Ctx-->>Page: settings
  Page->>UI: pass disable flags (captions/chapters/comments/reactions)
  UI-->>UI: conditionally render controls, tabs and inputs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Suggested reviewers

  • Brendonovich

Poem

"I nibble toggles, soft and spry,
Org flags flap beneath my eye.
When transcripts nap the status slips,
Players hush and silent clips.
Settings saved — a carrot dip! 🥕"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “feature: org settings” directly reflects the main change—adding organization-level settings flags across the application—while remaining concise and specific enough for team members to understand the PR’s purpose at a glance.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/lib/transcribe.ts (1)

146-158: Reset transcription status when skipping in development mode.

In development, transcribeAudio now returns an empty string, we hit this branch, and we return success immediately. However, the video was already marked PROCESSING, and we never transition it to SKIPPED (or any terminal state), so the status remains stuck. Update the status before returning (similar to the org/video disable branch) to keep metadata consistent.

 		if (transcription === "") {
 			if (serverEnv().NODE_ENV === "development") {
 				console.log(
 					"[transcribeVideo] Development mode, skipping transcription",
 				);
+				await db()
+					.update(videos)
+					.set({ transcriptionStatus: "SKIPPED" })
+					.where(eq(videos.id, videoId));
 				return {
 					success: true,
 					message: "Transcription skipped in development mode",
 				};
apps/web/app/s/[videoId]/Share.tsx (1)

304-312: Honor disableReactions on mobile toolbar.

The new reactions toggle is ignored on small screens because this Toolbar instance never receives disableReactions, so emojis remain available even when the feature is disabled.

Apply this diff to forward the flag exactly like the desktop toolbar:

 					<Toolbar
 						onOptimisticComment={handleOptimisticComment}
 						onCommentSuccess={handleCommentSuccess}
 						data={data}
 						user={user}
+						disableReactions={
+							videoSettings?.disableReactions ??
+							data.orgSettings?.disableReactions
+						}
 					/>
🧹 Nitpick comments (4)
apps/web/actions/videos/settings.ts (2)

39-44: Consider cache revalidation and settings merge strategy.

Two potential concerns:

  1. The settings object is completely replaced rather than merged. If the UI sends partial settings, this could unintentionally clear other flags. Consider fetching existing settings and merging, or ensure callers always provide complete settings objects.

  2. No cache revalidation after the update (e.g., revalidatePath). Components displaying these settings may show stale data until a manual refresh.

Example merge approach:

+const existingSettings = video.settings || {};
 await db()
   .update(videos)
-  .set({ settings: videoSettings })
+  .set({ settings: { ...existingSettings, ...videoSettings } })
   .where(eq(videos.id, videoId));

+revalidatePath(`/dashboard/caps`);
+revalidatePath(`/s/${videoId}`);
 return { success: true };

9-19: Consider extracting shared settings type.

The videoSettings parameter type is duplicated from the schema definition. Extracting it to a shared type would ensure consistency and easier maintenance if settings expand.

Example:

// In packages/database/schema.ts or shared types file
export type VideoSettings = {
  disableSummary?: boolean;
  disableCaptions?: boolean;
  disableChapters?: boolean;
  disableReactions?: boolean;
  disableTranscript?: boolean;
  disableComments?: boolean;
};

// Then use here:
export async function updateVideoSettings(
  videoId: Video.VideoId,
  videoSettings: VideoSettings,
) {
apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (1)

619-647: Consider simplifying the IIFE wrapper.

The IIFE pattern adds unnecessary complexity. Consider using useMemo for computed values or extracting to a helper function for better readability.

Example with useMemo:

+const filteredComments = useMemo(
+  () =>
+    comments.filter(
+      (comment) =>
+        comment &&
+        comment.timestamp !== null &&
+        comment.id &&
+        !(disableCommentStamps && comment.type === "text") &&
+        !(disableReactionStamps && comment.type === "emoji"),
+    ),
+  [comments, disableCommentStamps, disableReactionStamps],
+);

 {mainControlsVisible &&
   markersReady &&
-  (() => {
-    const filteredComments = comments.filter(
-      (comment) =>
-        comment &&
-        comment.timestamp !== null &&
-        comment.id &&
-        !(disableCommentStamps && comment.type === "text") &&
-        !(disableReactionStamps && comment.type === "emoji"),
-    );
-
-    return filteredComments.map((comment) => {
+  filteredComments.map((comment) => {
     const position = (Number(comment.timestamp) / duration) * 100;
     ...
     return <CommentStamp ... />;
-  });
-})()}
+  })}
apps/web/app/(org)/dashboard/dashboard-data.ts (1)

46-46: Remove unused settings from organizationsWithMembers select
Line 46: settings: organizations.settings, is never consumed; the actual settings are loaded later at lines 115–119.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99a7912 and bade5f6.

📒 Files selected for processing (40)
  • apps/web/actions/organization/settings.ts (1 hunks)
  • apps/web/actions/videos/generate-ai-metadata.ts (0 hunks)
  • apps/web/actions/videos/get-status.ts (4 hunks)
  • apps/web/actions/videos/settings.ts (1 hunks)
  • apps/web/app/(org)/dashboard/Contexts.tsx (4 hunks)
  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/caps/Caps.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (10 hunks)
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/caps/page.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/dashboard-data.ts (7 hunks)
  • apps/web/app/(org)/dashboard/layout.tsx (3 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx (2 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/page.tsx (0 hunks)
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx (1 hunks)
  • apps/web/app/(site)/Navbar.tsx (1 hunks)
  • apps/web/app/s/[videoId]/Share.tsx (8 hunks)
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (5 hunks)
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx (4 hunks)
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx (2 hunks)
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx (8 hunks)
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx (2 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx (5 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx (4 hunks)
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx (9 hunks)
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts (1 hunks)
  • apps/web/app/s/[videoId]/page.tsx (9 hunks)
  • apps/web/lib/transcribe.ts (5 hunks)
  • apps/web/package.json (1 hunks)
  • package.json (1 hunks)
  • packages/database/migrations/meta/_journal.json (1 hunks)
  • packages/database/schema.ts (2 hunks)
  • packages/ui/src/components/Switch.tsx (1 hunks)
  • packages/web-api-contract-effect/src/index.ts (1 hunks)
  • packages/web-domain/src/Video.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/app/(org)/dashboard/settings/organization/page.tsx
  • apps/web/actions/videos/generate-ai-metadata.ts
🧰 Additional context used
📓 Path-based instructions (9)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • apps/web/lib/transcribe.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/actions/videos/settings.ts
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/actions/videos/get-status.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • packages/web-domain/src/Video.ts
  • packages/database/schema.ts
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • packages/web-api-contract-effect/src/index.ts
  • apps/web/lib/transcribe.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/actions/videos/settings.ts
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • packages/ui/src/components/Switch.tsx
  • apps/web/actions/videos/get-status.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • packages/web-domain/src/Video.ts
  • packages/database/schema.ts
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • packages/web-api-contract-effect/src/index.ts
  • apps/web/lib/transcribe.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/actions/videos/settings.ts
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • packages/ui/src/components/Switch.tsx
  • apps/web/actions/videos/get-status.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • packages/web-domain/src/Video.ts
  • packages/database/schema.ts
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • packages/web-api-contract-effect/src/index.ts
  • apps/web/lib/transcribe.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/actions/videos/settings.ts
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • packages/ui/src/components/Switch.tsx
  • apps/web/actions/videos/get-status.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/_components/MobileTab.tsx
  • apps/web/app/(site)/Navbar.tsx
  • apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx
  • apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx
  • apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx
  • apps/web/app/s/[videoId]/_components/SummaryChapters.tsx
  • apps/web/app/(org)/dashboard/caps/Caps.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • apps/web/lib/transcribe.ts
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/s/[videoId]/_components/Toolbar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Summary.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx
  • apps/web/app/(org)/dashboard/caps/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/actions/videos/settings.ts
  • apps/web/app/s/[videoId]/Share.tsx
  • apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
  • apps/web/app/s/[videoId]/page.tsx
  • apps/web/actions/videos/get-status.ts
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx
  • apps/web/app/(org)/dashboard/Contexts.tsx
  • apps/web/app/(org)/dashboard/settings/organization/Organization.tsx
  • apps/web/app/s/[videoId]/_components/ShareVideo.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx
  • apps/web/app/s/[videoId]/_components/Sidebar.tsx
  • apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx
apps/web/actions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

All Groq/OpenAI calls must be implemented in Next.js Server Actions under apps/web/actions; do not place AI calls elsewhere

Files:

  • apps/web/actions/organization/settings.ts
  • apps/web/actions/videos/settings.ts
  • apps/web/actions/videos/get-status.ts
packages/web-api-contract-effect/**

📄 CodeRabbit inference engine (CLAUDE.md)

Update shared HTTP contracts in packages/web-api-contract-effect alongside any API route changes to keep schemas in sync

Files:

  • packages/web-api-contract-effect/src/index.ts
packages/ui/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Component files in packages/ui should use PascalCase naming if they define React/Solid components.

Files:

  • packages/ui/src/components/Switch.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-22T14:17:47.407Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.407Z
Learning: Applies to packages/web-api-contract-effect/** : Update shared HTTP contracts in packages/web-api-contract-effect alongside any API route changes to keep schemas in sync

Applied to files:

  • packages/web-api-contract-effect/src/index.ts
🧬 Code graph analysis (21)
apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx (1)
apps/web/app/s/[videoId]/_components/video/media-player.tsx (2)
  • MediaPlayerCaptions (3144-3144)
  • MediaPlayerCaptions (3168-3168)
apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (1)
packages/ui/src/components/Popover.tsx (1)
  • PopoverTrigger (30-30)
apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (1)
packages/database/schema.ts (1)
  • comments (335-355)
apps/web/app/s/[videoId]/_components/SummaryChapters.tsx (1)
apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts (1)
  • formatTimeMinutes (29-35)
apps/web/actions/organization/settings.ts (2)
packages/database/index.ts (1)
  • db (29-34)
packages/database/schema.ts (1)
  • organizations (152-180)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (2)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1)
  • SettingsDialog (64-222)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (1)
  • CapCardButton (17-43)
apps/web/app/(org)/dashboard/dashboard-data.ts (2)
packages/database/schema.ts (1)
  • organizations (152-180)
packages/database/index.ts (1)
  • db (29-34)
apps/web/lib/transcribe.ts (3)
packages/database/schema.ts (3)
  • videos (256-311)
  • organizations (152-180)
  • s3Buckets (396-406)
packages/database/index.ts (1)
  • db (29-34)
packages/env/server.ts (1)
  • serverEnv (83-87)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
apps/web/app/s/[videoId]/_components/Toolbar.tsx (4)
packages/database/schema.ts (1)
  • videos (256-311)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
packages/database/auth/session.ts (1)
  • userSelectProps (29-29)
apps/web/app/s/[videoId]/Share.tsx (1)
  • CommentType (30-33)
apps/web/app/(org)/dashboard/caps/page.tsx (1)
packages/database/schema.ts (5)
  • videos (256-311)
  • comments (335-355)
  • organizations (152-180)
  • users (50-99)
  • videoUploads (674-680)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (4)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/videos/settings.ts (1)
  • updateVideoSettings (9-45)
apps/web/actions/videos/settings.ts (2)
packages/database/index.ts (1)
  • db (29-34)
packages/database/schema.ts (1)
  • videos (256-311)
apps/web/app/s/[videoId]/Share.tsx (3)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/s/[videoId]/_components/Sidebar.tsx (1)
  • Sidebar (71-264)
apps/web/app/s/[videoId]/_components/Toolbar.tsx (1)
  • Toolbar (24-291)
apps/web/app/s/[videoId]/page.tsx (2)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
packages/database/schema.ts (2)
  • videos (256-311)
  • organizations (152-180)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
apps/web/app/(org)/dashboard/dashboard-data.ts (2)
  • Organization (15-26)
  • OrganizationSettings (28-29)
apps/web/app/s/[videoId]/_components/ShareVideo.tsx (5)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts (1)
  • TranscriptEntry (3-8)
apps/web/hooks/use-transcript.ts (1)
  • useTranscript (5-27)
apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (1)
  • CapVideoPlayer (56-685)
apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx (1)
  • HLSVideoPlayer (45-416)
apps/web/app/(org)/dashboard/layout.tsx (1)
apps/web/app/(org)/dashboard/dashboard-data.ts (4)
  • OrganizationSettings (28-29)
  • Spaces (31-37)
  • UserPreferences (39-39)
  • getDashboardData (41-292)
apps/web/app/s/[videoId]/_components/tabs/Activity/EmptyState.tsx (2)
apps/web/components/EmptyState.tsx (1)
  • EmptyState (12-31)
packages/ui/src/components/LoadingSpinner.tsx (1)
  • LoadingSpinner (1-36)
apps/web/app/s/[videoId]/_components/Sidebar.tsx (1)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/s/[videoId]/_components/tabs/Activity/Comments.tsx (1)
apps/web/components/EmptyState.tsx (1)
  • EmptyState (12-31)
🪛 GitHub Actions: Validate Migrations
packages/database/migrations/meta/_journal.json

[error] 2-2: Migration journal version cannot be changed (was: <BASE_VERSION>, now: <CURRENT_VERSION>)

⏰ 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: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (32)
apps/web/app/(org)/dashboard/spaces/[spaceId]/components/SharedCapCard.tsx (1)

1-2: Client directive is the right call

SharedCapCard attaches drag handlers, so marking it as a client component is required for those events to wire up correctly. Nice catch.

packages/ui/src/components/Switch.tsx (1)

17-17: LGTM: Design system alignment.

The disabled state styling now uses the design system gray scale (gray-4) and reduces opacity to opacity-40 for better visual consistency. This appears to be an intentional alignment with the broader design system updates.

apps/web/app/(org)/dashboard/_components/MobileTab.tsx (1)

47-47: LGTM: Layout spacing adjustment.

The addition of gap-5 increases horizontal spacing between child elements in the mobile tab container, improving visual layout consistency.

packages/web-api-contract-effect/src/index.ts (1)

11-16: LGTM: TranscriptionStatus extension.

Adding "SKIPPED" to the TranscriptionStatus schema properly extends the API contract to support the new transcription state introduced in this PR.

Based on coding guidelines: This update to the shared HTTP contract in packages/web-api-contract-effect aligns with the API route changes across the codebase for organization settings and transcription features.

apps/web/app/(site)/Navbar.tsx (1)

141-141: LGTM: Tailwind class standardization.

Replacing the arbitrary value duration-[0.2s] with the standard Tailwind utility duration-200 improves consistency and leverages built-in classes, which can help with bundle optimization.

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (1)

28-28: LGTM: Simplified event handler.

Since onClick has a default value of () => {} (line 19), the optional chaining was unnecessary. The direct reference is cleaner and functionally equivalent.

apps/web/package.json (1)

56-56: Test Slot behavior across SSR/RSC, ref‐forwarding, and TypeScript after upgrading
Ensure pages using Slot+asChild still render on the server, refs forward correctly to Next Link and fragment children, and your TypeScript build passes without errors.

packages/web-domain/src/Video.ts (1)

28-30: LGTM!

The addition of "SKIPPED" to the transcriptionStatus enum is clean and consistent with the broader PR changes supporting organization-level transcription controls.

packages/database/schema.ts (2)

162-169: LGTM!

The organization-level settings structure is well-defined with typed optional flags. The JSON column approach provides flexibility for future settings additions.


271-280: LGTM!

The video-level settings structure mirrors the organization settings, maintaining consistency. The addition of "SKIPPED" to transcriptionStatus completes the domain model alignment.

apps/web/actions/videos/settings.ts (1)

20-37: LGTM!

The authorization logic is well-structured with proper checks for user authentication, data validation, video existence, and ownership verification. Error messages are clear and actionable.

apps/web/actions/videos/get-status.ts (1)

17-17: LGTM!

The extraction of TranscriptionStatus into a named type alias improves code maintainability and readability. All usages are consistently updated throughout the file.

Also applies to: 20-20

apps/web/app/s/[videoId]/_components/CapVideoPlayer.tsx (2)

38-38: LGTM!

The new props for disabling captions and comment/reaction stamps are well-defined with sensible defaults and clear naming.

Also applies to: 44-45, 61-61, 68-69


671-676: LGTM!

The conditional rendering of MediaPlayerCaptions based on the disableCaptions flag is implemented correctly.

apps/web/app/s/[videoId]/_components/HLSVideoPlayer.tsx (3)

40-40: LGTM!

The disableCaptions prop is properly integrated into the component interface and signature.

Also applies to: 54-54


361-369: LGTM! Good improvement.

Making the track elements conditional on the presence of their sources is a solid enhancement that prevents rendering empty tracks and improves robustness.


402-407: LGTM!

The conditional rendering of MediaPlayerCaptions is implemented correctly and consistently with the CapVideoPlayer component.

apps/web/app/s/[videoId]/_components/tabs/Summary.tsx (2)

26-26: LGTM!

The isSummaryDisabled feature is cleanly implemented with an early return pattern that prevents rendering when the summary is disabled.

Also applies to: 68-68, 146-147


161-174: LGTM!

The replacement of the inline SVG with FontAwesomeIcon improves consistency with the rest of the codebase. The styling adjustments are cosmetic and maintain the existing UX.

apps/web/app/(org)/dashboard/_components/Navbar/Items.tsx (1)

97-97: LGTM!

The addition of suppressHydrationWarning is a standard Next.js pattern to address expected hydration mismatches in interactive components.

apps/web/app/(org)/dashboard/caps/Caps.tsx (1)

27-27: LGTM: Unused import removed.

The removal of useUploadingContext is correct, as it's not used anywhere in the file. This keeps imports clean.

apps/web/app/(org)/dashboard/settings/organization/Organization.tsx (1)

16-16: LGTM: CapSettingsCard integrated properly.

The new settings card is correctly imported and positioned in the organization settings flow. The component appears to use dashboard context for data access, consistent with other cards in this layout.

Also applies to: 68-70

apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts (1)

29-35: LGTM: Time formatting logic is correct.

The function correctly converts seconds to MM:SS format using floor division and proper padding.

apps/web/app/(org)/dashboard/layout.tsx (1)

13-13: LGTM: Organization settings properly integrated.

The organizationSettings data flows correctly from getDashboardData through the layout to DashboardContexts, with proper error handling that mirrors the pattern used for other dashboard data.

Also applies to: 36-36, 43-43, 50-50, 77-77

apps/web/app/s/[videoId]/_components/tabs/Activity/index.tsx (1)

6-6: LGTM: Comments disabled flag properly threaded.

The commentsDisabled prop is correctly added to the interface, destructured, and passed to the Comments component. The React import consolidation also improves code organization.

Also applies to: 24-24, 39-39, 70-70

apps/web/app/s/[videoId]/_components/SummaryChapters.tsx (3)

3-19: LGTM: Props interface well-defined.

The SummaryChaptersProps interface clearly defines all required inputs, including feature flags, seek handler, AI data, and loading state.


21-35: LGTM: Conditional rendering logic is clean.

The component efficiently computes hasSummary and hasChapters based on disabled flags and data availability, with an appropriate early return when there's nothing to display.


36-71: LGTM: UI structure is well-organized.

The component properly renders Summary and Chapters sections with appropriate styling, semantic HTML, and interactive chapter navigation via the handleSeek callback.

apps/web/app/(org)/dashboard/dashboard-data.ts (2)

28-29: LGTM: Type export is clean.

The OrganizationSettings type correctly extracts the settings field type from the organizations schema.


86-86: LGTM: Organization settings integration is complete.

The organization settings are properly fetched for the active organization, initialized with appropriate defaults, included in the return value, and handled correctly in error scenarios.

Also applies to: 115-120, 277-277, 289-289

apps/web/app/(org)/dashboard/caps/page.tsx (2)

178-178: LGTM: Video settings properly selected and propagated.

The settings field is correctly selected from the videos table and included in the processed output for downstream consumption.

Also applies to: 240-240


185-191: Verify org filtering behavior.

Adding eq(videos.orgId, user.activeOrganizationId) restricts the query to videos belonging to the user's active organization only. This is a significant behavioral change that will exclude videos from other organizations, even if the user previously had access to them.

Ensure this aligns with the product requirements for the caps page.

Also applies to: 198-198

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Pipeline failure on migration journal version.

The pipeline reports: "Migration journal version cannot be changed (was: <BASE_VERSION>, now: <CURRENT_VERSION>)". This indicates the migration journal's version field was modified, which violates migration integrity constraints.

This must be resolved before merging:

  1. Check if the migration was regenerated when it shouldn't have been
  2. Ensure the base migration journal wasn't modified
  3. Follow the project's migration workflow to properly add new migrations without altering the version field
  4. Verify with the team if this is a rebase artifact that needs resolution
#!/bin/bash

# Check for any other migration-related changes or conflicts
git log --oneline --all -- packages/database/migrations/

# Compare with the base branch to see what version field changed
git diff origin/main...HEAD -- packages/database/migrations/meta/_journal.json
🤖 Prompt for AI Agents
In packages/database/migrations/meta/_journal.json around lines 61 to 67, the
migration journal's "version" field was changed (which is not allowed) — revert
the version field and any other unintended edits in this file to match the base
branch, undo any accidental regeneration of the journal, and re-create new
migrations using the project's approved workflow; verify by comparing with
origin/main, restore the file from the base branch or resolve rebase conflicts,
confirm no other migration files were altered, and consult the team if this
change was received as a rebase artifact before re-committing.

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: 5

♻️ Duplicate comments (1)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

71-76: Sync local state when organizationSettings updates.

Local toggles never reflect newly delivered organizationSettings, so users arriving before the context resolves can overwrite true backend values with defaults. Mirror the incoming payload (or defaults) into settings and lastSavedSettings.

-	useEffect(() => {
-		if (organizationSettings) {
-			lastSavedSettings.current = organizationSettings;
-		}
-	}, [organizationSettings]);
+	useEffect(() => {
+		const next =
+			organizationSettings ?? {
+				disableComments: false,
+				disableSummary: false,
+				disableCaptions: false,
+				disableChapters: false,
+				disableReactions: false,
+				disableTranscript: false,
+			};
+		setSettings(next);
+		lastSavedSettings.current = next;
+	}, [organizationSettings]);
🧹 Nitpick comments (6)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (6)

72-79: State should be Partial and filtered, not an object of undefineds

Initialize overrides as Partial from settingsData, omitting undefineds. This prevents writing undefineds and matches “override” semantics.

-const [settings, setSettings] = useState<OrganizationSettings>({
-  disableComments: settingsData?.disableComments,
-  disableSummary: settingsData?.disableSummary,
-  disableCaptions: settingsData?.disableCaptions,
-  disableChapters: settingsData?.disableChapters,
-  disableReactions: settingsData?.disableReactions,
-  disableTranscript: settingsData?.disableTranscript,
-});
+const [settings, setSettings] = useState<Partial<OrganizationSettings>>(
+  (settingsData
+    ? (Object.fromEntries(
+        Object.entries(settingsData).filter(([, v]) => v !== undefined),
+      ) as Partial<OrganizationSettings>)
+    : {}) as Partial<OrganizationSettings>,
+);

As per coding guidelines


129-136: Simplify effective value calc

Use nullish coalescing; current condition is redundant.

-const getEffectiveValue = (key: keyof OrganizationSettings) => {
-  const videoValue = settings?.[key];
-  const orgValue = organizationSettings?.[key] ?? false;
-  return videoValue !== undefined || videoValue === true
-    ? videoValue
-    : orgValue;
-};
+const getEffectiveValue = (key: keyof OrganizationSettings) => {
+  const videoValue = settings?.[key];
+  const orgValue = organizationSettings?.[key] ?? false;
+  return videoValue ?? orgValue;
+};

98-103: Type the toggle handler to avoid casts

Accept a strongly-typed key instead of string + cast.

-const toggleSettingHandler = useCallback(
-  (value: string) => {
+const toggleSettingHandler = useCallback(
+  (key: keyof OrganizationSettings) => {
     setSettings((prev) => {
-      const key = value as keyof OrganizationSettings;
       const currentValue = prev?.[key];
       const orgValue = organizationSettings?.[key] ?? false;

And call with a typed value for options (see next comment). As per coding guidelines


189-191: Use Switch’s checked argument to set value explicitly (less brittle)

Avoid manual toggling; derive disable flag from checked. Keeps state in sync with UI source of truth.

-onCheckedChange={() => toggleSettingHandler(option.value)}
+onCheckedChange={(checked) => {
+  const key = option.value as keyof OrganizationSettings;
+  setSettings((prev) => {
+    const newValue = !checked; // checked == enabled -> disable flag false
+    if (key === "disableTranscript" && newValue === true) {
+      return {
+        ...prev,
+        [key]: newValue,
+        disableSummary: true,
+        disableChapters: true,
+      };
+    }
+    return { ...prev, [key]: newValue };
+  });
+}}

As per coding guidelines


105-109: Remove inline comments (repo guideline)

Inline comments are disallowed in TS/JS. Delete these comment lines.

-        // If using org default, set to opposite of org value
-        // If org disabled it (true), enabling means setting to false
-        // If org enabled it (false), disabling means setting to true
-        const newValue = currentValue === undefined ? !orgValue : !currentValue;
+        const newValue = currentValue === undefined ? !orgValue : !currentValue;
-// Helper to get the effective value (considering org defaults)
-                    // Disable summary and chapters if transcript is disabled

As per coding guidelines

Also applies to: 129-129, 183-187


83-96: Use useEffectMutation for the save, and update cache instead of blind close

Adopt the app’s EffectRuntime pattern for client mutations and patch related caches (e.g., caps list/cap detail) with setQueryData to reflect updated settings without a full refresh.

I can wire a useEffectMutation around updateVideoSettings and add a setQueryData update for your caps query key. Want a patch?
As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bade5f6 and 0bd11fa.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (10 hunks)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
  • apps/web/app/embed/[videoId]/page.tsx (4 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
🧬 Code graph analysis (4)
apps/web/app/embed/[videoId]/page.tsx (1)
packages/database/schema.ts (1)
  • videos (256-311)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (4)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/videos/settings.ts (1)
  • updateVideoSettings (9-45)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (2)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1)
  • SettingsDialog (64-218)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (1)
  • CapCardButton (17-43)
⏰ 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). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (2)
apps/web/app/embed/[videoId]/page.tsx (1)

119-160: Remove unused video.settings or implement feature-gating.

The query selects settings: videos.settings but this file never uses video.settings (nor does it fetch orgSettings). Either drop settings from the select to avoid fetching unused data, or add logic here to consume video.settings (and join organizations.settings if you need org-level flags).

Likely an incorrect or invalid review comment.

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (1)

301-306: SettingsDialog wiring LGTM

Props and owner gating look correct; closing via onClose updates local state.

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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/app/embed/[videoId]/page.tsx (1)

119-160: Include organization settings in the video query
Add a left join on organizations, select organizations.settings as orgSettings (using the OrganizationSettings type), and extend the returned video object so that downstream components can receive and render orgSettings.

apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (1)

158-168: Replace useMutation with useEffectMutation and remove duplicate Download button

  • In apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (lines 158–168), apply:
    - const deleteMutation = useMutation({
    -   mutationFn: async () => {
    -     await onDelete?.();
    -   },
    -   onError: (error) => {
    -     console.error("Error deleting cap:", error);
    -   },
    -   onSettled: () => {
    -     setConfirmOpen(false);
    -   },
    - });
    + const deleteMutation = useEffectMutation({
    +   mutationFn: () => Effect.promise(() => onDelete?.()),
    +   onSettled: () => setConfirmOpen(false),
    +   onError: (error) => console.error("Error deleting cap:", error),
    + });
    Also remove the unused useMutation import.
  • Remove the first non-owner “Download Cap” button (duplicate); keep the later one with spinner/disabled state.

Verify other occurrences:

rg -n '\buseMutation\(' --glob '*.ts' --glob '*.tsx' apps/web
♻️ Duplicate comments (2)
apps/web/actions/organization/settings.ts (1)

27-34: Good fix on organization existence check

Destructuring the first row and guarding “not found” resolves the prior bug.

apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

72-84: Good fix: sync local state with organizationSettings

Synchronizing both settings and lastSavedSettings addresses stale toggles on context updates.

🧹 Nitpick comments (5)
apps/web/app/embed/[videoId]/page.tsx (1)

256-261: Exclude SKIPPED in transcription trigger
The current check (!== "COMPLETE" && !== "PROCESSING") still re-triggers for SKIPPED (used when disableTranscript is true). Update to also exclude SKIPPED:

- if (
-   video.transcriptionStatus !== "COMPLETE" &&
-   video.transcriptionStatus !== "PROCESSING"
- ) {
+ if (
+   video.transcriptionStatus !== "COMPLETE" &&
+   video.transcriptionStatus !== "PROCESSING" &&
+   video.transcriptionStatus !== "SKIPPED"
+ ) {
    transcribeVideo(video.id, video.ownerId, aiGenerationEnabled);
}
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (2)

129-136: Simplify effective value logic and remove inline comment

Use nullish coalescing; comment not needed per guidelines.

Apply this diff:

-  // Helper to get the effective value (considering org defaults)
   const getEffectiveValue = (key: keyof OrganizationSettings) => {
     const videoValue = settings?.[key];
     const orgValue = organizationSettings?.[key] ?? false;
-    return videoValue !== undefined || videoValue === true
-      ? videoValue
-      : orgValue;
+    return videoValue ?? orgValue;
   };

105-108: Remove inline comments (project policy)

Inline comments are disallowed; make code self-explanatory or extract helpers.

Also applies to: 110-117, 181-188

apps/web/actions/organization/settings.ts (1)

27-31: Select only needed fields to reduce IO

Fetching the whole row isn’t required; select just the id.

Apply this diff:

-  const [organization] = await db()
-    .select()
+  const [organization] = await db()
+    .select({ id: organizations.id })
     .from(organizations)
     .where(eq(organizations.id, user.activeOrganizationId));
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

62-66: Remove inline comments (project policy)

Inline comments are not allowed; rely on clear naming or helper extraction.

Also applies to: 71-81, 91-101, 103-109, 112-124, 125-139, 145-153, 172-176, 181-205

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bade5f6 and e319cb7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • apps/web/actions/organization/settings.ts (1 hunks)
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (10 hunks)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
  • apps/web/app/embed/[videoId]/page.tsx (4 hunks)
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/app/s/[videoId]/_components/utils/transcript-utils.ts
🧰 Additional context used
📓 Path-based instructions (7)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/embed/[videoId]/page.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/actions/organization/settings.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/actions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

All Groq/OpenAI calls must be implemented in Next.js Server Actions under apps/web/actions; do not place AI calls elsewhere

Files:

  • apps/web/actions/organization/settings.ts
🧬 Code graph analysis (5)
apps/web/app/embed/[videoId]/page.tsx (1)
packages/database/schema.ts (1)
  • videos (256-311)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (2)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1)
  • SettingsDialog (64-218)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (1)
  • CapCardButton (17-43)
apps/web/actions/organization/settings.ts (2)
packages/database/index.ts (1)
  • db (29-34)
packages/database/schema.ts (1)
  • organizations (152-180)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (4)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-29)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/videos/settings.ts (1)
  • updateVideoSettings (9-45)
⏰ 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). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (2)
apps/web/app/embed/[videoId]/page.tsx (1)

186-192: LGTM: Styling consistency improvements.

The className changes across the three error/message display divs improve layout consistency using flexbox centering utilities.

Also applies to: 241-250, 288-290

apps/web/actions/organization/settings.ts (1)

36-39: Confirm full replacement vs. merge semantics

This overwrites settings with the provided object. If partial updates are ever passed, keys may be dropped. Confirm this is intentional for org defaults.

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

♻️ Duplicate comments (1)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

42-46: Clarify the transcript dependency relationship.

"This also allows chapters and summary" is ambiguous. Update to clearly state that transcript is required for downstream features.

Apply this diff:

-		description: "This also allows chapters and summary",
+		description: "Required for summary and chapters",
🧹 Nitpick comments (1)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

83-131: Consider removing organizationSettings from dependencies.

The organizationSettings dependency is only used in the error handler to revert state. Including it may cause unnecessary effect runs since the first effect (lines 70-81) already syncs organizationSettings to local state. You could remove it and accept that the error handler reverts to the organizationSettings value captured when the effect was registered, or refactor the error handling to be more explicit.

If you choose to remove the dependency:

-	}, [debouncedUpdateSettings, organizationSettings]);
+	}, [debouncedUpdateSettings]);

This is a minor optimization and the current implementation is safe.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e319cb7 and a4429f7.

📒 Files selected for processing (4)
  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (10 hunks)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/dashboard-data.ts (7 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/app/(org)/dashboard/dashboard-data.ts
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
🧬 Code graph analysis (2)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (2)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1)
  • SettingsDialog (69-226)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCardButton.tsx (1)
  • CapCardButton (17-43)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-30)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
⏰ 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). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (11)
apps/web/app/(org)/dashboard/caps/components/CapCard/CapCard.tsx (8)

18-18: LGTM!

The new imports for faGear and SettingsDialog are properly utilized within the component.

Also applies to: 46-46


77-84: LGTM!

The settings object is properly typed with optional boolean flags that align with the OrganizationSettings interface used in SettingsDialog.


126-126: LGTM!

The state declaration follows the standard pattern for controlling dialog visibility.


301-306: LGTM!

The SettingsDialog is properly integrated with correct props matching the interface from SettingsDialog.tsx.


345-369: Past review comments appear outdated; verify intentional UX asymmetry.

The previous review comments flagged duplicate Download buttons for non-owners, but in the current code:

  • Owners see a Settings button here + a dropdown menu (lines 411-483) containing Download
  • Non-owners see a Download button here + no dropdown (dropdown is owner-only)

There is no duplicate for non-owners. However, the UX is asymmetric: non-owners get direct download access while owners must use the dropdown. Verify this is intentional.


429-438: LGTM!

The Download menu item is properly implemented with consistent styling, proper event handling, and reuses the existing handleDownload function.


539-540: LGTM!

The z-index and positioning adjustments ensure proper layering of the upload progress overlay with the new SettingsDialog.


413-413: Verify and remove unnecessary suppressHydrationWarning

The suppressHydrationWarning props in layout.tsx (line 107), Navbar/Items.tsx (line 97) and CapCard.tsx (lines 413 & 427) can mask real server-client markup mismatches on client components. Confirm there are actual hydration warnings before keeping them; otherwise remove these props and address the root causes.

apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (3)

133-151: LGTM! Toggle logic correctly handles dependencies.

The special case for disableTranscript appropriately cascades to disableSummary and disableChapters, ensuring the transcript dependency constraint is enforced. The logic preserves user choices when re-enabling transcript.


163-198: LGTM! Render logic and disabled states are correct.

The grid layout cleanly presents each option with appropriate disabled states:

  • Pro features are gated for non-Pro users
  • Summary and chapters are disabled when transcript is disabled
  • The inverted checked state (!settings?.[option.value]) ensures switches are ON when features are enabled, which is intuitive

31-34: Rephrase description to match "Enable" framing.

The UI displays "Enable chapters" but the description says "Remove the chapters," which describes the opposite state. Update to something like "Show AI-generated chapters (requires transcript)" to match the enabled state.

Apply this diff:

-		description: "Remove the chapters for caps (requires transcript)",
+		description: "Show AI-generated chapters (requires transcript)",

Likely an incorrect or invalid review comment.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4429f7 and 1ee233e.

📒 Files selected for processing (3)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/layout.tsx (3 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/layout.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
🧬 Code graph analysis (3)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-30)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
apps/web/app/(org)/dashboard/layout.tsx (1)
apps/web/app/(org)/dashboard/dashboard-data.ts (3)
  • OrganizationSettings (28-30)
  • Spaces (32-38)
  • getDashboardData (42-293)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (4)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-30)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/videos/settings.ts (1)
  • updateVideoSettings (9-45)
⏰ 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). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)

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 (3)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (2)

101-102: Remove dead guard that's always false.

settings is initialized from buildSettings(settingsData) and always returns an object, so if (!settings) will never be true. Removing this guard simplifies the code without changing behavior.

Apply this diff:

 const saveHandler = async () => {
-  if (!settings) return;
   setSaveLoading(true);
   try {

146-152: Simplify redundant condition in getEffectiveValue.

The condition videoValue !== undefined || videoValue === true works correctly but the second part is redundant—videoValue !== undefined already handles all defined values including true.

Apply this diff:

 const getEffectiveValue = (key: keyof OrganizationSettings) => {
   const videoValue = settings?.[key];
   const orgValue = organizationSettings?.[key] ?? false;
-  return videoValue !== undefined || videoValue === true
-    ? videoValue
-    : orgValue;
+  return videoValue !== undefined ? videoValue : orgValue;
 };
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

107-115: Consider more robust label extraction for toast messages.

The string manipulation option?.label.split(" ")[1] assumes labels follow "Enable X" format. While it works for current labels, it's brittle and will break if label format changes. Consider extracting the feature name from the option value instead or using a label map.

Example alternative:

 changedKeys.forEach((changedKey) => {
-  const option = options.find((opt) => opt.value === changedKey);
   const isDisabled = debouncedUpdateSettings[changedKey];
   const action = isDisabled ? "disabled" : "enabled";
-  const label = option?.label.split(" ")[1] || changedKey;
+  const label = changedKey.replace("disable", "").replace(/([A-Z])/g, " $1").trim().toLowerCase();
   toast.success(
     `${label.charAt(0).toUpperCase()}${label.slice(1)} ${action}`,
   );
 });

Or maintain a dedicated label map for feature names.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ee233e and 734029f.

📒 Files selected for processing (2)
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (1 hunks)
  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/web/**/*.{ts,tsx}: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not add inline, block, or docstring comments in any language; code must be self-explanatory

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript and avoid any; leverage shared types from packages

**/*.{ts,tsx}: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by running pnpm format.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx}: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g., user-menu.tsx).
Use PascalCase for React/Solid components.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

On the client, always use useEffectQuery or useEffectMutation from @/lib/EffectRuntime; never call EffectRuntime.run* directly in components.

Files:

  • apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx
  • apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx
🧬 Code graph analysis (2)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (4)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-30)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/organization/settings.ts (1)
  • updateOrganizationSettings (9-44)
apps/web/app/(org)/dashboard/caps/components/SettingsDialog.tsx (4)
apps/web/app/(org)/dashboard/dashboard-data.ts (1)
  • OrganizationSettings (28-30)
apps/web/app/(org)/dashboard/Contexts.tsx (1)
  • useDashboardContext (50-50)
packages/utils/src/constants/plans.ts (1)
  • userIsPro (21-45)
apps/web/actions/videos/settings.ts (1)
  • updateVideoSettings (9-45)
⏰ 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). (3)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/web/app/(org)/dashboard/settings/organization/components/CapSettingsCard.tsx (1)

151-197: LGTM!

The JSX structure is clean and the component properly handles organization-level settings with debounced auto-save, per-key success notifications, and proper error recovery. The grid layout and Switch components are correctly configured with appropriate Pro gating and transcript dependency logic.

@ameer2468 ameer2468 merged commit 6da2563 into main Oct 7, 2025
16 checks passed
@ameer2468 ameer2468 deleted the org-settings branch October 7, 2025 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants