0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-30 20:33:54 -05:00

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
This commit is contained in:
Xiao Yijun 2024-08-28 09:53:54 +08:00 committed by GitHub
parent 652898f978
commit 3d3a220306
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 84 additions and 41 deletions

View file

@ -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'],
});
```

View file

@ -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, keyof typeof experience.routes> = {
[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,12 +125,9 @@ 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 (directSignIn) {
searchParams.append('fallback', firstScreen);

View file

@ -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 */}
<Route path={experience.routes.sso}>
{/* Single sign-on first screen landing page */}
{isDevFeaturesEnabled && <Route index element={<SingleSignOnLanding />} />}
<Route index element={<SingleSignOnLanding />} />
<Route path="email" element={<SingleSignOnEmail />} />
<Route path="connectors" element={<SingleSignOnConnectors />} />
</Route>
@ -127,27 +126,32 @@ const App = () => {
{/* Consent */}
<Route path="consent" element={<Consent />} />
{isDevFeaturesEnabled && (
<>
{/* Identifier sign-in */}
{/*
* Identifier sign-in (first screen)
* The first screen which only display specific identifier-based sign-in methods to users
*/}
<Route
path={experience.routes.identifierSignIn}
element={<IdentifierSignIn />}
/>
{/* Identifier register */}
{/*
* Identifier register (first screen)
* The first screen which only display specific identifier-based registration methods to users
*/}
<Route
path={experience.routes.identifierRegister}
element={<IdentifierRegister />}
/>
{/* Reset password */}
{/*
* Reset password (first screen)
* The first screen which allow users to directly access the password reset page
*/}
<Route
path={experience.routes.resetPassword}
element={<ResetPasswordLanding />}
/>
</>
)}
<Route path="*" element={<ErrorPage />} />
</Route>

View file

@ -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();

View file

@ -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();

View file

@ -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 () => {