This is an automated email from the ASF dual-hosted git repository.
bbovenzi 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 1c3789194c Add datasets to dag graph (#37604)
1c3789194c is described below
commit 1c3789194cf1d1af557cefd939395c047b2b122a
Author: Brent Bovenzi <[email protected]>
AuthorDate: Thu Feb 22 14:24:20 2024 -0500
Add datasets to dag graph (#37604)
* Add dataset nodes to dag graph
* Clean up dataset nodes
---
airflow/www/static/js/api/index.ts | 4 +-
airflow/www/static/js/api/useDatasets.ts | 60 ++----
.../api/{useDatasets.ts => useDatasetsSummary.ts} | 6 +-
.../graph/{Node.test.tsx => DagNode.test.tsx} | 12 +-
.../js/dag/details/graph/{Node.tsx => DagNode.tsx} | 75 +------
.../static/js/dag/details/graph/DatasetNode.tsx | 112 +++++++++++
airflow/www/static/js/dag/details/graph/Node.tsx | 218 ++++-----------------
airflow/www/static/js/dag/details/graph/index.tsx | 61 +++++-
airflow/www/static/js/datasets/List.test.tsx | 2 +-
airflow/www/static/js/datasets/List.tsx | 6 +-
airflow/www/static/js/types/index.ts | 8 +-
airflow/www/static/js/utils/graph.ts | 3 +-
airflow/www/templates/airflow/dag.html | 1 +
airflow/www/templates/airflow/datasets.html | 2 +-
14 files changed, 246 insertions(+), 324 deletions(-)
diff --git a/airflow/www/static/js/api/index.ts
b/airflow/www/static/js/api/index.ts
index 6369a819d2..d703feaef9 100644
--- a/airflow/www/static/js/api/index.ts
+++ b/airflow/www/static/js/api/index.ts
@@ -33,6 +33,7 @@ import useGraphData from "./useGraphData";
import useGridData from "./useGridData";
import useMappedInstances from "./useMappedInstances";
import useDatasets from "./useDatasets";
+import useDatasetsSummary from "./useDatasetsSummary";
import useDataset from "./useDataset";
import useDatasetDependencies from "./useDatasetDependencies";
import useDatasetEvents from "./useDatasetEvents";
@@ -72,9 +73,10 @@ export {
useDagRuns,
useDags,
useDataset,
+ useDatasets,
useDatasetDependencies,
useDatasetEvents,
- useDatasets,
+ useDatasetsSummary,
useExtraLinks,
useGraphData,
useGridData,
diff --git a/airflow/www/static/js/api/useDatasets.ts
b/airflow/www/static/js/api/useDatasets.ts
index 6150f51ce3..db46415062 100644
--- a/airflow/www/static/js/api/useDatasets.ts
+++ b/airflow/www/static/js/api/useDatasets.ts
@@ -21,65 +21,29 @@ import axios, { AxiosResponse } from "axios";
import { useQuery } from "react-query";
import { getMetaValue } from "src/utils";
-import type { DatasetListItem } from "src/types";
-import type { unitOfTime } from "moment";
-
-export interface DatasetsData {
- datasets: DatasetListItem[];
- totalEntries: number;
-}
-
-export interface DateOption {
- count: number;
- unit: unitOfTime.DurationConstructor;
-}
+import type { API } from "src/types";
interface Props {
- limit?: number;
- offset?: number;
- order?: string;
- uri?: string;
- updatedAfter?: DateOption;
+ dagIds?: string[];
+ enabled?: boolean;
}
-export default function useDatasets({
- limit,
- offset,
- order,
- uri,
- updatedAfter,
-}: Props) {
- const query = useQuery(
- ["datasets", limit, offset, order, uri, updatedAfter],
+export default function useDatasets({ dagIds, enabled = true }: Props) {
+ return useQuery(
+ ["datasets", dagIds],
() => {
const datasetsUrl = getMetaValue("datasets_api");
- const orderParam = order ? { order_by: order } : {};
- const uriParam = uri ? { uri_pattern: uri } : {};
- const updatedAfterParam =
- updatedAfter && updatedAfter.count && updatedAfter.unit
- ? {
- // @ts-ignore
- updated_after: moment()
- .subtract(updatedAfter.count, updatedAfter.unit)
- .toISOString(),
- }
- : {};
- return axios.get<AxiosResponse, DatasetsData>(datasetsUrl, {
+ const dagIdsParam =
+ dagIds && dagIds.length ? { dag_ids: dagIds.join(",") } : {};
+
+ return axios.get<AxiosResponse, API.DatasetCollection>(datasetsUrl, {
params: {
- offset,
- limit,
- ...orderParam,
- ...uriParam,
- ...updatedAfterParam,
+ ...dagIdsParam,
},
});
},
{
- keepPreviousData: true,
+ enabled,
}
);
- return {
- ...query,
- data: query.data ?? { datasets: [], totalEntries: 0 },
- };
}
diff --git a/airflow/www/static/js/api/useDatasets.ts
b/airflow/www/static/js/api/useDatasetsSummary.ts
similarity index 92%
copy from airflow/www/static/js/api/useDatasets.ts
copy to airflow/www/static/js/api/useDatasetsSummary.ts
index 6150f51ce3..6f902946f6 100644
--- a/airflow/www/static/js/api/useDatasets.ts
+++ b/airflow/www/static/js/api/useDatasetsSummary.ts
@@ -42,7 +42,7 @@ interface Props {
updatedAfter?: DateOption;
}
-export default function useDatasets({
+export default function useDatasetsSummary({
limit,
offset,
order,
@@ -50,9 +50,9 @@ export default function useDatasets({
updatedAfter,
}: Props) {
const query = useQuery(
- ["datasets", limit, offset, order, uri, updatedAfter],
+ ["datasets_summary", limit, offset, order, uri, updatedAfter],
() => {
- const datasetsUrl = getMetaValue("datasets_api");
+ const datasetsUrl = getMetaValue("datasets_summary");
const orderParam = order ? { order_by: order } : {};
const uriParam = uri ? { uri_pattern: uri } : {};
const updatedAfterParam =
diff --git a/airflow/www/static/js/dag/details/graph/Node.test.tsx
b/airflow/www/static/js/dag/details/graph/DagNode.test.tsx
similarity index 91%
rename from airflow/www/static/js/dag/details/graph/Node.test.tsx
rename to airflow/www/static/js/dag/details/graph/DagNode.test.tsx
index a01114ec04..34ddac7506 100644
--- a/airflow/www/static/js/dag/details/graph/Node.test.tsx
+++ b/airflow/www/static/js/dag/details/graph/DagNode.test.tsx
@@ -26,7 +26,8 @@ import { Wrapper } from "src/utils/testUtils";
import type { NodeProps } from "reactflow";
import type { Task, TaskInstance } from "src/types";
-import { CustomNodeProps, BaseNode as Node } from "./Node";
+import type { CustomNodeProps } from "./Node";
+import DagNode from "./DagNode";
const mockNode: NodeProps<CustomNodeProps> = {
id: "task_id",
@@ -34,6 +35,7 @@ const mockNode: NodeProps<CustomNodeProps> = {
label: "task_id",
height: 50,
width: 200,
+ class: "dag",
instance: {
state: "success",
runId: "run_id",
@@ -65,7 +67,7 @@ const mockNode: NodeProps<CustomNodeProps> = {
describe("Test Graph Node", () => {
test("Renders normal task correctly", async () => {
- const { getByText, getByTestId } = render(<Node {...mockNode} />, {
+ const { getByText, getByTestId } = render(<DagNode {...mockNode} />, {
wrapper: Wrapper,
});
@@ -77,7 +79,7 @@ describe("Test Graph Node", () => {
test("Renders mapped task correctly", async () => {
const { getByText } = render(
- <Node
+ <DagNode
{...mockNode}
data={{
...mockNode.data,
@@ -99,7 +101,7 @@ describe("Test Graph Node", () => {
test("Renders task group correctly", async () => {
const { getByText } = render(
- <Node
+ <DagNode
{...mockNode}
data={{ ...mockNode.data, childCount: 5, isOpen: false }}
/>,
@@ -114,7 +116,7 @@ describe("Test Graph Node", () => {
test("Renders normal task correctly", async () => {
const { getByTestId } = render(
- <Node {...mockNode} data={{ ...mockNode.data, isActive: false }} />,
+ <DagNode {...mockNode} data={{ ...mockNode.data, isActive: false }} />,
{
wrapper: Wrapper,
}
diff --git a/airflow/www/static/js/dag/details/graph/Node.tsx
b/airflow/www/static/js/dag/details/graph/DagNode.tsx
similarity index 74%
copy from airflow/www/static/js/dag/details/graph/Node.tsx
copy to airflow/www/static/js/dag/details/graph/DagNode.tsx
index 4ce193066c..06809249ed 100644
--- a/airflow/www/static/js/dag/details/graph/Node.tsx
+++ b/airflow/www/static/js/dag/details/graph/DagNode.tsx
@@ -18,38 +18,20 @@
*/
import React from "react";
-import { Box, Text, Flex } from "@chakra-ui/react";
-import { Handle, NodeProps, Position } from "reactflow";
+import { Box, Flex, Text } from "@chakra-ui/react";
+import type { NodeProps } from "reactflow";
import { SimpleStatus } from "src/dag/StatusBox";
import useSelection from "src/dag/useSelection";
-import type { DagRun, Task, TaskInstance } from "src/types";
import { getGroupAndMapSummary, hoverDelay } from "src/utils";
import Tooltip from "src/components/Tooltip";
import InstanceTooltip from "src/dag/InstanceTooltip";
import { useContainerRef } from "src/context/containerRef";
import TaskName from "src/dag/TaskName";
-export interface CustomNodeProps {
- label: string;
- height?: number;
- width?: number;
- isJoinNode?: boolean;
- instance?: TaskInstance;
- task?: Task | null;
- isSelected: boolean;
- latestDagRunId: DagRun["runId"];
- childCount?: number;
- onToggleCollapse: () => void;
- isOpen?: boolean;
- isActive?: boolean;
- setupTeardownType?: "setup" | "teardown";
- labelStyle?: string;
- style?: string;
- isZoomedOut: boolean;
-}
+import type { CustomNodeProps } from "./Node";
-export const BaseNode = ({
+const DagNode = ({
id,
data: {
label,
@@ -170,9 +152,7 @@ export const BaseNode = ({
maxWidth={`calc(${width}px - 12px)`}
fontWeight={400}
fontSize="md"
- width="fit-content"
color={operatorTextColor}
- px={1}
>
{task.operator}
</Text>
@@ -184,49 +164,4 @@ export const BaseNode = ({
);
};
-const Node = (props: NodeProps<CustomNodeProps>) => {
- const {
- data: { height, width, isJoinNode, task },
- } = props;
- if (isJoinNode) {
- return (
- <>
- <Handle
- type="target"
- position={Position.Top}
- style={{ visibility: "hidden" }}
- />
- <Box
- height={`${height}px`}
- width={`${width}px`}
- borderRadius={width}
- bg="gray.400"
- />
- <Handle
- type="source"
- position={Position.Bottom}
- style={{ visibility: "hidden" }}
- />
- </>
- );
- }
-
- if (!task) return null;
- return (
- <>
- <Handle
- type="target"
- position={Position.Top}
- style={{ visibility: "hidden" }}
- />
- <BaseNode {...props} />
- <Handle
- type="source"
- position={Position.Bottom}
- style={{ visibility: "hidden" }}
- />
- </>
- );
-};
-
-export default Node;
+export default DagNode;
diff --git a/airflow/www/static/js/dag/details/graph/DatasetNode.tsx
b/airflow/www/static/js/dag/details/graph/DatasetNode.tsx
new file mode 100644
index 0000000000..921341643b
--- /dev/null
+++ b/airflow/www/static/js/dag/details/graph/DatasetNode.tsx
@@ -0,0 +1,112 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from "react";
+import {
+ Box,
+ Link,
+ Popover,
+ PopoverArrow,
+ PopoverBody,
+ PopoverCloseButton,
+ PopoverContent,
+ PopoverHeader,
+ PopoverTrigger,
+ Portal,
+ Text,
+} from "@chakra-ui/react";
+import { HiDatabase } from "react-icons/hi";
+import type { NodeProps } from "reactflow";
+
+import { getMetaValue } from "src/utils";
+import { useContainerRef } from "src/context/containerRef";
+import type { CustomNodeProps } from "./Node";
+
+const datasetsUrl = getMetaValue("datasets_url");
+
+const DatasetNode = ({
+ data: { label, height, width, latestDagRunId, isZoomedOut },
+}: NodeProps<CustomNodeProps>) => {
+ const containerRef = useContainerRef();
+
+ return (
+ <Popover>
+ <PopoverTrigger>
+ <Box
+ borderRadius={isZoomedOut ? 10 : 5}
+ borderWidth={1}
+ borderColor="gray.400"
+ bg="white"
+ height={`${height}px`}
+ width={`${width}px`}
+ cursor={latestDagRunId ? "cursor" : "default"}
+ data-testid="node"
+ px={isZoomedOut ? 1 : 2}
+ mt={isZoomedOut ? -2 : 0}
+ >
+ <Text
+ fontWeight="bold"
+ mt={isZoomedOut ? -2 : 0}
+ noOfLines={2}
+ fontSize={isZoomedOut ? 24 : undefined}
+ textAlign="justify"
+ >
+ {label}
+ </Text>
+ {!isZoomedOut && (
+ <Text
+ maxWidth={`calc(${width}px - 12px)`}
+ fontWeight={400}
+ fontSize="md"
+ textAlign="justify"
+ color="gray.500"
+ >
+ <HiDatabase
+ size="16px"
+ style={{
+ display: "inline",
+ verticalAlign: "middle",
+ marginRight: "3px",
+ }}
+ />
+ Dataset
+ </Text>
+ )}
+ </Box>
+ </PopoverTrigger>
+ <Portal containerRef={containerRef}>
+ <PopoverContent bg="gray.100">
+ <PopoverArrow bg="gray.100" />
+ <PopoverCloseButton />
+ <PopoverHeader>{label}</PopoverHeader>
+ <PopoverBody>
+ <Link
+ color="blue"
+ href={`${datasetsUrl}?uri=${encodeURIComponent(label)}`}
+ >
+ View Dataset
+ </Link>
+ </PopoverBody>
+ </PopoverContent>
+ </Portal>
+ </Popover>
+ );
+};
+
+export default DatasetNode;
diff --git a/airflow/www/static/js/dag/details/graph/Node.tsx
b/airflow/www/static/js/dag/details/graph/Node.tsx
index 4ce193066c..04f1d56fa0 100644
--- a/airflow/www/static/js/dag/details/graph/Node.tsx
+++ b/airflow/www/static/js/dag/details/graph/Node.tsx
@@ -18,17 +18,13 @@
*/
import React from "react";
-import { Box, Text, Flex } from "@chakra-ui/react";
+import { Box } from "@chakra-ui/react";
import { Handle, NodeProps, Position } from "reactflow";
-import { SimpleStatus } from "src/dag/StatusBox";
-import useSelection from "src/dag/useSelection";
-import type { DagRun, Task, TaskInstance } from "src/types";
-import { getGroupAndMapSummary, hoverDelay } from "src/utils";
-import Tooltip from "src/components/Tooltip";
-import InstanceTooltip from "src/dag/InstanceTooltip";
-import { useContainerRef } from "src/context/containerRef";
-import TaskName from "src/dag/TaskName";
+import type { DepNode, DagRun, Task, TaskInstance } from "src/types";
+
+import DagNode from "./DagNode";
+import DatasetNode from "./DatasetNode";
export interface CustomNodeProps {
label: string;
@@ -47,186 +43,42 @@ export interface CustomNodeProps {
labelStyle?: string;
style?: string;
isZoomedOut: boolean;
+ class: DepNode["value"]["class"];
}
-export const BaseNode = ({
- id,
- data: {
- label,
- childCount,
- height,
- width,
- instance,
- task,
- isSelected,
- latestDagRunId,
- onToggleCollapse,
- isOpen,
- isActive,
- setupTeardownType,
- labelStyle,
- style,
- isZoomedOut,
- },
-}: NodeProps<CustomNodeProps>) => {
- const { onSelect } = useSelection();
- const containerRef = useContainerRef();
-
- if (!task) return null;
-
- const bg = isOpen ? "blackAlpha.50" : "white";
- const { isMapped } = task;
- const mappedStates = instance?.mappedStates;
-
- const { totalTasks } = getGroupAndMapSummary({ group: task, mappedStates });
-
- const taskName = isMapped
- ? `${label} [${instance ? totalTasks : " "}]`
- : label;
-
- let operatorTextColor = "";
- let operatorBG = "";
- if (style) {
- [, operatorBG] = style.split(":");
- }
-
- if (labelStyle) {
- [, operatorTextColor] = labelStyle.split(":");
- }
- if (!operatorTextColor || operatorTextColor === "#000;")
- operatorTextColor = "gray.500";
-
- const nodeBorderColor =
- instance?.state && stateColors[instance.state]
- ? `${stateColors[instance.state]}.400`
- : "gray.400";
-
- return (
- <Tooltip
- label={
- instance && task ? (
- <InstanceTooltip instance={instance} group={task} />
- ) : null
- }
- portalProps={{ containerRef }}
- hasArrow
- placement="top"
- openDelay={hoverDelay}
- >
- <Box
- borderRadius={isZoomedOut ? 10 : 5}
- borderWidth={(isSelected ? 4 : 2) * (isZoomedOut ? 3 : 1)}
- borderColor={nodeBorderColor}
- bg={
- !task.children?.length && operatorBG
- ? // Fade the operator color to clash less with the task instance
status
- `color-mix(in srgb, ${operatorBG.replace(";", "")} 80%, white)`
- : bg
- }
- height={`${height}px`}
- width={`${width}px`}
- cursor={latestDagRunId ? "cursor" : "default"}
- opacity={isActive ? 1 : 0.3}
- transition="opacity 0.2s"
- data-testid="node"
- onClick={() => {
- if (latestDagRunId) {
- onSelect({
- runId: instance?.runId || latestDagRunId,
- taskId: isSelected ? undefined : id,
- });
- }
- }}
- px={isZoomedOut ? 1 : 2}
- mt={isZoomedOut ? -2 : 0}
- >
- <TaskName
- label={taskName}
- isOpen={isOpen}
- isGroup={!!childCount}
- onClick={(e) => {
- e.stopPropagation();
- onToggleCollapse();
- }}
- setupTeardownType={setupTeardownType}
- fontWeight="bold"
- isZoomedOut={isZoomedOut}
- mt={isZoomedOut ? -2 : 0}
- noOfLines={2}
- />
- {!isZoomedOut && (
- <>
- {!!instance && instance.state && (
- <Flex alignItems="center">
- <SimpleStatus state={instance.state} />
- <Text ml={2} color="gray.500" fontWeight={400} fontSize="md">
- {instance.state}
- </Text>
- </Flex>
- )}
- {task?.operator && (
- <Text
- noOfLines={1}
- maxWidth={`calc(${width}px - 12px)`}
- fontWeight={400}
- fontSize="md"
- width="fit-content"
- color={operatorTextColor}
- px={1}
- >
- {task.operator}
- </Text>
- )}
- </>
- )}
- </Box>
- </Tooltip>
- );
-};
-
const Node = (props: NodeProps<CustomNodeProps>) => {
- const {
- data: { height, width, isJoinNode, task },
- } = props;
- if (isJoinNode) {
+ const { data } = props;
+
+ if (data.isJoinNode) {
return (
- <>
- <Handle
- type="target"
- position={Position.Top}
- style={{ visibility: "hidden" }}
- />
- <Box
- height={`${height}px`}
- width={`${width}px`}
- borderRadius={width}
- bg="gray.400"
- />
- <Handle
- type="source"
- position={Position.Bottom}
- style={{ visibility: "hidden" }}
- />
- </>
+ <Box
+ height={`${data.height}px`}
+ width={`${data.width}px`}
+ borderRadius={data.width}
+ bg="gray.400"
+ />
);
}
- if (!task) return null;
- return (
- <>
- <Handle
- type="target"
- position={Position.Top}
- style={{ visibility: "hidden" }}
- />
- <BaseNode {...props} />
- <Handle
- type="source"
- position={Position.Bottom}
- style={{ visibility: "hidden" }}
- />
- </>
- );
+ if (data.class === "dataset") return <DatasetNode {...props} />;
+
+ return <DagNode {...props} />;
};
-export default Node;
+const NodeWrapper = (props: NodeProps<CustomNodeProps>) => (
+ <>
+ <Handle
+ type="target"
+ position={Position.Top}
+ style={{ visibility: "hidden" }}
+ />
+ <Node {...props} />
+ <Handle
+ type="source"
+ position={Position.Bottom}
+ style={{ visibility: "hidden" }}
+ />
+ </>
+);
+
+export default NodeWrapper;
diff --git a/airflow/www/static/js/dag/details/graph/index.tsx
b/airflow/www/static/js/dag/details/graph/index.tsx
index 4fb3d21f6c..84f71313a3 100644
--- a/airflow/www/static/js/dag/details/graph/index.tsx
+++ b/airflow/www/static/js/dag/details/graph/index.tsx
@@ -30,11 +30,12 @@ import ReactFlow, {
Viewport,
} from "reactflow";
-import { useGraphData, useGridData } from "src/api";
+import { useDatasets, useGraphData, useGridData } from "src/api";
import useSelection from "src/dag/useSelection";
-import { useOffsetTop } from "src/utils";
+import { getMetaValue, useOffsetTop } from "src/utils";
import { useGraphLayout } from "src/utils/graph";
import Edge from "src/components/Graph/Edge";
+import type { DepNode, WebserverEdge } from "src/types";
import Node from "./Node";
import { buildEdges, nodeStrokeColor, nodeColor, flattenNodes } from "./utils";
@@ -48,6 +49,8 @@ interface Props {
hoveredTaskState?: string | null;
}
+const dagId = getMetaValue("dag_id");
+
const Graph = ({ openGroupIds, onToggleGroups, hoveredTaskState }: Props) => {
const graphRef = useRef(null);
const { data } = useGraphData();
@@ -59,13 +62,63 @@ const Graph = ({ openGroupIds, onToggleGroups,
hoveredTaskState }: Props) => {
setArrange(data?.arrange || "LR");
}, [data?.arrange]);
+ const { data: datasetsCollection } = useDatasets({
+ dagIds: [dagId],
+ });
+
+ const rawNodes =
+ data?.nodes && datasetsCollection?.datasets?.length
+ ? {
+ ...data.nodes,
+ children: [
+ ...(data.nodes.children || []),
+ ...(datasetsCollection?.datasets || []).map(
+ (dataset) =>
+ ({
+ id: dataset?.id?.toString() || "",
+ value: {
+ class: "dataset",
+ label: dataset.uri,
+ },
+ } as DepNode)
+ ),
+ ],
+ }
+ : data?.nodes;
+
+ const datasetEdges: WebserverEdge[] = [];
+
+ datasetsCollection?.datasets?.forEach((dataset) => {
+ const producingTask = dataset?.producingTasks?.find(
+ (t) => t.dagId === dagId
+ );
+ const consumingDag = dataset?.consumingDags?.find((d) => d.dagId ===
dagId);
+ if (dataset.id) {
+ if (producingTask?.taskId) {
+ datasetEdges.push({
+ sourceId: producingTask.taskId,
+ targetId: dataset.id.toString(),
+ });
+ }
+ if (consumingDag && data?.nodes?.children?.length) {
+ datasetEdges.push({
+ sourceId: dataset.id.toString(),
+ // Point upstream datasets to the first task
+ targetId: data.nodes?.children[0].id,
+ });
+ }
+ }
+ });
+
const { data: graphData } = useGraphLayout({
- edges: data?.edges,
- nodes: data?.nodes,
+ edges: [...(data?.edges || []), ...datasetEdges],
+ nodes: rawNodes,
openGroupIds,
arrange,
});
+
const { selected } = useSelection();
+
const {
data: { dagRuns, groups },
} = useGridData();
diff --git a/airflow/www/static/js/datasets/List.test.tsx
b/airflow/www/static/js/datasets/List.test.tsx
index c1cd0da344..f0c1523029 100644
--- a/airflow/www/static/js/datasets/List.test.tsx
+++ b/airflow/www/static/js/datasets/List.test.tsx
@@ -22,7 +22,7 @@
import React from "react";
import { render } from "@testing-library/react";
-import * as useDatasetsModule from "src/api/useDatasets";
+import * as useDatasetsModule from "src/api/useDatasetsSummary";
import { Wrapper } from "src/utils/testUtils";
import type { UseQueryResult } from "react-query";
diff --git a/airflow/www/static/js/datasets/List.tsx
b/airflow/www/static/js/datasets/List.tsx
index a327936883..9d83406d7f 100644
--- a/airflow/www/static/js/datasets/List.tsx
+++ b/airflow/www/static/js/datasets/List.tsx
@@ -37,11 +37,11 @@ import type { Row, SortingRule } from "react-table";
import { MdClose, MdSearch } from "react-icons/md";
import { useSearchParams } from "react-router-dom";
-import { useDatasets } from "src/api";
+import { useDatasetsSummary } from "src/api";
import { Table, TimeCell } from "src/components/Table";
import type { API } from "src/types";
import { getMetaValue } from "src/utils";
-import type { DateOption } from "src/api/useDatasets";
+import type { DateOption } from "src/api/useDatasetsSummary";
interface Props {
onSelect: (datasetId: string) => void;
@@ -99,7 +99,7 @@ const DatasetsList = ({ onSelect }: Props) => {
const {
data: { datasets, totalEntries },
isLoading,
- } = useDatasets({
+ } = useDatasetsSummary({
limit,
offset,
order,
diff --git a/airflow/www/static/js/types/index.ts
b/airflow/www/static/js/types/index.ts
index b9ada90370..926db4760d 100644
--- a/airflow/www/static/js/types/index.ts
+++ b/airflow/www/static/js/types/index.ts
@@ -135,13 +135,13 @@ interface DepNode {
id?: string;
class: "dag" | "dataset" | "trigger" | "sensor";
label: string;
- rx: number;
- ry: number;
+ rx?: number;
+ ry?: number;
isOpen?: boolean;
isJoinNode?: boolean;
childCount?: number;
- labelStyle: string;
- style: string;
+ labelStyle?: string;
+ style?: string;
setupTeardownType?: "setup" | "teardown";
};
children?: DepNode[];
diff --git a/airflow/www/static/js/utils/graph.ts
b/airflow/www/static/js/utils/graph.ts
index 71003b0f19..d1b4b47bde 100644
--- a/airflow/www/static/js/utils/graph.ts
+++ b/airflow/www/static/js/utils/graph.ts
@@ -174,6 +174,7 @@ const generateGraph = ({
}
const extraLabelLength =
value.label.length > 20 ? value.label.length - 19 : 0;
+
return {
id,
label: value.label,
@@ -218,7 +219,7 @@ export const useGraphLayout = ({
return useQuery(
[
"graphLayout",
- !!nodes?.children,
+ nodes?.children?.length,
openGroupIds,
arrange,
root,
diff --git a/airflow/www/templates/airflow/dag.html
b/airflow/www/templates/airflow/dag.html
index 6d6800e98c..5d854abe6e 100644
--- a/airflow/www/templates/airflow/dag.html
+++ b/airflow/www/templates/airflow/dag.html
@@ -79,6 +79,7 @@
<meta name="dag_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dag_endpoint_get_dag',
dag_id=dag.dag_id) }}">
<meta name="dag_source_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dag_source_endpoint_get_dag_source',
file_token='_FILE_TOKEN_') }}">
<meta name="dag_details_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dag_endpoint_get_dag_details',
dag_id=dag.dag_id) }}">
+ <meta name="datasets_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dataset_endpoint_get_datasets')
}}">
<!-- End Urls -->
<meta name="is_paused" content="{{ dag_is_paused }}">
diff --git a/airflow/www/templates/airflow/datasets.html
b/airflow/www/templates/airflow/datasets.html
index 0ffd11444a..164aaf0006 100644
--- a/airflow/www/templates/airflow/datasets.html
+++ b/airflow/www/templates/airflow/datasets.html
@@ -23,7 +23,7 @@
{% block head_meta %}
{{ super() }}
- <meta name="datasets_api" content="{{ url_for('Airflow.datasets_summary')
}}">
+ <meta name="datasets_summary" content="{{
url_for('Airflow.datasets_summary') }}">
<meta name="dataset_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dataset_endpoint_get_dataset',
uri='__URI__') }}">
<meta name="dataset_events_api" content="{{
url_for('/api/v1.airflow_api_connexion_endpoints_dataset_endpoint_get_dataset_events')
}}">
<meta name="grid_url" content="{{ url_for('Airflow.grid',
dag_id='__DAG_ID__') }}">