You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2025/04/23 18:22:27 UTC
(airflow) 02/12: feature(ui): Make entire task box clickable to select the task in Air… (#49299)
This is an automated email from the ASF dual-hosted git repository.
kaxilnaik pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 9dae52a3d3b588dd154d13146aef0a434463d0c2
Author: Jason <46...@users.noreply.github.com>
AuthorDate: Thu Apr 24 00:36:44 2025 +0700
feature(ui): Make entire task box clickable to select the task in Air… (#49299)
* feature(ui): Make entire task node clickable to select the task
* Add z-index to TogglePause for clickability
* Remove link component
* Remove unnecessary onClick handler from LinkOverlay
* Forward ref from LinkOverlay
(cherry picked from commit 20bdf5fc82415b6d67237794fd49174703af9230)
---
.../airflow/ui/src/components/Graph/AssetNode.tsx | 6 ++---
.../airflow/ui/src/components/Graph/DagNode.tsx | 13 +++++++----
.../airflow/ui/src/components/Graph/TaskLink.tsx | 27 +++++++++++-----------
.../airflow/ui/src/components/Graph/TaskNode.tsx | 22 ++++++++++--------
4 files changed, 37 insertions(+), 31 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/components/Graph/AssetNode.tsx b/airflow-core/src/airflow/ui/src/components/Graph/AssetNode.tsx
index 3d4539caf01..b95faf0fd86 100644
--- a/airflow-core/src/airflow/ui/src/components/Graph/AssetNode.tsx
+++ b/airflow-core/src/airflow/ui/src/components/Graph/AssetNode.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Flex, Heading, HStack, Link, Text } from "@chakra-ui/react";
+import { Flex, Heading, HStack, LinkOverlay, Text } from "@chakra-ui/react";
import type { NodeProps, Node as NodeType } from "@xyflow/react";
import { FiDatabase } from "react-icons/fi";
import { useParams, Link as RouterLink } from "react-router-dom";
@@ -69,9 +69,9 @@ export const AssetNode = ({
<Heading ml={-2} size="sm">
<FiDatabase />
</Heading>
- <Link asChild color="fg.info">
+ <LinkOverlay asChild>
<RouterLink to={`/assets/${assetId}`}>{label}</RouterLink>
- </Link>
+ </LinkOverlay>
</HStack>
{assetEvent === undefined ? undefined : (
<>
diff --git a/airflow-core/src/airflow/ui/src/components/Graph/DagNode.tsx b/airflow-core/src/airflow/ui/src/components/Graph/DagNode.tsx
index 73dfaf537f4..83b3db2d4d0 100644
--- a/airflow-core/src/airflow/ui/src/components/Graph/DagNode.tsx
+++ b/airflow-core/src/airflow/ui/src/components/Graph/DagNode.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Flex, HStack, Link } from "@chakra-ui/react";
+import { Flex, HStack, LinkOverlay } from "@chakra-ui/react";
import type { NodeProps, Node as NodeType } from "@xyflow/react";
import { Link as RouterLink } from "react-router-dom";
@@ -47,11 +47,16 @@ export const DagNode = ({
>
<HStack alignItems="center" justifyContent="space-between">
<DagIcon />
- <TogglePause dagId={dag?.dag_id ?? label} disabled={!Boolean(dag)} isPaused={dag?.is_paused} />
+ <TogglePause
+ dagId={dag?.dag_id ?? label}
+ disabled={!Boolean(dag)}
+ isPaused={dag?.is_paused}
+ style={{ zIndex: 2 }}
+ />
</HStack>
- <Link asChild color="fg.info" mb={2}>
+ <LinkOverlay asChild>
<RouterLink to={`/dags/${dag?.dag_id ?? label}`}>{dag?.dag_display_name ?? label}</RouterLink>
- </Link>
+ </LinkOverlay>
</Flex>
</NodeWrapper>
);
diff --git a/airflow-core/src/airflow/ui/src/components/Graph/TaskLink.tsx b/airflow-core/src/airflow/ui/src/components/Graph/TaskLink.tsx
index 685e79737ec..278c6af3092 100644
--- a/airflow-core/src/airflow/ui/src/components/Graph/TaskLink.tsx
+++ b/airflow-core/src/airflow/ui/src/components/Graph/TaskLink.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Link } from "@chakra-ui/react";
+import { forwardRef } from "react";
import { useParams, useSearchParams, Link as RouterLink } from "react-router-dom";
import { TaskName, type TaskNameProps } from "src/components/TaskName";
@@ -25,7 +25,7 @@ type Props = {
readonly id: string;
} & TaskNameProps;
-export const TaskLink = ({ id, isGroup, isMapped, ...rest }: Props) => {
+export const TaskLink = forwardRef<HTMLAnchorElement, Props>(({ id, isGroup, isMapped, ...rest }, ref) => {
const { dagId = "", runId, taskId } = useParams();
const [searchParams] = useSearchParams();
@@ -35,16 +35,15 @@ export const TaskLink = ({ id, isGroup, isMapped, ...rest }: Props) => {
}
return (
- <Link asChild data-testid={id}>
- <RouterLink
- to={{
- // Do not include runId if there is no selected run, clicking a second time will deselect a task id
- pathname: `/dags/${dagId}/${runId === undefined ? "" : `runs/${runId}/`}${taskId === id ? "" : `tasks/${id}`}${isMapped && taskId !== id && runId !== undefined ? "/mapped" : ""}`,
- search: searchParams.toString(),
- }}
- >
- <TaskName isMapped={isMapped} {...rest} />
- </RouterLink>
- </Link>
+ <RouterLink
+ ref={ref}
+ to={{
+ // Do not include runId if there is no selected run, clicking a second time will deselect a task id
+ pathname: `/dags/${dagId}/${runId === undefined ? "" : `runs/${runId}/`}${taskId === id ? "" : `tasks/${id}`}${isMapped && taskId !== id && runId !== undefined ? "/mapped" : ""}`,
+ search: searchParams.toString(),
+ }}
+ >
+ <TaskName isMapped={isMapped} {...rest} />
+ </RouterLink>
);
-};
+});
diff --git a/airflow-core/src/airflow/ui/src/components/Graph/TaskNode.tsx b/airflow-core/src/airflow/ui/src/components/Graph/TaskNode.tsx
index 657b6d51cd1..6f513066a13 100644
--- a/airflow-core/src/airflow/ui/src/components/Graph/TaskNode.tsx
+++ b/airflow-core/src/airflow/ui/src/components/Graph/TaskNode.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Box, Button, Flex, HStack, Text } from "@chakra-ui/react";
+import { Box, Button, Flex, HStack, LinkOverlay, Text } from "@chakra-ui/react";
import type { NodeProps, Node as NodeType } from "@xyflow/react";
import { CgRedo } from "react-icons/cg";
@@ -78,15 +78,17 @@ export const TaskNode = ({
width={`${width + (isSelected ? 4 : 0)}px`}
>
<Box>
- <TaskLink
- childCount={taskInstance?.task_count}
- id={id}
- isGroup={isGroup}
- isMapped={isMapped}
- isOpen={isOpen}
- label={label}
- setupTeardownType={setupTeardownType}
- />
+ <LinkOverlay asChild>
+ <TaskLink
+ childCount={taskInstance?.task_count}
+ id={id}
+ isGroup={isGroup}
+ isMapped={isMapped}
+ isOpen={isOpen}
+ label={label}
+ setupTeardownType={setupTeardownType}
+ />
+ </LinkOverlay>
<Text color="fg.muted" fontSize="sm" textTransform="capitalize">
{isGroup ? "Task Group" : operator}
</Text>