Skip to content

refactor: Remove deprecated react api usage#2034

Open
mfortman11 wants to merge 4 commits into
mainfrom
deprecated-react-apis
Open

refactor: Remove deprecated react api usage#2034
mfortman11 wants to merge 4 commits into
mainfrom
deprecated-react-apis

Conversation

@mfortman11

@mfortman11 mfortman11 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

no-react19-deprecated-apis

  • 6 context files — useContextuse() (auth-context, brand-context, chat-context, knowledge-filter-context, task-context, banner)
  • 13 UI component files — removed forwardRef wrappers, ref is now a regular prop (accordion, avatar, button, card, command, dialog, dropdown-menu, input, popover, scroll-area, select, separator, slider, switch, tabs, tooltip)
  • 1 app component — chat-input.tsx

Summary by CodeRabbit

  • Bug Fixes
    • Improved refresh speed after bulk delete and role changes by updating data in parallel.
    • Made connector availability checks more resilient and responsive by checking supported connections concurrently.
    • Updated shared UI components and context hooks for cleaner ref handling and more consistent behavior.

@github-actions github-actions Bot added community frontend 🟨 Issues related to the UI/UX and removed community labels Jul 6, 2026
@mfortman11 mfortman11 changed the title Deprecated react apis refactor: Remove deprecated react api usage Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR modernizes React usage by converting forwardRef-based UI components and ChatInput into plain function components that accept ref as a prop, and replaces useContext calls with React's use hook across context providers. Separately, several async handlers (bulk delete, role toggle, connector checks) are refactored to run operations concurrently via Promise.all.

Changes

React 19 API Modernization

Layer / File(s) Summary
ChatInput refactor
frontend/app/chat/_components/chat-input.tsx
Converted from forwardRef to a function component accepting ref via props, keeping useImperativeHandle for exposing ChatInputHandle.
Layout primitives
frontend/components/ui/accordion.tsx, avatar.tsx, card.tsx, separator.tsx, scroll-area.tsx
AccordionItem/Trigger/Content, Avatar*, Card*, Separator, and ScrollArea converted from forwardRef with displayName to plain functions destructuring ref.
Form controls
frontend/components/ui/button.tsx, input.tsx, switch.tsx, slider.tsx
Button, Input (with new ref field on InputProps), Switch, and Slider converted similarly, removing displayName assignments.
Overlay components
frontend/components/ui/dialog.tsx, popover.tsx, tooltip.tsx
DialogOverlay/Content/Title/Description, PopoverContent, and TooltipContent converted from forwardRef to function components with ref in props typing.
Menu/select components
frontend/components/ui/command.tsx, dropdown-menu.tsx, select.tsx, tabs.tsx
Command*, DropdownMenu*, Select*, and Tabs* sub-components converted from forwardRef, removing displayName assignments.
Context use() migration
frontend/components/ui/banner.tsx, frontend/contexts/*.tsx
BannerClose, useAuth, useBrand/useIsCloudBrand, useChat, useKnowledgeFilter, and useTask switched from useContext to use.

Concurrent Async Refactors

Layer / File(s) Summary
Parallelized post-action refresh
frontend/app/knowledge/page.tsx, frontend/components/dev-role-toggle.tsx, frontend/components/knowledge-dropdown.tsx
Bulk delete refresh/invalidate/refetch, role toggle success side effects, and connector status/token checks changed from sequential awaits/loops to concurrent Promise.all calls.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Handler
  participant QueryClient
  participant API

  Handler->>QueryClient: Promise.all([refresh, invalidate, refetch])
  par concurrent operations
    QueryClient->>API: refreshTasks / refreshPermissions
  and
    QueryClient->>QueryClient: invalidateQueries(search/connectors)
  and
    QueryClient->>API: refetchQueries / status+token checks
  end
  QueryClient-->>Handler: all resolved
Loading

Possibly related PRs

  • langflow-ai/openrag#1685: Both PRs modify handleBulkDelete in frontend/app/knowledge/page.tsx to run post-delete refresh/invalidate/refetch operations concurrently.
  • langflow-ai/openrag#1739: Both PRs modify frontend/contexts/task-context.tsx's useTask() hook and TaskProvider context.

Suggested reviewers: lucaseduoli, ricofurtado

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing deprecated React API usage across contexts and components.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deprecated-react-apis

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.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

React Doctor found 9 new issues in 5 files · 9 warnings · score 70 / 100 (Needs work) · 67 fixed · vs main

9 warnings

app/chat/_components/chat-input.tsx

  • ⚠️ L52 Large component is hard to read and change no-giant-component
  • ⚠️ L69 Many related useState calls prefer-useReducer

components/ui/accordion.tsx

  • ⚠️ L25 Multiple components in one file no-multi-comp
  • ⚠️ L48 Multiple components in one file no-multi-comp

components/ui/avatar.tsx

  • ⚠️ L25 Multiple components in one file no-multi-comp
  • ⚠️ L39 Multiple components in one file no-multi-comp

components/ui/input.tsx

  • ⚠️ L21 State only used in handlers rerender-state-only-in-handlers

components/ui/tabs.tsx

  • ⚠️ L26 Multiple components in one file no-multi-comp
  • ⚠️ L43 Multiple components in one file no-multi-comp

Reviewed by React Doctor for commit 3396b20. See inline comments for fixes.

// Fetch all filters once when dropdown opens
const { data: allFilters = [] } = useGetAllFiltersQuery({
enabled: isFilterDropdownOpen,
export function ChatInput({

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.

React Doctor · react-doctor/no-giant-component (warning)

Component "ChatInput" is 591 lines long, which is hard to read & change. Split it into a few smaller components.

Fix → Pull each section into its own component so the parent is easier to read, test, and change.

Docs

setIsFilterHighlighted,
onFileSelected,
ref,
}: ChatInputProps & { ref?: React.Ref<ChatInputHandle> }) {

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.

React Doctor · react-doctor/prefer-useReducer (warning)

5 useState calls in "ChatInput" can each trigger a separate render.

Fix → Group related state in useReducer so one logical update does not fan out into separate renders.

Docs

<div className={cn("p-4 pt-2", className)}>{children}</div>
</AccordionPrimitive.Content>
));
function AccordionTrigger({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

}

AccordionContent.displayName = AccordionPrimitive.Content.displayName;
function AccordionContent({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

/>
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
function AvatarImage({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

/>
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
function AvatarFallback({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

ref,
...props
}: InputProps) {
const [hasValue, setHasValue] = React.useState(

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.

React Doctor · react-doctor/rerender-state-only-in-handlers (warning)

Each update to "hasValue" redraws your component for nothing because this useState is set but never shown on screen.

Fix → Use useRef instead of useState when the value is only set and never shown on screen. ref.current = ... updates it without redrawing the component.

Docs

/>
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
function TabsTrigger({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

/>
));
TabsContent.displayName = TabsPrimitive.Content.displayName;
function TabsContent({

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.

React Doctor · react-doctor/no-multi-comp (warning)

This file declares several components, so each component is harder to find, test, and change.

Fix → Move secondary components into their own files so each component stays easier to find, test, and change.

Docs

@github-actions github-actions Bot added refactor and removed refactor labels Jul 6, 2026

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
frontend/app/knowledge/page.tsx (1)

794-800: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Redundant invalidate + refetch for the same query keys.

invalidateQueries defaults to refetchType: "active", so it already refetches active search/listFiles queries and its returned promise resolves only after those refetches settle. Pairing each invalidateQueries with a refetchQueries on the same key is redundant. You can drop the explicit refetchQueries calls, or use refetchType: "none" on the invalidations if the intent is to invalidate-then-refetch explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/app/knowledge/page.tsx` around lines 794 - 800, The `Promise.all`
block in `knowledge/page.tsx` is doing redundant cache work for the same
`search` and `listFiles` keys: `queryClient.invalidateQueries` already triggers
active refetches and waits for them, so the matching `refetchQueries` calls
should be removed. Update the logic around `refreshTasks`, `invalidateQueries`,
and `refetchQueries` so each query key is handled only once, or switch the
invalidations to `refetchType: "none"` if you want to keep an explicit
invalidate-then-refetch flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/components/knowledge-dropdown.tsx`:
- Around line 246-257: The handling of `connectorsResult.connectors` in
`knowledge-dropdown.tsx` is missing the same null-safe guard used elsewhere,
which can throw when the `/api/connectors` payload omits `connectors`. Update
the `availableTypes` filter and the `connectorInfo` population loop to use
optional chaining on `connectorsResult.connectors` and its indexed entries,
matching the existing access pattern around the connector type checks. This
should be fixed in the logic that builds `availableTypes` and fills
`connectorInfo` so the dropdown degrades safely when connector data is absent.

---

Nitpick comments:
In `@frontend/app/knowledge/page.tsx`:
- Around line 794-800: The `Promise.all` block in `knowledge/page.tsx` is doing
redundant cache work for the same `search` and `listFiles` keys:
`queryClient.invalidateQueries` already triggers active refetches and waits for
them, so the matching `refetchQueries` calls should be removed. Update the logic
around `refreshTasks`, `invalidateQueries`, and `refetchQueries` so each query
key is handled only once, or switch the invalidations to `refetchType: "none"`
if you want to keep an explicit invalidate-then-refetch flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c316934a-1011-4f2e-acca-7bffdfd696ca

📥 Commits

Reviewing files that changed from the base of the PR and between 857521d and 3396b20.

📒 Files selected for processing (26)
  • frontend/app/chat/_components/chat-input.tsx
  • frontend/app/knowledge/page.tsx
  • frontend/components/dev-role-toggle.tsx
  • frontend/components/knowledge-dropdown.tsx
  • frontend/components/ui/accordion.tsx
  • frontend/components/ui/avatar.tsx
  • frontend/components/ui/banner.tsx
  • frontend/components/ui/button.tsx
  • frontend/components/ui/card.tsx
  • frontend/components/ui/command.tsx
  • frontend/components/ui/dialog.tsx
  • frontend/components/ui/dropdown-menu.tsx
  • frontend/components/ui/input.tsx
  • frontend/components/ui/popover.tsx
  • frontend/components/ui/scroll-area.tsx
  • frontend/components/ui/select.tsx
  • frontend/components/ui/separator.tsx
  • frontend/components/ui/slider.tsx
  • frontend/components/ui/switch.tsx
  • frontend/components/ui/tabs.tsx
  • frontend/components/ui/tooltip.tsx
  • frontend/contexts/auth-context.tsx
  • frontend/contexts/brand-context.tsx
  • frontend/contexts/chat-context.tsx
  • frontend/contexts/knowledge-filter-context.tsx
  • frontend/contexts/task-context.tsx

Comment on lines +246 to +257
const availableTypes = cloudConnectorTypes.filter(
(type) => connectorsResult.connectors[type],
);

for (const type of availableTypes) {
connectorInfo[type] = {
name: connectorsResult.connectors[type].name,
available: connectorsResult.connectors[type].available,
connected: false,
hasToken: false,
};
}

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Inconsistent null-safety on connectorsResult.connectors.

At Line 227 you defensively read connectorsResult.connectors?.[d.connectorType]?.available, but here connectorsResult.connectors[type] (Lines 247, 252, 253) omits the guard. If connectors is absent from the /api/connectors payload, the .filter at Line 246 throws, and the outer catch swallows it — silently disabling all cloud connector entries. Apply the same optional chaining for consistency.

🛡️ Proposed guard
-          const availableTypes = cloudConnectorTypes.filter(
-            (type) => connectorsResult.connectors[type],
-          );
+          const availableTypes = cloudConnectorTypes.filter(
+            (type) => connectorsResult.connectors?.[type],
+          );
 
           for (const type of availableTypes) {
             connectorInfo[type] = {
-              name: connectorsResult.connectors[type].name,
-              available: connectorsResult.connectors[type].available,
+              name: connectorsResult.connectors[type]?.name,
+              available: connectorsResult.connectors[type]?.available,
               connected: false,
               hasToken: false,
             };
           }
📝 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
const availableTypes = cloudConnectorTypes.filter(
(type) => connectorsResult.connectors[type],
);
for (const type of availableTypes) {
connectorInfo[type] = {
name: connectorsResult.connectors[type].name,
available: connectorsResult.connectors[type].available,
connected: false,
hasToken: false,
};
}
const availableTypes = cloudConnectorTypes.filter(
(type) => connectorsResult.connectors?.[type],
);
for (const type of availableTypes) {
connectorInfo[type] = {
name: connectorsResult.connectors[type]?.name,
available: connectorsResult.connectors[type]?.available,
connected: false,
hasToken: false,
};
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/components/knowledge-dropdown.tsx` around lines 246 - 257, The
handling of `connectorsResult.connectors` in `knowledge-dropdown.tsx` is missing
the same null-safe guard used elsewhere, which can throw when the
`/api/connectors` payload omits `connectors`. Update the `availableTypes` filter
and the `connectorInfo` population loop to use optional chaining on
`connectorsResult.connectors` and its indexed entries, matching the existing
access pattern around the connector type checks. This should be fixed in the
logic that builds `availableTypes` and fills `connectorInfo` so the dropdown
degrades safely when connector data is absent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

frontend 🟨 Issues related to the UI/UX refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant