chore: adopt stable React Compiler lint rules (#4737)
This commit is contained in:
+35
-1
@@ -70,6 +70,19 @@
|
||||
"react/require-render-return": "error",
|
||||
"react/style-prop-object": "error",
|
||||
"react/void-dom-elements-no-children": "error",
|
||||
"react/error-boundaries": "off",
|
||||
"react/globals": "off",
|
||||
"react/immutability": "off",
|
||||
"react/incompatible-library": "off",
|
||||
"react/preserve-manual-memoization": "off",
|
||||
"react/purity": "off",
|
||||
"react/refs": "off",
|
||||
"react/set-state-in-effect": "off",
|
||||
"react/set-state-in-render": "off",
|
||||
"react/static-components": "off",
|
||||
"react/unsupported-syntax": "off",
|
||||
"react/use-memo": "off",
|
||||
"react/void-use-memo": "off",
|
||||
"react/checked-requires-onchange-or-readonly": "error",
|
||||
"react/forward-ref-uses-ref": "error",
|
||||
"react/iframe-missing-sandbox": "error",
|
||||
@@ -124,7 +137,22 @@
|
||||
"react/button-has-type": "error",
|
||||
"react/jsx-no-useless-fragment": "error",
|
||||
"react/no-unstable-nested-components": "error",
|
||||
"react/react-compiler": "error",
|
||||
"react/error-boundaries": "error",
|
||||
"react/globals": "error",
|
||||
"react/hooks": "error",
|
||||
"react/immutability": "error",
|
||||
"react/incompatible-library": "error",
|
||||
"react/memo-dependencies": "error",
|
||||
"react/no-deriving-state-in-effects": "error",
|
||||
"react/preserve-manual-memoization": "error",
|
||||
"react/purity": "error",
|
||||
"react/refs": "error",
|
||||
"react/set-state-in-effect": "error",
|
||||
"react/set-state-in-render": "error",
|
||||
"react/static-components": "error",
|
||||
"react/unsupported-syntax": "error",
|
||||
"react/use-memo": "error",
|
||||
"react/void-use-memo": "error",
|
||||
"react/rules-of-hooks": "error",
|
||||
"trigger-runops/no-control-plane-run-graph-access": "error",
|
||||
"trigger-runops/no-control-plane-in-runops-slot": "error"
|
||||
@@ -136,6 +164,12 @@
|
||||
"react/rules-of-hooks": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/*.ts", "**/*.tsx"],
|
||||
"rules": {
|
||||
"no-redeclare": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["apps/webapp/app/**/*.test.ts", "apps/webapp/app/**/*.test.tsx"],
|
||||
"rules": {
|
||||
|
||||
@@ -273,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setFeedbackGivenForQAs(new Set());
|
||||
}
|
||||
}, [conversation.length]);
|
||||
|
||||
@@ -55,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsConnected(undefined);
|
||||
return;
|
||||
}
|
||||
@@ -114,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setCrossEngineIsConnected(isConnected);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setType(open as FeedbackType);
|
||||
setOpen(true);
|
||||
// Clone instead of mutating in place
|
||||
|
||||
@@ -47,7 +47,7 @@ export function LoginPageLayout({
|
||||
const [randomQuote, setRandomQuote] = useState<QuoteType | null>(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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setRandomQuote(quotes[randomIndex]);
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -25,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsSplineReady(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export function FeatureFlagsDialog({
|
||||
const saveFetcher = useFetcher<ActionData>();
|
||||
const loadFeatureFlags = loadFetcher.load;
|
||||
const onOpenChangeRef = useRef(onOpenChange);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
onOpenChangeRef.current = onOpenChange;
|
||||
|
||||
const [overrides, setOverrides] = useState<Record<string, unknown>>({});
|
||||
@@ -68,7 +68,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setSaveError(null);
|
||||
setOverrides({});
|
||||
setInitialOverrides({});
|
||||
@@ -79,7 +79,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setOverrides({ ...loaded });
|
||||
setInitialOverrides({ ...loaded });
|
||||
}
|
||||
@@ -89,7 +89,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setSaveError(saveFetcher.data.error);
|
||||
}
|
||||
}, [saveFetcher.data]);
|
||||
|
||||
@@ -34,12 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
if (savedJustNow && !hasFieldErrors) setIsEditing(false);
|
||||
}, [savedJustNow, hasFieldErrors]);
|
||||
|
||||
|
||||
@@ -65,12 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
if (savedJustNow && !hasFieldErrors) setIsEditing(false);
|
||||
}, [savedJustNow, hasFieldErrors]);
|
||||
|
||||
|
||||
@@ -119,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setShowResetBanner(true);
|
||||
|
||||
if (searchParams.get("alertsReset") !== "1") {
|
||||
@@ -141,12 +141,12 @@ export function BillingAlertsSection({
|
||||
);
|
||||
const maxAlerts = isPercentageMode ? MAX_PERCENTAGE_ALERTS : MAX_ABSOLUTE_ALERTS;
|
||||
|
||||
/* oxlint-disable react/react-compiler -- Stable derived thresholds prevent the synchronization effect from resetting local edits. */
|
||||
/* oxlint-disable react/preserve-manual-memoization -- Stable derived thresholds prevent the synchronization effect from resetting local edits. */
|
||||
const savedThresholds = useMemo(
|
||||
() => storedAlertsToThresholds(alerts, billingLimitMode, effectiveLimitCents, planLimitCents),
|
||||
[alerts, billingLimitMode, effectiveLimitCents, planLimitCents]
|
||||
);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
/* oxlint-enable react/preserve-manual-memoization */
|
||||
const savedEmails = useMemo(() => alerts.emails, [alerts.emails]);
|
||||
const hasLegacySpikes = hasLegacySpikeAlertLevels(
|
||||
alerts,
|
||||
@@ -190,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setThresholdRows(toThresholdRows(savedThresholds));
|
||||
setEmailValues(savedEmails.length > 0 ? [...savedEmails, ""] : [""]);
|
||||
}, [savedThresholds, savedEmails]);
|
||||
|
||||
@@ -126,7 +126,7 @@ export function BillingLimitConfigSection({
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setMode(resetMode);
|
||||
setCustomAmount(savedCustomAmount);
|
||||
setCancelInProgressRuns(savedCancelInProgressRuns);
|
||||
|
||||
@@ -63,7 +63,7 @@ export function BillingLimitRecoveryPanel({
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- A refreshed server recommendation intentionally resets this editable amount draft.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- A refreshed server recommendation intentionally resets this editable amount draft.
|
||||
setNewAmount(String(suggestedNewLimitDollars));
|
||||
}, [suggestedNewLimitDollars]);
|
||||
|
||||
|
||||
@@ -61,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setMode("new");
|
||||
}
|
||||
}, [mode, canEdit]);
|
||||
|
||||
@@ -94,7 +94,7 @@ export function JSONEditor(opts: JSONEditorProps) {
|
||||
const editor = useRef<HTMLDivElement>(null);
|
||||
const settings: Omit<UseCodeMirror, "onBlur"> = {
|
||||
...opts,
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
container: editor.current,
|
||||
extensions,
|
||||
editable: !readOnly,
|
||||
|
||||
@@ -196,7 +196,7 @@ export function TSQLEditor(opts: TSQLEditorProps) {
|
||||
|
||||
const settings: Omit<UseCodeMirror, "onBlur"> = {
|
||||
...opts,
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
container: editor.current,
|
||||
extensions,
|
||||
editable: !readOnly,
|
||||
|
||||
@@ -224,7 +224,7 @@ const DebouncedInput = forwardRef<
|
||||
const [value, setValue] = useState(initialValue);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- Programmatic filter changes intentionally reset the debounced input draft.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- Programmatic filter changes intentionally reset the debounced input draft.
|
||||
setValue(initialValue);
|
||||
}, [initialValue]);
|
||||
|
||||
@@ -1065,7 +1065,6 @@ function ColumnResizeHandle({ header }: { header: Header<RowData, unknown> }) {
|
||||
}
|
||||
/* oxlint-enable jsx-a11y/no-static-element-interactions */
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Table is not compatible with compiler memoization.
|
||||
export const TSQLResultsTable = memo(function TSQLResultsTable({
|
||||
rows,
|
||||
columns,
|
||||
@@ -1122,6 +1121,7 @@ export const TSQLResultsTable = memo(function TSQLResultsTable({
|
||||
// Column resize mode: 'onChange' for real-time feedback, 'onEnd' for performance
|
||||
const columnResizeMode: ColumnResizeMode = "onChange";
|
||||
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Table is not compatible with compiler memoization.
|
||||
const table = useReactTable({
|
||||
data: rows,
|
||||
columns: columnDefs,
|
||||
|
||||
@@ -48,7 +48,7 @@ export function TextEditor(opts: TextEditorProps) {
|
||||
const editor = useRef<HTMLDivElement>(null);
|
||||
const settings: Omit<UseCodeMirror, "onBlur"> = {
|
||||
...opts,
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
container: editor.current,
|
||||
extensions,
|
||||
editable: !readOnly,
|
||||
|
||||
@@ -93,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState({ status: "error", error: "No environment context to run the query." });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ export function DashboardAgentChat({
|
||||
// The path this chat last rendered on. React never unmounts on a page teardown, so an
|
||||
// unmount whose live URL has moved is the router having navigated out from under it.
|
||||
const renderedPathRef = useRef(location.pathname);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
renderedPathRef.current = location.pathname;
|
||||
|
||||
const transport = useTriggerChatTransport<typeof dashboardAgent>({
|
||||
@@ -210,7 +210,7 @@ export function DashboardAgentChat({
|
||||
});
|
||||
|
||||
const orderRef = useRef(createTranscriptOrder(initialMessages));
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
const messages = orderTranscript(rawMessages, orderRef.current);
|
||||
|
||||
// Read here, not in the panel, so it re-reads as each turn settles.
|
||||
@@ -361,7 +361,7 @@ export function DashboardAgentChat({
|
||||
const navigatedRef = useRef<Set<string> | null>(null);
|
||||
if (navigatedRef.current === null) {
|
||||
navigatedRef.current = new Set();
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
pendingNavigateIntents(initialMessages, navigatedRef.current);
|
||||
}
|
||||
useEffect(() => {
|
||||
@@ -377,7 +377,7 @@ export function DashboardAgentChat({
|
||||
const watchProposedRef = useRef<Set<string> | null>(null);
|
||||
if (watchProposedRef.current === null) {
|
||||
watchProposedRef.current = new Set();
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
pendingWatchIntents(initialMessages, watchProposedRef.current);
|
||||
}
|
||||
useEffect(() => {
|
||||
@@ -392,7 +392,7 @@ export function DashboardAgentChat({
|
||||
}, [transport, chatId, aiStop]);
|
||||
|
||||
const teardownRef = useRef<() => void>(() => {});
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
teardownRef.current = () => {
|
||||
if (status !== "streaming" && status !== "submitted") return;
|
||||
const reason = unmountTeardown({
|
||||
@@ -406,7 +406,7 @@ export function DashboardAgentChat({
|
||||
|
||||
// Read by the settle effect, which must not re-run when the transcript changes.
|
||||
const messagesRef = useRef(messages);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
messagesRef.current = messages;
|
||||
|
||||
const prevStatus = useRef(status);
|
||||
|
||||
@@ -126,9 +126,9 @@ export function winningInvestigationOccurrences(messages: UIMessage[]): Map<stri
|
||||
function useInvestigationWinners(messages: UIMessage[]): Map<string, string> {
|
||||
const previous = useRef<Map<string, string>>();
|
||||
const next = useMemo(() => winningInvestigationOccurrences(messages), [messages]);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
previous.current = reuseWinners(previous.current, next);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
return previous.current;
|
||||
}
|
||||
|
||||
|
||||
@@ -168,13 +168,11 @@ 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]);
|
||||
|
||||
const loadHistory = useMemo(
|
||||
() =>
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
createCoalescedReload(async () => {
|
||||
try {
|
||||
const res = await fetch(actionPath);
|
||||
@@ -315,7 +313,6 @@ 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);
|
||||
@@ -344,7 +341,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
|
||||
@@ -361,7 +358,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 () => {
|
||||
@@ -389,7 +386,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -183,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState(computeInitialState());
|
||||
}
|
||||
prevIsOpenRef.current = isOpen;
|
||||
@@ -263,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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"));
|
||||
}
|
||||
@@ -331,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsRedirecting(false);
|
||||
}
|
||||
}, [isOpen]);
|
||||
@@ -393,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("project-selection");
|
||||
}
|
||||
}, [state, onboardingData?.availableProjects, onboardingData?.authInvalid]);
|
||||
@@ -404,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("env-var-sync");
|
||||
}
|
||||
}, [state, onboardingData?.environmentVariables, onboardingData?.authInvalid]);
|
||||
@@ -420,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("loading-env-mapping");
|
||||
if (onDataReload) {
|
||||
onDataReload();
|
||||
@@ -443,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("env-mapping");
|
||||
} else {
|
||||
setState("loading-env-vars");
|
||||
@@ -668,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("completed");
|
||||
}
|
||||
}, [completeOnboardingFetcher.data, completeOnboardingFetcher.state, state]);
|
||||
@@ -683,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("completed");
|
||||
}
|
||||
}, [state, isGitHubConnectedForOnboarding, fromMarketplaceContext, nextUrl, trackOnboarding]);
|
||||
@@ -713,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setState("loading-env-vars");
|
||||
}
|
||||
}, [envMappingFetcher.data, envMappingFetcher.state]);
|
||||
@@ -729,14 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setSelectedVercelProject(availableProjects[0]);
|
||||
}
|
||||
}, [state, availableProjects, selectedVercelProject]);
|
||||
|
||||
@@ -68,7 +68,6 @@ 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/${
|
||||
@@ -81,7 +80,6 @@ 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");
|
||||
|
||||
@@ -76,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setShowLoadMoreSpinner(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setSelectedDashboardId(available?.friendlyId ?? customDashboards[0].friendlyId);
|
||||
}
|
||||
}, [customDashboards, selectedDashboardId, widgetLimit]);
|
||||
|
||||
@@ -52,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [navigation.formAction, navigation.state, formAction]);
|
||||
|
||||
@@ -61,7 +61,6 @@ 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]);
|
||||
|
||||
@@ -250,7 +249,7 @@ function Branches({
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setMenuOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
|
||||
@@ -49,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setMenuOpen(false);
|
||||
}, [navigation.location?.pathname, navigation.location?.search]);
|
||||
|
||||
|
||||
@@ -445,7 +445,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setCustomizeConfirmPending(false);
|
||||
setCustomizeError("Couldn't save your changes. Please try again.");
|
||||
return;
|
||||
@@ -532,7 +532,7 @@ export function SideMenu({
|
||||
// object each render, so depending on it would fire the cleanup (flushing the debounce) every
|
||||
// render — and drags re-render constantly — instead of only on unmount.
|
||||
const flushPendingPreferencesRef = useRef<() => void>();
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
flushPendingPreferencesRef.current = () => {
|
||||
if (debounceTimeoutRef.current) {
|
||||
clearTimeout(debounceTimeoutRef.current);
|
||||
@@ -598,7 +598,7 @@ export function SideMenu({
|
||||
}, []);
|
||||
|
||||
// Animate width + progress over COLLAPSE_ANIM_MS (toggle button, ⌘B shortcut, release-snap).
|
||||
/* oxlint-disable react/react-compiler -- The animation step is local to each callback invocation. */
|
||||
|
||||
const animateTo = useCallback(
|
||||
(targetWidth: number, targetProgress: number) => {
|
||||
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
||||
@@ -629,7 +629,6 @@ export function SideMenu({
|
||||
},
|
||||
[writeVisual]
|
||||
);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
|
||||
// Collapse/expand to a resting state and remember it.
|
||||
const applyCollapsed = useCallback(
|
||||
@@ -648,7 +647,7 @@ export function SideMenu({
|
||||
|
||||
// Drag runs on window-level listeners so releasing anywhere finalizes it. (Pointer capture alone
|
||||
// was unreliable: if the browser drops it mid-drag, the release never fires and the menu strands.)
|
||||
/* oxlint-disable react/react-compiler -- Drag handlers share invocation-local state and listeners. */
|
||||
|
||||
const onHandlePointerDown = useCallback(
|
||||
(e: ReactPointerEvent<HTMLDivElement>) => {
|
||||
if (e.button !== 0) return;
|
||||
@@ -758,7 +757,6 @@ export function SideMenu({
|
||||
},
|
||||
[animateTo, applyCollapsed, persistSideMenuPreferences, writeVisual]
|
||||
);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
|
||||
// Keep the drag handlers' collapsed mirror in sync; tear down any in-flight animation/drag on unmount.
|
||||
useEffect(() => {
|
||||
@@ -1497,7 +1495,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
}, [navigation.location?.pathname, navigation.location?.search]);
|
||||
|
||||
@@ -1711,7 +1709,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setOrgMenuOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
@@ -1990,7 +1988,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
@@ -2045,7 +2043,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsMenuOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
@@ -2167,7 +2165,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
|
||||
@@ -19,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setHeaderMenuOpen(false);
|
||||
}, [navigation.location?.pathname]);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export function useReorderableList<T>({
|
||||
|
||||
const [order, setOrder] = useState<string[]>(() => initialOrder ?? items.map(itemKey));
|
||||
const resetOrderRef = useRef({ initialOrder, items, itemKey });
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
resetOrderRef.current = { initialOrder, items, itemKey };
|
||||
|
||||
// Only an organization switch resets user-managed order. Keep the latest inputs in a ref so
|
||||
|
||||
@@ -290,9 +290,9 @@ export function AgentDotMatrix({
|
||||
const playlistKey = playlist.join(",");
|
||||
const paletteObjRef = useRef(paletteObj);
|
||||
const playlistRef = useRef(playlist);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
paletteObjRef.current = paletteObj;
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
playlistRef.current = playlist;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -41,14 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setRendered(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setShowSpinner(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ export const CheckboxWithLabel = React.forwardRef<HTMLInputElement, CheckboxProp
|
||||
}, [isChecked]);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsChecked(defaultChecked ?? false);
|
||||
}, [defaultChecked]);
|
||||
|
||||
|
||||
@@ -120,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsSecure(secure !== undefined && secure);
|
||||
}, [secure]);
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ export function DateField({
|
||||
});
|
||||
|
||||
const stateValueRef = useRef(state.value);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
stateValueRef.current = state.value;
|
||||
|
||||
// Sync only when the passed value or timezone mode changes. Depending on state.value directly
|
||||
|
||||
@@ -372,7 +372,7 @@ export const RelativeDateTime = ({ date, timeZone, capitalize = true }: Relative
|
||||
|
||||
// On first render
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- A changed date intentionally resets the timer-backed relative text.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- A changed date intentionally resets the timer-backed relative text.
|
||||
setRelativeText(getRelativeText(realDate, capitalize));
|
||||
}, [realDate, capitalize]);
|
||||
|
||||
|
||||
@@ -48,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setHours(newHours);
|
||||
setMinutes(newMinutes);
|
||||
setSeconds(newSeconds);
|
||||
|
||||
@@ -10,7 +10,6 @@ type InputNumberStepperProps = Omit<JSX.IntrinsicElements["input"], "min" | "max
|
||||
controlSize?: "base" | "large";
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- The compiler cannot currently rewrite these hoisted function references.
|
||||
export function InputNumberStepper({
|
||||
value,
|
||||
onChange,
|
||||
|
||||
@@ -117,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
calculateTruncation();
|
||||
|
||||
// Recalculate on resize (guard for jsdom/older browsers)
|
||||
|
||||
@@ -100,9 +100,9 @@ function collapsibleHandleClassName(show: boolean) {
|
||||
|
||||
function useFrozenValue<T>(value: T | null | undefined): T | null | undefined {
|
||||
const ref = useRef(value);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
if (value != null) ref.current = value;
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setText(urlSearch);
|
||||
}
|
||||
}, [isControlled, controlledValue, value, isFocused, paramName]);
|
||||
|
||||
@@ -39,7 +39,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setPortalElement(el);
|
||||
return () => el.remove();
|
||||
}, []);
|
||||
|
||||
@@ -193,7 +193,6 @@ export type UseTreeStateOutput = {
|
||||
scrollToNode: (id: string) => void;
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Virtual is not compatible with compiler memoization.
|
||||
export function useTree<TData, TFilterValue>({
|
||||
tree,
|
||||
selectedId,
|
||||
@@ -277,6 +276,7 @@ export function useTree<TData, TFilterValue>({
|
||||
dispatch({ type: "UPDATE_FILTER", payload: { filter: latestFilterRef.current } });
|
||||
}, [serializedFilterValue]);
|
||||
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Virtual is not compatible with compiler memoization.
|
||||
const virtualizer = useVirtualizer({
|
||||
count: state.visibleNodeIds.length,
|
||||
getItemKey: (index) => state.visibleNodeIds[index],
|
||||
|
||||
@@ -55,7 +55,7 @@ export function useZoomSelection(): UseZoomSelectionReturn {
|
||||
const stateRef = useRef<ZoomSelectionState>(state);
|
||||
|
||||
// Keep ref in sync with state
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
stateRef.current = state;
|
||||
|
||||
const startSelection = useCallback((label: string) => {
|
||||
|
||||
@@ -505,7 +505,7 @@ export function QueryEditor({
|
||||
|
||||
// Use a ref so the effect can read chartConfig without re-firing on every config tweak
|
||||
const chartConfigRef = useRef(chartConfig);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
chartConfigRef.current = chartConfig;
|
||||
|
||||
// Reset chart config only when a column referenced by the current config is no
|
||||
@@ -563,7 +563,7 @@ export function QueryEditor({
|
||||
}, []);
|
||||
|
||||
// Compute current save data for the save render prop
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
const currentQuery = editorRef.current?.getQuery() ?? "";
|
||||
const saveData: QueryEditorSaveData = {
|
||||
title: queryTitle ?? "Untitled Query",
|
||||
@@ -792,7 +792,7 @@ export function QueryEditor({
|
||||
onRename={handleRenameTitle}
|
||||
/>
|
||||
}
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
query={editorRef.current?.getQuery() ?? defaultQuery}
|
||||
data={{
|
||||
rows: results.rows,
|
||||
@@ -847,7 +847,7 @@ export function QueryEditor({
|
||||
<ResultsChart
|
||||
rows={results.rows}
|
||||
columns={results.columns}
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
query={editorRef.current?.getQuery() ?? defaultQuery}
|
||||
chartConfig={chartConfig}
|
||||
onChartConfigChange={handleChartConfigChange}
|
||||
@@ -897,7 +897,7 @@ export function QueryEditor({
|
||||
<ResultsBigNumber
|
||||
rows={results.rows}
|
||||
columns={results.columns}
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
query={editorRef.current?.getQuery() ?? defaultQuery}
|
||||
bigNumberConfig={bigNumberConfig}
|
||||
onBigNumberConfigChange={setBigNumberConfig}
|
||||
@@ -960,7 +960,7 @@ export function QueryEditor({
|
||||
{mode.type === "standalone" && (
|
||||
<SaveToDashboardDialog
|
||||
title={queryTitle ?? "Untitled Query"}
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
query={editorRef.current?.getQuery() ?? ""}
|
||||
config={
|
||||
resultsView === "table"
|
||||
@@ -991,7 +991,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setRenameValue(title ?? "");
|
||||
}, [title]);
|
||||
|
||||
|
||||
@@ -183,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [navigation.state]);
|
||||
|
||||
@@ -39,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setText("");
|
||||
setIsFocused(false);
|
||||
|
||||
@@ -185,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setIsOpen(true);
|
||||
}
|
||||
if (timeout.current) {
|
||||
|
||||
@@ -100,7 +100,7 @@ function useChildRunStatusesTooltip({
|
||||
key: `child-statuses-${friendlyId}`,
|
||||
});
|
||||
const fetcherStateRef = useRef(fetcher.state);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
fetcherStateRef.current = fetcher.state;
|
||||
|
||||
const [childStatuses, setChildStatuses] = useState<ChildStatusEntry[] | undefined>();
|
||||
@@ -121,7 +121,7 @@ function useChildRunStatusesTooltip({
|
||||
// Keep the latest loader callback available to the polling interval
|
||||
// without recreating the interval on every render.
|
||||
const loadChildStatusesRef = useRef(loadChildStatuses);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
loadChildStatusesRef.current = loadChildStatuses;
|
||||
|
||||
const stopPolling = useCallback(() => {
|
||||
@@ -146,7 +146,6 @@ 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
|
||||
);
|
||||
@@ -172,7 +171,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();
|
||||
|
||||
@@ -519,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setCustomValue(parsed.value);
|
||||
setCustomUnit(parsed.unit);
|
||||
|
||||
|
||||
@@ -285,7 +285,6 @@ function useAgentSessionMessages({
|
||||
// `scheduleFlush`. The Map *reference* changes on every flush so React
|
||||
// detects the state update and the downstream `useMemo` recomputes.
|
||||
const [messagesById, setMessagesById] = useState<Map<string, UIMessage>>(
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
() => new Map(pendingRef.current)
|
||||
);
|
||||
|
||||
@@ -295,7 +294,7 @@ function useAgentSessionMessages({
|
||||
const lastFlushAtRef = useRef<number>(0);
|
||||
const pendingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const scheduleFlush = useRef<() => void>(() => {});
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
scheduleFlush.current = () => {
|
||||
if (pendingTimerRef.current !== null) return; // already scheduled
|
||||
const now = Date.now();
|
||||
@@ -672,7 +671,7 @@ function useAgentSessionMessages({
|
||||
return useMemo(() => {
|
||||
const timestamps = timestampsRef.current;
|
||||
const arr = Array.from(messagesById.values());
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
|
||||
arr.sort((a, b) => {
|
||||
const ta = timestamps.get(a.id) ?? 0;
|
||||
const tb = timestamps.get(b.id) ?? 0;
|
||||
|
||||
@@ -289,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setActiveTab((current) => current ?? "input");
|
||||
}
|
||||
}, [hasInput, hasSubAgent]);
|
||||
|
||||
@@ -2,10 +2,10 @@ import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import { useRef } from "react";
|
||||
import { SelectItem } from "../primitives/Select";
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Virtual is not compatible with compiler memoization.
|
||||
export function TimezoneList({ timezones }: { timezones: string[] }) {
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Virtual is not compatible with compiler memoization.
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: timezones.length,
|
||||
getScrollElement: () => parentRef.current,
|
||||
|
||||
@@ -75,7 +75,7 @@ export function PurchaseSchedulesModal({
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
// oxlint-disable-next-line react/react-compiler -- Keep the open draft aligned with authoritative billing values.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- Keep the open draft aligned with authoritative billing values.
|
||||
setBundles(Math.round(extraSchedules / stepSize));
|
||||
}, [open, extraSchedules, stepSize]);
|
||||
|
||||
@@ -88,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
}
|
||||
}, [fetcher.state, fetcher.data]);
|
||||
|
||||
@@ -46,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- 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;
|
||||
|
||||
@@ -124,7 +124,7 @@ export function useDeliveriesLiveReload({
|
||||
const location = useLocation();
|
||||
const deliveriesPollFetcher = useTypedFetcher<typeof liveDeliveriesLoader>();
|
||||
const deliveriesPollFetcherStateRef = useRef(deliveriesPollFetcher.state);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
deliveriesPollFetcherStateRef.current = deliveriesPollFetcher.state;
|
||||
|
||||
const [visibleDeliveries, setVisibleDeliveries] = useState(deliveries);
|
||||
@@ -141,7 +141,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setVisibleDeliveries(deliveries);
|
||||
resetNewDeliveriesTracking();
|
||||
}, [deliveries, location.search, resetNewDeliveriesTracking]);
|
||||
@@ -150,7 +150,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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setVisibleDeliveries((current) =>
|
||||
patchVisibleDeliveriesWithLiveUpdates(current, data.deliveries)
|
||||
);
|
||||
|
||||
@@ -11,7 +11,7 @@ export function useAutoRevalidate(options: UseAutoRevalidateOptions = {}) {
|
||||
const { interval = 5000, onFocus = true, disabled = false } = options;
|
||||
const revalidator = useRevalidator();
|
||||
const revalidatorRef = useRef(revalidator);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
revalidatorRef.current = revalidator;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -12,9 +12,9 @@ export function useChanged<T extends { id: string }>(
|
||||
const itemRef = useRef<T | undefined>();
|
||||
const itemId = item?.id;
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
actionRef.current = action;
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
itemRef.current = item;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -207,7 +207,7 @@ export function useDashboardEditor({
|
||||
const isInitializedRef = useRef(false);
|
||||
const currentLayoutJsonRef = useRef<string>(JSON.stringify(initialData.layout));
|
||||
const initialDataRef = useRef(initialData);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
initialDataRef.current = initialData;
|
||||
|
||||
// Sync queue to prevent race conditions
|
||||
@@ -258,7 +258,7 @@ export function useDashboardEditor({
|
||||
// Sync queue processor - ensures only one sync runs at a time
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/* oxlint-disable react/react-compiler -- The recursive callback drains a serialized sync queue. */
|
||||
/* oxlint-disable react/preserve-manual-memoization -- The recursive callback drains a serialized sync queue. */
|
||||
const processNextSync = useCallback(async () => {
|
||||
// If already syncing or queue is empty, do nothing
|
||||
if (isSyncingRef.current || syncQueueRef.current.length === 0) {
|
||||
@@ -311,7 +311,7 @@ export function useDashboardEditor({
|
||||
processNextSync();
|
||||
}
|
||||
}, [widgetActionUrl, layoutActionUrl, onSyncError]);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
/* oxlint-enable react/preserve-manual-memoization */
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Queue helpers
|
||||
|
||||
@@ -29,7 +29,7 @@ export function useDebounceEffect<T>(value: T, fn: (value: T) => void, delay: nu
|
||||
const fnRef = useRef(fn);
|
||||
|
||||
// Update the ref whenever the function changes
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
fnRef.current = fn;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -8,7 +8,7 @@ export function useElementVisibility({ onVisibilityChange }: UseElementVisibilit
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const isVisibleRef = useRef(false);
|
||||
const callbackRef = useRef(onVisibilityChange);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative integration outside React state.
|
||||
callbackRef.current = onVisibilityChange;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -24,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
setData(null);
|
||||
|
||||
const eventSource = new EventSource(url, init);
|
||||
|
||||
@@ -214,7 +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.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes local state after an external or lifecycle change.
|
||||
load();
|
||||
return () => abortRef.current?.abort();
|
||||
}, [load]);
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ export default function Page() {
|
||||
const usefulLinksPanelRef = useRef<PanelHandle>(null);
|
||||
const fetcher = useFetcher();
|
||||
const fetcherRef = useRef(fetcher);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
fetcherRef.current = fetcher;
|
||||
|
||||
const toggleUsefulLinks = useCallback((show: boolean) => {
|
||||
|
||||
+1
-1
@@ -617,7 +617,7 @@ function NewApiKeyDialog({
|
||||
}
|
||||
|
||||
if (actionData?.ok && actionData.action === "create") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setCreatedApiKey(actionData.apiKey);
|
||||
} else if (actionData && !actionData.ok) {
|
||||
setShowError(true);
|
||||
|
||||
+2
-2
@@ -652,7 +652,7 @@ function PurchaseBranchesModal({
|
||||
|
||||
const [amountValue, setAmountValue] = useState(extraBranches);
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- The authoritative branch count intentionally resets this modal draft.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- The authoritative branch count intentionally resets this modal draft.
|
||||
setAmountValue(extraBranches);
|
||||
}, [extraBranches]);
|
||||
const isLoading = fetcher.state !== "idle";
|
||||
@@ -667,7 +667,7 @@ function PurchaseBranchesModal({
|
||||
"ok" in data &&
|
||||
data.ok
|
||||
) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
}
|
||||
}, [fetcher.state, fetcher.data]);
|
||||
|
||||
+1
-1
@@ -648,7 +648,7 @@ function PurchaseConcurrencyModal({
|
||||
const [open, setOpen] = useState(false);
|
||||
useEffect(() => {
|
||||
if (purchaseSucceeded) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
setSearchParams((s) => {
|
||||
s.delete("success");
|
||||
|
||||
+1
-1
@@ -444,7 +444,7 @@ function useContainerWidth(initialWidth = 1280) {
|
||||
|
||||
useEffect(() => {
|
||||
measureWidth();
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setMounted(true);
|
||||
|
||||
const element = containerRef.current;
|
||||
|
||||
+3
-3
@@ -677,14 +677,14 @@ function RenameDashboardDialog({ title }: { title: string }) {
|
||||
// Close dialog when navigation completes
|
||||
useEffect(() => {
|
||||
if (navigation.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [navigation.state]);
|
||||
|
||||
// Sync newTitle state when title changes (after successful rename)
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- A completed rename intentionally resets this editable title draft.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- A completed rename intentionally resets this editable title draft.
|
||||
setNewTitle(title);
|
||||
}, [title]);
|
||||
|
||||
@@ -751,7 +751,7 @@ function DeleteDashboardDialog({ title }: { title: string }) {
|
||||
// Close dialog when navigation completes
|
||||
useEffect(() => {
|
||||
if (navigation.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [navigation.state]);
|
||||
|
||||
+2
-2
@@ -214,7 +214,7 @@ export default function Page() {
|
||||
|
||||
const abortController = new AbortController();
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setLogs([]);
|
||||
setStreamError(null);
|
||||
setIsStreaming(true);
|
||||
@@ -632,7 +632,7 @@ function LogsDisplay({
|
||||
const logsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- Deployment status changes intentionally reset the user-controlled collapse state.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- Deployment status changes intentionally reset the user-controlled collapse state.
|
||||
setCollapsed(initialCollapsed);
|
||||
}, [initialCollapsed]);
|
||||
|
||||
|
||||
+3
-3
@@ -451,7 +451,7 @@ function EnvironmentVariablesListPage({
|
||||
const [isVirtualized, setIsVirtualized] = useState(false);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsVirtualized(shouldVirtualize);
|
||||
}, [shouldVirtualize]);
|
||||
|
||||
@@ -744,7 +744,6 @@ function EnvironmentVariableTableRow({
|
||||
);
|
||||
}
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Virtual is not compatible with compiler memoization.
|
||||
function EnvironmentVariablesVirtualTableBody({
|
||||
groupedEnvironmentVariables,
|
||||
scrollRef,
|
||||
@@ -758,6 +757,7 @@ function EnvironmentVariablesVirtualTableBody({
|
||||
vercelIntegration: PageVercelIntegration | null;
|
||||
columnCount: number;
|
||||
}) {
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Virtual is not compatible with compiler memoization.
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: groupedEnvironmentVariables.length,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
@@ -816,7 +816,7 @@ function EditEnvironmentVariablePanel({
|
||||
// Close dialog on successful submission
|
||||
useEffect(() => {
|
||||
if (lastSubmission?.success && fetcher.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [lastSubmission?.success, fetcher.state]);
|
||||
|
||||
+2
-2
@@ -318,7 +318,7 @@ function LogsList({
|
||||
|
||||
// Clear accumulated logs immediately when filters change (for instant visual feedback)
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setAccumulatedLogs([]);
|
||||
setNextCursor(undefined);
|
||||
// Preserve log selection from URL param, clear if not present
|
||||
@@ -328,7 +328,7 @@ function LogsList({
|
||||
|
||||
// Populate accumulated logs when new data arrives
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setAccumulatedLogs(list.logs);
|
||||
setNextCursor(list.pagination.next);
|
||||
}, [list.logs, list.pagination.next]);
|
||||
|
||||
+9
-9
@@ -207,7 +207,7 @@ function PlaygroundChat() {
|
||||
activeConversation?.clientData ? JSON.stringify(activeConversation.clientData, null, 2) : "{}"
|
||||
);
|
||||
const clientDataJsonRef = useRef(clientDataJson);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
clientDataJsonRef.current = clientDataJson;
|
||||
const [machine, setMachine] = useState<string | undefined>(undefined);
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
@@ -268,14 +268,14 @@ function PlaygroundChat() {
|
||||
// silently ignored on the first send. Mirror the `clientDataJsonRef`
|
||||
// pattern so the transport always calls the latest `startSession`.
|
||||
const startSessionRef = useRef(startSession);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
startSessionRef.current = startSession;
|
||||
|
||||
// Create TriggerChatTransport directly (not via useTriggerChatTransport hook
|
||||
// to avoid React version mismatch between SDK and webapp)
|
||||
const transportRef = useRef<TriggerChatTransport | null>(null);
|
||||
if (transportRef.current === null) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
transportRef.current = new TriggerChatTransport({
|
||||
task: agent.slug,
|
||||
// The Remix action is idempotent on `(env, externalId)` and
|
||||
@@ -304,7 +304,7 @@ function PlaygroundChat() {
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
const transport = transportRef.current;
|
||||
|
||||
// Keep the transport's `defaultMetadata` in sync with the JSON editor.
|
||||
@@ -355,7 +355,7 @@ function PlaygroundChat() {
|
||||
);
|
||||
|
||||
// useChat from AI SDK — handles message accumulation, streaming, stop
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
const { messages, sendMessage, stop, status, error } = useChat({
|
||||
id: chatId,
|
||||
messages: initialMessages,
|
||||
@@ -396,10 +396,10 @@ function PlaygroundChat() {
|
||||
inputRef.current?.focus();
|
||||
}, [isEmpty]);
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
const session = transport.getSession(chatId);
|
||||
|
||||
/* oxlint-disable react/react-compiler -- The transport and chat ID are stable for this component's lifetime. */
|
||||
/* oxlint-disable react/memo-dependencies -- The transport and chat ID are stable for this component's lifetime. */
|
||||
const handlePreload = useCallback(async () => {
|
||||
setPreloading(true);
|
||||
try {
|
||||
@@ -410,7 +410,7 @@ function PlaygroundChat() {
|
||||
setPreloading(false);
|
||||
}
|
||||
}, [transport, chatId]);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
/* oxlint-enable react/memo-dependencies */
|
||||
|
||||
const handleNewConversation = useCallback(() => {
|
||||
// Navigate without ?conversation= so the loader returns activeConversation=null
|
||||
@@ -1177,7 +1177,7 @@ function usePlaygroundPendingMessages({
|
||||
[status, transport, chatId, sendMessage, metadata]
|
||||
);
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
const pending: PendingMessageEntry[] = pendingMsgs.map((m) => ({
|
||||
id: m.id,
|
||||
text: m.parts[0]?.text ?? "",
|
||||
|
||||
+3
-3
@@ -909,7 +909,7 @@ function OverrideDialog({
|
||||
// Reset when dialog opens
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setEditedContent(content);
|
||||
setCommitMessage("");
|
||||
setModel(currentOverrideModel ?? prompt.defaultModel ?? "");
|
||||
@@ -1333,7 +1333,7 @@ function GenerationsTab({
|
||||
// Append fetched rows when fetcher completes
|
||||
useEffect(() => {
|
||||
if (fetcher.data && fetcher.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setGenerations((prev) => {
|
||||
const existingIds = new Set(prev.map((g) => g.span_id));
|
||||
const newRows = fetcher.data!.generations.filter((g) => !existingIds.has(g.span_id));
|
||||
@@ -1424,7 +1424,7 @@ function GenerationsTab({
|
||||
const [showSpinner, setShowSpinner] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!isLoadingMore) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setShowSpinner(false);
|
||||
return;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1035,7 +1035,7 @@ function EnvironmentPauseResumeButton({
|
||||
|
||||
useEffect(() => {
|
||||
if (navigation.state === "loading" || navigation.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [navigation.state]);
|
||||
|
||||
+1
-1
@@ -899,7 +899,7 @@ function useConcurrencyKeys(opts: {
|
||||
}, [body]);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
load();
|
||||
return () => abortRef.current?.abort();
|
||||
}, [load]);
|
||||
|
||||
+1
-1
@@ -1264,7 +1264,7 @@ function TimelineView({
|
||||
const [duration, setDuration] = useState(queueAdjustedNs(totalDuration, queuedDuration));
|
||||
useEffect(() => {
|
||||
if (rootSpanStatus !== "executing" || !rootStartedAt) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setDuration(queueAdjustedNs(totalDuration, queuedDuration));
|
||||
return;
|
||||
}
|
||||
|
||||
+3
-3
@@ -165,7 +165,7 @@ export function useRunsLiveReload({
|
||||
const location = useLocation();
|
||||
const runsPollFetcher = useTypedFetcher<typeof liveRunsLoader>();
|
||||
const runsPollFetcherStateRef = useRef(runsPollFetcher.state);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
runsPollFetcherStateRef.current = runsPollFetcher.state;
|
||||
|
||||
const [visibleRuns, setVisibleRuns] = useState(runs);
|
||||
@@ -193,7 +193,7 @@ export function useRunsLiveReload({
|
||||
// Single reset path: new loader data or changed filters re-baseline both the
|
||||
// visible rows and new-run tracking.
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setVisibleRuns(runs);
|
||||
resetNewRunsTracking();
|
||||
}, [runs, searchKeyWithoutPagination, resetNewRunsTracking]);
|
||||
@@ -204,7 +204,7 @@ export function useRunsLiveReload({
|
||||
const data = runsPollFetcher.data;
|
||||
if (!data?.runs.length) return;
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setVisibleRuns((currentRuns) => patchVisibleRunsWithLiveUpdates(currentRuns, data.runs));
|
||||
}, [runsPollFetcher.data]);
|
||||
|
||||
|
||||
+1
-1
@@ -261,7 +261,6 @@ const ROW_NUMBER_COL_MIN_CH = 3;
|
||||
const TIME_COL_WIDTH = "7rem";
|
||||
const TYPE_COL_WIDTH = "5rem";
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Virtual is not compatible with compiler memoization.
|
||||
function RawConversationView({
|
||||
inResourcePath,
|
||||
outResourcePath,
|
||||
@@ -387,6 +386,7 @@ function RawConversationView({
|
||||
return () => cancelAnimationFrame(raf);
|
||||
}, [merged, isAtBottom]);
|
||||
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Virtual is not compatible with compiler memoization.
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: merged.length,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
|
||||
+4
-4
@@ -261,7 +261,7 @@ export default function IntegrationsSettingsPage() {
|
||||
if (onboardingData && vercelFetcher.state === "idle") {
|
||||
// Data is loaded, ensure modal is open (query param takes precedence)
|
||||
if (!isModalOpen) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
openVercelOnboarding();
|
||||
}
|
||||
} else if (vercelFetcher.state === "idle" && !hasVercelFetcherData) {
|
||||
@@ -290,7 +290,7 @@ export default function IntegrationsSettingsPage() {
|
||||
if (hasQueryParam && !isModalOpen) {
|
||||
// Query param is present but modal is closed, open it
|
||||
// This ensures the modal stays open during the onboarding flow
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
openVercelOnboarding();
|
||||
}
|
||||
}, [hasQueryParam, isModalOpen, openVercelOnboarding]);
|
||||
@@ -300,7 +300,7 @@ export default function IntegrationsSettingsPage() {
|
||||
if (hasQueryParam && onboardingData && vercelFetcher.state === "idle") {
|
||||
// Data loaded and query param is present, ensure modal is open
|
||||
if (!isModalOpen) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
openVercelOnboarding();
|
||||
}
|
||||
}
|
||||
@@ -445,7 +445,7 @@ function BuildSettingsForm({ buildSettings }: { buildSettings: BuildSettings })
|
||||
buildSettingsValues.installCommand !== (buildSettings?.installCommand || "") ||
|
||||
buildSettingsValues.triggerConfigFilePath !== (buildSettings?.triggerConfigFilePath || "") ||
|
||||
buildSettingsValues.useNativeBuildServer !== nativeBuildServerEnabled;
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setHasBuildSettingsChanges(hasChanges);
|
||||
}, [buildSettingsValues, buildSettings, nativeBuildServerEnabled]);
|
||||
|
||||
|
||||
+2
-2
@@ -651,7 +651,7 @@ function ScheduleSheet({
|
||||
|
||||
// Always reopen in inspect mode.
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setMode("inspect");
|
||||
}, [openScheduleId]);
|
||||
|
||||
@@ -694,7 +694,7 @@ function ScheduleSheet({
|
||||
handledUpdateRef.current = data;
|
||||
if (data.ok) {
|
||||
toast.success(data.message ?? "Schedule updated");
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setMode("inspect");
|
||||
if (detailPath) loadScheduleDetail(detailPath);
|
||||
revalidator.revalidate();
|
||||
|
||||
+2
-2
@@ -1585,7 +1585,7 @@ function RunTemplatesPopover({
|
||||
|
||||
useEffect(() => {
|
||||
if (lastSubmission && "success" in lastSubmission && lastSubmission.success === true) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsDeleteDialogOpen(false);
|
||||
}
|
||||
}, [lastSubmission]);
|
||||
@@ -1773,7 +1773,7 @@ function CreateTemplateModal({
|
||||
|
||||
useEffect(() => {
|
||||
if (lastSubmission && "success" in lastSubmission && lastSubmission.success === true) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsModalOpen(false);
|
||||
setShowCreatedSuccessMessage(true);
|
||||
clearTimeout(successMessageTimeoutRef.current);
|
||||
|
||||
+1
-1
@@ -614,7 +614,7 @@ function SetSecretDialog({
|
||||
// Close on a successful save; the loader revalidates and the state flips to "Set".
|
||||
useEffect(() => {
|
||||
if (fetcher.state === "idle" && fetcher.data?.success) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
}
|
||||
}, [fetcher.state, fetcher.data]);
|
||||
|
||||
@@ -375,7 +375,7 @@ function useOverrideDraft<T>(serverValue: T): {
|
||||
const [override, setOverride] = useState<{ value: T } | null>(null);
|
||||
useEffect(() => {
|
||||
// Server matches the pending edit → clear the override.
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setOverride((current) => (current && Object.is(current.value, serverValue) ? null : current));
|
||||
}, [serverValue]);
|
||||
const value = override ? override.value : serverValue;
|
||||
@@ -420,7 +420,7 @@ export default function Page() {
|
||||
|
||||
useEffect(() => {
|
||||
if (portalFetcher.data?.ok && portalFetcher.data.url) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setPortalUrl(portalFetcher.data.url);
|
||||
}
|
||||
}, [portalFetcher.data]);
|
||||
@@ -919,7 +919,7 @@ function DirectorySyncSection({
|
||||
// server value so polled-in groups appear and matched overrides drop.
|
||||
const [draftGroupRoles, setDraftGroupRoles] = useState<Record<string, string>>({});
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setDraftGroupRoles((current) => {
|
||||
const next: Record<string, string> = {};
|
||||
for (const g of directorySync.groups) {
|
||||
|
||||
@@ -970,7 +970,7 @@ export function PurchaseSeatsModal({
|
||||
|
||||
const [amountValue, setAmountValue] = useState(extraSeats);
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- The authoritative seat count intentionally resets this modal draft.
|
||||
// oxlint-disable-next-line react/set-state-in-effect, react/no-deriving-state-in-effects -- The authoritative seat count intentionally resets this modal draft.
|
||||
setAmountValue(extraSeats);
|
||||
}, [extraSeats]);
|
||||
const isLoading = fetcher.state !== "idle";
|
||||
@@ -985,7 +985,7 @@ export function PurchaseSeatsModal({
|
||||
"ok" in data &&
|
||||
data.ok
|
||||
) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setOpen(false);
|
||||
}
|
||||
}, [fetcher.state, fetcher.data]);
|
||||
|
||||
@@ -360,7 +360,7 @@ export default function Page() {
|
||||
|
||||
useEffect(() => {
|
||||
const nonOther = workingOnOptions.filter((o) => o !== WORKING_ON_OTHER);
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setShuffledWorkingOn([...shuffleArray(nonOther), WORKING_ON_OTHER]);
|
||||
|
||||
const nonOtherGoals = goalOptions.filter((o) => o !== GOALS_OTHER);
|
||||
|
||||
@@ -221,7 +221,7 @@ export default function Page() {
|
||||
const [contrastPreview, setContrastPreview] = useState(contrast);
|
||||
useEffect(() => {
|
||||
if (contrastFetcher.state === "idle") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setContrastPreview(contrast);
|
||||
document.documentElement.style.setProperty("--theme-contrast", String(contrast / 100));
|
||||
}
|
||||
|
||||
@@ -182,14 +182,14 @@ export default function AdminFeatureFlagsRoute() {
|
||||
editable[key] = value;
|
||||
}
|
||||
}
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setValues({ ...editable });
|
||||
setInitialValues({ ...editable });
|
||||
}, [globalFlags, unlocked]);
|
||||
|
||||
useEffect(() => {
|
||||
if (saveFetcher.data?.success) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setSaveError(null);
|
||||
setConfirmOpen(false);
|
||||
} else if (saveFetcher.data?.error) {
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function AdminQueueMetricsRoute() {
|
||||
const handledSaveDataRef = useRef(saveFetcher.data);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setEnabled(controls.enabled);
|
||||
setSampleRate(String(controls.sampleRate));
|
||||
}, [controls.enabled, controls.sampleRate]);
|
||||
@@ -77,7 +77,7 @@ export default function AdminQueueMetricsRoute() {
|
||||
handledSaveDataRef.current = saveFetcher.data;
|
||||
|
||||
if (saveFetcher.data.success) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setError(null);
|
||||
revalidate();
|
||||
} else if (saveFetcher.data.error) {
|
||||
|
||||
@@ -228,7 +228,7 @@ export default function Page() {
|
||||
|
||||
useEffect(() => {
|
||||
const nonOtherReferral = referralSourceOptions.filter((r) => r !== "Other");
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setShuffledReferralSources([...shuffleArray(nonOtherReferral), "Other"]);
|
||||
|
||||
const nonOtherRoles = roleOptions.filter((r) => r !== "Other");
|
||||
|
||||
@@ -197,7 +197,7 @@ export default function LoginMfaPage() {
|
||||
// Reset hideError when a new error appears
|
||||
React.useEffect(() => {
|
||||
if (rawMfaError) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setHideError(false);
|
||||
}
|
||||
}, [rawMfaError]);
|
||||
|
||||
@@ -178,10 +178,12 @@ export function useMfaSetup(initialIsEnabled: boolean) {
|
||||
disableMethod: "totp",
|
||||
});
|
||||
|
||||
const fetcherData = fetcher.data;
|
||||
|
||||
// Handle fetcher responses
|
||||
useEffect(() => {
|
||||
if (fetcher.data) {
|
||||
const { data } = fetcher;
|
||||
if (fetcherData) {
|
||||
const data = fetcherData;
|
||||
|
||||
switch (data.action) {
|
||||
case "enable-mfa":
|
||||
@@ -222,7 +224,7 @@ export function useMfaSetup(initialIsEnabled: boolean) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [fetcher.data]);
|
||||
}, [fetcherData]);
|
||||
|
||||
// Handle submitting state
|
||||
useEffect(() => {
|
||||
|
||||
@@ -99,7 +99,7 @@ export function NewBranchPanel({
|
||||
s.delete("dialogClosed");
|
||||
return s;
|
||||
});
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsOpen(false);
|
||||
}
|
||||
}, [searchParams, setSearchParams]);
|
||||
|
||||
@@ -207,7 +207,7 @@ export function MetricWidget({
|
||||
// Track the latest props so the submit callback always uses fresh values
|
||||
// without needing to be recreated (which would cause useInterval to re-register listeners).
|
||||
const propsRef = useRef(props);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
propsRef.current = props;
|
||||
|
||||
// Track visibility so we only fetch for on-screen widgets.
|
||||
@@ -220,7 +220,7 @@ export function MetricWidget({
|
||||
},
|
||||
});
|
||||
|
||||
/* oxlint-disable react/react-compiler -- These ref objects are stable callback inputs. */
|
||||
/* oxlint-disable react/memo-dependencies -- These ref objects are stable callback inputs. */
|
||||
const submit = useCallback(() => {
|
||||
if (!isVisibleRef.current) {
|
||||
isDirtyRef.current = true;
|
||||
@@ -265,8 +265,8 @@ export function MetricWidget({
|
||||
}
|
||||
});
|
||||
}, [isVisibleRef]);
|
||||
/* oxlint-enable react/react-compiler */
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
/* oxlint-enable react/memo-dependencies */
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
submitRef.current = submit;
|
||||
|
||||
// Clean up on unmount
|
||||
|
||||
+3
-3
@@ -442,7 +442,7 @@ export function ConnectGitHubRepoModal({
|
||||
const params = new URLSearchParams(searchParams);
|
||||
|
||||
if (params.get("openGithubRepoModal") === "1") {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsModalOpen(true);
|
||||
params.delete("openGithubRepoModal");
|
||||
setSearchParams(params);
|
||||
@@ -451,7 +451,7 @@ export function ConnectGitHubRepoModal({
|
||||
|
||||
useEffect(() => {
|
||||
if (lastSubmission && "success" in lastSubmission && lastSubmission.success === true) {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setIsModalOpen(false);
|
||||
}
|
||||
}, [lastSubmission]);
|
||||
@@ -812,7 +812,7 @@ export function ConnectedGitHubRepoForm({
|
||||
gitSettingsValues.stagingBranch !==
|
||||
(connectedGitHubRepo.branchTracking?.staging?.branch || "") ||
|
||||
gitSettingsValues.previewDeploymentsEnabled !== connectedGitHubRepo.previewDeploymentsEnabled;
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setHasGitSettingsChanges(hasChanges);
|
||||
}, [gitSettingsValues, connectedGitHubRepo]);
|
||||
|
||||
|
||||
+2
-2
@@ -105,7 +105,6 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
);
|
||||
};
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- TanStack Virtual is not compatible with compiler memoization.
|
||||
export function RealtimeStreamViewer({
|
||||
runId,
|
||||
streamKey,
|
||||
@@ -254,6 +253,7 @@ export function RealtimeStreamViewer({
|
||||
.length;
|
||||
|
||||
// Virtual rendering for list view
|
||||
// oxlint-disable-next-line react/incompatible-library -- TanStack Virtual is not compatible with compiler memoization.
|
||||
const rowVirtualizer = useVirtualizer({
|
||||
count: chunks.length,
|
||||
getScrollElement: () => scrollRef.current,
|
||||
@@ -540,7 +540,7 @@ export function useRealtimeStream(resourcePath: string, startIndex?: number) {
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setChunks([]);
|
||||
setError(null);
|
||||
|
||||
|
||||
+1
-1
@@ -1118,7 +1118,7 @@ function VercelSettingsPanel({
|
||||
useEffect(() => {
|
||||
if (!data?.authInvalid && !hasError && !data && !hasFetched) {
|
||||
load(vercelResourcePath(organizationSlug, projectSlug, environmentSlug));
|
||||
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
// oxlint-disable-next-line react/set-state-in-effect -- This effect intentionally synchronizes route state after an external or lifecycle change.
|
||||
setHasFetched(true);
|
||||
}
|
||||
}, [
|
||||
|
||||
+2
-2
@@ -249,7 +249,7 @@ function CompleteDateTimeWaitpointForm({
|
||||
const project = useProject();
|
||||
const environment = useEnvironment();
|
||||
|
||||
// oxlint-disable-next-line react/react-compiler -- This form intentionally snapshots wall-clock time for its deadline UI.
|
||||
// oxlint-disable-next-line react/purity -- This form intentionally snapshots wall-clock time for its deadline UI.
|
||||
const now = Date.now();
|
||||
const timeToComplete = waitpoint.completedAfter.getTime() - now;
|
||||
if (timeToComplete < 0) {
|
||||
@@ -368,7 +368,7 @@ function CompleteManualWaitpointForm({ waitpoint }: { waitpoint: { id: string }
|
||||
<div className="max-h-[70vh] min-h-40 overflow-y-auto bg-background-deep scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
|
||||
<JSONEditor
|
||||
autoFocus
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
defaultValue={currentJson.current}
|
||||
readOnly={false}
|
||||
basicSetup
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ export function AIGeneratedCronField({ onSuccess }: AIGeneratedCronFieldProps) {
|
||||
const fetcher = useFetcher<typeof action>();
|
||||
const [text, setText] = useState<string>("");
|
||||
const onSuccessRef = useRef(onSuccess);
|
||||
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
// oxlint-disable-next-line react/refs -- This ref intentionally coordinates an imperative route integration outside React state.
|
||||
onSuccessRef.current = onSuccess;
|
||||
const organization = useOrganization();
|
||||
const project = useProject();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user