Skip to content

Commit 25e782d

Browse files
committed
iterate
1 parent f78a276 commit 25e782d

3 files changed

Lines changed: 42 additions & 16 deletions

File tree

torchci/lib/ParamSelector.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ export function ParamSelector({
1818
onSubmit={(e: React.FormEvent<HTMLFormElement>) => {
1919
e.preventDefault();
2020
const form = e.currentTarget;
21-
const input = form.elements[0] as HTMLInputElement;
22-
handleSubmit(input.value);
21+
const input = form.querySelector(
22+
'input[type="text"]'
23+
) as HTMLInputElement;
24+
if (input) {
25+
handleSubmit(input.value);
26+
}
2327
}}
2428
>
2529
<input
@@ -29,7 +33,7 @@ export function ParamSelector({
2933
onFocus={(e: React.FocusEvent<HTMLInputElement>) => {
3034
e.target.select();
3135
}}
32-
onBlur={(e) => {
36+
onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
3337
if (e.target.value !== value && e.target.value.length > 0) {
3438
e.preventDefault();
3539
handleSubmit(e.target.value);

torchci/pages/api/runners/[org].ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export const ALLOWED_ORGS = ["pytorch", "meta-pytorch"];
1818

1919
// Shared function to map GitHub API runner response to our format
2020
function mapRunnerFromGitHubAPI(runner: any): RunnerData {
21-
2221
return {
2322
id: runner.id,
2423
name: runner.name,

torchci/pages/runners/[org].tsx

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ import {
4040
import { RunnerGroupCard } from "components/runners/RunnerGroupCard";
4141
import { ParamSelector } from "lib/ParamSelector";
4242
import { RunnersApiResponse, unknownGoesLast } from "lib/runnerUtils";
43+
import debounce from "lodash/debounce";
4344
import { useSession } from "next-auth/react";
4445
import { useRouter } from "next/router";
45-
import { useCallback, useEffect, useMemo, useState } from "react";
46-
import debounce from "lodash/debounce";
4746
import type { ParsedUrlQuery } from "querystring";
47+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4848
import useSWR from "swr";
4949

5050
// Define sort order constants to prevent typos
@@ -73,38 +73,61 @@ export default function RunnersPage() {
7373
const orgParam = typeof org === "string" ? org : null;
7474

7575
const { data: _session, status: _status } = useSession();
76-
76+
7777
// Utility function to extract search term from URL query
7878
const getSearchFromQuery = (query: ParsedUrlQuery): string => {
7979
return typeof query.search === "string" ? query.search : "";
8080
};
8181

8282
// Get search term from URL parameters
83-
const [searchTerm, setSearchTerm] = useState(getSearchFromQuery(router.query));
83+
const [searchTerm, setSearchTerm] = useState(
84+
getSearchFromQuery(router.query)
85+
);
8486
const [sortOrder, setSortOrder] = useState<SortOrder>(SORT_ALPHABETICAL);
8587
const [expandedGroup, setExpandedGroup] = useState<string | null>(null);
8688

89+
// Use ref to access current router.query without causing debounce recreations
90+
const routerQueryRef = useRef(router.query);
91+
routerQueryRef.current = router.query;
92+
8793
// Sync search state with URL changes
8894
useEffect(() => {
8995
const searchParam = router.query.search;
9096
const newSearchTerm = getSearchFromQuery({ search: searchParam });
91-
setSearchTerm(newSearchTerm);
92-
}, [router.query.search]);
97+
// Only update if different to prevent feedback loops
98+
if (newSearchTerm !== searchTerm) {
99+
setSearchTerm(newSearchTerm);
100+
}
101+
}, [router.query.search, searchTerm]);
93102

94103
// Debounced function to update search in URL
104+
// Debouncing lets us limit the rate at which the
105+
// function is called, so that it doesn't get called on every
106+
// keystroke. Instead, it'll wait for DEBOUNCE_DELAY_MS
107+
// before executing.
108+
const DEBOUNCE_DELAY_MS = 300;
95109
const updateSearchInUrl = useCallback(
96110
debounce((newSearchTerm: string) => {
97-
const query = { ...router.query };
111+
const query = { ...routerQueryRef.current };
98112
if (newSearchTerm) {
99113
query.search = newSearchTerm;
100114
} else {
101115
delete query.search;
102116
}
103-
router.push({ pathname: router.pathname, query }, undefined, { shallow: true });
104-
}, 300),
105-
[router]
117+
router.push({ pathname: router.pathname, query }, undefined, {
118+
shallow: true,
119+
});
120+
}, DEBOUNCE_DELAY_MS),
121+
[router.pathname]
106122
);
107123

124+
// Cleanup debounced function on unmount or when it changes
125+
useEffect(() => {
126+
return () => {
127+
updateSearchInUrl.cancel();
128+
};
129+
}, [updateSearchInUrl]);
130+
108131
// Handle URL editing for organization
109132
const handleOrgSubmit = (newOrg: string) => {
110133
if (!newOrg) return;
@@ -224,8 +247,8 @@ export default function RunnersPage() {
224247
value={searchTerm}
225248
onChange={(e) => {
226249
const value = e.target.value;
227-
setSearchTerm(value); // Immediate UI update
228-
updateSearchInUrl(value); // Debounced URL update
250+
setSearchTerm(value); // Immediate UI update
251+
updateSearchInUrl(value); // Debounced URL update
229252
}}
230253
sx={{ maxWidth: 600, mb: 2 }}
231254
/>

0 commit comments

Comments
 (0)