diff --git a/site/src/components/Badges/Badges.tsx b/site/src/components/Badges/Badges.tsx index cef5288091..07b653e7f4 100644 --- a/site/src/components/Badges/Badges.tsx +++ b/site/src/components/Badges/Badges.tsx @@ -137,7 +137,13 @@ export const EnterpriseBadge: FC = () => { ); }; -export const PremiumBadge: FC = () => { +interface PremiumBadgeProps { + children?: React.ReactNode; +} + +export const PremiumBadge: FC = ({ + children = "Premium", +}) => { return ( { }), ]} > - Premium + {children} ); }; diff --git a/site/src/components/Paywall/AIBridgePaywallConfig.ts b/site/src/components/Paywall/AIBridgePaywallConfig.ts new file mode 100644 index 0000000000..f7641453f2 --- /dev/null +++ b/site/src/components/Paywall/AIBridgePaywallConfig.ts @@ -0,0 +1,27 @@ +import type { ComponentProps } from "react"; +import type { Paywall } from "./Paywall"; + +// Centralized AI Bridge paywall configuration to avoid duplication. +export const aiBridgePaywallConfig: Omit, ""> = { + message: "AI Bridge", + description: + "AI Bridge provides auditable visibility into user prompts and LLM tool calls from developer tools within Coder Workspaces. AI Bridge requires a Premium license with AI Governance add-on.", + documentationLink: "https://coder.com/docs/ai-coder/ai-governance", + documentationLinkText: "Learn about AI Governance", + badgeText: "AI Governance", + ctaText: "Contact Sales", + ctaLink: "https://coder.com/contact", + features: [ + { text: "Auditable history of user prompts" }, + { text: "Logged LLM tool invocations" }, + { text: "Token usage and consumption visibility" }, + { text: "Centrally-managed MCP servers" }, + { + text: "Visit", + link: { + href: "https://coder.com/docs/ai-coder/ai-bridge", + text: "AI Bridge Docs", + }, + }, + ], +}; diff --git a/site/src/components/Paywall/Paywall.tsx b/site/src/components/Paywall/Paywall.tsx index cde84315b3..5236697240 100644 --- a/site/src/components/Paywall/Paywall.tsx +++ b/site/src/components/Paywall/Paywall.tsx @@ -10,61 +10,86 @@ interface PaywallProps { message: string; description?: ReactNode; documentationLink?: string; + documentationLinkText?: string; + features?: Array<{ + text: string; + link?: { href: string; text: string }; + }>; + badgeText?: string; + ctaText?: string; + ctaLink?: string; } export const Paywall: FC = ({ message, description, documentationLink, + documentationLinkText = "Read the documentation", + features, + badgeText = "Premium", + ctaText = "Learn about Premium", + ctaLink = "https://coder.com/pricing#compare-plans", }) => { + const defaultFeatures: Array<{ + text: string; + link?: { href: string; text: string }; + }> = [ + { text: "High availability & workspace proxies" }, + { text: "Multi-org & role-based access control" }, + { text: "24x7 global support with SLA" }, + { text: "Unlimited Git & external auth integrations" }, + ]; + + const displayFeatures = features ?? defaultFeatures; return (
{message}
- + {badgeText}
{description && ( -

{description}

+

{description}

+ )} + {documentationLink && ( + + {documentationLinkText} + )} - - Read the documentation -
    -
  • - - High availability & workspace proxies -
  • -
  • - - Multi-org & role-based access control -
  • -
  • - - 24x7 global support with SLA -
  • -
  • - - Unlimited Git & external auth integrations -
  • + {displayFeatures.map((feature, index) => ( +
  • + + {feature.text} + {feature.link && ( + <> + {" "} + + {feature.link.text} + + + )} +
  • + ))}
diff --git a/site/src/components/Paywall/PopoverPaywall.tsx b/site/src/components/Paywall/PopoverPaywall.tsx index 360c8b87ce..62502d3529 100644 --- a/site/src/components/Paywall/PopoverPaywall.tsx +++ b/site/src/components/Paywall/PopoverPaywall.tsx @@ -10,12 +10,18 @@ interface PopoverPaywallProps { message: string; description?: ReactNode; documentationLink?: string; + badgeText?: string; + ctaText?: string; + ctaLink?: string; } export const PopoverPaywall: FC = ({ message, description, documentationLink, + badgeText = "Premium", + ctaText = "Learn about Premium", + ctaLink = "https://coder.com/pricing#compare-plans", }) => { return (
= ({
{message}
- + {badgeText}
{description &&

{description}

} @@ -61,12 +67,8 @@ export const PopoverPaywall: FC = ({ diff --git a/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsPageView.tsx b/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsPageView.tsx index da2ab89f3c..27c80f8db8 100644 --- a/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsPageView.tsx +++ b/site/src/pages/AIBridgePage/RequestLogsPage/RequestLogsPageView.tsx @@ -3,6 +3,7 @@ import { PaginationContainer, type PaginationResult, } from "components/PaginationWidget/PaginationContainer"; +import { aiBridgePaywallConfig } from "components/Paywall/AIBridgePaywallConfig"; import { Paywall } from "components/Paywall/Paywall"; import { Table, @@ -14,7 +15,6 @@ import { import { TableEmpty } from "components/TableEmpty/TableEmpty"; import { TableLoader } from "components/TableLoader/TableLoader"; import type { ComponentProps, FC } from "react"; -import { docs } from "utils/docs"; import { RequestLogsFilter } from "./filter/RequestLogsFilter"; import { RequestLogsRow } from "./RequestLogsRow/RequestLogsRow"; @@ -34,13 +34,7 @@ export const RequestLogsPageView: FC = ({ filterProps, }) => { if (!isRequestLogsVisible) { - return ( - - ); + return ; } return ( diff --git a/site/src/pages/DeploymentSettingsPage/AIGovernanceSettingsPage/AIGovernanceSettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/AIGovernanceSettingsPage/AIGovernanceSettingsPageView.tsx index 45458177a3..8d69477519 100644 --- a/site/src/pages/DeploymentSettingsPage/AIGovernanceSettingsPage/AIGovernanceSettingsPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/AIGovernanceSettingsPage/AIGovernanceSettingsPageView.tsx @@ -1,7 +1,6 @@ import type { SerpentOption } from "api/typesGenerated"; -import { Badges, PremiumBadge } from "components/Badges/Badges"; +import { aiBridgePaywallConfig } from "components/Paywall/AIBridgePaywallConfig"; import { Paywall } from "components/Paywall/Paywall"; -import { PopoverPaywall } from "components/Paywall/PopoverPaywall"; import { SettingsHeader, SettingsHeaderDescription, @@ -9,11 +8,6 @@ import { SettingsHeaderTitle, } from "components/SettingsHeader/SettingsHeader"; import { Stack } from "components/Stack/Stack"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "components/Tooltip/Tooltip"; import type { FC } from "react"; import { deploymentGroupHasParent } from "utils/deployOptions"; import { docs } from "utils/docs"; @@ -29,33 +23,9 @@ export const AIGovernanceSettingsPageView: FC< > = ({ options, featureAIBridgeEnabled }) => { return ( -
- - AI Governance - - - - - - - - - - - - - - - -
+ + AI Governance + {featureAIBridgeEnabled ? (
@@ -79,11 +49,7 @@ export const AIGovernanceSettingsPageView: FC< />
) : ( - + )}
);