From c2c15e8bcfe3e9463570893a3a21332b230b3a2b Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Tue, 18 Jun 2024 10:00:35 +0800 Subject: [PATCH] refactor(console): show sso status in jit domains (#6040) --- .../Settings/index.module.scss | 5 ++ .../OrganizationDetails/Settings/index.tsx | 47 +++++++++++++++++-- .../admin-console/enterprise-sso-details.ts | 6 +-- .../admin-console/organization-details.ts | 2 + 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/packages/console/src/pages/OrganizationDetails/Settings/index.module.scss b/packages/console/src/pages/OrganizationDetails/Settings/index.module.scss index 41873ee06..704fd1293 100644 --- a/packages/console/src/pages/OrganizationDetails/Settings/index.module.scss +++ b/packages/console/src/pages/OrganizationDetails/Settings/index.module.scss @@ -4,6 +4,11 @@ margin-top: _.unit(3); } +.ssoEnabled { + vertical-align: middle; + color: var(--color-text-link); +} + .warning { margin-top: _.unit(3); } diff --git a/packages/console/src/pages/OrganizationDetails/Settings/index.tsx b/packages/console/src/pages/OrganizationDetails/Settings/index.tsx index 2645c3e92..3e77e8176 100644 --- a/packages/console/src/pages/OrganizationDetails/Settings/index.tsx +++ b/packages/console/src/pages/OrganizationDetails/Settings/index.tsx @@ -1,12 +1,14 @@ -import { type SignInExperience, type Organization } from '@logto/schemas'; +import { type SignInExperience, type Organization, type SsoConnector } from '@logto/schemas'; import { trySafe } from '@silverhand/essentials'; -import { useState } from 'react'; +import { useState, useCallback } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { toast } from 'react-hot-toast'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import { useOutletContext } from 'react-router-dom'; import useSWR from 'swr'; +import useSWRInfinite from 'swr/infinite'; +import SsoIcon from '@/assets/icons/single-sign-on.svg'; import DetailsForm from '@/components/DetailsForm'; import FormCard from '@/components/FormCard'; import MultiOptionInput from '@/components/MultiOptionInput'; @@ -82,6 +84,21 @@ function Settings() { const [isJitEnabled, isMfaRequired] = watch(['isJitEnabled', 'isMfaRequired']); const api = useApi(); const [keyword, setKeyword] = useState(''); + // Fetch all SSO connector to show if a domain is configured SSO + const { data: ssoConnectors } = useSWRInfinite( + (index, previous) => { + return previous && previous.length === 0 ? null : `api/sso-connectors?page=${index + 1}`; + }, + { initialSize: Number.POSITIVE_INFINITY } + ); + + const hasSsoEnabled = useCallback( + (domain: string) => + ssoConnectors?.some((connectors) => + connectors.some(({ domains }) => domains.includes(domain)) + ), + [ssoConnectors] + ); const onSubmit = handleSubmit( trySubmitSafe(async (data) => { @@ -167,14 +184,34 @@ function Settings() { {isJitEnabled && ( - + , + }} + > + {t('organization_details.jit.sso_email_domain_description')} + + } + > ( value} + renderValue={(value) => + hasSsoEnabled(value) ? ( + <> + + {value} + + ) : ( + value + ) + } validateInput={(input) => { if (!domainRegExp.test(input)) { return t('organization_details.jit.invalid_domain'); diff --git a/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso-details.ts b/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso-details.ts index c1a822fd0..aeb0e1500 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso-details.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/enterprise-sso-details.ts @@ -9,10 +9,10 @@ const enterprise_sso_details = { custom_branding_title: 'Display', custom_branding_description: "Customize the name and logo displayed in the end users' Single Sign-On flow. When empty, defaults are used.", - email_domain_field_name: 'Enterprise email domain', + email_domain_field_name: 'Enterprise email domains', email_domain_field_description: - 'Users with this email domain can use SSO for authentication. Please verify the domain belongs to the enterprise.', - email_domain_field_placeholder: 'Email domain', + 'Users with these email domains can use SSO for authentication. Please verify the domain ownership before adding.', + email_domain_field_placeholder: 'Enter one or more email domains (e.g. yourcompany.com)', sync_profile_field_name: 'Sync profile information from the identity provider', sync_profile_option: { register_only: 'Only sync at first sign-in', diff --git a/packages/phrases/src/locales/en/translation/admin-console/organization-details.ts b/packages/phrases/src/locales/en/translation/admin-console/organization-details.ts index bf40162d8..332ecb6e4 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/organization-details.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/organization-details.ts @@ -36,6 +36,8 @@ const organization_details = { email_domains: 'JIT provisioning email domains', email_domains_placeholder: 'Enter email domains for just-in-time provisioning', invalid_domain: 'Invalid domain', + sso_email_domain_description: + ' means the domain is enabled for enterprise SSO. Users who signed in through the configured IdP can automatically join the organization.', domain_already_added: 'Domain already added', organization_roles: 'Default organization roles', organization_roles_description: