mirror of
https://github.com/coder/coder.git
synced 2026-10-31 02:43:21 +08:00
feat: show a premium paywall on the external auth settings page (#28435)
This commit is contained in:
Generated
+2
@@ -23829,6 +23829,7 @@ const docTemplate = `{
|
||||
"browser_only",
|
||||
"connection_log",
|
||||
"custom_roles",
|
||||
"external_auth",
|
||||
"groups",
|
||||
"idp_org_sync",
|
||||
"idp_sync",
|
||||
@@ -23850,6 +23851,7 @@ const docTemplate = `{
|
||||
"PremiumFunnelSourceBrowserOnly",
|
||||
"PremiumFunnelSourceConnectionLog",
|
||||
"PremiumFunnelSourceCustomRoles",
|
||||
"PremiumFunnelSourceExternalAuth",
|
||||
"PremiumFunnelSourceGroups",
|
||||
"PremiumFunnelSourceIdpOrgSync",
|
||||
"PremiumFunnelSourceIdpSync",
|
||||
|
||||
Generated
+2
@@ -21814,6 +21814,7 @@
|
||||
"browser_only",
|
||||
"connection_log",
|
||||
"custom_roles",
|
||||
"external_auth",
|
||||
"groups",
|
||||
"idp_org_sync",
|
||||
"idp_sync",
|
||||
@@ -21835,6 +21836,7 @@
|
||||
"PremiumFunnelSourceBrowserOnly",
|
||||
"PremiumFunnelSourceConnectionLog",
|
||||
"PremiumFunnelSourceCustomRoles",
|
||||
"PremiumFunnelSourceExternalAuth",
|
||||
"PremiumFunnelSourceGroups",
|
||||
"PremiumFunnelSourceIdpOrgSync",
|
||||
"PremiumFunnelSourceIdpSync",
|
||||
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
PremiumFunnelSourceBrowserOnly PremiumFunnelSource = "browser_only"
|
||||
PremiumFunnelSourceConnectionLog PremiumFunnelSource = "connection_log"
|
||||
PremiumFunnelSourceCustomRoles PremiumFunnelSource = "custom_roles"
|
||||
PremiumFunnelSourceExternalAuth PremiumFunnelSource = "external_auth"
|
||||
PremiumFunnelSourceGroups PremiumFunnelSource = "groups"
|
||||
PremiumFunnelSourceIdpOrgSync PremiumFunnelSource = "idp_org_sync"
|
||||
PremiumFunnelSourceIdpSync PremiumFunnelSource = "idp_sync"
|
||||
@@ -49,6 +50,7 @@ func PremiumFunnelSources() []PremiumFunnelSource {
|
||||
PremiumFunnelSourceBrowserOnly,
|
||||
PremiumFunnelSourceConnectionLog,
|
||||
PremiumFunnelSourceCustomRoles,
|
||||
PremiumFunnelSourceExternalAuth,
|
||||
PremiumFunnelSourceGroups,
|
||||
PremiumFunnelSourceIdpOrgSync,
|
||||
PremiumFunnelSourceIdpSync,
|
||||
|
||||
Generated
+3
-3
@@ -10674,9 +10674,9 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
|
||||
#### Enumerated Values
|
||||
|
||||
| Value(s) |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ai_gateway_keys`, `ai_governance`, `aibridge_session_threads`, `aibridge_sessions`, `appearance`, `audit_log`, `browser_only`, `connection_log`, `custom_roles`, `direct`, `groups`, `idp_org_sync`, `idp_sync`, `multiple_organizations`, `observability`, `provisioner_keys`, `provisioners`, `template_permissions`, `workspace_proxies` |
|
||||
| Value(s) |
|
||||
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `ai_gateway_keys`, `ai_governance`, `aibridge_session_threads`, `aibridge_sessions`, `appearance`, `audit_log`, `browser_only`, `connection_log`, `custom_roles`, `direct`, `external_auth`, `groups`, `idp_org_sync`, `idp_sync`, `multiple_organizations`, `observability`, `provisioner_keys`, `provisioners`, `template_permissions`, `workspace_proxies` |
|
||||
|
||||
## codersdk.PremiumFunnelVariant
|
||||
|
||||
|
||||
Generated
+2
@@ -7412,6 +7412,7 @@ export type PremiumFunnelSource =
|
||||
| "connection_log"
|
||||
| "custom_roles"
|
||||
| "direct"
|
||||
| "external_auth"
|
||||
| "groups"
|
||||
| "idp_org_sync"
|
||||
| "idp_sync"
|
||||
@@ -7433,6 +7434,7 @@ export const PremiumFunnelSources: PremiumFunnelSource[] = [
|
||||
"connection_log",
|
||||
"custom_roles",
|
||||
"direct",
|
||||
"external_auth",
|
||||
"groups",
|
||||
"idp_org_sync",
|
||||
"idp_sync",
|
||||
|
||||
+9
-1
@@ -1,16 +1,24 @@
|
||||
import type { FC } from "react";
|
||||
import { useAuthenticated } from "#/hooks/useAuthenticated";
|
||||
import { useFeatureVisibility } from "#/modules/dashboard/useFeatureVisibility";
|
||||
import { useDeploymentConfig } from "#/modules/management/DeploymentConfigProvider";
|
||||
import { pageTitle } from "#/utils/page";
|
||||
import { ExternalAuthSettingsPageView } from "./ExternalAuthSettingsPageView";
|
||||
|
||||
const ExternalAuthSettingsPage: FC = () => {
|
||||
const { deploymentConfig } = useDeploymentConfig();
|
||||
const { permissions } = useAuthenticated();
|
||||
const { multiple_external_auth: isEntitled } = useFeatureVisibility();
|
||||
|
||||
return (
|
||||
<>
|
||||
<title>{pageTitle("External Authentication Settings")}</title>
|
||||
|
||||
<ExternalAuthSettingsPageView config={deploymentConfig.config} />
|
||||
<ExternalAuthSettingsPageView
|
||||
config={deploymentConfig.config}
|
||||
isEntitled={isEntitled}
|
||||
canViewPremium={permissions.viewAllLicenses}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+30
-6
@@ -34,6 +34,8 @@ const meta: Meta<typeof ExternalAuthSettingsPageView> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
isEntitled: false,
|
||||
canViewPremium: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -44,13 +46,35 @@ export const Page: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const notice = canvas.getByRole("alert");
|
||||
await expect(within(notice).getByText("Premium")).toBeVisible();
|
||||
await expect(
|
||||
within(notice).getByRole("link", {
|
||||
name: "Read the External Authentication documentation",
|
||||
}),
|
||||
).toBeVisible();
|
||||
canvas.getByRole("link", { name: "Start trial for free" }),
|
||||
).toHaveAttribute("href", "/deployment/premium");
|
||||
},
|
||||
};
|
||||
|
||||
export const Entitled: Story = {
|
||||
args: {
|
||||
isEntitled: true,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await expect(
|
||||
canvas.queryByRole("link", { name: "Start trial for free" }),
|
||||
).not.toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
export const PaywallWithoutLicenseAccess: Story = {
|
||||
args: {
|
||||
canViewPremium: false,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await expect(
|
||||
canvas.queryByRole("link", { name: "Start trial for free" }),
|
||||
).not.toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
+20
-19
@@ -3,7 +3,6 @@ import type {
|
||||
DeploymentValues,
|
||||
ExternalAuthConfig,
|
||||
} from "#/api/typesGenerated";
|
||||
import { Alert } from "#/components/Alert/Alert";
|
||||
import {
|
||||
SettingsHeader,
|
||||
SettingsHeaderDescription,
|
||||
@@ -19,15 +18,19 @@ import {
|
||||
TableRow,
|
||||
} from "#/components/Table/Table";
|
||||
import { TableEmpty } from "#/components/TableEmpty/TableEmpty";
|
||||
import { PremiumPaywallSmall } from "#/modules/paywall/PremiumPaywallSmall";
|
||||
import { docs } from "#/utils/docs";
|
||||
|
||||
type ExternalAuthSettingsPageViewProps = {
|
||||
config: DeploymentValues;
|
||||
/** True when the deployment may configure more than one provider. */
|
||||
isEntitled: boolean;
|
||||
canViewPremium: boolean;
|
||||
};
|
||||
|
||||
export const ExternalAuthSettingsPageView: FC<
|
||||
ExternalAuthSettingsPageViewProps
|
||||
> = ({ config }) => {
|
||||
> = ({ config, isEntitled, canViewPremium }) => {
|
||||
return (
|
||||
<>
|
||||
<SettingsHeader
|
||||
@@ -52,23 +55,21 @@ export const ExternalAuthSettingsPageView: FC<
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="mt-6 mb-6">
|
||||
<Alert severity="info">
|
||||
Integrating with multiple external authentication providers is a
|
||||
Premium feature.{" "}
|
||||
<a
|
||||
href={docs(
|
||||
"/admin/external-auth#multiple-external-providers-premium",
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="text-content-link font-medium"
|
||||
>
|
||||
Read the External Authentication documentation
|
||||
</a>
|
||||
.
|
||||
</Alert>
|
||||
</div>
|
||||
{!isEntitled && (
|
||||
<div className="mt-6 mb-6">
|
||||
<PremiumPaywallSmall
|
||||
source="external_auth"
|
||||
message="External Authentication"
|
||||
description="Connect multiple Git and OAuth providers at once."
|
||||
features={[
|
||||
"Connect multiple Git providers at once",
|
||||
"Match providers by regex per host",
|
||||
"Separate credentials for each provider",
|
||||
]}
|
||||
canViewPremium={canViewPremium}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Table className="[&_td]:py-6 [&_td:last-child]:pl-8 [&_th:last-child]:pl-8">
|
||||
<TableHeader>
|
||||
|
||||
Reference in New Issue
Block a user