@@ -3,16 +3,25 @@ import { InviteLinkEnabledSettingsCard } from "./components/inviteLinkEnabledSet
33import { MemberApprovalRequiredSettingsCard } from "./components/memberApprovalRequiredSettingsCard" ;
44import { CredentialsLoginEnabledSettingsCard } from "./components/credentialsLoginEnabledSettingsCard" ;
55import { EmailCodeLoginEnabledSettingsCard } from "./components/emailCodeLoginEnabledSettingsCard" ;
6- import { isAnonymousAccessEnabled } from "@/lib/entitlements" ;
6+ import { IdentityProviderSettingsCard } from "./components/identityProviderSettingsCard" ;
7+ import { IdentityProviderUpsellCard } from "./components/identityProviderUpsellCard" ;
8+ import { UpgradeBadge } from "@/app/(app)/@sidebar/components/upgradeBadge" ;
9+ import { getProviders , IdentityProvider } from "@/auth" ;
10+ import { hasEntitlement , isAnonymousAccessEnabled } from "@/lib/entitlements" ;
711import { createInviteLink } from "@/lib/utils" ;
812import { authenticatedPage } from "@/middleware/authenticatedPage" ;
913import { OrgRole } from "@sourcebot/db" ;
1014import { env , getSMTPConnectionURL , isCredentialsLoginEnabled , isEmailCodeLoginEnabled , isMemberApprovalRequired } from "@sourcebot/shared" ;
1115import { SettingsCardGroup } from "../components/settingsCard" ;
16+ import { Alert , AlertDescription } from "@/components/ui/alert" ;
17+ import { Info } from "lucide-react" ;
1218
1319export default authenticatedPage ( async ( { org } ) => {
1420 const anonymousAccessEnabled = await isAnonymousAccessEnabled ( ) ;
1521 const inviteLink = createInviteLink ( env . AUTH_URL , org . inviteLinkId ) ;
22+ const hasSSOEntitlement = await hasEntitlement ( "sso" ) ;
23+ const identityProviders = await getConfiguredIdentityProviders ( ) ;
24+
1625
1726 return (
1827 < div className = "flex flex-col gap-6" >
@@ -25,7 +34,7 @@ export default authenticatedPage(async ({ org }) => {
2534 href = "https://docs.sourcebot.dev/docs/configuration/auth/access-settings"
2635 target = "_blank"
2736 rel = "noopener"
28- className = "underline text-primary hover:text-primary/80 transition-colors"
37+ className = "text-link hover:underline transition-colors"
2938 >
3039 Learn more
3140 </ a >
@@ -45,7 +54,7 @@ export default authenticatedPage(async ({ org }) => {
4554 />
4655 </ SettingsCardGroup >
4756
48- < p className = "text-md font-medium" > Authentication methods </ p >
57+ < p className = "text-md font-medium" > Email login </ p >
4958
5059 < SettingsCardGroup >
5160 < CredentialsLoginEnabledSettingsCard
@@ -56,10 +65,59 @@ export default authenticatedPage(async ({ org }) => {
5665 isEmailServiceConfigured = { ! ! getSMTPConnectionURL ( ) && ! ! env . EMAIL_FROM_ADDRESS }
5766 />
5867 </ SettingsCardGroup >
68+
69+ < div >
70+ < div className = "flex items-center gap-2" >
71+ < p className = "text-md font-medium" > Single Sign-On</ p >
72+ { ! hasSSOEntitlement && < UpgradeBadge /> }
73+ </ div >
74+ < p className = "text-sm text-muted-foreground" > Let users sign in with an external identity provider such as GitHub, Google, or Okta. Providers are managed in your config file.{ " " }
75+ < a
76+ href = "https://docs.sourcebot.dev/docs/configuration/idp"
77+ target = "_blank"
78+ rel = "noopener"
79+ className = "text-link hover:underline transition-colors"
80+ >
81+ Learn more
82+ </ a >
83+ </ p >
84+ </ div >
85+
86+ { ! hasSSOEntitlement ? (
87+ < IdentityProviderUpsellCard />
88+ ) : identityProviders . length > 0 ? (
89+ < SettingsCardGroup >
90+ { identityProviders . map ( ( provider ) => (
91+ < IdentityProviderSettingsCard key = { provider . id } provider = { provider } />
92+ ) ) }
93+ </ SettingsCardGroup >
94+ ) : (
95+ < Alert className = "items-center p-4" >
96+ < Info className = "w-4 h-4 text-muted-foreground" />
97+ < AlertDescription >
98+ No identity providers are configured. Add them in your config file.{ " " }
99+ < a
100+ href = "https://docs.sourcebot.dev/docs/configuration/idp"
101+ target = "_blank"
102+ rel = "noopener"
103+ className = "!text-link !no-underline hover:!underline"
104+ >
105+ Learn more
106+ </ a >
107+ </ AlertDescription >
108+ </ Alert >
109+ ) }
59110 </ div >
60111 </ div >
61112 )
62113} , {
63114 minRole : OrgRole . OWNER ,
64115 redirectTo : '/settings' ,
65116} ) ;
117+
118+ const getConfiguredIdentityProviders = async ( ) : Promise < IdentityProvider [ ] > => {
119+ const providers = await getProviders ( ) ;
120+ return providers . filter ( ( provider ) =>
121+ provider . purpose === "sso" && ! [ "credentials" , "nodemailer" ] . includes ( provider . type )
122+ ) ;
123+ }
0 commit comments