From 3bb7975a17df8b48aacefc6e012e19794c93b6a5 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Wed, 12 Nov 2025 11:41:41 +1100 Subject: [PATCH] feat: add page for ai-bridge interception logs (#20331) Relates #20287 This pull-request introduces a basic routing for `AI Governance`'s Request Logs feature. Currently we're just pulling back the basics from the database and rendering it into the table. Nothing exciting. The idea is to extend further upon the `/aigovernance` route so it has been appropriately wrapped with a `` to introduce a navigation later. --- site/src/api/api.ts | 10 + site/src/api/queries/aiBridge.ts | 21 ++ .../dashboard/Navbar/DeploymentDropdown.tsx | 15 ++ site/src/modules/dashboard/Navbar/Navbar.tsx | 3 + .../modules/dashboard/Navbar/NavbarView.tsx | 3 + site/src/modules/permissions/index.ts | 7 + .../AIGovernanceHelpTooltip.tsx | 32 +++ .../AIGovernancePage/AIGovernanceLayout.tsx | 30 +++ .../RequestLogsPage/RequestLogsPage.tsx | 66 ++++++ .../RequestLogsPageView.stories.tsx | 77 +++++++ .../RequestLogsPage/RequestLogsPageView.tsx | 82 +++++++ .../RequestLogsRow/RequestLogsRow.stories.tsx | 27 +++ .../RequestLogsRow/RequestLogsRow.tsx | 200 ++++++++++++++++++ .../filter/RequestLogsFilter.tsx | 44 ++++ .../RequestLogsPage/filter/filter.tsx | 57 +++++ site/src/router.tsx | 14 ++ site/src/testHelpers/entities.ts | 30 +++ 17 files changed, 718 insertions(+) create mode 100644 site/src/api/queries/aiBridge.ts create mode 100644 site/src/pages/AIGovernancePage/AIGovernanceHelpTooltip.tsx create mode 100644 site/src/pages/AIGovernancePage/AIGovernanceLayout.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/RequestLogsPage.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/RequestLogsPageView.stories.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/RequestLogsPageView.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.stories.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/RequestLogsRow/RequestLogsRow.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/filter/RequestLogsFilter.tsx create mode 100644 site/src/pages/AIGovernancePage/RequestLogsPage/filter/filter.tsx diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 8c665e3c60..438f059c53 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -2716,6 +2716,16 @@ class ExperimentalApiMethods { setTimeout(() => res(), 500); }); }; + + getAIBridgeInterceptions = async (options: SearchParamOptions) => { + const url = getURLWithSearchParams( + "/api/experimental/aibridge/interceptions", + options, + ); + const response = + await this.axios.get(url); + return response.data; + }; } // This is a hard coded CSRF token/cookie pair for local development. In prod, diff --git a/site/src/api/queries/aiBridge.ts b/site/src/api/queries/aiBridge.ts new file mode 100644 index 0000000000..ba623637e9 --- /dev/null +++ b/site/src/api/queries/aiBridge.ts @@ -0,0 +1,21 @@ +import { API } from "api/api"; +import type { AIBridgeListInterceptionsResponse } from "api/typesGenerated"; +import { useFilterParamsKey } from "components/Filter/Filter"; +import type { UsePaginatedQueryOptions } from "hooks/usePaginatedQuery"; + +export const paginatedInterceptions = ( + searchParams: URLSearchParams, +): UsePaginatedQueryOptions => { + return { + queryPayload: () => searchParams.get(useFilterParamsKey) ?? "", + queryKey: ({ payload, pageNumber }) => { + return ["aiBridgeInterceptions", payload, pageNumber] as const; + }, + queryFn: ({ limit, offset, payload }) => + API.experimental.getAIBridgeInterceptions({ + offset, + limit, + q: payload, + }), + }; +}; diff --git a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx index 7089342727..53e498e1be 100644 --- a/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx +++ b/site/src/modules/dashboard/Navbar/DeploymentDropdown.tsx @@ -18,6 +18,7 @@ interface DeploymentDropdownProps { canViewAuditLog: boolean; canViewConnectionLog: boolean; canViewHealth: boolean; + canViewAIGovernance: boolean; } export const DeploymentDropdown: FC = ({ @@ -26,6 +27,7 @@ export const DeploymentDropdown: FC = ({ canViewAuditLog, canViewConnectionLog, canViewHealth, + canViewAIGovernance, }) => { if ( !canViewAuditLog && @@ -56,6 +58,7 @@ export const DeploymentDropdown: FC = ({ canViewAuditLog={canViewAuditLog} canViewConnectionLog={canViewConnectionLog} canViewHealth={canViewHealth} + canViewAIGovernance={canViewAIGovernance} /> @@ -68,6 +71,7 @@ const DeploymentDropdownContent: FC = ({ canViewAuditLog, canViewHealth, canViewConnectionLog, + canViewAIGovernance, }) => { return (