Skip to content

Commit

Permalink
fix: Adds a loading message when needed in the Select component (apac…
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-s-molina authored and Emmanuel Bavoux committed Nov 14, 2021
1 parent c652a6c commit e83de04
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 31 deletions.
3 changes: 3 additions & 0 deletions superset-frontend/src/components/Select/Select.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ const USERS = [
];

export const AsyncSelect = ({
fetchOnlyOnSearch,
withError,
withInitialValue,
responseTime,
Expand Down Expand Up @@ -381,7 +382,9 @@ export const AsyncSelect = ({
>
<Select
{...rest}
fetchOnlyOnSearch={fetchOnlyOnSearch}
options={withError ? fetchUserListError : fetchUserListPage}
placeholder={fetchOnlyOnSearch ? 'Type anything' : 'Select...'}
value={
withInitialValue
? { label: 'Valentina', value: 'Valentina' }
Expand Down
98 changes: 67 additions & 31 deletions superset-frontend/src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ const StyledSpin = styled(Spin)`
margin-top: ${({ theme }) => -theme.gridUnit}px;
`;

const StyledLoadingText = styled.span`
${({ theme }) => `
margin-left: ${theme.gridUnit * 3}px;
color: ${theme.colors.grayscale.light1};
`}
`;

const MAX_TAG_COUNT = 4;
const TOKEN_SEPARATORS = [',', '\n', '\t', ';'];
const DEBOUNCE_TIMEOUT = 500;
Expand Down Expand Up @@ -175,7 +182,8 @@ const Select = ({
);
const [selectValue, setSelectValue] = useState(value);
const [searchedValue, setSearchedValue] = useState('');
const [isLoading, setLoading] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isTyping, setIsTyping] = useState(false);
const [error, setError] = useState('');
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
const [page, setPage] = useState(0);
Expand Down Expand Up @@ -350,9 +358,10 @@ const Select = ({
const cachedCount = fetchedQueries.current.get(key);
if (cachedCount) {
setTotalCount(cachedCount);
setIsTyping(false);
return;
}
setLoading(true);
setIsLoading(true);
const fetchOptions = options as OptionsPagePromise;
fetchOptions(value, page, pageSize)
.then(({ data, totalCount }: OptionsTypePage) => {
Expand All @@ -361,39 +370,56 @@ const Select = ({
setTotalCount(totalCount);
})
.catch(onError)
.finally(() => setLoading(false));
.finally(() => {
setIsLoading(false);
setIsTyping(false);
});
},
[options],
);

const handleOnSearch = debounce((search: string) => {
const searchValue = search.trim();
// enables option creation
if (allowNewOptions && isSingleMode) {
const firstOption = selectOptions.length > 0 && selectOptions[0].value;
// replaces the last search value entered with the new one
// only when the value wasn't part of the original options
if (
searchValue &&
firstOption === searchedValue &&
!initialOptions.find(o => o.value === searchedValue)
) {
selectOptions.shift();
setSelectOptions(selectOptions);
}
if (searchValue && !hasOption(searchValue, selectOptions)) {
const newOption = {
label: searchValue,
value: searchValue,
};
// adds a custom option
const newOptions = [...selectOptions, newOption];
setSelectOptions(newOptions);
setSelectValue(searchValue);
}
}
setSearchedValue(searchValue);
}, DEBOUNCE_TIMEOUT);
const handleOnSearch = useMemo(
() =>
debounce((search: string) => {
const searchValue = search.trim();
// enables option creation
if (allowNewOptions && isSingleMode) {
const firstOption =
selectOptions.length > 0 && selectOptions[0].value;
// replaces the last search value entered with the new one
// only when the value wasn't part of the original options
if (
searchValue &&
firstOption === searchedValue &&
!initialOptions.find(o => o.value === searchedValue)
) {
selectOptions.shift();
setSelectOptions(selectOptions);
}
if (searchValue && !hasOption(searchValue, selectOptions)) {
const newOption = {
label: searchValue,
value: searchValue,
};
// adds a custom option
const newOptions = [...selectOptions, newOption];
setSelectOptions(newOptions);
setSelectValue(searchValue);
}
}
setSearchedValue(searchValue);
if (!searchValue) {
setIsTyping(false);
}
}, DEBOUNCE_TIMEOUT),
[
allowNewOptions,
initialOptions,
isSingleMode,
searchedValue,
selectOptions,
],
);

const handlePagination = (e: UIEvent<HTMLElement>) => {
const vScroll = e.currentTarget;
Expand Down Expand Up @@ -469,9 +495,18 @@ const Select = ({
if (!isDropdownVisible) {
originNode.ref?.current?.scrollTo({ top: 0 });
}
if ((isLoading && selectOptions.length === 0) || isTyping) {
return <StyledLoadingText>{t('Loading...')}</StyledLoadingText>;
}
return error ? <Error error={error} /> : originNode;
};

const onInputKeyDown = () => {
if (isAsync && !isTyping) {
setIsTyping(true);
}
};

const SuffixIcon = () => {
if (isLoading) {
return <StyledSpin size="small" />;
Expand All @@ -496,6 +531,7 @@ const Select = ({
mode={mappedMode}
onDeselect={handleOnDeselect}
onDropdownVisibleChange={handleOnDropdownVisibleChange}
onInputKeyDown={onInputKeyDown}
onPopupScroll={isAsync ? handlePagination : undefined}
onSearch={shouldShowSearch ? handleOnSearch : undefined}
onSelect={handleOnSelect}
Expand Down

0 comments on commit e83de04

Please sign in to comment.