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

kaxilnaik pushed a commit to branch v3-0-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit a40c476b4ab23fbb7841a7aab0e682b61e19bab3
Author: Brent Bovenzi <[email protected]>
AuthorDate: Sun May 4 07:43:54 2025 -0400

    Add audit log extra to table and improve UX (#50100)
    
    * Add Audit Log events extra
    
    * Rearrange audit log columns for readability
    
    * Add expand/collapse all button for extra json
    
    (cherry picked from commit b7b0daf0850f42d2ac79f1b6b3ebbea97b4ab53e)
---
 .../src/airflow/ui/src/pages/Events/Events.tsx     | 105 +++++++++++++++------
 1 file changed, 75 insertions(+), 30 deletions(-)

diff --git a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx 
b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
index f93d8a07526..e1527e2c33a 100644
--- a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
@@ -16,8 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Box } from "@chakra-ui/react";
+import { Box, ButtonGroup, Code, Flex, Heading, IconButton, useDisclosure } 
from "@chakra-ui/react";
 import type { ColumnDef } from "@tanstack/react-table";
+import { MdCompress, MdExpand } from "react-icons/md";
 import { useParams } from "react-router-dom";
 
 import { useEventLogServiceGetEventLogs } from "openapi/queries";
@@ -25,13 +26,17 @@ import type { EventLogResponse } 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 RenderedJsonField from "src/components/RenderedJsonField";
 import Time from "src/components/Time";
 
-const eventsColumn = (
-  dagId?: string,
-  runId?: string,
-  taskId?: string,
-): Array<ColumnDef<EventLogResponse>> => [
+type EventsColumn = {
+  dagId?: string;
+  open?: boolean;
+  runId?: string;
+  taskId?: string;
+};
+
+const eventsColumn = ({ dagId, open, runId, taskId }: EventsColumn): 
Array<ColumnDef<EventLogResponse>> => [
   {
     accessorKey: "when",
     cell: ({ row: { original } }) => <Time datetime={original.when} />,
@@ -41,6 +46,43 @@ const eventsColumn = (
       skeletonWidth: 10,
     },
   },
+  {
+    accessorKey: "event",
+    enableSorting: true,
+    header: "Event",
+    meta: {
+      skeletonWidth: 10,
+    },
+  },
+  {
+    accessorKey: "owner",
+    enableSorting: true,
+    header: "User",
+    meta: {
+      skeletonWidth: 10,
+    },
+  },
+  {
+    accessorKey: "extra",
+    cell: ({ row: { original } }) => {
+      if (original.extra !== null) {
+        try {
+          const parsed = JSON.parse(original.extra) as Record<string, unknown>;
+
+          return <RenderedJsonField content={parsed} jsonProps={{ collapsed: 
!open }} />;
+        } catch {
+          return <Code>{original.extra}</Code>;
+        }
+      }
+
+      return undefined;
+    },
+    enableSorting: false,
+    header: "Extra",
+    meta: {
+      skeletonWidth: 200,
+    },
+  },
   ...(Boolean(dagId)
     ? []
     : [
@@ -93,22 +135,6 @@ const eventsColumn = (
       skeletonWidth: 10,
     },
   },
-  {
-    accessorKey: "event",
-    enableSorting: true,
-    header: "Event",
-    meta: {
-      skeletonWidth: 10,
-    },
-  },
-  {
-    accessorKey: "owner",
-    enableSorting: true,
-    header: "User",
-    meta: {
-      skeletonWidth: 10,
-    },
-  },
 ];
 
 export const Events = () => {
@@ -116,15 +142,11 @@ export const Events = () => {
   const { setTableURLState, tableURLState } = useTableURLState();
   const { pagination, sorting } = tableURLState;
   const [sort] = sorting;
+  const { onClose, onOpen, open } = useDisclosure();
 
   const orderBy = sort ? `${sort.desc ? "-" : ""}${sort.id}` : "-when";
 
-  const {
-    data,
-    error: EventsError,
-    isFetching,
-    isLoading,
-  } = useEventLogServiceGetEventLogs(
+  const { data, error, isFetching, isLoading } = 
useEventLogServiceGetEventLogs(
     {
       dagId,
       limit: pagination.pageSize,
@@ -139,9 +161,32 @@ export const Events = () => {
 
   return (
     <Box>
-      <ErrorAlert error={EventsError} />
+      <Flex alignItems="center" justifyContent="space-between">
+        <Heading>Audit Log Events</Heading>
+        <ButtonGroup attached size="sm" variant="surface">
+          <IconButton
+            aria-label="Expand all extra json"
+            onClick={onOpen}
+            size="sm"
+            title="Expand all extra json"
+            variant="surface"
+          >
+            <MdExpand />
+          </IconButton>
+          <IconButton
+            aria-label="Collapse all extra json"
+            onClick={onClose}
+            size="sm"
+            title="Collapse all extra json"
+            variant="surface"
+          >
+            <MdCompress />
+          </IconButton>
+        </ButtonGroup>
+      </Flex>
+      <ErrorAlert error={error} />
       <DataTable
-        columns={eventsColumn(dagId, runId, taskId)}
+        columns={eventsColumn({ dagId, open, runId, taskId })}
         data={data ? data.event_logs : []}
         displayMode="table"
         initialState={tableURLState}

Reply via email to