Skip to content

Commit 722d314

Browse files
committed
fix(webapp,react-hooks): enforce stable hook ordering
1 parent a302f65 commit 722d314

6 files changed

Lines changed: 53 additions & 59 deletions

File tree

.oxlintrc.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"import/no-duplicates": "error",
4747
"import/namespace": "off",
4848
"react-hooks/exhaustive-deps": "off",
49-
"react-hooks/rules-of-hooks": "off",
49+
"react/rules-of-hooks": "off",
5050
"guard-for-in": "error",
5151
"symbol-description": "error",
5252
"no-unneeded-ternary": "error",
@@ -115,10 +115,17 @@
115115
{
116116
"files": ["apps/webapp/app/**/*.ts", "apps/webapp/app/**/*.tsx"],
117117
"rules": {
118+
"react/rules-of-hooks": "error",
118119
"trigger-runops/no-control-plane-run-graph-access": "error",
119120
"trigger-runops/no-control-plane-in-runops-slot": "error"
120121
}
121122
},
123+
{
124+
"files": ["packages/react-hooks/src/**/*.ts", "packages/react-hooks/src/**/*.tsx"],
125+
"rules": {
126+
"react/rules-of-hooks": "error"
127+
}
128+
},
122129
{
123130
"files": ["apps/webapp/app/**/*.test.ts", "apps/webapp/app/**/*.test.tsx"],
124131
"rules": {

apps/webapp/app/components/primitives/Switch.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,15 @@ export const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitives.
6868

6969
const { container, root, thumb, text } = variations[variant];
7070

71-
if (props.shortcut) {
72-
useShortcutKeys({
73-
shortcut: props.shortcut,
74-
action: () => {
75-
if (innerRef.current) {
76-
innerRef.current.click();
77-
}
78-
},
79-
disabled: props.disabled,
80-
});
81-
}
71+
useShortcutKeys({
72+
shortcut: props.shortcut,
73+
action: () => {
74+
if (innerRef.current) {
75+
innerRef.current.click();
76+
}
77+
},
78+
disabled: props.disabled,
79+
});
8280

8381
const labelElement = label ? (
8482
<label

apps/webapp/app/components/primitives/TextLink.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,14 @@ export function TextLink({
4646
const innerRef = useRef<HTMLAnchorElement>(null);
4747
const classes = variations[variant];
4848

49-
if (shortcut) {
50-
useShortcutKeys({
51-
shortcut: shortcut,
52-
action: () => {
53-
if (innerRef.current) {
54-
innerRef.current.click();
55-
}
56-
},
57-
});
58-
}
49+
useShortcutKeys({
50+
shortcut,
51+
action: () => {
52+
if (innerRef.current) {
53+
innerRef.current.click();
54+
}
55+
},
56+
});
5957

6058
const renderShortcutKey = () =>
6159
shortcut &&

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -602,12 +602,11 @@ function shouldLiveReload({
602602
return true;
603603
}
604604

605-
function TraceView({
606-
run,
607-
trace,
608-
maximumLiveReloadingSetting,
609-
resizable,
610-
}: Pick<LoaderData, "run" | "trace" | "maximumLiveReloadingSetting" | "resizable">) {
605+
type TraceViewProps = Pick<LoaderData, "run" | "maximumLiveReloadingSetting" | "resizable"> & {
606+
trace: NonNullable<LoaderData["trace"]>;
607+
};
608+
609+
function TraceView({ run, trace, maximumLiveReloadingSetting, resizable }: TraceViewProps) {
611610
const organization = useOrganization();
612611
const project = useProject();
613612
const environment = useEnvironment();
@@ -616,10 +615,6 @@ function TraceView({
616615
const frozenSpanId = useFrozenValue(selectedSpanId);
617616
const displaySpanId = selectedSpanId ?? frozenSpanId;
618617

619-
if (!trace) {
620-
return <></>;
621-
}
622-
623618
const {
624619
events,
625620
duration,

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -295,15 +295,11 @@ export const handle: Handle = {
295295
export default function Page() {
296296
const result = useTypedLoaderData<typeof loader>();
297297

298-
if (!result.foundTask) {
299-
return <div />;
300-
}
301-
302298
const params = useParams();
303299
const queueFetcher = useFetcher<typeof queuesLoader>();
304300

305301
useEffect(() => {
306-
if (params.organizationSlug && params.projectParam && params.envParam) {
302+
if (result.foundTask && params.organizationSlug && params.projectParam && params.envParam) {
307303
const searchParams = new URLSearchParams();
308304
searchParams.set("type", "custom");
309305
searchParams.set("per_page", "100");
@@ -314,9 +310,9 @@ export default function Page() {
314310
}/queues?${searchParams.toString()}`
315311
);
316312
}
317-
}, [params.organizationSlug, params.projectParam, params.envParam]);
313+
}, [result.foundTask, params.organizationSlug, params.projectParam, params.envParam]);
318314

319-
const defaultTaskQueue = "queue" in result ? result.queue : undefined;
315+
const defaultTaskQueue = result.foundTask && "queue" in result ? result.queue : undefined;
320316
const queues = useMemo(() => {
321317
const customQueues = queueFetcher.data?.queues ?? [];
322318

@@ -325,6 +321,10 @@ export default function Page() {
325321
: customQueues;
326322
}, [queueFetcher.data?.queues, defaultTaskQueue]);
327323

324+
if (!result.foundTask) {
325+
return <div />;
326+
}
327+
328328
const { triggerSource } = result;
329329

330330
switch (triggerSource) {

packages/react-hooks/src/hooks/useRealtime.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -750,33 +750,29 @@ export function useRealtimeStream<TPart>(
750750
streamKeyOrOptionsOrRunId?: string | UseRealtimeStreamOptions<TPart>,
751751
options?: UseRealtimeStreamOptions<TPart>
752752
): UseRealtimeStreamInstance<TPart> {
753+
let runId: string;
754+
let streamKey: string;
755+
let resolvedOptions: UseRealtimeStreamOptions<TPart> | undefined;
756+
753757
if (typeof runIdOrDefinedStream === "string") {
754-
if (typeof streamKeyOrOptionsOrRunId === "string") {
755-
return useRealtimeStreamImplementation(
756-
runIdOrDefinedStream,
757-
streamKeyOrOptionsOrRunId,
758-
options
759-
);
760-
} else {
761-
return useRealtimeStreamImplementation(
762-
runIdOrDefinedStream,
763-
"default",
764-
streamKeyOrOptionsOrRunId
765-
);
766-
}
758+
runId = runIdOrDefinedStream;
759+
streamKey =
760+
typeof streamKeyOrOptionsOrRunId === "string" ? streamKeyOrOptionsOrRunId : "default";
761+
resolvedOptions =
762+
typeof streamKeyOrOptionsOrRunId === "string" ? options : streamKeyOrOptionsOrRunId;
767763
} else {
768-
if (typeof streamKeyOrOptionsOrRunId === "string") {
769-
return useRealtimeStreamImplementation(
770-
streamKeyOrOptionsOrRunId,
771-
runIdOrDefinedStream.id,
772-
options
773-
);
774-
} else {
764+
if (typeof streamKeyOrOptionsOrRunId !== "string") {
775765
throw new Error(
776766
"Invalid second argument to useRealtimeStream. When using a defined stream instance, the second argument to useRealtimeStream must be a run ID."
777767
);
778768
}
769+
770+
runId = streamKeyOrOptionsOrRunId;
771+
streamKey = runIdOrDefinedStream.id;
772+
resolvedOptions = options;
779773
}
774+
775+
return useRealtimeStreamImplementation(runId, streamKey, resolvedOptions);
780776
}
781777

782778
function useRealtimeStreamImplementation<TPart>(

0 commit comments

Comments
 (0)