Skip to content

fix: resolve react-doctor diagnostics across desktop, marketing, and web#1579

Closed
AviPeltz wants to merge 1 commit into
mainfrom
fix/react-doctor-diagnostics
Closed

fix: resolve react-doctor diagnostics across desktop, marketing, and web#1579
AviPeltz wants to merge 1 commit into
mainfrom
fix/react-doctor-diagnostics

Conversation

@AviPeltz
Copy link
Copy Markdown
Collaborator

@AviPeltz AviPeltz commented Feb 19, 2026

Summary

  • Fix all react-doctor errors and reduce warnings across desktop (89→93), marketing (97→99), and web (97→98)
  • Eliminate state-reset-in-useEffect anti-patterns, fix array index keys, remove unnecessary useMemo, parallelize sequential awaits, remove permanent will-change, add missing page metadata, extract inline render functions, and improve accessibility on interactive elements

Changes

Errors fixed (5):

  • FontSettingSection.tsx -- removed redundant useEffect that reset draft state (already cleared in onBlur handlers)
  • NewWorkspaceModal.tsx -- replaced useEffect state reset with a selectProject() helper that co-locates the baseBranch reset with the project setter
  • plans/page.tsx -- extracted inline renderComparisonValue() to a ComparisonValueCell component

Warnings fixed (17):

  • Removed unnecessary useMemo in WorkspaceSidebar.tsx (trivially cheap reduce over small array)
  • Fixed array index keys in MessagePartsRenderer.tsx, ApiKeysSettings.tsx, AppMockup.tsx
  • Parallelized sequential awaits with Promise.all() in CollectionsProvider.tsx
  • Removed permanent will-change from ProductDemo.tsx and TrustedBySection.tsx
  • Added role and guarded keyboard handler to BasePaneWindow.tsx and ProjectPage
  • Added metadata exports to desktop/success/page.tsx and oauth/consent/page.tsx

Test plan

  • Desktop app launches and workspaces can be created via NewWorkspaceModal
  • Font settings in appearance work correctly (edit + blur behavior)
  • Plans page renders comparison table correctly
  • Sidebar renders workspace shortcuts
  • Marketing hero section animations still work
  • Web OAuth consent and desktop auth pages render with correct metadata
  • Pane focus in desktop editor works; typing space in child inputs doesn't trigger focus handler

Generated with Ami

Summary by CodeRabbit

Release Notes

  • Accessibility

    • Added keyboard navigation support (Enter/Space) for focus controls in modals.
    • Improved form accessibility semantics for better screen reader compatibility.
  • Performance

    • Optimized organization switching with parallel data loading operations.
  • SEO

    • Added page metadata to authentication pages for improved search engine visibility.

Fix errors and warnings flagged by react-doctor to improve codebase health scores:
- desktop: 89 → 93 (eliminated 2 errors, reduced warnings 44 → 37)
- marketing: 97 → 99 (reduced warnings 8 → 4)
- web: 97 → 98 (reduced warnings 3 → 1)

Generated with [Ami](https://ami.dev)
Co-Authored-By: Ami <noreply@ami.dev>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR consolidates multiple quality improvements and refactoring across desktop and marketing applications, including state management enhancements, accessibility features, React key handling corrections, concurrent async operations, page metadata additions, and style optimization adjustments.

Changes

Cohort / File(s) Summary
State Management Refactoring
apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx, apps/desktop/src/renderer/routes/.../settings/appearance/components/FontSettingSection/FontSettingSection.tsx, apps/desktop/src/renderer/routes/.../providers/CollectionsProvider/CollectionsProvider.tsx
Introduced selectProject helper for consistent project selection with baseBranch reset; removed automatic baseBranch reset effect. Eliminated useEffect for fontSizeDraft auto-clear. Changed async collection preload and session refetch from sequential to concurrent Promise.all execution.
Accessibility Enhancements
apps/desktop/src/renderer/routes/.../project/$projectId/page.tsx, apps/desktop/src/renderer/screens/main/components/WorkspaceView/.../BasePaneWindow/BasePaneWindow.tsx
Added form role semantics and improved keyboard interaction support (Enter/Space handling) for focus management. Removed biome-ignore lint comments.
React Key Handling
apps/desktop/src/renderer/routes/.../settings/api-keys/components/ApiKeysSettings/ApiKeysSettings.tsx, apps/desktop/src/renderer/screens/main/components/.../MessagePartsRenderer/MessagePartsRenderer.tsx, apps/marketing/src/app/components/HeroSection/components/AppMockup/AppMockup.tsx
Updated list item keys from numeric indices to stable string identifiers. Changed skeleton placeholders and file path keys for improved React reconciliation.
Component Extraction
apps/desktop/src/renderer/routes/.../billing/plans/page.tsx
Extracted inline renderComparisonValue function into a dedicated local ComparisonValueCell component for better modularity and reusability.
Optimization Removal
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx
Removed useMemo optimization from projectShortcutIndices calculation, converting to direct per-render computation without memoization overhead.
Marketing Style Adjustments
apps/marketing/src/app/components/HeroSection/components/ProductDemo/ProductDemo.tsx, apps/marketing/src/app/components/TrustedBySection/TrustedBySection.tsx
Removed willChange: "transform" CSS optimization hints from motion containers and client logo rendering. Adjusted map callback to remove unused index parameter in AppMockup.
Page Metadata
apps/web/src/app/auth/desktop/success/page.tsx, apps/web/src/app/oauth/consent/page.tsx
Added Next.js Metadata exports for page title, description, and robots directives.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • #391: Modifies NewWorkspaceModal component's project selection and baseBranch reset logic.
  • #910: Touches AppMockup.tsx file with overlapping changes to FILE_CHANGES rendering and key handling.
  • #459: Modifies marketing HeroSection and ProductDemo components with related animation and style updates.

Poem

🐰 Keys refined and states aligned,
Accessibility improved, keyboard-designed,
Concurrent flows now dance together,
Style hints trimmed for lighter tether,
Metadata blooms, the pages now shine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective: fixing react-doctor diagnostics across three applications (desktop, marketing, web).
Description check ✅ Passed The PR description is comprehensive and well-structured, including a clear summary, detailed change breakdown, specific errors and warnings fixed with file names, and a test plan.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/react-doctor-diagnostics

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.

@github-actions
Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

🔗 Preview Links

Service Status Link
Neon Database (Neon) View Branch
Fly.io Electric (Fly.io) View App
Vercel API (Vercel) Open Preview
Vercel Web (Vercel) Open Preview
Vercel Marketing (Vercel) Open Preview
Vercel Admin (Vercel) Open Preview
Vercel Docs (Vercel) Open Preview

Preview updates automatically with new commits

Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx (1)

22-31: LGTM — useMemo removal is appropriate here.

The reduce logic is correct: each group receives the cumulative workspace count of all preceding groups as its shortcutBaseIndex, and .indices is the right final projection. For a sidebar with a small, bounded number of project groups, running this inline every render is negligible and the useMemo overhead (closure + dep-array allocation on every render) was comparable to the computation itself.

One cosmetic note: the [...acc.indices, acc.cumulative] spread inside reduce produces O(n²) intermediate allocations as the array grows. This is entirely harmless at sidebar scale, but if you ever wanted to micro-optimize it's easy to swap for a mutable accumulator:

♻️ Optional O(n) alternative
-	const projectShortcutIndices = groups.reduce<{
-		indices: number[];
-		cumulative: number;
-	}>(
-		(acc, group) => ({
-			indices: [...acc.indices, acc.cumulative],
-			cumulative: acc.cumulative + group.workspaces.length,
-		}),
-		{ indices: [], cumulative: 0 },
-	).indices;
+	let cumulative = 0;
+	const projectShortcutIndices = groups.map((group) => {
+		const index = cumulative;
+		cumulative += group.workspaces.length;
+		return index;
+	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx`
around lines 22 - 31, The current reduce in projectShortcutIndices uses
[...acc.indices, acc.cumulative] which creates O(n^2) intermediate arrays; to
micro-optimize, switch to a mutable accumulator: keep acc.indices as a single
array and push acc.cumulative into it instead of spreading, update
acc.cumulative += group.workspaces.length, and return the same acc object each
iteration; keep the final .indices projection the same so existing callers of
projectShortcutIndices are unaffected.
apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx (1)

78-81: Wrap selectProject in useCallback to satisfy react-hooks/exhaustive-deps.

selectProject is consumed inside the useEffect at lines 134–138 but is absent from its dependency array. React's exhaustive-deps rule will flag this. Because both _setSelectedProjectId and setBaseBranch are stable useState setters, a useCallback with an empty dependency array is correct and safe here, and selectProject can then be cleanly listed in the effect's deps.

♻️ Proposed fix
-	const selectProject = (projectId: string | null) => {
-		_setSelectedProjectId(projectId);
-		setBaseBranch(null);
-	};
+	const selectProject = useCallback((projectId: string | null) => {
+		_setSelectedProjectId(projectId);
+		setBaseBranch(null);
+	}, []);
 	useEffect(() => {
 		if (isOpen && !selectedProjectId && preSelectedProjectId) {
 			selectProject(preSelectedProjectId);
 		}
-	}, [isOpen, selectedProjectId, preSelectedProjectId]);
+	}, [isOpen, selectedProjectId, preSelectedProjectId, selectProject]);

(useCallback is already imported via line 31.)

Also applies to: 134-138

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx`
around lines 78 - 81, The selectProject function should be wrapped in React's
useCallback to make it stable for the useEffect that consumes it; change the
definition of selectProject to useCallback(() => {
_setSelectedProjectId(projectId); setBaseBranch(null); }, []) since
_setSelectedProjectId and setBaseBranch are stable state setters, then add
selectProject to the effect's dependency array so react-hooks/exhaustive-deps is
satisfied.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/project/`$projectId/page.tsx:
- Line 158: The container currently uses role="form" on a div (role="form") with
onKeyDown={handleKeyDown} so screen readers won't expose it because it lacks an
accessible name; either add an accessible name by assigning an id to the page
heading (the <h1>) and reference it via aria-labelledby on the role="form"
element, or replace the div with a native <form> element and move the keyboard
handler to an onSubmit handler (update handleKeyDown usage accordingly) so the
landmark is properly exposed and submission is handled semantically.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/components/BasePaneWindow/BasePaneWindow.tsx`:
- Around line 111-114: The onKeyDown handler on the pane container is never
invoked from keyboard because the div cannot be focused; update the pane
container element (the div that registers onKeyDown) to include an explicit
tabIndex (e.g., tabIndex={0} to make it reachable by Tab or tabIndex={-1} if you
only want programmatic focus), so that e.target === e.currentTarget can be true
and handleFocus() will run; ensure the change is applied where onKeyDown and
handleFocus are defined (BasePaneWindow component) and consider accessibility
impact on internal focusable content when choosing 0 vs -1.

---

Nitpick comments:
In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/NewWorkspaceModal.tsx`:
- Around line 78-81: The selectProject function should be wrapped in React's
useCallback to make it stable for the useEffect that consumes it; change the
definition of selectProject to useCallback(() => {
_setSelectedProjectId(projectId); setBaseBranch(null); }, []) since
_setSelectedProjectId and setBaseBranch are stable state setters, then add
selectProject to the effect's dependency array so react-hooks/exhaustive-deps is
satisfied.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceSidebar.tsx`:
- Around line 22-31: The current reduce in projectShortcutIndices uses
[...acc.indices, acc.cumulative] which creates O(n^2) intermediate arrays; to
micro-optimize, switch to a mutable accumulator: keep acc.indices as a single
array and push acc.cumulative into it instead of spreading, update
acc.cumulative += group.workspaces.length, and return the same acc object each
iteration; keep the final .indices projection the same so existing callers of
projectShortcutIndices are unaffected.

<div className="flex-1 flex items-center justify-center">
{/* biome-ignore lint/a11y/noStaticElementInteractions: onKeyDown for Enter-to-submit */}
<div className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
<div role="form" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

role="form" missing accessible name — landmark won't be announced by screen readers

Per the WAI-ARIA spec, a form landmark is only exposed (and navigable) by assistive technologies when it carries an accessible name via aria-label or aria-labelledby. Without one, the role is silently dropped by most screen readers.

The <h1> on line 159 is the natural label — adding an id to it and referencing it with aria-labelledby is the minimal fix:

♿ Proposed fix
-<div role="form" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
-    <h1 className="text-3xl font-semibold text-foreground tracking-tight mb-2">
-        Create your first workspace
-    </h1>
+<div role="form" aria-labelledby="create-workspace-heading" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
+    <h1 id="create-workspace-heading" className="text-3xl font-semibold text-foreground tracking-tight mb-2">
+        Create your first workspace
+    </h1>

Alternatively, a native <form> element provides the same semantics without requiring an explicit role (its landmark is implicit when labelled) and allows using onSubmit instead of an onKeyDown intercept, which is cleaner:

✨ Optional: prefer native <form>
-<div role="form" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
+<form
+  aria-labelledby="create-workspace-heading"
+  className="w-full max-w-md mx-6"
+  onSubmit={(e) => { e.preventDefault(); handleCreateWorkspace(); }}
+>
     <h1 ...>Create your first workspace</h1>
     ...
     <Button
       size="lg"
-      onClick={handleCreateWorkspace}
+      type="submit"
       ...
     >
-<div>
+</form>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div role="form" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
<div role="form" aria-labelledby="create-workspace-heading" className="w-full max-w-md mx-6" onKeyDown={handleKeyDown}>
<h1 id="create-workspace-heading" className="text-3xl font-semibold text-foreground tracking-tight mb-2">
Create your first workspace
</h1>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/project/`$projectId/page.tsx
at line 158, The container currently uses role="form" on a div (role="form")
with onKeyDown={handleKeyDown} so screen readers won't expose it because it
lacks an accessible name; either add an accessible name by assigning an id to
the page heading (the <h1>) and reference it via aria-labelledby on the
role="form" element, or replace the div with a native <form> element and move
the keyboard handler to an onSubmit handler (update handleKeyDown usage
accordingly) so the landmark is properly exposed and submission is handled
semantically.

Comment on lines +111 to +114
onKeyDown={(e) => {
if (e.target !== e.currentTarget) return;
if (e.key === "Enter" || e.key === " ") handleFocus();
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

onKeyDown Enter/Space path is unreachable — missing tabIndex

The guard e.target !== e.currentTarget means "only fire when the div itself is the keyboard event target." Because this div has no tabIndex, it cannot receive keyboard focus through standard navigation; e.target === e.currentTarget is never true in practice, so handleFocus() is never called from the keyboard. The handler satisfies the linter syntactically but not functionally.

To make the keyboard shortcut reachable, add tabIndex={0} to the div (or tabIndex={-1} for programmatic-only focus):

🛠️ Proposed fix
 <div
   role="group"
+  tabIndex={0}
   ref={containerRef}
   className={contentClassName}
   style={isDragging ? { pointerEvents: "none" } : undefined}
   onClick={handleFocus}
   onKeyDown={(e) => {
     if (e.target !== e.currentTarget) return;
     if (e.key === "Enter" || e.key === " ") handleFocus();
   }}
 >

Note: adding tabIndex={0} inserts the pane container into the tab order, which may interfere with Tab navigation inside pane content (terminals, editors). If that's undesirable, tabIndex={-1} allows programmatic focus without affecting the tab order, though keyboard users won't be able to tab to the pane itself.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onKeyDown={(e) => {
if (e.target !== e.currentTarget) return;
if (e.key === "Enter" || e.key === " ") handleFocus();
}}
<div
role="group"
tabIndex={0}
ref={containerRef}
className={contentClassName}
style={isDragging ? { pointerEvents: "none" } : undefined}
onClick={handleFocus}
onKeyDown={(e) => {
if (e.target !== e.currentTarget) return;
if (e.key === "Enter" || e.key === " ") handleFocus();
}}
>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/components/BasePaneWindow/BasePaneWindow.tsx`
around lines 111 - 114, The onKeyDown handler on the pane container is never
invoked from keyboard because the div cannot be focused; update the pane
container element (the div that registers onKeyDown) to include an explicit
tabIndex (e.g., tabIndex={0} to make it reachable by Tab or tabIndex={-1} if you
only want programmatic focus), so that e.target === e.currentTarget can be true
and handleFocus() will run; ensure the change is applied where onKeyDown and
handleFocus are defined (BasePaneWindow component) and consider accessibility
impact on internal focusable content when choosing 0 vs -1.

@AviPeltz AviPeltz requested a review from Kitenite March 6, 2026 21:10
@Kitenite
Copy link
Copy Markdown
Collaborator

Closing: stale react-doctor diagnostics fix from Feb 19. Likely outdated given ongoing dependency changes.

@Kitenite Kitenite closed this Mar 13, 2026
@Kitenite
Copy link
Copy Markdown
Collaborator

Hey — just a heads up, this was closed as part of an automated stale PR cleanup. If you think this was done in error, feel free to reopen it!

@Kitenite
Copy link
Copy Markdown
Collaborator

Hey — this was closed by an automated cleanup of PRs with major merge conflicts that are 3+ weeks old. If you think this was done incorrectly, please feel free to reopen it. Sorry for any inconvenience!

@Kitenite Kitenite deleted the fix/react-doctor-diagnostics branch March 15, 2026 16:08
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