Skip to content

Commit

Permalink
Persist queried summaries in state and style loading texts
Browse files Browse the repository at this point in the history
  • Loading branch information
kurukimi committed Jun 19, 2024
1 parent 2472bab commit 3d5c98c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 15 deletions.
3 changes: 2 additions & 1 deletion web/src/components/entry-dialog/DimensionComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ type DimensionComboBoxProps<T extends FieldValues> = {
title: string;
rules?: ControllerProps["rules"];
autoCompleteProps?: Partial<
AutocompleteProps<string, boolean | undefined, boolean | undefined, boolean | undefined>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
AutocompleteProps<any, boolean | undefined, boolean | undefined, boolean | undefined>
>;
};

Expand Down
49 changes: 35 additions & 14 deletions web/src/jira/components/JiraIssueComboBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ListItem } from "@mui/material";
import { ListItem, Typography } from "@mui/material";
import { ControllerProps, FieldValues, UseFormReturn } from "react-hook-form";
import { FindDimensionOptionsDocument } from "../../graphql/generated/graphql";
import { useQuery } from "@apollo/client";
Expand All @@ -8,6 +8,7 @@ import { useDebounceValue } from "usehooks-ts";
import { useGetIssues, useSearchIssues } from "../jiraApi";
import { issueKeyToSummary } from "../jiraUtils";
import { jiraQueryMaxResults } from "../jiraConfig";
import { useEffect, useState } from "react";

type JiraIssueComboBoxProps<T extends FieldValues> = {
form: UseFormReturn<T>;
Expand All @@ -24,6 +25,9 @@ const JiraIssueComboBox = <T extends FieldValues>({
const options = data?.findDimensionOptions[name] || [];

const [issueFilter, setIssueFilter] = useDebounceValue("", 500);
const [debounceLoading, setDebounceLoading] = useState(false);

const [keyToSummary, setKeyToSummary] = useState<Record<string, string>>({});
const {
data: dataPages,
error,
Expand All @@ -45,12 +49,17 @@ const JiraIssueComboBox = <T extends FieldValues>({
delayInMs: 0,
});

const pagedIssueData = dataPages?.pages;
const queriedKeys = [
...(pagedIssueData || []),
...(searchedIssueData ? [searchedIssueData] : []),
];
const keyToSummary = issueKeyToSummary(queriedKeys);
useEffect(() => {
const queriedKeys = [
...(dataPages?.pages || []),
...(searchedIssueData ? [searchedIssueData] : []),
];
setKeyToSummary((prev) => ({ ...prev, ...issueKeyToSummary(queriedKeys) }));
}, [dataPages?.pages, searchedIssueData]);

useEffect(() => {
if (issueFilter) setDebounceLoading(false);
}, [issueFilter]);

const getOptionText = (option: string) =>
keyToSummary[option] ? `${option}: ${keyToSummary[option]}` : option;
Expand All @@ -60,35 +69,47 @@ const JiraIssueComboBox = <T extends FieldValues>({
{...params}
name={name}
autoCompleteProps={{
options: options,
options: options.map((text) => ({ label: text, type: "option" })),
renderOption: (props, option, state) => {
const maxIndex = (dataPages?.pageParams.length || 1) * jiraQueryMaxResults - 1;
const shouldLoadMore = (state.index + 1) % jiraQueryMaxResults === 0 && state.index > 0;
if (state.index + 1 > (dataPages?.pageParams.length || 1) * jiraQueryMaxResults)
return null;
if (option.type === "loader")
return (
<ListItem>
<Typography color="GrayText">{option.label}</Typography>
</ListItem>
);
if (state.index > maxIndex) return null;
return (
<ListItem {...props} ref={shouldLoadMore ? sentryRef : undefined}>
{getOptionText(option as string)}

{!keyToSummary[option] && searchLoading && " ..."}
{getOptionText(option.label)}
&nbsp;
{!keyToSummary[option.label] && (searchLoading || debounceLoading) && (
<Typography color="GrayText">...</Typography>
)}
</ListItem>
);
},
filterOptions: (options, state) => {
const filtered = options.filter((option) =>
getOptionText(option as string)
getOptionText(option.label)
.toLowerCase()
.trim()
.includes(state.inputValue.toLowerCase().trim()),
);
if (searchLoading || debounceLoading || pagesLoading)
filtered.push({ label: "Loading...", type: "loader" });
return filtered;
},
ListboxProps: {
ref: rootRef,
},
onInputChange: (_, value, reason) => {
if (reason === "input") {
setDebounceLoading(true);
setIssueFilter(value);
}
if (!value || value === issueFilter) setDebounceLoading(false);
},
}}
/>
Expand Down
3 changes: 3 additions & 0 deletions web/src/jira/jiraApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
useQuery,
useInfiniteQuery,
UseInfiniteQueryResult,
keepPreviousData,
} from "@tanstack/react-query";
import { axiosJira, axiosKeijo } from "./axiosInstance";
import { jiraQueryMaxResults } from "./jiraConfig";
Expand Down Expand Up @@ -99,6 +100,7 @@ export const useSearchIssues = ({
);
return useQuery({
queryKey: ["issueSearch", searchFilter],
staleTime: Infinity,
queryFn: async () => {
return await getIssues(
`${filteredKeys.length ? `key in (${filteredKeys.map((key) => `'${key}'`).join(", ")}) OR ` : ""}key in (${issueKeys
Expand All @@ -109,6 +111,7 @@ export const useSearchIssues = ({
);
},
enabled: !!searchFilter,
placeholderData: keepPreviousData,
});
};

Expand Down

0 comments on commit 3d5c98c

Please sign in to comment.