This is an automated email from the ASF dual-hosted git repository.
pierrejeambrun pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-0-test by this push:
new c53b53a5f56 Move asset events to its own tab (#51625) (#51655)
c53b53a5f56 is described below
commit c53b53a5f56a62ef371c3293ece943fb0dbe6895
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Thu Jun 12 15:35:35 2025 +0200
Move asset events to its own tab (#51625) (#51655)
* Move asset events to its own tab
* Address PR comments
(cherry picked from commit e8505aaff3a081b87c57bb725598af1b2bb7c656)
---
.../src/airflow/ui/src/pages/Run/AssetEvents.tsx | 45 +++++++++++++++++++
.../src/airflow/ui/src/pages/Run/Details.tsx | 11 +----
airflow-core/src/airflow/ui/src/pages/Run/Run.tsx | 5 ++-
.../src/airflow/ui/src/pages/Task/Task.tsx | 2 +-
.../ui/src/pages/TaskInstance/AssetEvents.tsx | 51 ++++++++++++++++++++++
.../airflow/ui/src/pages/TaskInstance/Details.tsx | 18 --------
.../ui/src/pages/TaskInstance/TaskInstance.tsx | 5 ++-
airflow-core/src/airflow/ui/src/router.tsx | 4 ++
8 files changed, 108 insertions(+), 33 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/pages/Run/AssetEvents.tsx
b/airflow-core/src/airflow/ui/src/pages/Run/AssetEvents.tsx
new file mode 100644
index 00000000000..c7fd536b950
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/Run/AssetEvents.tsx
@@ -0,0 +1,45 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useParams } from "react-router-dom";
+
+import { useDagRunServiceGetDagRun, useDagRunServiceGetUpstreamAssetEvents }
from "openapi/queries";
+import { AssetEvents as AssetEventsTable } from
"src/components/Assets/AssetEvents";
+import { isStatePending, useAutoRefresh } from "src/utils";
+
+export const AssetEvents = () => {
+ const { dagId = "", runId = "" } = useParams();
+
+ const refetchInterval = useAutoRefresh({ dagId });
+
+ const { data: dagRun } = useDagRunServiceGetDagRun(
+ {
+ dagId,
+ dagRunId: runId,
+ },
+ undefined,
+ { refetchInterval: (query) => (isStatePending(query.state.data?.state) ?
refetchInterval : false) },
+ );
+
+ const { data, isLoading } = useDagRunServiceGetUpstreamAssetEvents({ dagId,
dagRunId: runId }, undefined, {
+ enabled: dagRun?.run_type === "asset_triggered",
+ refetchInterval: () => (isStatePending(dagRun?.state) ? refetchInterval :
false),
+ });
+
+ return <AssetEventsTable data={data} isLoading={isLoading} title="Source
Asset Event" />;
+};
diff --git a/airflow-core/src/airflow/ui/src/pages/Run/Details.tsx
b/airflow-core/src/airflow/ui/src/pages/Run/Details.tsx
index 43140625fbe..582f6182071 100644
--- a/airflow-core/src/airflow/ui/src/pages/Run/Details.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Run/Details.tsx
@@ -19,8 +19,7 @@
import { Box, Flex, HStack, StackSeparator, Table, Text, VStack } from
"@chakra-ui/react";
import { useParams } from "react-router-dom";
-import { useDagRunServiceGetDagRun, useDagRunServiceGetUpstreamAssetEvents }
from "openapi/queries";
-import { AssetEvents } from "src/components/Assets/AssetEvents";
+import { useDagRunServiceGetDagRun } from "openapi/queries";
import { DagVersionDetails } from "src/components/DagVersionDetails";
import RenderedJsonField from "src/components/RenderedJsonField";
import { RunTypeIcon } from "src/components/RunTypeIcon";
@@ -43,17 +42,9 @@ export const Details = () => {
{ refetchInterval: (query) => (isStatePending(query.state.data?.state) ?
refetchInterval : false) },
);
- const { data, isLoading } = useDagRunServiceGetUpstreamAssetEvents({ dagId,
dagRunId: runId }, undefined, {
- enabled: dagRun?.run_type === "asset_triggered",
- refetchInterval: () => (isStatePending(dagRun?.state) ? refetchInterval :
false),
- });
-
// TODO : Render DagRun configuration object
return (
<Box p={2}>
- {data === undefined || dagRun?.run_type !== "asset_triggered" ?
undefined : (
- <AssetEvents data={data} isLoading={isLoading} title="Source Asset
Event" />
- )}
{dagRun === undefined ? (
<div />
) : (
diff --git a/airflow-core/src/airflow/ui/src/pages/Run/Run.tsx
b/airflow-core/src/airflow/ui/src/pages/Run/Run.tsx
index 04ffb61cd89..5b4dfffd3e5 100644
--- a/airflow-core/src/airflow/ui/src/pages/Run/Run.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Run/Run.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
import { ReactFlowProvider } from "@xyflow/react";
-import { FiCode } from "react-icons/fi";
+import { FiCode, FiDatabase } from "react-icons/fi";
import { MdDetails, MdOutlineEventNote, MdOutlineTask } from "react-icons/md";
import { useParams } from "react-router-dom";
@@ -29,9 +29,10 @@ import { Header } from "./Header";
const tabs = [
{ icon: <MdOutlineTask />, label: "Task Instances", value: "" },
- { icon: <MdOutlineEventNote />, label: "Events", value: "events" },
+ { icon: <MdOutlineEventNote />, label: "Audit Logs", value: "events" },
{ icon: <FiCode />, label: "Code", value: "code" },
{ icon: <MdDetails />, label: "Details", value: "details" },
+ { icon: <FiDatabase />, label: "Asset Events", value: "asset_events" },
];
export const Run = () => {
diff --git a/airflow-core/src/airflow/ui/src/pages/Task/Task.tsx
b/airflow-core/src/airflow/ui/src/pages/Task/Task.tsx
index 44da8f8368b..3c772cf32c1 100644
--- a/airflow-core/src/airflow/ui/src/pages/Task/Task.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Task/Task.tsx
@@ -29,7 +29,7 @@ import { Header } from "./Header";
const tabs = [
{ icon: <LuChartColumn />, label: "Overview", value: "" },
{ icon: <MdOutlineTask />, label: "Task Instances", value: "task_instances"
},
- { icon: <MdOutlineEventNote />, label: "Events", value: "events" },
+ { icon: <MdOutlineEventNote />, label: "Audit Logs", value: "events" },
];
export const Task = () => {
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
new file mode 100644
index 00000000000..d5917aa8aab
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
@@ -0,0 +1,51 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { useParams } from "react-router-dom";
+
+import { useAssetServiceGetAssetEvents,
useTaskInstanceServiceGetMappedTaskInstance } from "openapi/queries";
+import { AssetEvents as AssetEventsTable } from
"src/components/Assets/AssetEvents";
+import { isStatePending, useAutoRefresh } from "src/utils";
+
+export const AssetEvents = () => {
+ const { dagId = "", mapIndex = "-1", runId = "", taskId = "" } = useParams();
+
+ const { data: taskInstance } = useTaskInstanceServiceGetMappedTaskInstance({
+ dagId,
+ dagRunId: runId,
+ mapIndex: parseInt(mapIndex, 10),
+ taskId,
+ });
+
+ const refetchInterval = useAutoRefresh({ dagId });
+
+ const { data: assetEventsData, isLoading } = useAssetServiceGetAssetEvents(
+ {
+ sourceDagId: dagId,
+ sourceMapIndex: parseInt(mapIndex, 10),
+ sourceRunId: runId,
+ sourceTaskId: taskId,
+ },
+ undefined,
+ {
+ refetchInterval: () => (isStatePending(taskInstance?.state) ?
refetchInterval : false),
+ },
+ );
+
+ return <AssetEventsTable data={assetEventsData} isLoading={isLoading}
title="Created Asset Event" />;
+};
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
index f02b27dbcfc..9fed186008f 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
@@ -20,11 +20,9 @@ import { Box, Flex, HStack, Table, Heading } from
"@chakra-ui/react";
import { useParams, useSearchParams } from "react-router-dom";
import {
- useAssetServiceGetAssetEvents,
useTaskInstanceServiceGetMappedTaskInstance,
useTaskInstanceServiceGetTaskInstanceTryDetails,
} from "openapi/queries";
-import { AssetEvents } from "src/components/Assets/AssetEvents";
import { DagVersionDetails } from "src/components/DagVersionDetails";
import { StateBadge } from "src/components/StateBadge";
import { TaskTrySelect } from "src/components/TaskTrySelect";
@@ -76,24 +74,8 @@ export const Details = () => {
},
);
- const { data: assetEventsData, isLoading: isLoadingAssetEvents } =
useAssetServiceGetAssetEvents(
- {
- sourceDagId: dagId,
- sourceMapIndex: parseInt(mapIndex, 10),
- sourceRunId: runId,
- sourceTaskId: taskId,
- },
- undefined,
- {
- refetchInterval: () => (isStatePending(taskInstance?.state) ?
refetchInterval : false),
- },
- );
-
return (
<Box p={2}>
- {assetEventsData !== undefined && assetEventsData.asset_events.length >
0 ? (
- <AssetEvents data={assetEventsData} isLoading={isLoadingAssetEvents}
title="Created Asset Event" />
- ) : undefined}
{taskInstance === undefined || tryNumber === undefined ||
taskInstance.try_number <= 1 ? (
<div />
) : (
diff --git
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
index 8e19e7dbec2..c11fce76741 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
@@ -17,7 +17,7 @@
* under the License.
*/
import { ReactFlowProvider } from "@xyflow/react";
-import { FiCode } from "react-icons/fi";
+import { FiCode, FiDatabase } from "react-icons/fi";
import { MdDetails, MdOutlineEventNote, MdOutlineTask, MdReorder, MdSyncAlt }
from "react-icons/md";
import { PiBracketsCurlyBold } from "react-icons/pi";
import { useParams } from "react-router-dom";
@@ -36,9 +36,10 @@ const tabs = [
{ icon: <MdReorder />, label: "Logs", value: "" },
{ icon: <PiBracketsCurlyBold />, label: "Rendered Templates", value:
"rendered_templates" },
{ icon: <MdSyncAlt />, label: "XCom", value: "xcom" },
- { icon: <MdOutlineEventNote />, label: "Events", value: "events" },
+ { icon: <MdOutlineEventNote />, label: "Audit Logs", value: "events" },
{ icon: <FiCode />, label: "Code", value: "code" },
{ icon: <MdDetails />, label: "Details", value: "details" },
+ { icon: <FiDatabase />, label: "Asset Events", value: "asset_events" },
];
export const TaskInstance = () => {
diff --git a/airflow-core/src/airflow/ui/src/router.tsx
b/airflow-core/src/airflow/ui/src/router.tsx
index 77d55de10bf..30437d251bc 100644
--- a/airflow-core/src/airflow/ui/src/router.tsx
+++ b/airflow-core/src/airflow/ui/src/router.tsx
@@ -53,7 +53,9 @@ import { Variables } from "src/pages/Variables";
import { XCom } from "src/pages/XCom";
import { Configs } from "./pages/Configs";
+import { AssetEvents as DagRunAssetEvents } from "./pages/Run/AssetEvents";
import { Security } from "./pages/Security";
+import { AssetEvents as TaskInstanceAssetEvents } from
"./pages/TaskInstance/AssetEvents";
import { client } from "./queryClient";
const taskInstanceRoutes = [
@@ -64,6 +66,7 @@ const taskInstanceRoutes = [
{ element: <TaskInstanceDetails />, path: "details" },
{ element: <RenderedTemplates />, path: "rendered_templates" },
{ element: <TaskInstances />, path: "task_instances" },
+ { element: <TaskInstanceAssetEvents />, path: "asset_events" },
];
export const routerConfig = [
@@ -156,6 +159,7 @@ export const routerConfig = [
{ element: <Events />, path: "events" },
{ element: <Code />, path: "code" },
{ element: <DagRunDetails />, path: "details" },
+ { element: <DagRunAssetEvents />, path: "asset_events" },
],
element: <Run />,
path: "dags/:dagId/runs/:runId",