Skip to content

Commit 753d4a1

Browse files
author
trigger-release-bot[bot]
committed
Merge remote-tracking branch 'upstream/main' into release/2026-08-12
2 parents 1fe5326 + c668b72 commit 753d4a1

150 files changed

Lines changed: 1366 additions & 980 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.oxlintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"typescript/consistent-type-imports": "error",
4646
"import/no-duplicates": "error",
4747
"import/namespace": "off",
48-
"react/exhaustive-deps": "off",
48+
"react/exhaustive-deps": "error",
4949
"react/rules-of-hooks": "off",
5050
"guard-for-in": "error",
5151
"symbol-description": "error",
@@ -124,6 +124,7 @@
124124
"react/button-has-type": "error",
125125
"react/jsx-no-useless-fragment": "error",
126126
"react/no-unstable-nested-components": "error",
127+
"react/react-compiler": "error",
127128
"react/rules-of-hooks": "error",
128129
"trigger-runops/no-control-plane-run-graph-access": "error",
129130
"trigger-runops/no-control-plane-in-runops-slot": "error"
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useAnimate } from "framer-motion";
22
import { HourglassIcon } from "lucide-react";
3-
import { useEffect } from "react";
3+
import { useEffect, useRef } from "react";
44

55
export function AnimatedHourglassIcon({
66
className,
@@ -10,18 +10,21 @@ export function AnimatedHourglassIcon({
1010
delay?: number;
1111
}) {
1212
const [scope, animate] = useAnimate();
13+
const initialDelay = useRef(delay);
1314

1415
useEffect(() => {
15-
animate(
16+
const controls = animate(
1617
[
1718
[scope.current, { rotate: 0 }, { duration: 0.7 }],
1819
[scope.current, { rotate: 180 }, { duration: 0.3 }],
1920
[scope.current, { rotate: 180 }, { duration: 0.7 }],
2021
[scope.current, { rotate: 360 }, { duration: 0.3 }],
2122
],
22-
{ repeat: Infinity, delay }
23+
{ repeat: Infinity, delay: initialDelay.current }
2324
);
24-
}, []);
25+
26+
return () => controls.stop();
27+
}, [animate, scope]);
2528

2629
return <HourglassIcon ref={scope} className={className} />;
2730
}

apps/webapp/app/components/AskAI.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ function useAskAIState() {
7676
next.delete(ASK_AI_DEEP_LINK_PARAM);
7777
setSearchParams(next);
7878
}
79-
}, [searchParams, openAskAI]);
79+
}, [searchParams, setSearchParams, openAskAI]);
8080

8181
return { isOpen, setIsOpen, initialQuery, openAskAI, closeAskAI };
8282
}
@@ -273,6 +273,7 @@ function ChatMessages({
273273
// Reset feedback state when conversation is reset
274274
useEffect(() => {
275275
if (conversation.length === 0) {
276+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
276277
setFeedbackGivenForQAs(new Set());
277278
}
278279
}, [conversation.length]);

apps/webapp/app/components/DevPresence.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
5555
useEffect(() => {
5656
// If disabled or no events
5757
if (!enabled || streamedEvents === null) {
58+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
5859
setIsConnected(undefined);
5960
return;
6061
}
@@ -80,7 +81,7 @@ export function DevPresenceProvider({ children, enabled = true }: DevPresencePro
8081
// Calculate isConnected and memoize the context value
8182
const contextValue = useMemo(() => {
8283
return { isConnected };
83-
}, [isConnected, enabled]);
84+
}, [isConnected]);
8485

8586
return <DevPresenceContext.Provider value={contextValue}>{children}</DevPresenceContext.Provider>;
8687
}
@@ -113,6 +114,7 @@ export function useCrossEngineIsConnected({
113114

114115
useEffect(() => {
115116
if (project.engine === "V2") {
117+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
116118
setCrossEngineIsConnected(isConnected);
117119
return;
118120
}

apps/webapp/app/components/Feedback.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,21 @@ export function Feedback({
7070
) {
7171
setOpen(false);
7272
}
73-
}, [navigation.formAction, navigation.state, form.allErrors]);
73+
}, [navigation.formAction, navigation.state, form.allErrors, setOpen]);
7474

7575
// Handle URL param functionality
7676
useEffect(() => {
7777
const open = searchParams.get("feedbackPanel");
7878
if (open) {
79+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
7980
setType(open as FeedbackType);
8081
setOpen(true);
8182
// Clone instead of mutating in place
8283
const next = new URLSearchParams(searchParams);
8384
next.delete("feedbackPanel");
8485
setSearchParams(next);
8586
}
86-
}, [searchParams]);
87+
}, [searchParams, setOpen, setSearchParams]);
8788

8889
// Reset the topic to the default once the dialog closes, so reopening always starts fresh. The
8990
// dialog is now persistently mounted (hosted outside the popover), so without this it would keep

apps/webapp/app/components/LoginPageLayout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export function LoginPageLayout({
4747
const [randomQuote, setRandomQuote] = useState<QuoteType | null>(null);
4848
useEffect(() => {
4949
const randomIndex = Math.floor(Math.random() * quotes.length);
50+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
5051
setRandomQuote(quotes[randomIndex]);
5152
}, []);
5253

apps/webapp/app/components/TriggerRotatingLogo.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function TriggerRotatingLogo() {
2525
useEffect(() => {
2626
// Already registered from a previous render
2727
if (customElements.get("spline-viewer")) {
28+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
2829
setIsSplineReady(true);
2930
return;
3031
}

apps/webapp/app/components/admin/FeatureFlagsDialog.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useFetcher } from "@remix-run/react";
2-
import { useEffect, useState } from "react";
2+
import { useEffect, useRef, useState } from "react";
33
import stableStringify from "json-stable-stringify";
44
import {
55
Dialog,
@@ -54,6 +54,10 @@ export function FeatureFlagsDialog({
5454
}: FeatureFlagsDialogProps) {
5555
const loadFetcher = useFetcher<LoaderData>();
5656
const saveFetcher = useFetcher<ActionData>();
57+
const loadFeatureFlags = loadFetcher.load;
58+
const onOpenChangeRef = useRef(onOpenChange);
59+
// oxlint-disable-next-line react/react-compiler -- This ref intentionally coordinates an imperative integration outside React state.
60+
onOpenChangeRef.current = onOpenChange;
5761

5862
const [overrides, setOverrides] = useState<Record<string, unknown>>({});
5963
const [initialOverrides, setInitialOverrides] = useState<Record<string, unknown>>({});
@@ -64,25 +68,28 @@ export function FeatureFlagsDialog({
6468

6569
useEffect(() => {
6670
if (open && orgId) {
71+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
6772
setSaveError(null);
6873
setOverrides({});
6974
setInitialOverrides({});
70-
loadFetcher.load(`/admin/api/v2/orgs/${orgId}/feature-flags`);
75+
loadFeatureFlags(`/admin/api/v2/orgs/${orgId}/feature-flags`);
7176
}
72-
}, [open, orgId]);
77+
}, [loadFeatureFlags, open, orgId]);
7378

7479
useEffect(() => {
7580
if (loadFetcher.data) {
7681
const loaded = loadFetcher.data.orgFlags ?? {};
82+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
7783
setOverrides({ ...loaded });
7884
setInitialOverrides({ ...loaded });
7985
}
8086
}, [loadFetcher.data]);
8187

8288
useEffect(() => {
8389
if (saveFetcher.data?.success) {
84-
onOpenChange(false);
90+
onOpenChangeRef.current(false);
8591
} else if (saveFetcher.data?.error) {
92+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
8693
setSaveError(saveFetcher.data.error);
8794
}
8895
}, [saveFetcher.data]);

apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ export function MaxProjectsSection({
3434
const [value, setValue] = useState(String(maximumProjectCount));
3535

3636
useEffect(() => {
37+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
3738
if (hasFieldErrors) setIsEditing(true);
3839
}, [hasFieldErrors]);
3940

4041
useEffect(() => {
42+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
4143
if (savedJustNow && !hasFieldErrors) setIsEditing(false);
4244
}, [savedJustNow, hasFieldErrors]);
4345

apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ export function RateLimitSection({
6565
const [maxTokens, setMaxTokens] = useState(current ? String(current.maxTokens) : "");
6666

6767
useEffect(() => {
68+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
6869
if (hasFieldErrors) setIsEditing(true);
6970
}, [hasFieldErrors]);
7071

7172
useEffect(() => {
73+
// oxlint-disable-next-line react/react-compiler -- This effect intentionally synchronizes local state after an external or lifecycle change.
7274
if (savedJustNow && !hasFieldErrors) setIsEditing(false);
7375
}, [savedJustNow, hasFieldErrors]);
7476

0 commit comments

Comments
 (0)