diff --git a/site/src/modules/dashboard/entitlements.ts b/site/src/modules/dashboard/entitlements.ts index a11af9faedecd..cd567bc3f6b5f 100644 --- a/site/src/modules/dashboard/entitlements.ts +++ b/site/src/modules/dashboard/entitlements.ts @@ -28,17 +28,3 @@ export const selectFeatureVisibility = ( ): Record => { return getFeatureVisibility(entitlements.has_license, entitlements.features); }; - -/** - * Keep the AI seats column visible while in grace period so admins can - * identify who is consuming seats while remediating overages. - */ -export const shouldShowAISeatColumn = (entitlements: Entitlements): boolean => { - const aiGovernanceUserLimit = entitlements.features.ai_governance_user_limit; - return ( - entitlements.has_license && - aiGovernanceUserLimit.enabled && - (aiGovernanceUserLimit.entitlement === "entitled" || - aiGovernanceUserLimit.entitlement === "grace_period") - ); -}; diff --git a/site/src/modules/users/AISeatCell.tsx b/site/src/modules/users/AISeatCell.tsx deleted file mode 100644 index 696c58d0b00b4..0000000000000 --- a/site/src/modules/users/AISeatCell.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { CheckIcon } from "lucide-react"; -import type { FC } from "react"; -import { TableCell } from "#/components/Table/Table"; - -interface AISeatCellProps { - hasAISeat: boolean; -} - -export const AISeatCell: FC = ({ hasAISeat }) => { - return ( - - {hasAISeat ? ( - - ) : ( - - — - - )} - - ); -}; diff --git a/site/src/modules/users/UserHelpPopovers.tsx b/site/src/modules/users/UserHelpPopovers.tsx index ddc636350385d..93e4ec94c3693 100644 --- a/site/src/modules/users/UserHelpPopovers.tsx +++ b/site/src/modules/users/UserHelpPopovers.tsx @@ -49,18 +49,3 @@ export const GroupsHelpPopover: FC = () => { ); }; - -export const AiAddonHelpPopover: FC = () => { - return ( - - - - What is the AI add-on? - - Users with access to AI features like AI Gateway or Tasks who are - actively consuming a seat. - - - - ); -}; diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceAddOnCard.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceAddOnCard.tsx index 648d29d55b451..e4f2abdca44f5 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceAddOnCard.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/AIGovernanceAddOnCard.tsx @@ -1,6 +1,5 @@ import { InfoIcon } from "lucide-react"; import type { FC } from "react"; -import { Badge } from "#/components/Badge/Badge"; import { Tooltip, TooltipContent, @@ -32,29 +31,24 @@ export const AIGovernanceAddOnCard: FC = ({ >
-
-
- - {title} - - - - - - - Seats consumed by users using AI Governance features. - - -
- - AI add-on - +
+ + {title} + + + + + + + Seats consumed by users using AI Governance features. + +
diff --git a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.stories.tsx b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.stories.tsx index 88cc7a320812d..3c51194b9b591 100644 --- a/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/LicensesSettingsPage/LicenseCard.stories.tsx @@ -362,6 +362,5 @@ export const EnterpriseDoesNotShowAIGovernanceAddOn: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await expect(canvas.queryByText("Add-ons")).not.toBeInTheDocument(); - await expect(canvas.queryByText("AI add-on")).not.toBeInTheDocument(); }, }; diff --git a/site/src/pages/GroupsPage/GroupSettingsPageView.stories.tsx b/site/src/pages/GroupsPage/GroupSettingsPageView.stories.tsx index a80aba46e5547..edae2f08cdc29 100644 --- a/site/src/pages/GroupsPage/GroupSettingsPageView.stories.tsx +++ b/site/src/pages/GroupsPage/GroupSettingsPageView.stories.tsx @@ -24,7 +24,7 @@ type Story = StoryObj; export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); - // Without the AI add-on, the AI budget section is hidden. + // Without the aibridge feature, the AI budget section is hidden. await expect(canvas.queryByText("AI budget")).not.toBeInTheDocument(); }, }; diff --git a/site/src/pages/GroupsPage/GroupSettingsPageView.tsx b/site/src/pages/GroupsPage/GroupSettingsPageView.tsx index 4bc3596e5d533..efdd070402645 100644 --- a/site/src/pages/GroupsPage/GroupSettingsPageView.tsx +++ b/site/src/pages/GroupsPage/GroupSettingsPageView.tsx @@ -3,7 +3,6 @@ import type { FC, ReactNode } from "react"; import * as Yup from "yup"; import type { Group } from "#/api/typesGenerated"; import { Alert } from "#/components/Alert/Alert"; -import { Badge } from "#/components/Badge/Badge"; import { Button } from "#/components/Button/Button"; import { IconField } from "#/components/IconField/IconField"; import { Input } from "#/components/Input/Input"; @@ -111,7 +110,7 @@ const AIBudgetFeedback: FC = ({ interface UpdateGroupFormProps { group: Group; - /** Whether the AI add-on settings are shown (gated by the aibridge feature). */ + /** Whether the AI budget settings are shown (gated by the aibridge feature). */ showAISettings: boolean; /** Per-member AI budget in dollars, or null for unlimited spend. */ initialBudgetDollars: number | null; @@ -227,14 +226,9 @@ const UpdateGroupForm: FC = ({ {showAISettings && (
-
-

- AI budget -

- - AI add-on - -
+

+ AI budget +

diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx index c63be41c2f53f..23911f3f67a3a 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx @@ -21,7 +21,6 @@ import { EmptyState } from "#/components/EmptyState/EmptyState"; import { useFilter } from "#/components/Filter/Filter"; import { useAuthenticated } from "#/hooks/useAuthenticated"; import { usePaginatedQuery } from "#/hooks/usePaginatedQuery"; -import { shouldShowAISeatColumn } from "#/modules/dashboard/entitlements"; import { useDashboard } from "#/modules/dashboard/useDashboard"; import { useOrganizationSettings } from "#/modules/management/OrganizationSettingsLayout"; import { RequirePermission } from "#/modules/permissions/RequirePermission"; @@ -38,7 +37,6 @@ const OrganizationMembersPage: FC = () => { const { organization, organizationPermissions } = useOrganizationSettings(); const { entitlements } = useDashboard(); const searchParamsResult = useSearchParams(); - const showAISeatColumn = shouldShowAISeatColumn(entitlements); const organizationRolesQuery = useQuery(organizationRoles(organizationName)); const groupsByUserIdQuery = useQuery( @@ -123,7 +121,6 @@ const OrganizationMembersPage: FC = () => { organizationName={organizationName} membersQuery={membersQuery} members={members} - showAISeatColumn={showAISeatColumn} addMembers={async (users: User[]) => { // TODO: Replace with a batch endpoint (POST /organizations/{org}/members) // to add all users in a single request instead of N individual calls. diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx index 49e076f2c6a31..50e0a58208586 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.stories.tsx @@ -54,12 +54,6 @@ type Story = StoryObj; export const Default: Story = {}; -export const WithAIAddonColumn: Story = { - args: { - showAISeatColumn: true, - }, -}; - export const Loading: Story = { args: { members: undefined, diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersTable.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersTable.tsx index c881f4bd789bd..77e16c62e39df 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersTable.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersTable.tsx @@ -25,10 +25,8 @@ import { } from "#/components/Table/Table"; import { TableEmpty } from "#/components/TableEmpty/TableEmpty"; import { TableLoader } from "#/components/TableLoader/TableLoader"; -import { AISeatCell } from "#/modules/users/AISeatCell"; import { UserGroupsCell } from "#/modules/users/UserGroupsCell"; import { - AiAddonHelpPopover, GroupsHelpPopover, RolesHelpPopover, } from "#/modules/users/UserHelpPopovers"; @@ -38,7 +36,6 @@ export type OrganizationMembersTableProps = { // State organizationName: string; members: Array | undefined; - showAISeatColumn?: boolean; // Actions onEditMemberRoles: (member: OrganizationMemberWithUserData) => void; @@ -62,8 +59,6 @@ type OrganizationMemberTableEntry = OrganizationMemberWithUserData & { export const OrganizationMembersTable: React.FC< OrganizationMembersTableProps > = (props) => { - const { showAISeatColumn } = props; - return ( @@ -81,14 +76,6 @@ export const OrganizationMembersTable: React.FC< - {showAISeatColumn && ( - -
- AI add-on - -
-
- )}
@@ -101,7 +88,6 @@ export const OrganizationMembersTable: React.FC< const OrganizationMembersTableBody: React.FC = ({ organizationName, members, - showAISeatColumn, isUpdatingMemberRoles, removeMember, @@ -141,7 +127,6 @@ const OrganizationMembersTableBody: React.FC = ({ roles={member.roles} /> - {showAISeatColumn && }
{member.user_id !== me && canEditMembers && ( diff --git a/site/src/pages/UsersPage/UsersPage.stories.tsx b/site/src/pages/UsersPage/UsersPage.stories.tsx index 23eaaaa98bb25..194f43a52ff4f 100644 --- a/site/src/pages/UsersPage/UsersPage.stories.tsx +++ b/site/src/pages/UsersPage/UsersPage.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; -import { expect, screen, spyOn, userEvent, within } from "storybook/test"; +import { screen, spyOn, userEvent, within } from "storybook/test"; import { API } from "#/api/api"; import { deploymentConfigQueryKey } from "#/api/queries/deployment"; import { groupsQueryKey } from "#/api/queries/groups"; @@ -79,34 +79,6 @@ type Story = StoryObj; export const Loaded: Story = {}; -export const WithAIAddonColumn: Story = { - parameters: { - features: ["ai_governance_user_limit"], - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - const header = await canvas.findByRole("columnheader", { - name: /AI add-on/i, - }); - - await expect(header).toBeVisible(); - }, -}; - -export const WithoutAIAddonColumn: Story = { - parameters: { - features: ["audit_log"], - }, - play: async ({ canvasElement }) => { - const canvas = within(canvasElement); - await canvas.findByRole("columnheader", { name: "User" }); - - await expect( - canvas.queryByRole("columnheader", { name: /AI add-on/i }), - ).not.toBeInTheDocument(); - }, -}; - export const SuspendUserSuccess: Story = { play: async ({ canvasElement }) => { const user = userEvent.setup(); diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index 2151dc954db9b..c55459fe489b2 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -21,7 +21,6 @@ import { useFilter } from "#/components/Filter/Filter"; import { useStatusFilterMenu } from "#/components/Filter/UsersFilter"; import { useAuthenticated } from "#/hooks/useAuthenticated"; import { usePaginatedQuery } from "#/hooks/usePaginatedQuery"; -import { shouldShowAISeatColumn } from "#/modules/dashboard/entitlements"; import { useDashboard } from "#/modules/dashboard/useDashboard"; import { RoleSelectorDialog } from "#/modules/roles/RoleSelectorDialog"; import { pageTitle } from "#/utils/page"; @@ -33,7 +32,6 @@ const UsersPage: React.FC = () => { const queryClient = useQueryClient(); const [searchParams, setSearchParams] = useSearchParams(); const { entitlements } = useDashboard(); - const showAISeatColumn = shouldShowAISeatColumn(entitlements); const groupsByUserIdQuery = useQuery(groupsByUserId()); @@ -113,7 +111,6 @@ const UsersPage: React.FC = () => { }} usersQuery={usersQuery} groupsByUserId={groupsByUserIdQuery.data} - showAISeatColumn={showAISeatColumn} onEditUserRoles={setUserToEditRoles} isUpdatingUserRoles={updateUserRolesMutation.isPending} onResetUserPassword={(user) => { diff --git a/site/src/pages/UsersPage/UsersPageView.stories.tsx b/site/src/pages/UsersPage/UsersPageView.stories.tsx index 713de8d2e2b86..381ab6328cce2 100644 --- a/site/src/pages/UsersPage/UsersPageView.stories.tsx +++ b/site/src/pages/UsersPage/UsersPageView.stories.tsx @@ -35,10 +35,7 @@ const meta: Meta = { totalRecords: 2, data: { count: 2, - users: [ - { ...MockUserOwner, has_ai_seat: false }, - { ...MockUserMember, has_ai_seat: false }, - ], + users: [MockUserOwner, MockUserMember], }, }, }, diff --git a/site/src/pages/UsersPage/UsersTable.stories.tsx b/site/src/pages/UsersPage/UsersTable.stories.tsx index 7aeced6972360..7435b28575fd4 100644 --- a/site/src/pages/UsersPage/UsersTable.stories.tsx +++ b/site/src/pages/UsersPage/UsersTable.stories.tsx @@ -26,74 +26,17 @@ type Story = StoryObj; export const Example: Story = { args: { - users: [ - { ...MockUserOwner, has_ai_seat: false }, - { ...MockUserMember, has_ai_seat: false }, - ], - canEditUsers: false, - groupsByUserId: mockGroupsByUserId, - }, -}; - -export const ExampleWithAISeatColumn: Story = { - args: { - users: [ - { ...MockUserOwner, has_ai_seat: true }, - { ...MockUserMember, has_ai_seat: false }, - ], + users: [MockUserOwner, MockUserMember], canEditUsers: false, groupsByUserId: mockGroupsByUserId, - showAISeatColumn: true, }, }; export const Editable: Story = { args: { users: [ - { ...MockUserOwner, has_ai_seat: false }, - { ...MockUserMember, has_ai_seat: false }, - { - ...MockUserOwner, - username: "John Doe", - email: "john.doe@coder.com", - roles: [ - MockUserAdminRole, - MockTemplateAdminRole, - MockMemberRole, - MockAuditorRole, - ], - status: "dormant", - has_ai_seat: false, - }, - { - ...MockUserOwner, - username: "Roger Moore", - email: "roger.moore@coder.com", - roles: [], - status: "suspended", - has_ai_seat: false, - }, - { - ...MockUserOwner, - username: "OIDC User", - email: "oidc.user@coder.com", - roles: [], - status: "active", - login_type: "oidc", - has_ai_seat: false, - }, - ], - canEditUsers: true, - canViewActivity: true, - groupsByUserId: mockGroupsByUserId, - }, -}; - -export const EditableWithAISeatColumn: Story = { - args: { - users: [ - { ...MockUserOwner, has_ai_seat: true }, - { ...MockUserMember, has_ai_seat: false }, + MockUserOwner, + MockUserMember, { ...MockUserOwner, username: "John Doe", @@ -105,7 +48,6 @@ export const EditableWithAISeatColumn: Story = { MockAuditorRole, ], status: "dormant", - has_ai_seat: false, }, { ...MockUserOwner, @@ -113,7 +55,6 @@ export const EditableWithAISeatColumn: Story = { email: "roger.moore@coder.com", roles: [], status: "suspended", - has_ai_seat: false, }, { ...MockUserOwner, @@ -122,13 +63,11 @@ export const EditableWithAISeatColumn: Story = { roles: [], status: "active", login_type: "oidc", - has_ai_seat: false, }, ], canEditUsers: true, canViewActivity: true, groupsByUserId: mockGroupsByUserId, - showAISeatColumn: true, }, }; diff --git a/site/src/pages/UsersPage/UsersTable.tsx b/site/src/pages/UsersPage/UsersTable.tsx index 8cf958c83f677..8cc43048a23b6 100644 --- a/site/src/pages/UsersPage/UsersTable.tsx +++ b/site/src/pages/UsersPage/UsersTable.tsx @@ -30,10 +30,8 @@ import { TableLoaderSkeleton, TableRowSkeleton, } from "#/components/TableLoader/TableLoader"; -import { AISeatCell } from "#/modules/users/AISeatCell"; import { UserGroupsCell } from "#/modules/users/UserGroupsCell"; import { - AiAddonHelpPopover, GroupsHelpPopover, RolesHelpPopover, } from "#/modules/users/UserHelpPopovers"; @@ -47,7 +45,6 @@ export type UsersTableProps = { isLoading: boolean; users: readonly TypesGen.User[] | undefined; groupsByUserId: GroupsByUserId | undefined; - showAISeatColumn?: boolean; // Actions onEditUserRoles: (user: TypesGen.User) => void; @@ -70,8 +67,6 @@ export type UsersTableProps = { }; export const UsersTable: React.FC = (props) => { - const { showAISeatColumn } = props; - return (
@@ -89,14 +84,6 @@ export const UsersTable: React.FC = (props) => { - {showAISeatColumn && ( - -
- AI add-on - -
-
- )} Status
@@ -112,7 +99,6 @@ const UsersTableBody: React.FC = ({ isLoading, users, groupsByUserId, - showAISeatColumn, onEditUserRoles, isUpdatingUserRoles, @@ -127,12 +113,7 @@ const UsersTableBody: React.FC = ({ oidcRoleSyncEnabled, }) => { if (isLoading) { - return ( - - ); + return ; } if (!users || users.length === 0) { @@ -157,8 +138,6 @@ const UsersTableBody: React.FC = ({ - {showAISeatColumn && } - = ({ }; type UsersTableSkeletonProps = { - showAISeatColumn?: boolean; canEditUsers: boolean; }; const UsersTableSkeleton: React.FC = ({ - showAISeatColumn, canEditUsers, }) => { return ( @@ -284,12 +261,6 @@ const UsersTableSkeleton: React.FC = ({ - {showAISeatColumn && ( - - - - )} -