function FilterableHudTable()

in torchci/pages/hud/[repoOwner]/[repoName]/[branch]/[page].tsx [145:207]


function FilterableHudTable({
  params,
  jobNames,
  children,
}: {
  params: HudParams;
  jobNames: string[];
  children: React.ReactNode;
}) {
  const router = useRouter();

  const [jobFilter, setJobFilter] = useState<string | null>(null);
  // null and empty string both correspond to no filter; otherwise lowercase it
  // to make the filter case-insensitive.
  const normalizedJobFilter =
    jobFilter === null || jobFilter === "" ? null : jobFilter.toLowerCase();

  useEffect(() => {
    document.addEventListener("keydown", (e) => {
      if (e.code === "Escape") {
        setJobFilter(null);
      }
    });
  }, []);
  const handleInput = useCallback((f) => setJobFilter(f), []);
  const handleSubmit = useCallback(() => {
    if (jobFilter === "") {
      router.push(formatHudURL("hud", params), undefined, { shallow: true });
    } else {
      router.push(
        formatHudURL("hud", params) + `?name_filter=${jobFilter}`,
        undefined,
        {
          shallow: true,
        }
      );
    }
  }, [params, router, jobFilter]);

  // We have to use an effect hook here because query params are undefined at
  // static generation time; they only become available after hydration.
  useEffect(() => {
    const filterValue = (router.query.name_filter as string) || "";
    setJobFilter(filterValue);
    handleInput(filterValue);
  }, [router.query.name_filter, handleInput]);

  return (
    <>
      <JobFilterInput
        currentFilter={jobFilter}
        handleSubmit={handleSubmit}
        handleInput={handleInput}
      />

      <table className={styles.hudTable}>
        <HudTableColumns filter={normalizedJobFilter} names={jobNames} />
        <HudTableHeader filter={normalizedJobFilter} names={jobNames} />
        {children}
      </table>
    </>
  );
}