This is an automated email from the ASF dual-hosted git repository.
jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new a69fd9b1a6a Fix filter in gantt and grid view (#55845)
a69fd9b1a6a is described below
commit a69fd9b1a6a215b7d716cbb0ab205a097b4061b1
Author: Guan Ming(Wesley) Chiu <[email protected]>
AuthorDate: Fri Sep 19 06:44:05 2025 +0800
Fix filter in gantt and grid view (#55845)
---
.../airflow/ui/src/layouts/Details/DetailsLayout.tsx | 4 +++-
.../airflow/ui/src/layouts/Details/Gantt/Gantt.tsx | 20 ++++++++++++++------
.../src/airflow/ui/src/layouts/Details/Grid/Grid.tsx | 8 +++++++-
.../ui/src/layouts/Details/Grid/TaskNames.tsx | 3 ++-
.../src/airflow/ui/src/queries/useGridTISummaries.ts | 4 +++-
5 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
index c19d621ba9a..f7d4662ca05 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
@@ -153,7 +153,9 @@ export const DetailsLayout = ({ children, error, isLoading,
tabs }: Props) => {
showGantt={Boolean(runId) && showGantt}
triggeringUser={triggeringUserFilter}
/>
- {showGantt ? <Gantt limit={limit} /> : undefined}
+ {showGantt ? (
+ <Gantt limit={limit} runType={runTypeFilter}
triggeringUser={triggeringUserFilter} />
+ ) : undefined}
</HStack>
)}
</Box>
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 ff522f06376..57121c1921b 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
@@ -40,6 +40,7 @@ import { useTranslation } from "react-i18next";
import { useParams, useNavigate, useLocation } from "react-router-dom";
import { useTaskInstanceServiceGetTaskInstances } from "openapi/queries";
+import type { DagRunType } from "openapi/requests/types.gen";
import { useColorMode } from "src/context/colorMode";
import { useHover } from "src/context/hover";
import { useOpenGroups } from "src/context/openGroups";
@@ -70,13 +71,15 @@ ChartJS.register(
type Props = {
readonly limit: number;
+ readonly runType?: DagRunType | undefined;
+ readonly triggeringUser?: string | undefined;
};
const CHART_PADDING = 36;
const CHART_ROW_HEIGHT = 20;
const MIN_BAR_WIDTH = 10;
-export const Gantt = ({ limit }: Props) => {
+export const Gantt = ({ limit, runType, triggeringUser }: Props) => {
const { dagId = "", groupId: selectedGroupId, runId = "", taskId:
selectedTaskId } = useParams();
const { openGroupIds } = useOpenGroups();
const deferredOpenGroupIds = useDeferredValue(openGroupIds);
@@ -99,14 +102,19 @@ export const Gantt = ({ limit }: Props) => {
const selectedItemColor = colorMode === "light" ? lightSelectedColor :
darkSelectedColor;
const hoveredItemColor = colorMode === "light" ? lightHoverColor :
darkHoverColor;
- const { data: gridRuns, isLoading: runsLoading } = useGridRuns({ limit });
- const { data: dagStructure, isLoading: structureLoading } =
useGridStructure({ limit });
+ const { data: gridRuns, isLoading: runsLoading } = useGridRuns({ limit,
runType, triggeringUser });
+ const { data: dagStructure, isLoading: structureLoading } =
useGridStructure({
+ limit,
+ runType,
+ triggeringUser,
+ });
const selectedRun = gridRuns?.find((run) => run.run_id === runId);
const refetchInterval = useAutoRefresh({ dagId });
// Get grid summaries for groups (which have min/max times)
const { data: gridTiSummaries, isLoading: summariesLoading } =
useGridTiSummaries({
dagId,
+ enabled: Boolean(selectedRun),
runId,
state: selectedRun?.state,
});
@@ -120,7 +128,7 @@ export const Gantt = ({ limit }: Props) => {
},
undefined,
{
- enabled: Boolean(dagId) && Boolean(runId),
+ enabled: Boolean(dagId) && Boolean(runId) && Boolean(selectedRun),
refetchInterval: (query) =>
query.state.data?.task_instances.some((ti) =>
isStatePending(ti.state)) ? refetchInterval : false,
},
@@ -205,14 +213,14 @@ export const Gantt = ({ limit }: Props) => {
datasets: [
{
backgroundColor: data.map((dataItem) => stateColorMap[dataItem.state
?? "none"]),
- data,
+ data: Boolean(selectedRun) ? data : [],
maxBarThickness: CHART_ROW_HEIGHT,
minBarLength: MIN_BAR_WIDTH,
},
],
labels: flatNodes.map((node) => node.id),
}),
- [data, flatNodes, stateColorMap],
+ [data, flatNodes, stateColorMap, selectedRun],
);
const fixedHeight = flatNodes.length * CHART_ROW_HEIGHT + CHART_PADDING;
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
index 6e47a4fc4f6..8c2537aa29f 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
@@ -56,6 +56,7 @@ export const Grid = ({ limit, runType, showGantt,
triggeringUser }: Props) => {
const { dagId = "", runId = "" } = useParams();
const { data: gridRuns, isLoading } = useGridRuns({ limit, runType,
triggeringUser });
+ const selectedRun = gridRuns?.find((run) => run.run_id === runId);
// Check if the selected dag run is inside of the grid response, if not,
we'll update the grid filters
// Eventually we should redo the api endpoint to make this work better
@@ -109,7 +110,12 @@ export const Grid = ({ limit, runType, showGantt,
triggeringUser }: Props) => {
tabIndex={0}
width={showGantt ? "1/2" : "full"}
>
- <Box flexGrow={1} minWidth={7} position="relative" top="100px">
+ <Box
+ flexGrow={1}
+ minWidth={7}
+ position="relative"
+ top={Boolean(runId) && !Boolean(selectedRun) ? "50px" : "100px"}
+ >
<TaskNames nodes={flatNodes} onRowClick={() => setMode("task")} />
</Box>
<Box position="relative">
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
index 05bf16c83c9..c807458c771 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
@@ -67,11 +67,12 @@ export const TaskNames = ({ nodes, onRowClick }: Props) => {
const { dagId = "", groupId, taskId } = useParams();
const [searchParams] = useSearchParams();
- return nodes.map((node) => (
+ return nodes.map((node, index) => (
<Box
bg={node.id === taskId || node.id === groupId ? "info.muted" : undefined}
borderBottomWidth={1}
borderColor={node.isGroup ? "border.emphasized" : "border"}
+ borderTopWidth={index === 0 ? 1 : 0}
cursor="pointer"
id={node.id.replaceAll(".", "-")}
key={node.id}
diff --git a/airflow-core/src/airflow/ui/src/queries/useGridTISummaries.ts
b/airflow-core/src/airflow/ui/src/queries/useGridTISummaries.ts
index 877719a0ab7..51f07ce99e5 100644
--- a/airflow-core/src/airflow/ui/src/queries/useGridTISummaries.ts
+++ b/airflow-core/src/airflow/ui/src/queries/useGridTISummaries.ts
@@ -22,10 +22,12 @@ import { isStatePending, useAutoRefresh } from "src/utils";
export const useGridTiSummaries = ({
dagId,
+ enabled,
runId,
state,
}: {
dagId: string;
+ enabled?: boolean;
runId: string;
state?: TaskInstanceState | null | undefined;
}) => {
@@ -38,7 +40,7 @@ export const useGridTiSummaries = ({
},
undefined,
{
- enabled: Boolean(runId) && Boolean(dagId),
+ enabled: Boolean(runId) && Boolean(dagId) && enabled,
placeholderData: (prev) => prev,
refetchInterval: (query) =>
((state !== undefined && isStatePending(state)) ||