diff --git a/apps/webapp/app/components/AskAI.tsx b/apps/webapp/app/components/AskAI.tsx index 37911b87334..2f31a970426 100644 --- a/apps/webapp/app/components/AskAI.tsx +++ b/apps/webapp/app/components/AskAI.tsx @@ -273,6 +273,7 @@ function ChatMessages({ // Reset feedback state when conversation is reset useEffect(() => { if (conversation.length === 0) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setFeedbackGivenForQAs(new Set()); } }, [conversation.length]); diff --git a/apps/webapp/app/components/DevPresence.tsx b/apps/webapp/app/components/DevPresence.tsx index 907a520723c..cd9b79cf1f3 100644 --- a/apps/webapp/app/components/DevPresence.tsx +++ b/apps/webapp/app/components/DevPresence.tsx @@ -55,6 +55,7 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro useEffect(() => { // If disabled or no events if (!enabled || streamedEvents === null) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsConnected(undefined); return; } @@ -113,6 +114,7 @@ export function useCrossEngineIsConnected({ useEffect(() => { if (project.engine === "V2") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setCrossEngineIsConnected(isConnected); return; } diff --git a/apps/webapp/app/components/Feedback.tsx b/apps/webapp/app/components/Feedback.tsx index f6a9971cce3..52d7bb95005 100644 --- a/apps/webapp/app/components/Feedback.tsx +++ b/apps/webapp/app/components/Feedback.tsx @@ -76,6 +76,7 @@ export function Feedback({ useEffect(() => { const open = searchParams.get("feedbackPanel"); if (open) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setType(open as FeedbackType); setOpen(true); // Clone instead of mutating in place diff --git a/apps/webapp/app/components/LoginPageLayout.tsx b/apps/webapp/app/components/LoginPageLayout.tsx index 1db614eb926..a0c2cbf5237 100644 --- a/apps/webapp/app/components/LoginPageLayout.tsx +++ b/apps/webapp/app/components/LoginPageLayout.tsx @@ -47,6 +47,7 @@ export function LoginPageLayout({ const [randomQuote, setRandomQuote] = useState(null); useEffect(() => { const randomIndex = Math.floor(Math.random() * quotes.length); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setRandomQuote(quotes[randomIndex]); }, []); diff --git a/apps/webapp/app/components/TriggerRotatingLogo.tsx b/apps/webapp/app/components/TriggerRotatingLogo.tsx index 878c203a3ca..055fd7703a3 100644 --- a/apps/webapp/app/components/TriggerRotatingLogo.tsx +++ b/apps/webapp/app/components/TriggerRotatingLogo.tsx @@ -25,6 +25,7 @@ export function TriggerRotatingLogo() { useEffect(() => { // Already registered from a previous render if (customElements.get("spline-viewer")) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsSplineReady(true); return; } diff --git a/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx b/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx index 8433c74f39d..21014f5630d 100644 --- a/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx +++ b/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx @@ -67,6 +67,7 @@ export function FeatureFlagsDialog({ useEffect(() => { if (open && orgId) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setSaveError(null); setOverrides({}); setInitialOverrides({}); @@ -77,6 +78,7 @@ export function FeatureFlagsDialog({ useEffect(() => { if (loadFetcher.data) { const loaded = loadFetcher.data.orgFlags ?? {}; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setOverrides({ ...loaded }); setInitialOverrides({ ...loaded }); } @@ -86,6 +88,7 @@ export function FeatureFlagsDialog({ if (saveFetcher.data?.success) { onOpenChangeRef.current(false); } else if (saveFetcher.data?.error) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setSaveError(saveFetcher.data.error); } }, [saveFetcher.data]); diff --git a/apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx b/apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx index 6b0185e33a1..7375cdb6caf 100644 --- a/apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx +++ b/apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx @@ -34,10 +34,12 @@ export function MaxProjectsSection({ const [value, setValue] = useState(String(maximumProjectCount)); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. if (hasFieldErrors) setIsEditing(true); }, [hasFieldErrors]); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. if (savedJustNow && !hasFieldErrors) setIsEditing(false); }, [savedJustNow, hasFieldErrors]); diff --git a/apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx b/apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx index 5da447ff121..b9f2c5bff41 100644 --- a/apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx +++ b/apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx @@ -65,10 +65,12 @@ export function RateLimitSection({ const [maxTokens, setMaxTokens] = useState(current ? String(current.maxTokens) : ""); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. if (hasFieldErrors) setIsEditing(true); }, [hasFieldErrors]); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. if (savedJustNow && !hasFieldErrors) setIsEditing(false); }, [savedJustNow, hasFieldErrors]); diff --git a/apps/webapp/app/components/billing/BillingAlertsSection.tsx b/apps/webapp/app/components/billing/BillingAlertsSection.tsx index ed95af59238..b3afe574f7d 100644 --- a/apps/webapp/app/components/billing/BillingAlertsSection.tsx +++ b/apps/webapp/app/components/billing/BillingAlertsSection.tsx @@ -119,6 +119,7 @@ export function BillingAlertsSection({ return; } + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setShowResetBanner(true); if (searchParams.get("alertsReset") !== "1") { @@ -189,6 +190,7 @@ export function BillingAlertsSection({ useEffect(() => { nextThresholdIdRef.current = savedThresholds.length; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setThresholdRows(toThresholdRows(savedThresholds)); setEmailValues(savedEmails.length > 0 ? [...savedEmails, ""] : [""]); }, [savedThresholds, savedEmails]); diff --git a/apps/webapp/app/components/billing/BillingLimitConfigSection.tsx b/apps/webapp/app/components/billing/BillingLimitConfigSection.tsx index e6362d4cb1d..d031bb6c674 100644 --- a/apps/webapp/app/components/billing/BillingLimitConfigSection.tsx +++ b/apps/webapp/app/components/billing/BillingLimitConfigSection.tsx @@ -126,6 +126,7 @@ export function BillingLimitConfigSection({ const formRef = useRef(null); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setMode(resetMode); setCustomAmount(savedCustomAmount); setCancelInProgressRuns(savedCancelInProgressRuns); diff --git a/apps/webapp/app/components/code/AIQueryInput.tsx b/apps/webapp/app/components/code/AIQueryInput.tsx index e06d0326837..9ac49fba72e 100644 --- a/apps/webapp/app/components/code/AIQueryInput.tsx +++ b/apps/webapp/app/components/code/AIQueryInput.tsx @@ -61,6 +61,7 @@ export function AIQueryInput({ // If mode is edit but there's no current query, switch to new useEffect(() => { if (mode === "edit" && !canEdit) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setMode("new"); } }, [mode, canEdit]); diff --git a/apps/webapp/app/components/dashboard-agent/AgentChart.tsx b/apps/webapp/app/components/dashboard-agent/AgentChart.tsx index dda01b7f192..70beed5a200 100644 --- a/apps/webapp/app/components/dashboard-agent/AgentChart.tsx +++ b/apps/webapp/app/components/dashboard-agent/AgentChart.tsx @@ -93,6 +93,7 @@ export function AgentChart({ // The block can render before `query` has streamed in; an empty query 400s. if (!block.query) return; if (!organizationId || !projectId || !environmentId) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState({ status: "error", error: "No environment context to run the query." }); return; } diff --git a/apps/webapp/app/components/dashboard-agent/DashboardAgentPanel.tsx b/apps/webapp/app/components/dashboard-agent/DashboardAgentPanel.tsx index 598167f260c..ff7a71e0f93 100644 --- a/apps/webapp/app/components/dashboard-agent/DashboardAgentPanel.tsx +++ b/apps/webapp/app/components/dashboard-agent/DashboardAgentPanel.tsx @@ -168,6 +168,7 @@ export function DashboardAgentPanel({ // Ordering-safe: if the new chat has not reported yet, its own report re-sets the marker. useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setThinkingChatId((previous) => markerAfterActiveChat(previous, active?.chatId)); }, [active?.chatId]); @@ -313,6 +314,7 @@ export function DashboardAgentPanel({ void loadHistory(); const stored = readLastChat(storageKey); if (stored && stored.path === location.pathname) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. void openChat(stored.chatId); } else { setLoading(false); @@ -341,6 +343,7 @@ export function DashboardAgentPanel({ handledOpenChatSeq.current = openChatRequest.seq; // Reloading the visible transcript would drop a turn in flight. if (openChatRequest.chatId === active?.chatId) return; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. void openChat(openChatRequest.chatId); // `active` is read, not tracked: a later change must not re-run the request. // eslint-disable-next-line react-hooks/exhaustive-deps @@ -357,6 +360,7 @@ export function DashboardAgentPanel({ onChatRead?.(chatId, { leaving: false }); visibleChatId.current = nextVisibleChat(chatId, { leaving: false }); justRead.current.add(chatId); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setChats((previous) => markChatListRead(previous, chatId)); // Read again on the way out: a wake can land while the chat is open. return () => { @@ -384,6 +388,7 @@ export function DashboardAgentPanel({ if (target === "hold") return; handledRequestSeq.current = requestedMessage.seq; if (target === "new-chat") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. void createChat(requestedMessage.text); return; } diff --git a/apps/webapp/app/components/integrations/VercelOnboardingModal.tsx b/apps/webapp/app/components/integrations/VercelOnboardingModal.tsx index d606b512579..189f409dc7a 100644 --- a/apps/webapp/app/components/integrations/VercelOnboardingModal.tsx +++ b/apps/webapp/app/components/integrations/VercelOnboardingModal.tsx @@ -183,6 +183,7 @@ export function VercelOnboardingModal({ hasSyncedStagingRef.current = false; hasSyncedPreviewRef.current = false; } else if (isOpen && state === "idle") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState(computeInitialState()); } prevIsOpenRef.current = isOpen; @@ -262,6 +263,7 @@ export function VercelOnboardingModal({ // Strip "stg" from build settings when the staging environment mapping is cleared useEffect(() => { if (!vercelStagingEnvironment) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setPullEnvVarsBeforeBuild((prev) => prev.filter((s) => s !== "stg")); setDiscoverEnvVars((prev) => prev.filter((s) => s !== "stg")); } @@ -329,6 +331,7 @@ export function VercelOnboardingModal({ useEffect(() => { if (!isOpen) { hasTriggeredMarketplaceRedirectRef.current = false; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsRedirecting(false); } }, [isOpen]); @@ -390,6 +393,7 @@ export function VercelOnboardingModal({ state === "loading-projects" && onboardingData?.availableProjects !== undefined ) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("project-selection"); } }, [state, onboardingData?.availableProjects, onboardingData?.authInvalid]); @@ -400,6 +404,7 @@ export function VercelOnboardingModal({ state === "loading-env-vars" && onboardingData?.environmentVariables ) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("env-var-sync"); } }, [state, onboardingData?.environmentVariables, onboardingData?.authInvalid]); @@ -415,6 +420,7 @@ export function VercelOnboardingModal({ trackOnboarding("vercel onboarding project selected", { vercel_project_name: selectedVercelProject?.name, }); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("loading-env-mapping"); if (onDataReload) { onDataReload(); @@ -437,6 +443,7 @@ export function VercelOnboardingModal({ const hasCustomEnvs = (onboardingData.customEnvironments?.length ?? 0) > 0 && hasStagingEnvironment; if (hasCustomEnvs && !fromMarketplaceContext) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("env-mapping"); } else { setState("loading-env-vars"); @@ -661,6 +668,7 @@ export function VercelOnboardingModal({ } return; } + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("completed"); } }, [completeOnboardingFetcher.data, completeOnboardingFetcher.state, state]); @@ -675,6 +683,7 @@ export function VercelOnboardingModal({ return; } } + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("completed"); } }, [state, isGitHubConnectedForOnboarding, fromMarketplaceContext, nextUrl, trackOnboarding]); @@ -704,6 +713,7 @@ export function VercelOnboardingModal({ envMappingFetcher.data.success && envMappingFetcher.state === "idle" ) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setState("loading-env-vars"); } }, [envMappingFetcher.data, envMappingFetcher.state]); @@ -719,12 +729,14 @@ export function VercelOnboardingModal({ selectedEnv = stagingEnv ?? customEnvironments[0]; } + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setVercelStagingEnvironment({ environmentId: selectedEnv.id, displayName: selectedEnv.slug }); } }, [state, customEnvironments, vercelStagingEnvironment]); useEffect(() => { if (state === "project-selection" && availableProjects.length > 0 && !selectedVercelProject) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setSelectedVercelProject(availableProjects[0]); } }, [state, availableProjects, selectedVercelProject]); diff --git a/apps/webapp/app/components/logs/LogDetailView.tsx b/apps/webapp/app/components/logs/LogDetailView.tsx index c0f52b76a46..adf691884f9 100644 --- a/apps/webapp/app/components/logs/LogDetailView.tsx +++ b/apps/webapp/app/components/logs/LogDetailView.tsx @@ -68,6 +68,7 @@ export function LogDetailView({ logId, initialLog, onClose, searchTerm }: LogDet useEffect(() => { if (!logId) return; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setError(null); fetcher.load( `/resources/orgs/${organization.slug}/projects/${project.slug}/env/${ @@ -80,6 +81,7 @@ export function LogDetailView({ logId, initialLog, onClose, searchTerm }: LogDet // Handle fetch errors useEffect(() => { if (fetcher.data && typeof fetcher.data === "object" && "error" in fetcher.data) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setError(fetcher.data.error as string); } else if (fetcher.state === "idle" && fetcher.data === null && !initialLog) { setError("Failed to load log details"); diff --git a/apps/webapp/app/components/logs/LogsTable.tsx b/apps/webapp/app/components/logs/LogsTable.tsx index 32016a6a7f5..73cefe32a0a 100644 --- a/apps/webapp/app/components/logs/LogsTable.tsx +++ b/apps/webapp/app/components/logs/LogsTable.tsx @@ -76,6 +76,7 @@ export function LogsTable({ // Show load more spinner only after 0.2 seconds of loading time useEffect(() => { if (!isLoadingMore) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setShowLoadMoreSpinner(false); return; } diff --git a/apps/webapp/app/components/metrics/SaveToDashboardDialog.tsx b/apps/webapp/app/components/metrics/SaveToDashboardDialog.tsx index 19f50436dc1..90ebec0e9c7 100644 --- a/apps/webapp/app/components/metrics/SaveToDashboardDialog.tsx +++ b/apps/webapp/app/components/metrics/SaveToDashboardDialog.tsx @@ -88,6 +88,7 @@ export function SaveToDashboardDialog({ useEffect(() => { if (customDashboards.length > 0 && !selectedDashboardId) { const available = customDashboards.find((d) => d.widgetCount < widgetLimit); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setSelectedDashboardId(available?.friendlyId ?? customDashboards[0].friendlyId); } }, [customDashboards, selectedDashboardId, widgetLimit]); diff --git a/apps/webapp/app/components/navigation/DashboardDialogs.tsx b/apps/webapp/app/components/navigation/DashboardDialogs.tsx index 85fcf4c4278..f9e4c643b5a 100644 --- a/apps/webapp/app/components/navigation/DashboardDialogs.tsx +++ b/apps/webapp/app/components/navigation/DashboardDialogs.tsx @@ -52,6 +52,7 @@ function useCreateDashboard({ useEffect(() => { if (navigation.formAction === formAction && navigation.state === "loading") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsOpen(false); } }, [navigation.formAction, navigation.state, formAction]); diff --git a/apps/webapp/app/components/navigation/EnvironmentSelector.tsx b/apps/webapp/app/components/navigation/EnvironmentSelector.tsx index 99cfdaa540c..925c583d529 100644 --- a/apps/webapp/app/components/navigation/EnvironmentSelector.tsx +++ b/apps/webapp/app/components/navigation/EnvironmentSelector.tsx @@ -61,6 +61,7 @@ export function EnvironmentSelector({ const revalidator = useRevalidator(); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsMenuOpen(false); }, [navigation.location?.pathname]); @@ -249,6 +250,7 @@ function Branches({ }, []); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setMenuOpen(false); }, [navigation.location?.pathname]); diff --git a/apps/webapp/app/components/navigation/FavoritesSection.tsx b/apps/webapp/app/components/navigation/FavoritesSection.tsx index 835289243f1..48c6ecf1f04 100644 --- a/apps/webapp/app/components/navigation/FavoritesSection.tsx +++ b/apps/webapp/app/components/navigation/FavoritesSection.tsx @@ -49,6 +49,7 @@ export function FavoriteMenuItem({ // Watch search too: navigating to a favorite can change only the search on the same pathname useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setMenuOpen(false); }, [navigation.location?.pathname, navigation.location?.search]); diff --git a/apps/webapp/app/components/navigation/SideMenu.tsx b/apps/webapp/app/components/navigation/SideMenu.tsx index 640d0c6ebe3..d653d44dc1b 100644 --- a/apps/webapp/app/components/navigation/SideMenu.tsx +++ b/apps/webapp/app/components/navigation/SideMenu.tsx @@ -438,6 +438,7 @@ export function SideMenu({ const data = customizationFetcher.data; if (!data) { // Settled with no response body (e.g. a session-expiry redirect): fail rather than spin + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setCustomizeConfirmPending(false); setCustomizeError("Couldn't save your changes. Please try again."); return; @@ -1488,6 +1489,7 @@ function SideMenuMoreItem({ // Watch search too: navigating to a favorite can change only the search on the same pathname useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setOpen(false); }, [navigation.location?.pathname, navigation.location?.search]); @@ -1701,6 +1703,7 @@ function OrgSelector({ const planTitle = currentPlan?.v3Subscription?.plan?.title; useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setOrgMenuOpen(false); }, [navigation.location?.pathname]); @@ -1979,6 +1982,7 @@ function AccountMenu({ isAdmin, isImpersonating }: { isAdmin: boolean; isImperso const navigation = useNavigation(); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsOpen(false); }, [navigation.location?.pathname]); @@ -2033,6 +2037,7 @@ function ProjectSelector({ const { urlForProject } = usePageSwitcher(); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsMenuOpen(false); }, [navigation.location?.pathname]); @@ -2154,6 +2159,7 @@ function SideMenuPopoverSubMenu({ // Close the submenu on navigation (the parent popover closes too). useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsOpen(false); }, [navigation.location?.pathname]); diff --git a/apps/webapp/app/components/navigation/SideMenuHeader.tsx b/apps/webapp/app/components/navigation/SideMenuHeader.tsx index 698ab1a2326..4bd88c2f6ca 100644 --- a/apps/webapp/app/components/navigation/SideMenuHeader.tsx +++ b/apps/webapp/app/components/navigation/SideMenuHeader.tsx @@ -19,6 +19,7 @@ export function SideMenuHeader({ const navigation = useNavigation(); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setHeaderMenuOpen(false); }, [navigation.location?.pathname]); diff --git a/apps/webapp/app/components/primitives/AnimatedCallout.tsx b/apps/webapp/app/components/primitives/AnimatedCallout.tsx index 2391f893e99..e71ba8bd7fd 100644 --- a/apps/webapp/app/components/primitives/AnimatedCallout.tsx +++ b/apps/webapp/app/components/primitives/AnimatedCallout.tsx @@ -41,12 +41,14 @@ export function AnimatedCallout({ useEffect(() => { if (!show) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setAutoDismissed(false); } }, [show]); useEffect(() => { if (shouldShow) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setRendered(true); return; } diff --git a/apps/webapp/app/components/primitives/Buttons.tsx b/apps/webapp/app/components/primitives/Buttons.tsx index d6ec92f79f0..c4332606013 100644 --- a/apps/webapp/app/components/primitives/Buttons.tsx +++ b/apps/webapp/app/components/primitives/Buttons.tsx @@ -261,6 +261,7 @@ export function ButtonContent(props: ButtonContentPropsType) { const [showSpinner, setShowSpinner] = useState(false); useEffect(() => { if (!isLoading) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setShowSpinner(false); return; } diff --git a/apps/webapp/app/components/primitives/Checkbox.tsx b/apps/webapp/app/components/primitives/Checkbox.tsx index e22be7e712c..6972294c48e 100644 --- a/apps/webapp/app/components/primitives/Checkbox.tsx +++ b/apps/webapp/app/components/primitives/Checkbox.tsx @@ -111,6 +111,7 @@ export const CheckboxWithLabel = React.forwardRef { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsChecked(defaultChecked ?? false); }, [defaultChecked]); diff --git a/apps/webapp/app/components/primitives/ClipboardField.tsx b/apps/webapp/app/components/primitives/ClipboardField.tsx index 73facf3bcc0..c3498a915d9 100644 --- a/apps/webapp/app/components/primitives/ClipboardField.tsx +++ b/apps/webapp/app/components/primitives/ClipboardField.tsx @@ -120,6 +120,7 @@ export function ClipboardField({ const { container, input, buttonVariant, button, size } = variants[variant]; useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsSecure(secure !== undefined && secure); }, [secure]); diff --git a/apps/webapp/app/components/primitives/DurationPicker.tsx b/apps/webapp/app/components/primitives/DurationPicker.tsx index e1ce40f5d9b..991563cec30 100644 --- a/apps/webapp/app/components/primitives/DurationPicker.tsx +++ b/apps/webapp/app/components/primitives/DurationPicker.tsx @@ -48,6 +48,7 @@ export function DurationPicker({ const newMinutes = Math.floor((controlledValue % 3600) / 60); const newSeconds = controlledValue % 60; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setHours(newHours); setMinutes(newMinutes); setSeconds(newSeconds); diff --git a/apps/webapp/app/components/primitives/MiddleTruncate.tsx b/apps/webapp/app/components/primitives/MiddleTruncate.tsx index 45915c2521d..2cf6f3d0e6a 100644 --- a/apps/webapp/app/components/primitives/MiddleTruncate.tsx +++ b/apps/webapp/app/components/primitives/MiddleTruncate.tsx @@ -117,6 +117,7 @@ export function MiddleTruncate({ text, className }: MiddleTruncateProps) { }, [text]); useLayoutEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. calculateTruncation(); // Recalculate on resize (guard for jsdom/older browsers) diff --git a/apps/webapp/app/components/primitives/SearchInput.tsx b/apps/webapp/app/components/primitives/SearchInput.tsx index 0ec8a4d6441..2597cb9ec3b 100644 --- a/apps/webapp/app/components/primitives/SearchInput.tsx +++ b/apps/webapp/app/components/primitives/SearchInput.tsx @@ -70,6 +70,7 @@ export function SearchInput({ // Only mark synced once we actually apply it, so a URL change during focus still syncs on blur. if (!isFocused) { lastSyncedRef.current = urlSearch; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setText(urlSearch); } }, [isControlled, controlledValue, value, isFocused, paramName]); diff --git a/apps/webapp/app/components/primitives/TooltipPortal.tsx b/apps/webapp/app/components/primitives/TooltipPortal.tsx index 011c5aae7ef..42fd4b28252 100644 --- a/apps/webapp/app/components/primitives/TooltipPortal.tsx +++ b/apps/webapp/app/components/primitives/TooltipPortal.tsx @@ -44,6 +44,7 @@ export default function TooltipPortal({ active = true, children }: PopperPortalP useEffect(() => { const el = document.createElement("div"); document.body.appendChild(el); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setPortalElement(el); return () => el.remove(); }, []); diff --git a/apps/webapp/app/components/query/QueryEditor.tsx b/apps/webapp/app/components/query/QueryEditor.tsx index 8c842c35f5c..c5665fa88fb 100644 --- a/apps/webapp/app/components/query/QueryEditor.tsx +++ b/apps/webapp/app/components/query/QueryEditor.tsx @@ -985,6 +985,7 @@ function QueryTitle({ // Update rename value when title changes useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setRenameValue(title ?? ""); }, [title]); diff --git a/apps/webapp/app/components/queues/QueueControls.tsx b/apps/webapp/app/components/queues/QueueControls.tsx index 7817749b0cd..5cfe0c69e9c 100644 --- a/apps/webapp/app/components/queues/QueueControls.tsx +++ b/apps/webapp/app/components/queues/QueueControls.tsx @@ -183,6 +183,7 @@ export function QueueOverrideConcurrencyButton({ useEffect(() => { if (navigation.state === "loading" || navigation.state === "idle") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsOpen(false); } }, [navigation.state]); diff --git a/apps/webapp/app/components/runs/v3/AIFilterInput.tsx b/apps/webapp/app/components/runs/v3/AIFilterInput.tsx index 10b4986c2f0..5faf1581496 100644 --- a/apps/webapp/app/components/runs/v3/AIFilterInput.tsx +++ b/apps/webapp/app/components/runs/v3/AIFilterInput.tsx @@ -39,6 +39,7 @@ export function AIFilterInput() { useEffect(() => { if (fetcher.data?.success && fetcher.state === "loading") { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setText(""); setIsFocused(false); @@ -184,6 +185,7 @@ function ErrorPopover({ useEffect(() => { if (error) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setIsOpen(true); } if (timeout.current) { diff --git a/apps/webapp/app/components/runs/v3/RunStatusCellTooltip.tsx b/apps/webapp/app/components/runs/v3/RunStatusCellTooltip.tsx index 789572d7d83..ea65bfaab2e 100644 --- a/apps/webapp/app/components/runs/v3/RunStatusCellTooltip.tsx +++ b/apps/webapp/app/components/runs/v3/RunStatusCellTooltip.tsx @@ -144,6 +144,7 @@ function useChildRunStatusesTooltip({ const entry = fetcher.data.runs.find((run) => run.friendlyId === friendlyId); if (!entry) return; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setChildStatuses((previous) => areChildStatusesEqual(previous, entry.statuses) ? previous : entry.statuses ); @@ -169,6 +170,7 @@ function useChildRunStatusesTooltip({ useEffect(() => { prevHasFinishedRef.current = hasFinished; stopPolling(); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setChildStatuses(undefined); if (isOpenRef.current) { loadChildStatuses(); diff --git a/apps/webapp/app/components/runs/v3/SharedFilters.tsx b/apps/webapp/app/components/runs/v3/SharedFilters.tsx index 70832a1d098..0588ece063f 100644 --- a/apps/webapp/app/components/runs/v3/SharedFilters.tsx +++ b/apps/webapp/app/components/runs/v3/SharedFilters.tsx @@ -519,6 +519,7 @@ function TimeDropdown({ // Sync state when props change useEffect(() => { const parsed = getInitialCustomDuration(period); + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setCustomValue(parsed.value); setCustomUnit(parsed.unit); diff --git a/apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx b/apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx index 96b1b094e10..bdafce941e0 100644 --- a/apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx +++ b/apps/webapp/app/components/runs/v3/ai/AIChatMessages.tsx @@ -289,6 +289,7 @@ export function ToolUseRow({ tool }: { tool: ToolUse }) { // Auto-select input tab when input arrives after initial render (e.g. streaming tool calls) useEffect(() => { if (!hasSubAgent && hasInput) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setActiveTab((current) => current ?? "input"); } }, [hasInput, hasSubAgent]); diff --git a/apps/webapp/app/components/schedules/PurchaseSchedulesModal.tsx b/apps/webapp/app/components/schedules/PurchaseSchedulesModal.tsx index 67a142ce36f..497486b530b 100644 --- a/apps/webapp/app/components/schedules/PurchaseSchedulesModal.tsx +++ b/apps/webapp/app/components/schedules/PurchaseSchedulesModal.tsx @@ -88,6 +88,7 @@ export function PurchaseSchedulesModal({ "ok" in data && data.ok ) { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setOpen(false); } }, [fetcher.state, fetcher.data]); diff --git a/apps/webapp/app/components/webhookConsole/SampleSourcePicker.tsx b/apps/webapp/app/components/webhookConsole/SampleSourcePicker.tsx index 272cda08ad8..7f2c2b83bb8 100644 --- a/apps/webapp/app/components/webhookConsole/SampleSourcePicker.tsx +++ b/apps/webapp/app/components/webhookConsole/SampleSourcePicker.tsx @@ -46,6 +46,7 @@ export function SampleSourcePicker({ useEffect(() => { if (!providers || providers.length === 0) return; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setSelectedProvider((current) => { if (current && providers.some((p) => p.id === current)) return current; if (endpointSource && providers.some((p) => p.id === endpointSource)) return endpointSource; diff --git a/apps/webapp/app/components/webhookDeliveries/v1/useDeliveriesLiveReload.ts b/apps/webapp/app/components/webhookDeliveries/v1/useDeliveriesLiveReload.ts index 3905a8aea85..aee736a3f16 100644 --- a/apps/webapp/app/components/webhookDeliveries/v1/useDeliveriesLiveReload.ts +++ b/apps/webapp/app/components/webhookDeliveries/v1/useDeliveriesLiveReload.ts @@ -140,6 +140,7 @@ export function useDeliveriesLiveReload({ } = useNewDeliveriesDetection({ deliveries, isLoading }); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setVisibleDeliveries(deliveries); resetNewDeliveriesTracking(); }, [deliveries, location.search, resetNewDeliveriesTracking]); @@ -148,6 +149,7 @@ export function useDeliveriesLiveReload({ const data = deliveriesPollFetcher.data; if (!data?.deliveries.length) return; + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setVisibleDeliveries((current) => patchVisibleDeliveriesWithLiveUpdates(current, data.deliveries) ); diff --git a/apps/webapp/app/hooks/useEventSource.tsx b/apps/webapp/app/hooks/useEventSource.tsx index 4bcdac6f522..63c3b18734e 100644 --- a/apps/webapp/app/hooks/useEventSource.tsx +++ b/apps/webapp/app/hooks/useEventSource.tsx @@ -24,6 +24,7 @@ export function useEventSource( } // reset data if dependencies change + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. setData(null); const eventSource = new EventSource(url, init); diff --git a/apps/webapp/app/hooks/useMetricResourceQuery.ts b/apps/webapp/app/hooks/useMetricResourceQuery.ts index f830fcb3e95..8fa3738376d 100644 --- a/apps/webapp/app/hooks/useMetricResourceQuery.ts +++ b/apps/webapp/app/hooks/useMetricResourceQuery.ts @@ -214,6 +214,7 @@ export function useMetricResourceQuery(query: string, opts: MetricResourceQueryO ]); useEffect(() => { + // oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change. load(); return () => abortRef.current?.abort(); }, [load]);