From 62704eb8583bfa7d22798f477a96217b14a6d748 Mon Sep 17 00:00:00 2001 From: Jake Howell Date: Thu, 29 Jan 2026 11:22:11 +1100 Subject: [PATCH] feat: implement ai governance consumption frontend (#21595) Closes [#1246](https://github.com/coder/internal/issues/1246) This PR adds a new component to display AI Governance user entitlements in the Licenses Settings page. The implementation includes: - New `AIGovernanceUsersConsumptionChart` component that shows the number of entitled users for AI Governance features - Storybook stories for various states (default, disabled, error states) - Integration with the existing license settings page - Collapsible "Learn more" section with links to relevant documentation - Updated the ManagedAgentsConsumption component with clearer terminology ("Agent Workspace Builds" instead of "Managed AI Agents") The chart displays the number of users entitled to use AI features like AI Bridge, Boundary, and Tasks, with a note that additional analytics are coming soon. ### Preview CleanShot 2026-01-27 at 22 44
25@2x CleanShot 2026-01-27 at 22 45
04@2x --------- Co-authored-by: Jaayden Halko --- ...overnanceUsersConsumptionChart.stories.tsx | 55 ++++++++ .../AIGovernanceUsersConsumptionChart.tsx | 119 ++++++++++++++++++ .../LicensesSettingsPage.tsx | 3 + .../LicensesSettingsPageView.tsx | 12 +- .../ManagedAgentsConsumption.tsx | 44 ++++--- 5 files changed, 217 insertions(+), 16 deletions(-) create mode 100644 site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.stories.tsx create mode 100644 site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.tsx diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.stories.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.stories.tsx new file mode 100644 index 0000000000..23a62a047c --- /dev/null +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.stories.tsx @@ -0,0 +1,55 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { AIGovernanceUsersConsumption } from "./AIGovernanceUsersConsumptionChart"; + +const meta: Meta = { + title: + "pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart", + component: AIGovernanceUsersConsumption, + args: { + aiGovernanceUserFeature: { + enabled: true, + entitlement: "entitled", + limit: 1000, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Disabled: Story = { + args: { + aiGovernanceUserFeature: { + enabled: false, + entitlement: "not_entitled", + }, + }, +}; + +export const NoFeature: Story = { + args: { + aiGovernanceUserFeature: undefined, + }, +}; + +export const ErrorMissingData: Story = { + args: { + aiGovernanceUserFeature: { + enabled: true, + entitlement: "entitled", + limit: undefined, + }, + }, +}; + +export const ErrorNegativeValues: Story = { + args: { + aiGovernanceUserFeature: { + enabled: true, + entitlement: "entitled", + limit: -1000, + }, + }, +}; diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.tsx new file mode 100644 index 0000000000..a5610550d9 --- /dev/null +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceUsersConsumptionChart.tsx @@ -0,0 +1,119 @@ +import type { Feature } from "api/typesGenerated"; +import { ErrorAlert } from "components/Alert/ErrorAlert"; +import { Button } from "components/Button/Button"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "components/Collapsible/Collapsible"; +import { Link } from "components/Link/Link"; +import { ChevronRightIcon } from "lucide-react"; +import type { FC } from "react"; +import { docs } from "utils/docs"; + +interface AIGovernanceUsersConsumptionProps { + aiGovernanceUserFeature?: Feature; +} + +export const AIGovernanceUsersConsumption: FC< + AIGovernanceUsersConsumptionProps +> = ({ aiGovernanceUserFeature }) => { + // If no feature is provided or it's disabled, show disabled state + if (!aiGovernanceUserFeature?.enabled) { + return ( +
+
+
+ Users with AI Governance Add-On + + AI Governance is not included in your current license. Contact{" "} + sales to upgrade your + license and unlock this addon. + +
+
+
+ ); + } + + const limit = aiGovernanceUserFeature.limit; + + if (limit === undefined || limit < 0) { + return ; + } + + return ( +
+
+ +
+

+ Users with AI Governance Add-On +

+ + + + +
+ + +

+ Users using AI features like{" "} + + AI Bridge + + ,{" "} + + Boundary + + , or{" "} + + Tasks + + . +

+
+
+
+ +
+
+
+
{limit.toLocaleString()}
+
Users Entitled
+
+
+ Additional analytics and measurements coming soon +
+
+
+
+ ); +}; diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPage.tsx index 3b9b58212e..8f151cdf15 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPage.tsx @@ -86,6 +86,9 @@ const LicensesSettingsPage: FC = () => { managedAgentFeature={ entitlementsQuery.data?.features.managed_agent_limit } + aiGovernanceUserFeature={ + entitlementsQuery.data?.features.ai_governance_user_limit + } refreshEntitlements={async () => { try { await refreshEntitlementsMutation.mutateAsync(); diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx index 9b56ae5a12..b6096d2b78 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicensesSettingsPageView.tsx @@ -21,6 +21,7 @@ import { PlusIcon, RotateCwIcon } from "lucide-react"; import type { FC } from "react"; import Confetti from "react-confetti"; import { Link } from "react-router"; +import { AIGovernanceUsersConsumption } from "./AIGovernanceUsersConsumptionChart"; import { LicenseCard } from "./LicenseCard"; import { LicenseSeatConsumptionChart } from "./LicenseSeatConsumptionChart"; import { ManagedAgentsConsumption } from "./ManagedAgentsConsumption"; @@ -37,6 +38,7 @@ type Props = { refreshEntitlements: () => void; activeUsers: UserStatusChangeCount[] | undefined; managedAgentFeature?: Feature; + aiGovernanceUserFeature?: Feature; }; const LicensesSettingsPageView: FC = ({ @@ -51,6 +53,7 @@ const LicensesSettingsPageView: FC = ({ refreshEntitlements, activeUsers, managedAgentFeature, + aiGovernanceUserFeature, }) => { const theme = useTheme(); const { width, height } = useWindowSize(); @@ -164,7 +167,14 @@ const LicensesSettingsPageView: FC = ({ )} {licenses && licenses.length > 0 && ( - + <> + + + )} diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx index 022627c11d..c887a7ac71 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/ManagedAgentsConsumption.tsx @@ -1,4 +1,3 @@ -import MuiLink from "@mui/material/Link"; import type { Feature } from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Button } from "components/Button/Button"; @@ -7,7 +6,7 @@ import { CollapsibleContent, CollapsibleTrigger, } from "components/Collapsible/Collapsible"; -import { Stack } from "components/Stack/Stack"; +import { Link } from "components/Link/Link"; import dayjs from "dayjs"; import { ChevronRightIcon } from "lucide-react"; import type { FC } from "react"; @@ -24,16 +23,16 @@ export const ManagedAgentsConsumption: FC = ({ if (!managedAgentFeature?.enabled) { return (
- - - Managed AI Agents Disabled +
+
+ Agent Workspace Builds Disabled - Managed AI agents are not included in your current license. - Contact sales to + Agent Workspace Builds are not included in your current license. + Contact sales to upgrade your license and unlock this feature. - - +
+
); } @@ -76,7 +75,7 @@ export const ManagedAgentsConsumption: FC = ({
-

Managed AI Agents Usage

+

Agent Workspace Builds