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

amoghrajesh 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 40aac72bef2 UI: Add a column in asset store display table linking to 
the TI that wrote it (#68395)
40aac72bef2 is described below

commit 40aac72bef2d83523ec719f272e36362e03ce44d
Author: Amogh Desai <[email protected]>
AuthorDate: Fri Jun 12 09:38:41 2026 +0530

    UI: Add a column in asset store display table linking to the TI that wrote 
it (#68395)
---
 .../airflow/ui/public/i18n/locales/en/assets.json  |  3 ++
 .../ui/src/pages/Asset/AssetStore/AssetStore.tsx   | 57 ++++++++++++++++++++--
 2 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/assets.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/en/assets.json
index 2e933a2fbcc..95b7fe7c5da 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/assets.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/assets.json
@@ -13,6 +13,9 @@
     "deleteWarning": "The asset will lose this persisted store entry.",
     "edit": "Edit Asset Store",
     "emptyState": "Asset store stores values scoped to an asset identity, 
shared across all Dag runs. Workers can write asset store via the Task SDK.",
+    "lastUpdatedBy": "Last Updated By",
+    "lastUpdatedByApi": "API",
+    "lastUpdatedByWatcher": "Watcher",
     "title": "Asset Store"
   },
   "consumingDags": "Consuming Dags",
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStore/AssetStore.tsx 
b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStore/AssetStore.tsx
index 418a46b17cd..99ca52fc5be 100644
--- a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStore/AssetStore.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStore/AssetStore.tsx
@@ -16,24 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Flex, Text } from "@chakra-ui/react";
+import { Flex, Link, Text } from "@chakra-ui/react";
 import type { ColumnDef } from "@tanstack/react-table";
 import { useTranslation } from "react-i18next";
-import { useParams } from "react-router-dom";
+import { Link as RouterLink, useParams } from "react-router-dom";
 
 import { useAssetStoreServiceListAssetStore } from "openapi/queries";
-import type { AssetStoreResponse } from "openapi/requests";
+import type { AssetStoreLastUpdatedBy, AssetStoreResponse } from 
"openapi/requests";
 import { DataTable } from "src/components/DataTable";
 import { useTableURLState } from "src/components/DataTable/useTableUrlState";
 import { ErrorAlert } from "src/components/ErrorAlert";
 import { StoreValueCell } from "src/components/StoreValueCell";
 import Time from "src/components/Time";
+import { getTaskInstanceLink } from "src/utils/links";
 
 import { AddAssetStoreButton } from "./AddAssetStoreButton";
 import { ClearAllAssetStoreButton } from "./ClearAllAssetStoreButton";
 import { DeleteAssetStoreButton } from "./DeleteAssetStoreButton";
 import { EditAssetStoreButton } from "./EditAssetStoreButton";
 
+type TaskWriter = { dag_id: string; run_id: string; task_id: string } & 
AssetStoreLastUpdatedBy;
+
+const isTaskWriter = (writer: AssetStoreLastUpdatedBy): writer is TaskWriter =>
+  writer.kind === "task" &&
+  writer.dag_id !== null &&
+  writer.dag_id !== undefined &&
+  writer.run_id !== null &&
+  writer.run_id !== undefined &&
+  writer.task_id !== null &&
+  writer.task_id !== undefined;
+
 type ColumnsProps = {
   readonly assetId: number;
   readonly translate: (key: string) => string;
@@ -56,6 +68,45 @@ const getColumns = ({ assetId, translate }: ColumnsProps): 
Array<ColumnDef<Asset
     cell: ({ row: { original } }) => <Time datetime={original.updated_at} />,
     header: translate("common:table.updatedAt"),
   },
+  {
+    accessorKey: "last_updated_by",
+    cell: ({ row: { original } }) => {
+      const writer = original.last_updated_by;
+
+      if (!writer) {
+        return <Text color="fg.muted">—</Text>;
+      }
+      if (isTaskWriter(writer)) {
+        const path = getTaskInstanceLink({
+          dagId: writer.dag_id,
+          dagRunId: writer.run_id,
+          mapIndex: writer.map_index ?? undefined,
+          taskId: writer.task_id,
+        });
+
+        return (
+          <Flex direction="column">
+            <Link asChild color="fg.info">
+              <RouterLink to={path}>{writer.task_id}</RouterLink>
+            </Link>
+            <Text color="fg.muted" fontSize="xs">
+              {writer.dag_id}
+            </Text>
+          </Flex>
+        );
+      }
+
+      return (
+        <Text>
+          {writer.kind === "api"
+            ? translate("assets:assetStore.lastUpdatedByApi")
+            : translate("assets:assetStore.lastUpdatedByWatcher")}
+        </Text>
+      );
+    },
+    enableSorting: false,
+    header: translate("assets:assetStore.lastUpdatedBy"),
+  },
   {
     accessorKey: "actions",
     cell: ({ row: { original } }) => (

Reply via email to