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>