From 3d3a220306716e21a4bab9352574b6464e20397b Mon Sep 17 00:00:00 2001 From: Xiao Yijun Date: Wed, 28 Aug 2024 09:53:54 +0800 Subject: [PATCH] chore: remove dev feature guard for first screens (#6522) * chore: remove dev feature guard for new first screens * chore: add changeset * chore(experience): add comments for identifier sign-in and register page --- .changeset/nine-vans-whisper.md | 30 ++++++++++++ packages/core/src/oidc/utils.ts | 25 ++++------ packages/experience/src/App.tsx | 46 ++++++++++--------- .../src/pages/IdentifierRegister/index.tsx | 9 ++++ .../src/pages/IdentifierSignIn/index.tsx | 12 +++++ .../src/tests/experience/first-screen.test.ts | 3 -- 6 files changed, 84 insertions(+), 41 deletions(-) create mode 100644 .changeset/nine-vans-whisper.md diff --git a/.changeset/nine-vans-whisper.md b/.changeset/nine-vans-whisper.md new file mode 100644 index 000000000..ab48d6f55 --- /dev/null +++ b/.changeset/nine-vans-whisper.md @@ -0,0 +1,30 @@ +--- +"@logto/integration-tests": minor +"@logto/experience": minor +"@logto/core": minor +--- + +add support for additional first screen options + +This feature introduces new first screen options, allowing developers to customize the initial screen presented to users. In addition to the existing `sign_in` and `register` options, the following first screen choices are now supported: + +- `identifier:sign_in`: Only display specific identifier-based sign-in methods to users. +- `identifier:register`: Only display specific identifier-based registration methods to users. +- `reset_password`: Allow users to directly access the password reset page. +- `single_sign_on`: Allow users to directly access the single sign-on (SSO) page. + +Example: + +```javascript +// Example usage (React project using React SDK) +void signIn({ + redirectUri, + firstScreen: 'identifier:sign_in', + /** + * Optional. Specifies which sign-in methods to display on the identifier sign-in page. + * If not specified, the default sign-in experience configuration will be used. + * This option is effective when the `firstScreen` value is `identifier:sign_in`, `identifier:register`, or `reset_password`. + */ + identifiers: ['email', 'phone'], +}); +``` diff --git a/packages/core/src/oidc/utils.ts b/packages/core/src/oidc/utils.ts index 90d86252f..e5faf35bc 100644 --- a/packages/core/src/oidc/utils.ts +++ b/packages/core/src/oidc/utils.ts @@ -12,9 +12,7 @@ import { import { conditional } from '@silverhand/essentials'; import { type AllClientMetadata, type ClientAuthMethod, errors } from 'oidc-provider'; -import { EnvSet } from '#src/env-set/index.js'; - -const { isDevFeaturesEnabled } = EnvSet.values; +import { type EnvSet } from '#src/env-set/index.js'; export const getConstantClientMetadata = ( envSet: EnvSet, @@ -91,19 +89,15 @@ export const getUtcStartOfTheDay = (date: Date) => { const firstScreenRouteMapping: Record = { [FirstScreen.SignIn]: 'signIn', [FirstScreen.Register]: 'register', - /** - * Todo @xiaoyijun remove isDevFeaturesEnabled check - * Fallback to signIn when dev feature is not ready (these three screens are not supported yet) - */ - [FirstScreen.ResetPassword]: isDevFeaturesEnabled ? 'resetPassword' : 'signIn', - [FirstScreen.IdentifierSignIn]: isDevFeaturesEnabled ? 'identifierSignIn' : 'signIn', - [FirstScreen.IdentifierRegister]: isDevFeaturesEnabled ? 'identifierRegister' : 'signIn', - [FirstScreen.SingleSignOn]: isDevFeaturesEnabled ? 'sso' : 'signIn', + [FirstScreen.ResetPassword]: 'resetPassword', + [FirstScreen.IdentifierSignIn]: 'identifierSignIn', + [FirstScreen.IdentifierRegister]: 'identifierRegister', + [FirstScreen.SingleSignOn]: 'sso', [FirstScreen.SignInDeprecated]: 'signIn', }; // Note: this eslint comment can be removed once the dev feature flag is removed -// eslint-disable-next-line complexity + export const buildLoginPromptUrl = (params: ExtraParamsObject, appId?: unknown): string => { const firstScreenKey = params[ExtraParamsKey.FirstScreen] ?? @@ -131,11 +125,8 @@ export const buildLoginPromptUrl = (params: ExtraParamsObject, appId?: unknown): searchParams.append(ExtraParamsKey.LoginHint, params[ExtraParamsKey.LoginHint]); } - if (isDevFeaturesEnabled) { - // eslint-disable-next-line unicorn/no-lonely-if - if (params[ExtraParamsKey.Identifier]) { - searchParams.append(ExtraParamsKey.Identifier, params[ExtraParamsKey.Identifier]); - } + if (params[ExtraParamsKey.Identifier]) { + searchParams.append(ExtraParamsKey.Identifier, params[ExtraParamsKey.Identifier]); } if (directSignIn) { diff --git a/packages/experience/src/App.tsx b/packages/experience/src/App.tsx index c23c4eb57..3f2912334 100644 --- a/packages/experience/src/App.tsx +++ b/packages/experience/src/App.tsx @@ -7,7 +7,6 @@ import LoadingLayerProvider from './Providers/LoadingLayerProvider'; import PageContextProvider from './Providers/PageContextProvider'; import SettingsProvider from './Providers/SettingsProvider'; import UserInteractionContextProvider from './Providers/UserInteractionContextProvider'; -import { isDevFeaturesEnabled } from './constants/env'; import Callback from './pages/Callback'; import Consent from './pages/Consent'; import Continue from './pages/Continue'; @@ -119,7 +118,7 @@ const App = () => { {/* Single sign-on */} {/* Single sign-on first screen landing page */} - {isDevFeaturesEnabled && } />} + } /> } /> } /> @@ -127,27 +126,32 @@ const App = () => { {/* Consent */} } /> - {isDevFeaturesEnabled && ( - <> - {/* Identifier sign-in */} - } - /> + {/* + * Identifier sign-in (first screen) + * The first screen which only display specific identifier-based sign-in methods to users + */} + } + /> - {/* Identifier register */} - } - /> + {/* + * Identifier register (first screen) + * The first screen which only display specific identifier-based registration methods to users + */} + } + /> - {/* Reset password */} - } - /> - - )} + {/* + * Reset password (first screen) + * The first screen which allow users to directly access the password reset page + */} + } + /> } /> diff --git a/packages/experience/src/pages/IdentifierRegister/index.tsx b/packages/experience/src/pages/IdentifierRegister/index.tsx index 09477f1cb..231ae0cc7 100644 --- a/packages/experience/src/pages/IdentifierRegister/index.tsx +++ b/packages/experience/src/pages/IdentifierRegister/index.tsx @@ -10,6 +10,15 @@ import { identifierInputDescriptionMap } from '@/utils/form'; import useIdentifierSignUpMethods from './use-identifier-sign-up-methods'; +/** + * Identifier register page + * + * This page is used to display specific identifier-based registration methods to users. + * + * This page can be used as the first screen of the authentication flow, + * and can be configured by setting the `first_screen` parameter to `identifier:register` + * in the authentication URL. + */ const IdentifierRegister = () => { const { t } = useTranslation(); const signUpMethods = useIdentifierSignUpMethods(); diff --git a/packages/experience/src/pages/IdentifierSignIn/index.tsx b/packages/experience/src/pages/IdentifierSignIn/index.tsx index f81a8ed91..95ed287e6 100644 --- a/packages/experience/src/pages/IdentifierSignIn/index.tsx +++ b/packages/experience/src/pages/IdentifierSignIn/index.tsx @@ -11,6 +11,18 @@ import { identifierInputDescriptionMap } from '@/utils/form'; import useIdentifierSignInMethods from './use-identifier-sign-in-methods'; +/** + * Identifier sign-in page + * + * This page is used to display specific identifier-based sign-in methods to users. + * + * This page can be used as the first screen of the authentication flow, + * and can be configured by setting the `first_screen` parameter to `identifier:sign_in` + * in the authentication URL. + * + * identifiers used in this page can be configured by setting the `identifier` parameter + * in the authentication URL, multiple identifiers can be separated by space. + */ const IdentifierSignIn = () => { const { t } = useTranslation(); diff --git a/packages/integration-tests/src/tests/experience/first-screen.test.ts b/packages/integration-tests/src/tests/experience/first-screen.test.ts index 343e05a01..e86948d50 100644 --- a/packages/integration-tests/src/tests/experience/first-screen.test.ts +++ b/packages/integration-tests/src/tests/experience/first-screen.test.ts @@ -10,9 +10,6 @@ import { setSmsConnector, } from '#src/helpers/connector.js'; import ExpectExperience from '#src/ui-helpers/expect-experience.js'; -import { devFeatureTest } from '#src/utils.js'; - -const { describe, it } = devFeatureTest; describe('first screen', () => { beforeAll(async () => {