Skip to content

Conversation

oscartbeaumont
Copy link
Member

@oscartbeaumont oscartbeaumont commented Sep 23, 2025

This allows accessing React Query Devtools, toggling feature flags and more.

In the future will do a PR to add an easy utility for toggling Cap pro on a user as that will make testing different flows wayyyy easier.

Summary by CodeRabbit

  • New Features

    • Introduced app-wide feature flags to safely roll out UI changes.
    • Added a toggleable upload progress indicator (disabled by default).
  • Chores

    • Updated TanStack libraries to the latest versions for improved stability and tooling.

Copy link
Contributor

vercel bot commented Sep 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
cap-web Ready Ready Preview Comment Sep 23, 2025 7:18am

Copy link
Contributor

coderabbitai bot commented Sep 23, 2025

Walkthrough

Adds a feature flag store for Layout persisted in localStorage, introduces hooks to read flags, updates ProgressCircle to use a flag for upload progress, integrates TanStack React Query Devtools and a custom CapDevtools panel in development, and updates TanStack-related dependencies in apps/web.

Changes

Cohort / File(s) Summary
Feature flags (store + hooks)
apps/web/app/Layout/features.ts
Adds FeatureFlags type and default flags; initializes a TanStack Store from localStorage with safe JSON parsing; persists updates back to localStorage; exports featureFlags store and hooks useFeatureFlag and useFeatureFlags.
Devtools integration (development)
apps/web/app/Layout/providers.tsx
Adds Devtools component wired with useQueryClient, integrates TanStack Devtools and React Query Devtools Panel; adds CapDevtools with feature-toggle UI; conditionally renders Devtools in provider during development.
App layout imports for devtools
apps/web/app/layout.tsx
Adds imports for @tanstack/react-devtools and @tanstack/react-query-devtools; no behavioral changes.
ProgressCircle feature-gating
apps/web/app/s/[videoId]/_components/ProgressCircle.tsx
Replaces legacy localStorage beta flag with useFeatureFlag("enableUploadProgress") to enable upload progress logic; removes old flag handling.
Dependency updates (TanStack)
apps/web/package.json
Updates @tanstack/react-query to ^5.90.1; adds @tanstack/react-query-devtools and @tanstack/react-devtools; updates @tanstack/react-store to ^0.7.7; removes deprecated @tanstack/store and old @tanstack/react-store version.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer (Dev)
  participant UI as CapDevtools (UI)
  participant FF as featureFlags Store
  participant LS as localStorage
  participant PC as ProgressCircle

  rect rgb(245,248,255)
    note over UI,FF: Feature flag toggle flow (new)
    Dev->>UI: Toggle "enableUploadProgress"
    UI-->>FF: update(flag=true/false)
    FF-->>LS: Persist JSON under "featureFlags"
  end

  rect rgb(245,255,245)
    note over PC,FF: Flag consumption
    PC->>FF: useFeatureFlag("enableUploadProgress")
    FF-->>PC: current boolean value
    PC->>PC: Enable/disable upload progress query
  end
Loading
sequenceDiagram
  autonumber
  participant App as React App
  participant Prov as ReactQueryProvider
  participant DevT as Devtools (TanStack/Cap)
  participant ENV as NODE_ENV

  App->>Prov: Mount provider
  Prov->>ENV: Check if development
  alt development
    Prov-->>DevT: Render Devtools UI (React Query + CapDevtools)
  else production
    Prov-->>Prov: Skip Devtools
  end
  Prov-->>App: Render children
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I flip a flag with a twitch of my ear,
Devtools bloom when dev is near.
Progress circles spin, then rest—
A carrot-tick toggles what’s best.
In local burrow, settings stay,
Store squeaks, JSON’s okay—
Hop, save, ship—another fine day! 🥕🐇

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 PR title "Tanstack Devtools in web" succinctly captures the primary change—adding TanStack/React Query devtools to the web app—and is concise, relevant, and easy for a teammate scanning history to understand; it appropriately focuses on the main change even though the PR also introduces feature-flagging and dependency updates.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tanstack-devtools

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

🧹 Nitpick comments (6)
apps/web/package.json (1)

61-64: Avoid shipping DevTools in production bundles.

These deps are dev-only. Either move them to devDependencies or dynamically import them in code so they're excluded from prod bundles. The code currently imports them at module scope in a client provider, which risks bundling in prod.

Do you prefer moving to devDependencies, or keeping in dependencies but loading via next/dynamic with ssr: false? The latter keeps the runtime path clean in dev while ensuring no prod bundle impact.

apps/web/app/Layout/providers.tsx (2)

66-70: Gate is good; but devtools still get bundled. Dynamically import to keep prod bundles lean.

Even behind NODE_ENV === "development", static imports can end up in prod bundles. Use next/dynamic with ssr: false and remove top-level DevTools imports.

Apply these diffs:

-import { TanStackDevtools } from "@tanstack/react-devtools";
-import {
-  QueryClient,
-  QueryClientProvider,
-  useQueryClient,
-} from "@tanstack/react-query";
-import { ReactQueryDevtoolsPanel } from "@tanstack/react-query-devtools";
+import dynamic from "next/dynamic";
+import {
+  QueryClient,
+  QueryClientProvider,
+  useQueryClient,
+} from "@tanstack/react-query";

And update the Devtools component:

 export function Devtools() {
   const client = useQueryClient();
 
   return (
-    <TanStackDevtools
+    {(() => {
+      const TanStackDevtools = dynamic(
+        () => import("@tanstack/react-devtools").then((m) => m.TanStackDevtools),
+        { ssr: false },
+      );
+      const ReactQueryDevtoolsPanel = dynamic(
+        () =>
+          import("@tanstack/react-query-devtools").then(
+            (m) => m.ReactQueryDevtoolsPanel,
+          ),
+        { ssr: false },
+      );
+      return (
+        <TanStackDevtools
           config={{
-            // TODO: This doesn't seem to be working?
             position: "top-left",
           }}
           plugins={[
             {
               name: "Cap",
               render: <CapDevtools />,
             },
             {
               name: "Tanstack Query",
-              render: <ReactQueryDevtoolsPanel client={client} />,
+              render: <ReactQueryDevtoolsPanel client={client} />,
             },
           ]}
-    />
+        />
+      );
+    })()}
   );
 }

85-88: Remove inline TODO per repo guidelines (no inline comments).

Apply this diff:

-        config={{
-          // TODO: This doesn't seem to be working?
-          position: "top-left",
-        }}
+        config={{ position: "top-left" }}
apps/web/app/s/[videoId]/_components/ProgressCircle.tsx (1)

60-64: Clamp computed progress to [0, 100] to avoid overshoot/NaN edge cases.

When uploaded > total, the arc can exceed 100%. Clamp to keep SVG rendering stable.

Apply this diff:

-          : (query.data.uploaded / query.data.total) * 100,
+          : Math.max(
+              0,
+              Math.min(100, (query.data.uploaded / query.data.total) * 100),
+            ),
apps/web/app/Layout/features.ts (2)

23-30: Guard localStorage side-effect for SSR.

Mounting this effect during SSR will throw since localStorage isn’t defined. Wrap in a window check.

Apply this diff:

-new Effect({
-  fn: () =>
-    localStorage.setItem(
-      featureFlagsLocalStorageKey,
-      JSON.stringify(featureFlags.state),
-    ),
-  deps: [featureFlags],
-}).mount();
+if (typeof window !== "undefined") {
+  new Effect({
+    fn: () =>
+      localStorage.setItem(
+        featureFlagsLocalStorageKey,
+        JSON.stringify(featureFlags.state),
+      ),
+    deps: [featureFlags],
+  }).mount();
+}

9-15: Type the localStorage helper to the flags shape.

Avoids implicit any and improves call-site inference.

Apply this diff:

-function safeJsonFromLocalStorage(key: string) {
+function safeJsonFromLocalStorage(
+  key: string,
+): Partial<FeatureFlags> {
   try {
-    return JSON.parse(localStorage.getItem(key) || "{}");
+    return JSON.parse(localStorage.getItem(key) || "{}") as Partial<FeatureFlags>;
   } catch {
-    return {};
+    return {};
   }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9de830a and 7955928.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • apps/web/app/Layout/features.ts (1 hunks)
  • apps/web/app/Layout/providers.tsx (2 hunks)
  • apps/web/app/layout.tsx (1 hunks)
  • apps/web/app/s/[videoId]/_components/ProgressCircle.tsx (2 hunks)
  • apps/web/package.json (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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.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/Layout/providers.tsx
  • apps/web/app/Layout/features.ts
  • apps/web/app/layout.tsx
  • apps/web/app/s/[videoId]/_components/ProgressCircle.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Use TanStack Query v5 for all client-side server state and data fetching in the web app

Applied to files:

  • apps/web/app/Layout/providers.tsx
  • apps/web/app/layout.tsx
  • apps/web/package.json
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : In the desktop app, use tanstack/solid-query for server state management

Applied to files:

  • apps/web/app/layout.tsx
📚 Learning: 2025-09-22T14:17:47.380Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-22T14:17:47.380Z
Learning: Applies to apps/web/**/*.{ts,tsx} : Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components

Applied to files:

  • apps/web/app/s/[videoId]/_components/ProgressCircle.tsx
🧬 Code graph analysis (2)
apps/web/app/Layout/providers.tsx (1)
apps/web/app/Layout/features.ts (2)
  • useFeatureFlags (36-38)
  • featureFlags (18-21)
apps/web/app/s/[videoId]/_components/ProgressCircle.tsx (1)
apps/web/app/Layout/features.ts (1)
  • useFeatureFlag (32-34)
⏰ 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/s/[videoId]/_components/ProgressCircle.tsx (1)

27-29: LGTM: Feature flag gating is clean and localized.

This switch simplifies rollout and aligns with the new flags store.

apps/web/app/Layout/providers.tsx (1)

96-97: No change needed — prop is client.
ReactQueryDevtoolsPanel v5 expects the prop client (not queryClient); keep the current code as-is.

@Brendonovich Brendonovich merged commit 2aca476 into main Sep 23, 2025
15 checks passed
@oscartbeaumont oscartbeaumont deleted the tanstack-devtools branch September 24, 2025 00:45
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.

2 participants