This is an automated email from the ASF dual-hosted git repository. kaxilnaik pushed a commit to branch v3-1-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit bb53eedfddab0bebe06d66e25360f86847a33691 Author: Guan Ming(Wesley) Chiu <[email protected]> AuthorDate: Wed Sep 10 01:41:00 2025 +0800 Optimize Gantt group expansion with debouncing and deferred rendering (#55334) --- .../src/context/openGroups/OpenGroupsProvider.tsx | 32 ++++++++++++++++++---- .../airflow/ui/src/layouts/Details/Gantt/Gantt.tsx | 8 ++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/context/openGroups/OpenGroupsProvider.tsx b/airflow-core/src/airflow/ui/src/context/openGroups/OpenGroupsProvider.tsx index 1fde16745c3..c65e9a9e1c3 100644 --- a/airflow-core/src/airflow/ui/src/context/openGroups/OpenGroupsProvider.tsx +++ b/airflow-core/src/airflow/ui/src/context/openGroups/OpenGroupsProvider.tsx @@ -17,6 +17,7 @@ * under the License. */ import { useCallback, useMemo, useEffect, type PropsWithChildren } from "react"; +import { useDebouncedCallback } from "use-debounce"; import { useLocalStorage } from "usehooks-ts"; import { useStructureServiceStructureData } from "openapi/queries"; @@ -59,20 +60,41 @@ export const OpenGroupsProvider = ({ children, dagId }: Props) => { } }, [structure.nodes, allGroupIds, setAllGroupIds]); + const debouncedSetOpenGroupIds = useDebouncedCallback( + (newGroupIds: Array<string>) => { + setOpenGroupIds(newGroupIds); + }, + 100, // 100ms debounce for batch operations + ); + const toggleGroupId = useCallback( (groupId: string) => { if (openGroupIds.includes(groupId)) { - setOpenGroupIds(openGroupIds.filter((id) => id !== groupId)); + debouncedSetOpenGroupIds(openGroupIds.filter((id) => id !== groupId)); } else { - setOpenGroupIds([...openGroupIds, groupId]); + debouncedSetOpenGroupIds([...openGroupIds, groupId]); } }, - [openGroupIds, setOpenGroupIds], + [openGroupIds, debouncedSetOpenGroupIds], + ); + + const setOpenGroupIdsImmediate = useCallback( + (newGroupIds: Array<string>) => { + debouncedSetOpenGroupIds.cancel(); + setOpenGroupIds(newGroupIds); + }, + [debouncedSetOpenGroupIds, setOpenGroupIds], ); const value = useMemo<OpenGroupsContextType>( - () => ({ allGroupIds, openGroupIds, setAllGroupIds, setOpenGroupIds, toggleGroupId }), - [allGroupIds, openGroupIds, setAllGroupIds, setOpenGroupIds, toggleGroupId], + () => ({ + allGroupIds, + openGroupIds, + setAllGroupIds, + setOpenGroupIds: setOpenGroupIdsImmediate, + toggleGroupId, + }), + [allGroupIds, openGroupIds, setAllGroupIds, setOpenGroupIdsImmediate, toggleGroupId], ); return <OpenGroupsContext.Provider value={value}>{children}</OpenGroupsContext.Provider>; diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx index 3b6bdceb2da..004272fa4e6 100644 --- a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx +++ b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx @@ -33,7 +33,7 @@ import { import "chart.js/auto"; import "chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm"; import annotationPlugin from "chartjs-plugin-annotation"; -import { useMemo, useRef } from "react"; +import { useMemo, useRef, useDeferredValue } from "react"; import { Bar } from "react-chartjs-2"; import { useTranslation } from "react-i18next"; import { useParams, useNavigate, useLocation } from "react-router-dom"; @@ -77,6 +77,7 @@ const MIN_BAR_WIDTH = 10; export const Gantt = ({ limit }: Props) => { const { dagId = "", groupId: selectedGroupId, runId = "", taskId: selectedTaskId } = useParams(); const { openGroupIds } = useOpenGroups(); + const deferredOpenGroupIds = useDeferredValue(openGroupIds); const { t: translate } = useTranslation("common"); const { selectedTimezone } = useTimezone(); const { colorMode } = useColorMode(); @@ -119,7 +120,10 @@ export const Gantt = ({ limit }: Props) => { }, ); - const { flatNodes } = useMemo(() => flattenNodes(dagStructure, openGroupIds), [dagStructure, openGroupIds]); + const { flatNodes } = useMemo( + () => flattenNodes(dagStructure, deferredOpenGroupIds), + [dagStructure, deferredOpenGroupIds], + ); const isLoading = runsLoading || structureLoading || summariesLoading || tiLoading;
