mirror of
https://github.com/logto-io/logto.git
synced 2025-03-24 22:41:28 -05:00
refactor(console): hide saml social connector entrance and fix SSO creation paywall (#5056)
This commit is contained in:
parent
a1725669d4
commit
774de5cc7b
4 changed files with 67 additions and 39 deletions
packages
console/src
integration-tests/src/tests/console/connectors
|
@ -54,7 +54,11 @@ function CreateConnectorForm({ onClose, isOpen: isFormOpen, type }: Props) {
|
|||
}
|
||||
|
||||
const allGroups = getConnectorGroups<ConnectorFactoryResponse>(
|
||||
factories.filter(({ type: factoryType, isDemo }) => factoryType === type && !isDemo)
|
||||
factories
|
||||
.filter(({ type: factoryType, isDemo }) => factoryType === type && !isDemo)
|
||||
// Hide the entrance of adding SAML social connectors, users should go to Enterprise SSO if they want to use SAML.
|
||||
// Should not remove the SAML factory from GET /connector-factories API, since that could break the existing SAML connectors.
|
||||
.filter(({ id }) => id !== 'saml')
|
||||
);
|
||||
|
||||
return allGroups
|
||||
|
|
|
@ -4,14 +4,18 @@ import {
|
|||
type RequestErrorBody,
|
||||
} from '@logto/schemas';
|
||||
import { HTTPError } from 'ky';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useMemo, useState, useContext } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import Modal from 'react-modal';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import ContactUsPhraseLink from '@/components/ContactUsPhraseLink';
|
||||
import Skeleton from '@/components/CreateConnectorForm/Skeleton';
|
||||
import { getConnectorRadioGroupSize } from '@/components/CreateConnectorForm/utils';
|
||||
import QuotaGuardFooter from '@/components/QuotaGuardFooter';
|
||||
import { isCloud } from '@/consts/env';
|
||||
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||
import Button from '@/ds-components/Button';
|
||||
import DynamicT from '@/ds-components/DynamicT';
|
||||
import FormField from '@/ds-components/FormField';
|
||||
|
@ -19,6 +23,7 @@ import ModalLayout from '@/ds-components/ModalLayout';
|
|||
import TextInput from '@/ds-components/TextInput';
|
||||
import { type RequestError } from '@/hooks/use-api';
|
||||
import useApi from '@/hooks/use-api';
|
||||
import useSubscriptionPlan from '@/hooks/use-subscription-plan';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
import { trySubmitSafe } from '@/utils/form';
|
||||
|
||||
|
@ -39,7 +44,12 @@ const duplicateConnectorNameErrorCode = 'single_sign_on.duplicate_connector_name
|
|||
|
||||
function SsoCreationModal({ isOpen, onClose: rawOnClose }: Props) {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const { currentTenantId } = useContext(TenantsContext);
|
||||
const { data: currentPlan } = useSubscriptionPlan(currentTenantId);
|
||||
const [selectedProviderName, setSelectedProviderName] = useState<string>();
|
||||
|
||||
const isSsoEnabled = !isCloud || currentPlan?.quota.ssoEnabled;
|
||||
|
||||
const { data, error } = useSWR<SsoConnectorProvidersResponse, RequestError>(
|
||||
'api/sso-connector-providers'
|
||||
);
|
||||
|
@ -122,18 +132,30 @@ function SsoCreationModal({ isOpen, onClose: rawOnClose }: Props) {
|
|||
<ModalLayout
|
||||
title="enterprise_sso.create_modal.title"
|
||||
footer={
|
||||
<Button
|
||||
title="enterprise_sso.create_modal.create_button_text"
|
||||
type="primary"
|
||||
disabled={
|
||||
// The button is available only when:
|
||||
// 1. `connectorName` field is not empty.
|
||||
// 2. At least one connector is selected.
|
||||
// 3. Error is resolved. Since `connectorName` is the only field of this form, it means `connectorName` field error is resolved.
|
||||
!(watch('connectorName') && isAnyConnectorSelected) || Boolean(errors.connectorName)
|
||||
}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
isSsoEnabled ? (
|
||||
<Button
|
||||
title="enterprise_sso.create_modal.create_button_text"
|
||||
type="primary"
|
||||
disabled={
|
||||
// The button is available only when:
|
||||
// 1. `connectorName` field is not empty.
|
||||
// 2. At least one connector is selected.
|
||||
// 3. Error is resolved. Since `connectorName` is the only field of this form, it means `connectorName` field error is resolved.
|
||||
!(watch('connectorName') && isAnyConnectorSelected) || Boolean(errors.connectorName)
|
||||
}
|
||||
onClick={onSubmit}
|
||||
/>
|
||||
) : (
|
||||
<QuotaGuardFooter>
|
||||
<Trans
|
||||
components={{
|
||||
a: <ContactUsPhraseLink />,
|
||||
}}
|
||||
>
|
||||
{t('upsell.paywall.organizations')}
|
||||
</Trans>
|
||||
</QuotaGuardFooter>
|
||||
)
|
||||
}
|
||||
size={radioGroupSize}
|
||||
onClose={onClose}
|
||||
|
|
|
@ -72,9 +72,10 @@ function EnterpriseSsoConnectors() {
|
|||
pageMeta={{ titleKey: 'enterprise_sso.page_title' }}
|
||||
createButton={conditional(
|
||||
ssoConnectors?.length && {
|
||||
title: isSsoEnabled ? 'enterprise_sso.create' : 'upsell.upgrade_plan',
|
||||
onClick: handleButtonClick,
|
||||
icon: conditional(isSsoEnabled && <Plus />),
|
||||
title: 'enterprise_sso.create',
|
||||
onClick: () => {
|
||||
navigate(createEnterpriseSsoPathname);
|
||||
},
|
||||
}
|
||||
)}
|
||||
table={{
|
||||
|
|
|
@ -87,35 +87,36 @@ const wechatWeb: SocialConnectorCase = {
|
|||
},
|
||||
};
|
||||
|
||||
const saml: SocialConnectorCase = {
|
||||
factoryId: 'saml',
|
||||
name: 'SAML',
|
||||
const oidc: SocialConnectorCase = {
|
||||
factoryId: 'oidc',
|
||||
name: 'OIDC',
|
||||
initialFormData: {
|
||||
'formConfig.entityID': 'entity-id',
|
||||
'formConfig.signInEndpoint': 'sign-in-endpoint',
|
||||
'formConfig.x509Certificate': 'x509-certificate',
|
||||
'formConfig.idpMetadataXml': 'idp-metadata-xml',
|
||||
'formConfig.assertionConsumerServiceUrl': 'assertion-consumer-service-url',
|
||||
'formConfig.authorizationEndpoint': 'authorization-endpoint',
|
||||
'formConfig.tokenEndpoint': 'token-endpoint',
|
||||
'formConfig.clientId': 'client-id',
|
||||
'formConfig.clientSecret': 'client-secret',
|
||||
'formConfig.scope': 'scope1 scope2',
|
||||
},
|
||||
updateFormData: {
|
||||
'formConfig.entityID': 'new-entity-id',
|
||||
'formConfig.signInEndpoint': 'new-sign-in-endpoint',
|
||||
'formConfig.x509Certificate': 'new-x509-certificate',
|
||||
'formConfig.idpMetadataXml': 'new-idp-metadata-xml',
|
||||
'formConfig.assertionConsumerServiceUrl': 'new-assertion-consumer-service-url',
|
||||
'formConfig.authorizationEndpoint': 'new-authorization-endpoint',
|
||||
'formConfig.tokenEndpoint': 'new-token-endpoint',
|
||||
'formConfig.clientId': 'new-client-id',
|
||||
'formConfig.clientSecret': 'new-client-secret',
|
||||
'formConfig.scope': 'scope1 scope2 scope3',
|
||||
},
|
||||
errorFormData: {
|
||||
'formConfig.entityID': '',
|
||||
'formConfig.signInEndpoint': '',
|
||||
'formConfig.x509Certificate': '',
|
||||
'formConfig.idpMetadataXml': '',
|
||||
'formConfig.assertionConsumerServiceUrl': '',
|
||||
'formConfig.authorizationEndpoint': '',
|
||||
'formConfig.tokenEndpoint': '',
|
||||
'formConfig.clientId': '',
|
||||
'formConfig.clientSecret': '',
|
||||
'formConfig.scope': '',
|
||||
},
|
||||
standardBasicFormData: {
|
||||
name: 'SAML',
|
||||
target: 'saml',
|
||||
name: 'OIDC',
|
||||
target: 'oidc-test',
|
||||
},
|
||||
};
|
||||
|
||||
export const socialConnectorTestCases = [
|
||||
// Universal
|
||||
google,
|
||||
|
@ -126,5 +127,5 @@ export const socialConnectorTestCases = [
|
|||
// Group - Web
|
||||
wechatWeb,
|
||||
// Standard
|
||||
saml,
|
||||
oidc,
|
||||
];
|
||||
|
|
Loading…
Add table
Reference in a new issue