Compare commits

...

5 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
06fc59dfa3 Improve comments in DatasetsList loading state logic
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
2025-12-15 13:56:18 -07:00
copilot-swe-agent[bot]
6cc2e48332 Simplify loading state logic in DatasetsList
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
2025-12-15 13:56:18 -07:00
copilot-swe-agent[bot]
de5fe9f05d Fix debouncing logic in DatasetsList to correctly handle instant updates on loading end
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
2025-12-15 13:56:18 -07:00
copilot-swe-agent[bot]
81d2e0745f Improve DatasetsList debouncing implementation using Mantine's useDebouncedValue
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
2025-12-15 13:56:18 -07:00
copilot-swe-agent[bot]
1d2e1329ff Replace useDebouncedValue hook with @mantine/hooks version
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
2025-12-15 13:56:18 -07:00
13 changed files with 22 additions and 49 deletions

View File

@@ -1,3 +1,4 @@
import { useDebouncedValue } from "@mantine/hooks";
import { Fragment, useMemo, useState } from "react";
import { t } from "ttag";
@@ -6,7 +7,6 @@ import type { InputProps } from "metabase/common/components/Input";
import Input from "metabase/common/components/Input";
import { Tree } from "metabase/common/components/tree";
import type { ITreeNodeItem } from "metabase/common/components/tree/types";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { SEARCH_DEBOUNCE_DURATION } from "metabase/lib/constants";
import type { IconName } from "metabase/ui";

View File

@@ -1,3 +1,4 @@
import { useDebouncedValue } from "@mantine/hooks";
import PropTypes from "prop-types";
import { useMemo, useState } from "react";
import { t } from "ttag";
@@ -6,7 +7,6 @@ import EmptyState from "metabase/common/components/EmptyState";
import Input from "metabase/common/components/Input";
import Subhead from "metabase/common/components/type/Subhead";
import Text from "metabase/common/components/type/Text";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { SEARCH_DEBOUNCE_DURATION } from "metabase/lib/constants";
import { PermissionsTable } from "../PermissionsTable";

View File

@@ -1,28 +0,0 @@
import { useEffect, useState } from "react";
export function useDebouncedValue<TVALUE>(
value: TVALUE,
delay: number,
onlyFor: (lastValue: TVALUE, newValue: TVALUE) => boolean = () => true,
): TVALUE {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
if (onlyFor) {
if (onlyFor(debouncedValue, value) === false) {
setDebouncedValue(value);
return;
}
}
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(handler);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [delay, value, onlyFor]);
return debouncedValue;
}

View File

@@ -1,9 +1,9 @@
import { useDebouncedValue } from "@mantine/hooks";
import type { Location, Query } from "history";
import { useCallback, useEffect, useState } from "react";
import { push, replace } from "react-router-redux";
import { useEffectOnce, useLatest } from "react-use";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { useDispatch } from "metabase/lib/redux";
type BaseState = Record<string, unknown>;

View File

@@ -1,3 +1,4 @@
import { useDebouncedValue } from "@mantine/hooks";
import { useState } from "react";
import { t } from "ttag";
import _ from "underscore";
@@ -7,7 +8,6 @@ import Breadcrumbs from "metabase/common/components/Breadcrumbs";
import Input from "metabase/common/components/Input";
import SelectList from "metabase/common/components/SelectList";
import type { BaseSelectListItemProps } from "metabase/common/components/SelectList/BaseSelectListItem";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { useDashboardContext } from "metabase/dashboard/context";
import { getDashboard } from "metabase/dashboard/selectors";
import { isEmbeddingSdk } from "metabase/embedding-sdk/config";

View File

@@ -1,8 +1,8 @@
import { useDebouncedValue } from "@mantine/hooks";
import { useMemo, useState } from "react";
import { t } from "ttag";
import { coercions_for_type } from "cljs/metabase.types.core";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { Select, type SelectProps } from "metabase/ui";
import type { Field } from "metabase-types/api";

View File

@@ -1,9 +1,8 @@
import { useDebouncedValue } from "@mantine/hooks";
import { useState } from "react";
import { useKeyPressEvent } from "react-use";
import { t } from "ttag";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { useSearch } from "../hooks";
import type { TreePath } from "../types";
import { flatten } from "../utils";

View File

@@ -1,3 +1,4 @@
import { useDebouncedValue } from "@mantine/hooks";
import type * as React from "react";
import { useCallback, useMemo, useState } from "react";
import { t } from "ttag";
@@ -7,7 +8,6 @@ import EmptyState from "metabase/common/components/EmptyState";
import type { InputProps } from "metabase/common/components/Input";
import Input from "metabase/common/components/Input";
import LoadingSpinner from "metabase/common/components/LoadingSpinner";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { useTranslateContent } from "metabase/i18n/hooks";
import { delay } from "metabase/lib/delay";
import { optionItemEqualsFilter } from "metabase/parameters/components/widgets/ParameterFieldWidget/FieldValuesWidget/SingleSelectListField/utils";

View File

@@ -1,3 +1,4 @@
import { useDebouncedValue } from "@mantine/hooks";
import type * as React from "react";
import { useMemo, useState } from "react";
import { t } from "ttag";
@@ -7,7 +8,6 @@ import EmptyState from "metabase/common/components/EmptyState";
import type { InputProps } from "metabase/common/components/Input";
import Input from "metabase/common/components/Input";
import LoadingSpinner from "metabase/common/components/LoadingSpinner";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { useTranslateContent } from "metabase/i18n/hooks";
import { delay } from "metabase/lib/delay";
import { PLUGIN_CONTENT_TRANSLATION } from "metabase/plugins";

View File

@@ -1,8 +1,8 @@
import { useDebouncedValue } from "@mantine/hooks";
import { type ChangeEvent, useCallback, useMemo, useState } from "react";
import { t } from "ttag";
import Input from "metabase/common/components/Input";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { SEARCH_DEBOUNCE_DURATION } from "metabase/lib/constants";
import { isNotNull } from "metabase/lib/types";
import {

View File

@@ -1,10 +1,10 @@
import { useDebouncedValue } from "@mantine/hooks";
import { useCallback, useMemo, useState } from "react";
import { t } from "ttag";
import _ from "underscore";
import EntityMenu from "metabase/common/components/EntityMenu";
import type { InputProps } from "metabase/common/components/Input";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import ButtonsS from "metabase/css/components/buttons.module.css";
import { SEARCH_DEBOUNCE_DURATION } from "metabase/lib/constants";
import { parseTimestamp } from "metabase/lib/time-dayjs";

View File

@@ -1,8 +1,7 @@
import { useDisclosure } from "@mantine/hooks";
import { useDebouncedValue, useDisclosure } from "@mantine/hooks";
import { useCallback, useState } from "react";
import { t } from "ttag";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { trackSimpleEvent } from "metabase/lib/analytics";
import { SEARCH_DEBOUNCE_DURATION } from "metabase/lib/constants";
import { useDispatch, useSelector } from "metabase/lib/redux";

View File

@@ -1,8 +1,8 @@
import { useDebouncedValue } from "@mantine/hooks";
import { useCallback, useMemo } from "react";
import { t } from "ttag";
import { useListRecentsQuery, useSearchQuery } from "metabase/api";
import { useDebouncedValue } from "metabase/common/hooks/use-debounced-value";
import { getDashboard } from "metabase/dashboard/selectors";
import { trackSimpleEvent } from "metabase/lib/analytics";
import { useDispatch, useSelector } from "metabase/lib/redux";
@@ -151,11 +151,14 @@ export function DatasetsList({
},
);
const debouncedIsFetching = useDebouncedValue(
isSearchFetching || isListRecentsFetching,
300, // Adjust debounce duration as needed
(_lastValue, newValue) => newValue === true, // We want instant updates when loading ends
);
// Handle debouncing of loading state with instant updates when loading ends
// When loading starts (false → true): debouncedIsFetching stays false for 300ms,
// so shouldShowLoading delays showing the loading indicator
// When loading ends (true → false): shouldShowLoading immediately becomes false
// regardless of debouncedIsFetching's debounced value
const isFetching = isSearchFetching || isListRecentsFetching;
const debouncedIsFetching = useDebouncedValue(isFetching, 300);
const shouldShowLoading = isFetching && debouncedIsFetching;
const handleSwapDataSources = useCallback(
(item: VisualizerDataSource) => {
@@ -261,7 +264,7 @@ export function DatasetsList({
data-testid="datasets-list"
style={{ overflow: "auto", ...style }}
>
{debouncedIsFetching && (
{shouldShowLoading && (
<>
<Skeleton height={30} radius="sm" />
<Skeleton height={30} mt={6} radius="sm" />
@@ -273,7 +276,7 @@ export function DatasetsList({
{items && items.length === 0 && (
<Box m="auto">{t`No compatible results`}</Box>
)}
{items && !debouncedIsFetching
{items && !shouldShowLoading
? items.map((item, index) => (
<DatasetsListItem
key={index}