This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun 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 63b5cd63e63 Add support for changing graph orientation (#47923)
63b5cd63e63 is described below
commit 63b5cd63e63a95eef5f8a76d7a4aba30f7664de9
Author: Aritra Basu <[email protected]>
AuthorDate: Wed Mar 26 19:13:46 2025 +0530
Add support for changing graph orientation (#47923)
* WIP: Initial graph
* Add icon and rerender
* Implemented direction dropdown
---
.../ui/src/components/Graph/useGraphLayout.ts | 13 ++++++++--
.../airflow/ui/src/layouts/Details/Graph/Graph.tsx | 5 ++--
.../ui/src/layouts/Details/PanelButtons.tsx | 29 ++++++++++++++++++++++
3 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/components/Graph/useGraphLayout.ts
b/airflow-core/src/airflow/ui/src/components/Graph/useGraphLayout.ts
index bb46eb76996..9c74318db75 100644
--- a/airflow-core/src/airflow/ui/src/components/Graph/useGraphLayout.ts
+++ b/airflow-core/src/airflow/ui/src/components/Graph/useGraphLayout.ts
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { createListCollection } from "@chakra-ui/react";
import { useQuery } from "@tanstack/react-query";
import ELK, { type ElkNode, type ElkExtendedEdge, type ElkShape } from "elkjs";
@@ -23,7 +24,15 @@ import type { EdgeResponse, NodeResponse,
StructureDataResponse } from "openapi/
import { flattenGraph, formatFlowEdges } from "./reactflowUtils";
-type Direction = "BOTTOM" | "LEFT" | "RIGHT" | "TOP";
+export type Direction = "DOWN" | "LEFT" | "RIGHT" | "UP";
+export const directionOptions = createListCollection({
+ items: [
+ { label: "Left to Right", value: "RIGHT" as Direction },
+ { label: "Right to Left", value: "LEFT" as Direction },
+ { label: "Bottom to Top", value: "UP" as Direction },
+ { label: "Top to Bottom", value: "DOWN" as Direction },
+ ],
+});
type EdgeLabel = {
height: number;
@@ -258,5 +267,5 @@ export const useGraphLayout = ({
return { edges: formattedEdges, nodes: flattenedData.nodes };
},
- queryKey: ["graphLayout", nodes, openGroupIds, versionNumber, edges],
+ queryKey: ["graphLayout", nodes, openGroupIds, versionNumber, edges,
direction],
});
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Graph/Graph.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Graph/Graph.tsx
index cd2dadf0a55..0497c455b57 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Graph/Graph.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Graph/Graph.tsx
@@ -36,7 +36,7 @@ import Edge from "src/components/Graph/Edge";
import { JoinNode } from "src/components/Graph/JoinNode";
import { TaskNode } from "src/components/Graph/TaskNode";
import type { CustomNodeProps } from "src/components/Graph/reactflowUtils";
-import { useGraphLayout } from "src/components/Graph/useGraphLayout";
+import { type Direction, useGraphLayout } from
"src/components/Graph/useGraphLayout";
import { useColorMode } from "src/context/colorMode";
import { useOpenGroups } from "src/context/openGroups";
import useSelectedVersion from "src/hooks/useSelectedVersion";
@@ -95,6 +95,7 @@ export const Graph = () => {
const refetchInterval = useAutoRefresh({ dagId });
const [dependencies] = useLocalStorage<"all" | "immediate" |
"tasks">(`dependencies-${dagId}`, "immediate");
+ const [direction] = useLocalStorage<Direction>(`direction-${dagId}`,
"RIGHT");
const selectedColor = colorMode === "dark" ? selectedDarkColor :
selectedLightColor;
@@ -121,7 +122,7 @@ export const Graph = () => {
const dagDepNodes = dependencies === "all" ? dagDependencies.nodes : [];
const { data } = useGraphLayout({
- direction: "RIGHT",
+ direction,
edges: [...graphData.edges, ...dagDepEdges],
nodes: dagDepNodes.length
? dagDepNodes.map((node) =>
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/PanelButtons.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/PanelButtons.tsx
index bae3c7a5957..002ee2e9aca 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/PanelButtons.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/PanelButtons.tsx
@@ -31,6 +31,7 @@ import { useParams } from "react-router-dom";
import { useLocalStorage } from "usehooks-ts";
import DagVersionSelect from "src/components/DagVersionSelect";
+import { directionOptions, type Direction } from
"src/components/Graph/useGraphLayout";
import { Select } from "src/components/ui";
import { DagRunSelect } from "./DagRunSelect";
@@ -60,6 +61,7 @@ export const PanelButtons = ({ dagView, limit, setDagView,
setLimit, ...rest }:
`dependencies-${dagId}`,
"immediate",
);
+ const [direction, setDirection] =
useLocalStorage<Direction>(`direction-${dagId}`, "RIGHT");
const displayRunOptions = createListCollection({
items: [
{ label: "5", value: "5" },
@@ -84,6 +86,14 @@ export const PanelButtons = ({ dagView, limit, setDagView,
setLimit, ...rest }:
}
};
+ const handleDirectionUpdate = (
+ event: SelectValueChangeDetails<{ label: string; value: Array<string> }>,
+ ) => {
+ if (event.value[0] !== undefined) {
+ setDirection(event.value[0] as Direction);
+ }
+ };
+
return (
<HStack
alignItems="flex-start"
@@ -140,6 +150,25 @@ export const PanelButtons = ({ dagView, limit, setDagView,
setLimit, ...rest }:
</HStack>
{dagView === "graph" ? (
<>
+ <Select.Root
+ bg="bg"
+ collection={directionOptions}
+ onValueChange={handleDirectionUpdate}
+ size="sm"
+ value={[direction]}
+ width="150px"
+ >
+ <Select.Trigger>
+ <Select.ValueText />
+ </Select.Trigger>
+ <Select.Content>
+ {directionOptions.items.map((option) => (
+ <Select.Item item={option} key={option.value}>
+ {option.label}
+ </Select.Item>
+ ))}
+ </Select.Content>
+ </Select.Root>
<Select.Root
bg="bg"
collection={options}