diff --git a/airflow/www/static/js/components/Graph/Edge.tsx b/airflow/www/static/js/components/Graph/Edge.tsx index 3d9e1447952aa..99b62590559d1 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) => { 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 6e1a4bca134ac..251f3c6aeb1d4 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 = { 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 6c72f041ac23a..7be5ae7b887b3 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) => { 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} > {taskName} @@ -152,37 +164,48 @@ export const BaseNode = ({ )} - {!!instance && instance.state && ( - - - - {instance.state} - - - )} - {task?.operator && ( - - {task.operator} - + {!isZoomedOut && ( + <> + {!!instance && instance.state && ( + + + + {instance.state} + + + )} + {task?.operator && ( + + {task.operator} + + )} + )} {!!childCount && ( { 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 29e07d65aa320..4fb3d21f6c13a 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 ac940d46c7847..901b47ab18031 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[] = []; 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[]; 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 a75c1ace23ca0..b9ada90370907 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; }; }