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 359447665af Restore hover+selection crosshairs to grid view (#50050)
359447665af is described below
commit 359447665af41b43913f8cf7a22d9b9b353a7cf9
Author: Brent Bovenzi <[email protected]>
AuthorDate: Thu May 1 11:32:21 2025 -0400
Restore hover+selection crosshairs to grid view (#50050)
---
.../airflow/ui/src/layouts/Details/Grid/Grid.tsx | 2 +-
.../airflow/ui/src/layouts/Details/Grid/GridTI.tsx | 105 +++++++++++----------
.../ui/src/layouts/Details/Grid/TaskNames.tsx | 22 ++++-
3 files changed, 76 insertions(+), 53 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
index ba4ecad0b01..75fe7209dc8 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/Grid.tsx
@@ -72,7 +72,7 @@ export const Grid = ({ limit }: Props) => {
return (
<Flex justifyContent="flex-start" position="relative" pt={50} width="100%">
- <Box flexGrow={1} minWidth={7} mr={3} position="relative" top="100px">
+ <Box flexGrow={1} minWidth={7} position="relative" top="100px">
<TaskNames nodes={flatNodes} />
</Box>
<Box position="relative">
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/GridTI.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/GridTI.tsx
index 85a8342d8ac..08a17ea9e75 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/GridTI.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/GridTI.tsx
@@ -19,7 +19,7 @@
import { Badge, Flex } from "@chakra-ui/react";
import type { MouseEvent } from "react";
import React from "react";
-import { Link } from "react-router-dom";
+import { Link, useParams } from "react-router-dom";
import type { TaskInstanceState } from "openapi/requests/types.gen";
import { StateIcon } from "src/components/StateIcon";
@@ -36,7 +36,7 @@ type Props = {
};
const onMouseEnter = (event: MouseEvent<HTMLDivElement>) => {
- const tasks =
document.querySelectorAll<HTMLDivElement>(`#name-${event.currentTarget.id}`);
+ const tasks =
document.querySelectorAll<HTMLDivElement>(`#${event.currentTarget.id}`);
tasks.forEach((task) => {
task.style.backgroundColor = "var(--chakra-colors-blue-subtle)";
@@ -44,56 +44,32 @@ const onMouseEnter = (event: MouseEvent<HTMLDivElement>) =>
{
};
const onMouseLeave = (event: MouseEvent<HTMLDivElement>) => {
- const tasks =
document.querySelectorAll<HTMLDivElement>(`#name-${event.currentTarget.id}`);
+ const tasks =
document.querySelectorAll<HTMLDivElement>(`#${event.currentTarget.id}`);
tasks.forEach((task) => {
task.style.backgroundColor = "";
});
};
-const Instance = ({ dagId, isGroup, isMapped, runId, search, state, taskId }:
Props) => (
- <Flex
- alignItems="center"
- height="20px"
- id={taskId.replaceAll(".", "-")}
- justifyContent="center"
- key={taskId}
- onMouseEnter={onMouseEnter}
- onMouseLeave={onMouseLeave}
- px="2px"
- py={0}
- transition="background-color 0.2s"
- zIndex={1}
- >
- {isGroup ? (
- <Badge
- borderRadius={4}
- colorPalette={state === null ? "none" : state}
- height="14px"
- minH={0}
- opacity={state === "success" ? 0.6 : 1}
- p={0}
- variant="solid"
- width="14px"
- >
- {state === undefined ? undefined : (
- <StateIcon
- size={10}
- state={state}
- style={{
- marginLeft: "2px",
- }}
- />
- )}
- </Badge>
- ) : (
- <Link
- replace
- to={{
- pathname: `/dags/${dagId}/runs/${runId}/tasks/${taskId}${isMapped ?
"/mapped" : ""}`,
- search,
- }}
- >
+const Instance = ({ dagId, isGroup, isMapped, runId, search, state, taskId }:
Props) => {
+ const { taskId: selectedTaskId } = useParams();
+
+ return (
+ <Flex
+ alignItems="center"
+ bg={selectedTaskId === taskId ? "blue.muted" : undefined}
+ height="20px"
+ id={taskId.replaceAll(".", "-")}
+ justifyContent="center"
+ key={taskId}
+ onMouseEnter={onMouseEnter}
+ onMouseLeave={onMouseLeave}
+ px="2px"
+ py={0}
+ transition="background-color 0.2s"
+ zIndex={1}
+ >
+ {isGroup ? (
<Badge
borderRadius={4}
colorPalette={state === null ? "none" : state}
@@ -114,9 +90,38 @@ const Instance = ({ dagId, isGroup, isMapped, runId,
search, state, taskId }: Pr
/>
)}
</Badge>
- </Link>
- )}
- </Flex>
-);
+ ) : (
+ <Link
+ replace
+ to={{
+ pathname: `/dags/${dagId}/runs/${runId}/tasks/${taskId}${isMapped
? "/mapped" : ""}`,
+ search,
+ }}
+ >
+ <Badge
+ borderRadius={4}
+ colorPalette={state === null ? "none" : state}
+ height="14px"
+ minH={0}
+ opacity={state === "success" ? 0.6 : 1}
+ p={0}
+ variant="solid"
+ width="14px"
+ >
+ {state === undefined ? undefined : (
+ <StateIcon
+ size={10}
+ state={state}
+ style={{
+ marginLeft: "2px",
+ }}
+ />
+ )}
+ </Badge>
+ </Link>
+ )}
+ </Flex>
+ );
+};
export const GridTI = React.memo(Instance);
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
index 4fe7420c8a9..60105579223 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Grid/TaskNames.tsx
@@ -17,6 +17,7 @@
* under the License.
*/
import { Box, chakra, Flex, Link } from "@chakra-ui/react";
+import type { MouseEvent } from "react";
import { FiChevronUp } from "react-icons/fi";
import { Link as RouterLink, useParams, useSearchParams } from
"react-router-dom";
@@ -30,6 +31,22 @@ type Props = {
nodes: Array<GridTask>;
};
+const onMouseEnter = (event: MouseEvent<HTMLDivElement>) => {
+ const tasks =
document.querySelectorAll<HTMLDivElement>(`#${event.currentTarget.id}`);
+
+ tasks.forEach((task) => {
+ task.style.backgroundColor = "var(--chakra-colors-blue-subtle)";
+ });
+};
+
+const onMouseLeave = (event: MouseEvent<HTMLDivElement>) => {
+ const tasks =
document.querySelectorAll<HTMLDivElement>(`#${event.currentTarget.id}`);
+
+ tasks.forEach((task) => {
+ task.style.backgroundColor = "";
+ });
+};
+
export const TaskNames = ({ nodes }: Props) => {
const { toggleGroupId } = useOpenGroups();
const { dagId = "", taskId } = useParams();
@@ -37,13 +54,14 @@ export const TaskNames = ({ nodes }: Props) => {
return nodes.map((node) => (
<Box
- _hover={{ bg: "blue.subtle" }}
bg={node.id === taskId ? "blue.muted" : undefined}
borderBottomWidth={1}
borderColor={node.isGroup ? "border.emphasized" : "border.muted"}
- id={`name-${node.id.replaceAll(".", "-")}`}
+ id={node.id.replaceAll(".", "-")}
key={node.id}
maxHeight="20px"
+ onMouseEnter={onMouseEnter}
+ onMouseLeave={onMouseLeave}
transition="background-color 0.2s"
>
{node.isGroup ? (