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 3e8284d2b5e Reuse Asset Event card list in Asset Details page (#47403)
3e8284d2b5e is described below

commit 3e8284d2b5e34957b4f613e96065cce5a023ab24
Author: Brent Bovenzi <[email protected]>
AuthorDate: Wed Mar 5 13:24:26 2025 -0500

    Reuse Asset Event card list in Asset Details page (#47403)
---
 .../Assets}/AssetEvent.tsx                         | 42 ++++++-----
 .../Assets}/AssetEvents.tsx                        | 56 +++++++-------
 airflow/ui/src/pages/Asset/Asset.tsx               |  4 +-
 airflow/ui/src/pages/AssetEvents.tsx               | 86 ----------------------
 .../HistoricalMetrics/HistoricalMetrics.tsx        |  6 +-
 5 files changed, 60 insertions(+), 134 deletions(-)

diff --git a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvent.tsx 
b/airflow/ui/src/components/Assets/AssetEvent.tsx
similarity index 78%
rename from airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvent.tsx
rename to airflow/ui/src/components/Assets/AssetEvent.tsx
index 6013a1954c1..6b0b71cffbd 100644
--- a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvent.tsx
+++ b/airflow/ui/src/components/Assets/AssetEvent.tsx
@@ -25,7 +25,13 @@ import type { AssetEventResponse } from 
"openapi/requests/types.gen";
 import Time from "src/components/Time";
 import { Tooltip } from "src/components/ui";
 
-export const AssetEvent = ({ event }: { readonly event: AssetEventResponse }) 
=> {
+export const AssetEvent = ({
+  assetId,
+  event,
+}: {
+  readonly assetId?: number;
+  readonly event: AssetEventResponse;
+}) => {
   const hasDagRuns = event.created_dagruns.length > 0;
   let source = "";
 
@@ -40,22 +46,24 @@ export const AssetEvent = ({ event }: { readonly event: 
AssetEventResponse }) =>
       <Text fontWeight="bold">
         <Time datetime={event.timestamp} />
       </Text>
-      <HStack>
-        <FiDatabase />
-        <Tooltip
-          content={
-            <div>
-              <Text> group: {event.group ?? ""} </Text>
-              <Text> uri: {event.uri ?? ""} </Text>
-            </div>
-          }
-          showArrow
-        >
-          <Link to={`/assets/${event.asset_id}`}>
-            <Text color="fg.info"> {event.name ?? ""} </Text>
-          </Link>
-        </Tooltip>
-      </HStack>
+      {Boolean(assetId) ? undefined : (
+        <HStack>
+          <FiDatabase />
+          <Tooltip
+            content={
+              <div>
+                <Text> group: {event.group ?? ""} </Text>
+                <Text> uri: {event.uri ?? ""} </Text>
+              </div>
+            }
+            showArrow
+          >
+            <Link to={`/assets/${event.asset_id}`}>
+              <Text color="fg.info"> {event.name ?? ""} </Text>
+            </Link>
+          </Tooltip>
+        </HStack>
+      )}
       <HStack>
         <MdOutlineAccountTree /> <Text> Source: </Text>
         {source === "" ? (
diff --git a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvents.tsx 
b/airflow/ui/src/components/Assets/AssetEvents.tsx
similarity index 66%
rename from airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvents.tsx
rename to airflow/ui/src/components/Assets/AssetEvents.tsx
index ff9823b41e8..4097d442274 100644
--- a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/AssetEvents.tsx
+++ b/airflow/ui/src/components/Assets/AssetEvents.tsx
@@ -27,16 +27,18 @@ import { Select } from "src/components/ui";
 import { AssetEvent } from "./AssetEvent";
 
 type AssetEventProps = {
-  readonly assetSortBy: string;
-  readonly endDate: string;
-  readonly setAssetSortBy: React.Dispatch<React.SetStateAction<string>>;
-  readonly startDate: string;
+  readonly assetId?: number;
+  readonly endDate?: string;
+  readonly orderBy?: string;
+  readonly setOrderBy?: React.Dispatch<React.SetStateAction<string>>;
+  readonly startDate?: string;
 };
 
-export const AssetEvents = ({ assetSortBy, endDate, setAssetSortBy, startDate 
}: AssetEventProps) => {
+export const AssetEvents = ({ assetId, endDate, orderBy, setOrderBy, startDate 
}: AssetEventProps) => {
   const { data, isLoading } = useAssetServiceGetAssetEvents({
+    assetId,
     limit: 6,
-    orderBy: assetSortBy,
+    orderBy,
     timestampGte: startDate,
     timestampLte: endDate,
   });
@@ -60,26 +62,28 @@ export const AssetEvents = ({ assetSortBy, endDate, 
setAssetSortBy, startDate }:
             Asset Events
           </Heading>
         </HStack>
-        <Select.Root
-          borderWidth={0}
-          collection={assetSortOptions}
-          data-testid="asset-sort-duration"
-          defaultValue={["-timestamp"]}
-          onValueChange={(option) => setAssetSortBy(option.value[0] as string)}
-          width={130}
-        >
-          <Select.Trigger>
-            <Select.ValueText placeholder="Sort by" />
-          </Select.Trigger>
+        {setOrderBy === undefined ? undefined : (
+          <Select.Root
+            borderWidth={0}
+            collection={assetSortOptions}
+            data-testid="asset-sort-duration"
+            defaultValue={["-timestamp"]}
+            onValueChange={(option) => setOrderBy(option.value[0] as string)}
+            width={130}
+          >
+            <Select.Trigger>
+              <Select.ValueText placeholder="Sort by" />
+            </Select.Trigger>
 
-          <Select.Content>
-            {assetSortOptions.items.map((option) => (
-              <Select.Item item={option} key={option.value[0]}>
-                {option.label}
-              </Select.Item>
-            ))}
-          </Select.Content>
-        </Select.Root>
+            <Select.Content>
+              {assetSortOptions.items.map((option) => (
+                <Select.Item item={option} key={option.value[0]}>
+                  {option.label}
+                </Select.Item>
+              ))}
+            </Select.Content>
+          </Select.Root>
+        )}
       </Flex>
       {isLoading ? (
         <VStack px={3} separator={<StackSeparator />}>
@@ -89,7 +93,7 @@ export const AssetEvents = ({ assetSortBy, endDate, 
setAssetSortBy, startDate }:
         </VStack>
       ) : (
         <VStack px={3} separator={<StackSeparator />}>
-          {data?.asset_events.map((event) => <AssetEvent event={event} 
key={event.id} />)}
+          {data?.asset_events.map((event) => <AssetEvent assetId={assetId} 
event={event} key={event.id} />)}
         </VStack>
       )}
     </Box>
diff --git a/airflow/ui/src/pages/Asset/Asset.tsx 
b/airflow/ui/src/pages/Asset/Asset.tsx
index 2e9385c3e58..60401907e0d 100644
--- a/airflow/ui/src/pages/Asset/Asset.tsx
+++ b/airflow/ui/src/pages/Asset/Asset.tsx
@@ -22,10 +22,10 @@ import { Panel, PanelGroup, PanelResizeHandle } from 
"react-resizable-panels";
 import { useParams } from "react-router-dom";
 
 import { useAssetServiceGetAsset } from "openapi/queries";
+import { AssetEvents } from "src/components/Assets/AssetEvents";
 import { BreadcrumbStats } from "src/components/BreadcrumbStats";
 import { ProgressBar } from "src/components/ui";
 
-import { AssetEvents } from "../AssetEvents";
 import { AssetGraph } from "./AssetGraph";
 import { Header } from "./Header";
 
@@ -67,7 +67,7 @@ export const Asset = () => {
           <Panel defaultSize={50} minSize={20}>
             <Header asset={asset} />
             <Box h="100%" overflow="auto" px={2}>
-              <AssetEvents />
+              <AssetEvents assetId={asset?.id} />
             </Box>
           </Panel>
         </PanelGroup>
diff --git a/airflow/ui/src/pages/AssetEvents.tsx 
b/airflow/ui/src/pages/AssetEvents.tsx
deleted file mode 100644
index 639b9672363..00000000000
--- a/airflow/ui/src/pages/AssetEvents.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-/*!
- * 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 type { ColumnDef } from "@tanstack/react-table";
-import { useParams } from "react-router-dom";
-
-import { useAssetServiceGetAssetEvents } from "openapi/queries";
-import type { AssetEventResponse } from "openapi/requests/types.gen";
-import { DataTable } from "src/components/DataTable";
-import { useTableURLState } from "src/components/DataTable/useTableUrlState";
-import { ErrorAlert } from "src/components/ErrorAlert";
-import Time from "src/components/Time";
-
-type AssetEventRow = { row: { original: AssetEventResponse } };
-
-const assetEventColumns = (assetId?: string): 
Array<ColumnDef<AssetEventResponse>> => [
-  ...(Boolean(assetId)
-    ? []
-    : [
-        {
-          accessorKey: "name",
-          enableSorting: false,
-          header: "Asset",
-        },
-      ]),
-  {
-    accessorKey: "timestamp",
-    cell: ({ row: { original } }: AssetEventRow) => <Time 
datetime={original.timestamp} />,
-    header: "Timestamp",
-  },
-  {
-    accessorKey: "source_run_id",
-    enableSorting: false,
-    header: "Source",
-  },
-  {
-    accessorKey: "created_dagruns",
-    cell: ({ row: { original } }: AssetEventRow) => 
original.created_dagruns.length,
-    enableSorting: false,
-    header: "Created Dag Runs",
-  },
-];
-
-export const AssetEvents = () => {
-  const { assetId } = useParams();
-
-  const { setTableURLState, tableURLState } = useTableURLState();
-  const { pagination, sorting } = tableURLState;
-  const [sort] = sorting;
-  const orderBy = sort ? `${sort.desc ? "-" : ""}${sort.id}` : "-timestamp";
-
-  const { data, error, isLoading } = useAssetServiceGetAssetEvents({
-    assetId: assetId === undefined ? undefined : parseInt(assetId, 10),
-    limit: pagination.pageSize,
-    offset: pagination.pageIndex * pagination.pageSize,
-    orderBy,
-  });
-
-  return (
-    <DataTable
-      columns={assetEventColumns(assetId)}
-      data={data?.asset_events ?? []}
-      errorMessage={<ErrorAlert error={error} />}
-      initialState={tableURLState}
-      isLoading={isLoading}
-      modelName="Asset Event"
-      onStateChange={setTableURLState}
-      total={data?.total_entries}
-    />
-  );
-};
diff --git 
a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/HistoricalMetrics.tsx 
b/airflow/ui/src/pages/Dashboard/HistoricalMetrics/HistoricalMetrics.tsx
index 043f3680893..94f9e6d6e7c 100644
--- a/airflow/ui/src/pages/Dashboard/HistoricalMetrics/HistoricalMetrics.tsx
+++ b/airflow/ui/src/pages/Dashboard/HistoricalMetrics/HistoricalMetrics.tsx
@@ -22,10 +22,10 @@ import { useState } from "react";
 import { PiBooks } from "react-icons/pi";
 
 import { useDashboardServiceHistoricalMetrics } from "openapi/queries";
+import { AssetEvents } from "src/components/Assets/AssetEvents";
 import { ErrorAlert } from "src/components/ErrorAlert";
 import TimeRangeSelector from "src/components/TimeRangeSelector";
 
-import { AssetEvents } from "./AssetEvents";
 import { DagRunMetrics } from "./DagRunMetrics";
 import { MetricSectionSkeleton } from "./MetricSectionSkeleton";
 import { TaskInstanceMetrics } from "./TaskInstanceMetrics";
@@ -90,9 +90,9 @@ export const HistoricalMetrics = () => {
           </GridItem>
           <GridItem colSpan={{ base: 3 }}>
             <AssetEvents
-              assetSortBy={assetSortBy}
               endDate={endDate}
-              setAssetSortBy={setAssetSortBy}
+              orderBy={assetSortBy}
+              setOrderBy={setAssetSortBy}
               startDate={startDate}
             />
           </GridItem>

Reply via email to