This is an automated email from the ASF dual-hosted git repository.

jedcunningham 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 7ea7abc75d Adjust graph node layout (#37207)
7ea7abc75d is described below

commit 7ea7abc75d9bb8349e95fc330b43657950837d30
Author: Brent Bovenzi <[email protected]>
AuthorDate: Tue Feb 6 17:24:49 2024 -0500

    Adjust graph node layout (#37207)
---
 airflow/www/static/js/components/Graph/Edge.tsx    |  6 +-
 .../www/static/js/dag/details/graph/Node.test.tsx  |  1 +
 airflow/www/static/js/dag/details/graph/Node.tsx   | 79 ++++++++++++++--------
 airflow/www/static/js/dag/details/graph/index.tsx  | 14 ++++
 airflow/www/static/js/dag/details/graph/utils.ts   |  8 +++
 airflow/www/static/js/types/index.ts               |  1 +
 6 files changed, 80 insertions(+), 29 deletions(-)

diff --git a/airflow/www/static/js/components/Graph/Edge.tsx 
b/airflow/www/static/js/components/Graph/Edge.tsx
index 3d9e144795..99b6259055 100644
--- a/airflow/www/static/js/components/Graph/Edge.tsx
+++ b/airflow/www/static/js/components/Graph/Edge.tsx
@@ -32,6 +32,10 @@ const CustomEdge = ({ data }: EdgeProps) => {
   const { colors } = useTheme();
   if (!data) return null;
   const { rest } = data;
+  let strokeWidth = 2;
+  if (rest.isSelected) strokeWidth = 3;
+  if (rest.isZoomedOut) strokeWidth = 5;
+  if (rest.isZoomedOut && rest.isSelected) strokeWidth = 7;
   return (
     <>
       {rest?.labels?.map(({ id, x, y, text, width, height }) => {
@@ -48,7 +52,7 @@ const CustomEdge = ({ data }: EdgeProps) => {
         <LinePath
           key={s.id}
           stroke={rest.isSelected ? colors.blue[400] : colors.gray[400]}
-          strokeWidth={rest.isSelected ? 3 : 2}
+          strokeWidth={strokeWidth}
           x={(d) => d.x || 0}
           y={(d) => d.y || 0}
           data={[s.startPoint, ...(s.bendPoints || []), s.endPoint]}
diff --git a/airflow/www/static/js/dag/details/graph/Node.test.tsx 
b/airflow/www/static/js/dag/details/graph/Node.test.tsx
index 6e1a4bca13..251f3c6aeb 100644
--- a/airflow/www/static/js/dag/details/graph/Node.test.tsx
+++ b/airflow/www/static/js/dag/details/graph/Node.test.tsx
@@ -52,6 +52,7 @@ const mockNode: NodeProps<CustomNodeProps> = {
     latestDagRunId: "run_id",
     onToggleCollapse: () => {},
     isActive: true,
+    isZoomedOut: false,
   },
   selected: false,
   zIndex: 0,
diff --git a/airflow/www/static/js/dag/details/graph/Node.tsx 
b/airflow/www/static/js/dag/details/graph/Node.tsx
index 6c72f041ac..7be5ae7b88 100644
--- a/airflow/www/static/js/dag/details/graph/Node.tsx
+++ b/airflow/www/static/js/dag/details/graph/Node.tsx
@@ -46,6 +46,7 @@ export interface CustomNodeProps {
   setupTeardownType?: "setup" | "teardown";
   labelStyle?: string;
   style?: string;
+  isZoomedOut: boolean;
 }
 
 export const BaseNode = ({
@@ -65,6 +66,7 @@ export const BaseNode = ({
     setupTeardownType,
     labelStyle,
     style,
+    isZoomedOut,
   },
 }: NodeProps<CustomNodeProps>) => {
   const { colors } = useTheme();
@@ -92,6 +94,8 @@ export const BaseNode = ({
   if (labelStyle) {
     [, operatorTextColor] = labelStyle.split(":");
   }
+  if (!operatorTextColor || operatorTextColor === "#000;")
+    operatorTextColor = "gray.500";
 
   const nodeBorderColor =
     instance?.state && stateColors[instance.state]
@@ -111,10 +115,15 @@ export const BaseNode = ({
       openDelay={hoverDelay}
     >
       <Box
-        borderRadius={5}
-        borderWidth={isSelected ? 2.5 : 1.5}
+        borderRadius={isZoomedOut ? 10 : 5}
+        borderWidth={(isSelected ? 4 : 2) * (isZoomedOut ? 3 : 1)}
         borderColor={nodeBorderColor}
-        bg={isSelected ? "blue.50" : bg}
+        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"}
@@ -134,13 +143,16 @@ export const BaseNode = ({
           justifyContent="space-between"
           width={width}
           p={2}
-          flexWrap="wrap"
+          flexWrap={isZoomedOut ? "nowrap" : "wrap"}
+          flexDirection={isZoomedOut ? "row" : "column"}
         >
           <Flex flexDirection="column" width="100%">
             <Flex
               justifyContent="space-between"
               alignItems="center"
               width="100%"
+              fontSize={isZoomedOut ? 25 : undefined}
+              fontWeight="bold"
             >
               <Text noOfLines={1} maxWidth={`calc(${width}px - 8px)`}>
                 {taskName}
@@ -152,37 +164,48 @@ export const BaseNode = ({
                 <ImArrowDownRight2 size={15} color={colors.gray[800]} />
               )}
             </Flex>
-            {!!instance && instance.state && (
-              <Flex alignItems="center">
-                <SimpleStatus state={instance.state} />
-                <Text ml={2} color="gray.500" fontSize="lg">
-                  {instance.state}
-                </Text>
-              </Flex>
-            )}
-            {task?.operator && (
-              <Text
-                noOfLines={1}
-                maxWidth={`calc(${width}px - 12px)`}
-                fontWeight={400}
-                fontSize="md"
-                width="fit-content"
-                borderRadius={5}
-                bg={operatorBG}
-                color={operatorTextColor || "gray.500"}
-                px={1}
-              >
-                {task.operator}
-              </Text>
+            {!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>
+                )}
+              </>
             )}
           </Flex>
           {!!childCount && (
             <Text
+              noOfLines={1}
+              fontSize={isZoomedOut ? 25 : undefined}
               color="blue.600"
               cursor="pointer"
+              width="150px"
+              fontWeight="bold"
               // Increase the target area to expand/collapse a group
-              p={3}
-              m={-3}
+              p={2}
+              m={-2}
               onClick={(e) => {
                 e.stopPropagation();
                 onToggleCollapse();
diff --git a/airflow/www/static/js/dag/details/graph/index.tsx 
b/airflow/www/static/js/dag/details/graph/index.tsx
index 29e07d65aa..4fb3d21f6c 100644
--- a/airflow/www/static/js/dag/details/graph/index.tsx
+++ b/airflow/www/static/js/dag/details/graph/index.tsx
@@ -26,6 +26,8 @@ import ReactFlow, {
   MiniMap,
   useReactFlow,
   Panel,
+  useOnViewportChange,
+  Viewport,
 } from "reactflow";
 
 import { useGraphData, useGridData } from "src/api";
@@ -51,6 +53,7 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
   const { data } = useGraphData();
   const [arrange, setArrange] = useState(data?.arrange || "LR");
   const [hasRendered, setHasRendered] = useState(false);
+  const [isZoomedOut, setIsZoomedOut] = useState(false);
 
   useEffect(() => {
     setArrange(data?.arrange || "LR");
@@ -71,6 +74,13 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
   const latestDagRunId = dagRuns[dagRuns.length - 1]?.runId;
   const offsetTop = useOffsetTop(graphRef);
 
+  useOnViewportChange({
+    onEnd: (viewport: Viewport) => {
+      if (viewport.zoom < 0.5 && !isZoomedOut) setIsZoomedOut(true);
+      if (viewport.zoom >= 0.5 && isZoomedOut) setIsZoomedOut(false);
+    },
+  });
+
   const { nodes, edges: nodeEdges } = useMemo(
     () =>
       flattenNodes({
@@ -81,6 +91,7 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
         latestDagRunId,
         groups,
         hoveredTaskState,
+        isZoomedOut,
       }),
     [
       graphData?.children,
@@ -90,6 +101,7 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
       latestDagRunId,
       groups,
       hoveredTaskState,
+      isZoomedOut,
     ]
   );
 
@@ -97,6 +109,7 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
   useEffect(() => {
     if (hasRendered) {
       const zoom = getZoom();
+      if (zoom < 0.5) setIsZoomedOut(true);
       fitView({
         duration: 750,
         nodes: selected.taskId ? [{ id: selected.taskId }] : undefined,
@@ -116,6 +129,7 @@ const Graph = ({ openGroupIds, onToggleGroups, 
hoveredTaskState }: Props) => {
     edges: flatEdges,
     nodes,
     selectedTaskId: selected.taskId,
+    isZoomedOut,
   });
 
   return (
diff --git a/airflow/www/static/js/dag/details/graph/utils.ts 
b/airflow/www/static/js/dag/details/graph/utils.ts
index ac940d46c7..901b47ab18 100644
--- a/airflow/www/static/js/dag/details/graph/utils.ts
+++ b/airflow/www/static/js/dag/details/graph/utils.ts
@@ -36,6 +36,7 @@ interface FlattenNodesProps {
   openGroupIds: string[];
   onToggleGroups: (groupIds: string[]) => void;
   hoveredTaskState?: string | null;
+  isZoomedOut: boolean;
 }
 
 // Generate a flattened list of nodes for react-flow to render
@@ -48,6 +49,7 @@ export const flattenNodes = ({
   openGroupIds,
   parent,
   hoveredTaskState,
+  isZoomedOut,
 }: FlattenNodesProps) => {
   let nodes: ReactFlowNode<CustomNodeProps>[] = [];
   let edges: ElkExtendedEdge[] = [];
@@ -76,6 +78,7 @@ export const flattenNodes = ({
         isSelected,
         latestDagRunId,
         isActive,
+        isZoomedOut,
         onToggleCollapse: () => {
           let newGroupIds = [];
           if (!node.value.isOpen) {
@@ -115,6 +118,7 @@ export const flattenNodes = ({
         openGroupIds,
         parent: newNode,
         hoveredTaskState,
+        isZoomedOut,
       });
       nodes = [...nodes, ...childNodes];
       edges = [...edges, ...childEdges];
@@ -153,6 +157,7 @@ interface BuildEdgesProps {
   edges?: Edge[];
   nodes: ReactFlowNode<CustomNodeProps>[];
   selectedTaskId?: string | null;
+  isZoomedOut?: boolean;
 }
 
 // Format edge data to what react-flow needs to render successfully
@@ -160,6 +165,7 @@ export const buildEdges = ({
   edges = [],
   nodes,
   selectedTaskId,
+  isZoomedOut,
 }: BuildEdgesProps) =>
   edges
     .map((edge) => ({
@@ -184,6 +190,7 @@ export const buildEdges = ({
           ...e,
           data: {
             rest: {
+              isZoomedOut,
               ...e.data.rest,
               labels: e.data.rest.labels?.map((l) =>
                 l.x && l.y ? { ...l, x: l.x + parentX, y: l.y + parentY } : l
@@ -215,6 +222,7 @@ export const buildEdges = ({
           rest: {
             ...e.data.rest,
             isSelected,
+            isZoomedOut,
           },
         },
       };
diff --git a/airflow/www/static/js/types/index.ts 
b/airflow/www/static/js/types/index.ts
index a75c1ace23..b9ada90370 100644
--- a/airflow/www/static/js/types/index.ts
+++ b/airflow/www/static/js/types/index.ts
@@ -165,6 +165,7 @@ export interface EdgeData {
     layoutOptions?: LayoutOptions;
     isSetupTeardown?: boolean;
     parentNode?: string;
+    isZoomedOut?: boolean;
   };
 }
 

Reply via email to