From a7b0f8ba3636e5d16e27e35993066daf9d2429be Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sat, 20 Jul 2024 19:25:50 -0400 Subject: [PATCH] feat!: new server-only, faster and immediate autoLogin (#7224) - When autoLogin is enabled, it will no longer flash an unresponsive "login" screen. Instead, it will straight up open the admin panel. That's because, on the server, we will now always & immediately see the user as authenticated, thus no initial login view is pushed to the client until the client component sends the auth request anymore. Less useless requests. Additionally, jwt verification is now completely skipped - No more auto-login related frontend code. autoLogin handling has been removed from the frontend `Auth` component - less code to maintain, this is way simpler now **For reviewers:** - The new logic for autoFill without prefillOnly is here: [jwt auth strategy](https://github.com/payloadcms/payload/pull/7224/files#diff-7d40839079a8b2abb58233e5904513ab321023a70538229dfaf1dfee067dc8bfR21) - The new logic for autoFill with prefillOnly is here: [Server Login View](https://github.com/payloadcms/payload/pull/7224/files#diff-683770104f196196743398a698fbf8987f00e4426ca1c0ace3658d18ab80e82dL72) => [Client Login Form](https://github.com/payloadcms/payload/pull/7224/files#diff-ac3504d3b3b0489455245663649bef9e84477bf0c1185da5a4d3a612450f01eeL20) **BREAKING** `autoLogin` without `prefillOnly` set now also affects graphQL/Rest operations. Only the user specified in `autoLogin` will be returned. Within the graphQL/Rest/Local API, this should still allow you to authenticate with a different user, as the autoLogin user is only used if no token is set. --- docs/admin/overview.mdx | 26 +- docs/authentication/overview.mdx | 34 +- docs/configuration/overview.mdx | 62 +- .../next/src/views/Login/LoginForm/index.tsx | 20 +- packages/next/src/views/Login/index.tsx | 27 +- packages/payload/src/auth/strategies/jwt.ts | 41 + packages/payload/src/config/client.ts | 54 +- packages/payload/src/config/types.ts | 9 +- packages/ui/src/providers/Auth/index.tsx | 53 +- test/_community/e2e.spec.ts | 4 +- test/_community/payload-types.ts | 8 +- test/access-control/e2e.spec.ts | 4 +- test/admin/e2e/1/e2e.spec.ts | 14 +- test/admin/e2e/2/e2e.spec.ts | 6 +- test/admin/payload-types.ts | 8 +- test/auth/e2e.spec.ts | 4 +- test/buildConfigWithDefaults.ts | 11 +- test/field-error-states/e2e.spec.ts | 8 +- test/fields-relationship/e2e.spec.ts | 6 +- test/fields/collections/Array/e2e.spec.ts | 6 +- test/fields/collections/Blocks/e2e.spec.ts | 6 +- test/fields/collections/Date/e2e.spec.ts | 6 +- .../Lexical/e2e/blocks/e2e.spec.ts | 4 +- .../collections/Lexical/e2e/main/e2e.spec.ts | 4 +- test/fields/collections/Number/e2e.spec.ts | 6 +- test/fields/collections/Point/e2e.spec.ts | 6 +- .../collections/Relationship/e2e.spec.ts | 6 +- test/fields/collections/RichText/e2e.spec.ts | 6 +- test/fields/collections/Tabs/e2e.spec.ts | 6 +- test/fields/collections/Text/e2e.spec.ts | 6 +- test/fields/collections/Upload/e2e.spec.ts | 6 +- test/fields/e2e.spec.ts | 10 +- test/fields/payload-types.ts | 1762 +++++++++-------- test/helpers.ts | 17 +- test/helpers/NextRESTClient.ts | 3 + test/i18n/e2e.spec.ts | 6 +- test/live-preview/e2e.spec.ts | 4 +- test/localization/e2e.spec.ts | 4 +- test/package.json | 10 + test/plugin-cloud-storage/e2e.spec.ts | 4 +- test/plugin-form-builder/e2e.spec.ts | 4 +- test/plugin-nested-docs/e2e.spec.ts | 4 +- test/plugin-seo/e2e.spec.ts | 4 +- test/uploads/e2e.spec.ts | 4 +- test/versions/e2e.spec.ts | 4 +- 45 files changed, 1171 insertions(+), 1136 deletions(-) diff --git a/docs/admin/overview.mdx b/docs/admin/overview.mdx index f483a3bc1..137d3956e 100644 --- a/docs/admin/overview.mdx +++ b/docs/admin/overview.mdx @@ -86,19 +86,19 @@ const config = buildConfig({ The following options are available: -| Option | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More details](../authentication/overview). | -| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. | -| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. | -| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). | -| `custom` | Any custom properties you wish to pass to the Admin Panel. | -| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. | -| `disable` | If set to `true`, the entire Admin Panel will be disabled. | -| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). | -| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. | -| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). | -| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). | +| Option | Description | +|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. | +| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). | +| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. | +| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). | +| `custom` | Any custom properties you wish to pass to the Admin Panel. | +| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. | +| `disable` | If set to `true`, the entire Admin Panel will be disabled. | +| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). | +| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. | +| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). | +| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). | Reminder: diff --git a/docs/authentication/overview.mdx b/docs/authentication/overview.mdx index 22bd60679..e1c402949 100644 --- a/docs/authentication/overview.mdx +++ b/docs/authentication/overview.mdx @@ -127,30 +127,27 @@ If set to `true`, users can log in with either their username or email address. If set to `true`, an email address is required when creating a new user. If set to `false`, email is not required upon creation. -## Admin Auto-Login +## Auto-Login -For testing and demo purposes you may want to skip forcing the admin user to login in order to access the [Admin Panel](../admin/overview). Typically, all users should be required to login to access the Admin Panel, however, you can speed up local development time by enabling auto-login. +For testing and demo purposes you may want to skip forcing the user to login in order to access your application. Typically, all users should be required to login, however, you can speed up local development time by enabling auto-login. To enable auto-login, set the `autoLogin` property in the [Admin Config](../configuration/admin): ```ts -import { buildConfig } from 'payload/config' +import { buildConfig } from 'payload' export default buildConfig({ // ... - admin: { - // ... - // highlight-start - autoLogin: - process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true' - ? { - email: 'test@example.com', - password: 'test', - prefillOnly: true, - } - : false, - // highlight-end - }, + // highlight-start + autoLogin: + process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true' + ? { + email: 'test@example.com', + password: 'test', + prefillOnly: true, + } + : false, + // highlight-end }) ``` @@ -162,9 +159,10 @@ export default buildConfig({ The following options are available: | Option | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------- | +|-------------------|-----------------------------------------------------------------------------------------------------------------| +| **`username`** | The username of the user to login as | | **`email`** | The email address of the user to login as | -| **`password`** | The password of the user to login as | +| **`password`** | The password of the user to login as. This is only needed if `prefillOnly` is set to true | | **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. | ## Operations diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index 233d0dcc7..487e6bb5a 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -64,38 +64,38 @@ export default buildConfig({ The following options are available: -| Option | Description | -| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). | -| **`bin`** | Register custom bin scripts for Payload to execute. | -| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). | -| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). | -| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. | -| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). | -| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). | +| Option | Description | +|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). | +| **`bin`** | Register custom bin scripts for Payload to execute. | +| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). | +| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). | +| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. | +| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). | +| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). | | **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). | -| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). | -| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). | -| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. | -| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). | -| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). | -| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. | -| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). | -| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. | -| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). | -| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). | -| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). | -| **`debug`** | Enable to expose more detailed error information. | -| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). | -| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). | -| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). | -| **`plugins`** | An array of Plugins. [More details](../plugins/overview). | -| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). | -| **`custom`** | Extension point for adding custom data (e.g. for plugins). | -| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). | -| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. | -| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. | -| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). | +| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). | +| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). | +| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. | +| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). | +| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). | +| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. | +| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). | +| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. | +| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). | +| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). | +| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). | +| **`debug`** | Enable to expose more detailed error information. | +| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). | +| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). | +| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). | +| **`plugins`** | An array of Plugins. [More details](../plugins/overview). | +| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). | +| **`custom`** | Extension point for adding custom data (e.g. for plugins). | +| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). | +| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. | +| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. | +| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). | _\* An asterisk denotes that a property is required._ diff --git a/packages/next/src/views/Login/LoginForm/index.tsx b/packages/next/src/views/Login/LoginForm/index.tsx index 0673c9397..05aef5f60 100644 --- a/packages/next/src/views/Login/LoginForm/index.tsx +++ b/packages/next/src/views/Login/LoginForm/index.tsx @@ -17,13 +17,15 @@ import { LoginField } from '../LoginField/index.js' import './index.scss' export const LoginForm: React.FC<{ + prefillEmail?: string + prefillPassword?: string + prefillUsername?: string searchParams: { [key: string]: string | string[] | undefined } -}> = ({ searchParams }) => { +}> = ({ prefillEmail, prefillPassword, prefillUsername, searchParams }) => { const config = useConfig() const { admin: { - autoLogin, routes: { forgot: forgotRoute }, user: userSlug, }, @@ -45,27 +47,25 @@ export const LoginForm: React.FC<{ const { t } = useTranslation() - const prefillForm = autoLogin && autoLogin.prefillOnly - const initialState: FormState = { password: { - initialValue: prefillForm ? autoLogin.password : undefined, + initialValue: prefillPassword ?? undefined, valid: true, - value: prefillForm ? autoLogin.password : undefined, + value: prefillPassword ?? undefined, }, } if (loginWithUsername) { initialState.username = { - initialValue: prefillForm ? autoLogin.username : undefined, + initialValue: prefillUsername ?? undefined, valid: true, - value: prefillForm ? autoLogin.username : undefined, + value: prefillUsername ?? undefined, } } else { initialState.email = { - initialValue: prefillForm ? autoLogin.email : undefined, + initialValue: prefillEmail ?? undefined, valid: true, - value: prefillForm ? autoLogin.email : undefined, + value: prefillEmail ?? undefined, } } diff --git a/packages/next/src/views/Login/index.tsx b/packages/next/src/views/Login/index.tsx index be61f74ff..827155f82 100644 --- a/packages/next/src/views/Login/index.tsx +++ b/packages/next/src/views/Login/index.tsx @@ -70,6 +70,24 @@ export const LoginView: React.FC = ({ initPageResult, params, se const collectionConfig = collections.find(({ slug }) => slug === userSlug) + const prefillAutoLogin = + typeof config.admin?.autoLogin === 'object' && config.admin?.autoLogin.prefillOnly + + const prefillUsername = + prefillAutoLogin && typeof config.admin?.autoLogin === 'object' + ? config.admin?.autoLogin.username + : undefined + + const prefillEmail = + prefillAutoLogin && typeof config.admin?.autoLogin === 'object' + ? config.admin?.autoLogin.email + : undefined + + const prefillPassword = + prefillAutoLogin && typeof config.admin?.autoLogin === 'object' + ? config.admin?.autoLogin.password + : undefined + return (
@@ -84,7 +102,14 @@ export const LoginView: React.FC = ({ initPageResult, params, se />
{Array.isArray(BeforeLogins) && BeforeLogins.map((Component) => Component)} - {!collectionConfig?.auth?.disableLocalStrategy && } + {!collectionConfig?.auth?.disableLocalStrategy && ( + + )} {Array.isArray(AfterLogins) && AfterLogins.map((Component) => Component)}
) diff --git a/packages/payload/src/auth/strategies/jwt.ts b/packages/payload/src/auth/strategies/jwt.ts index 2d77fba60..7482c030e 100644 --- a/packages/payload/src/auth/strategies/jwt.ts +++ b/packages/payload/src/auth/strategies/jwt.ts @@ -1,5 +1,6 @@ import jwt from 'jsonwebtoken' +import type { Where } from '../../types/index.js' import type { AuthStrategyFunction, User } from '../index.js' import { extractJWT } from '../extractJWT.js' @@ -16,6 +17,46 @@ export const JWTAuthentication: AuthStrategyFunction = async ({ }) => { try { const token = extractJWT({ headers, payload }) + + if ( + !token && + typeof payload?.config?.admin?.autoLogin === 'object' && + !payload.config.admin?.autoLogin.prefillOnly && + headers.get('DisableAutologin') !== 'true' + ) { + const collection = payload.collections[payload.config.admin.user] + + const where: Where = { + or: [], + } + if (payload.config.admin?.autoLogin.email) { + where.or.push({ + email: { + equals: payload.config.admin?.autoLogin.email, + }, + }) + } else if (payload.config.admin?.autoLogin.username) { + where.or.push({ + username: { + equals: payload.config.admin?.autoLogin.username, + }, + }) + } + + const user = ( + await payload.find({ + collection: collection.config.slug, + depth: isGraphQL ? 0 : collection.config.auth.depth, + where, + }) + ).docs[0] + user.collection = collection.config.slug + user._strategy = 'local-jwt' + return { + user: user as User, + } + } + const decodedPayload = jwt.verify(token, payload.secret) as JWTToken & jwt.JwtPayload const collection = payload.collections[decodedPayload.collection] diff --git a/packages/payload/src/config/client.ts b/packages/payload/src/config/client.ts index 01fa5a341..d9b23a235 100644 --- a/packages/payload/src/config/client.ts +++ b/packages/payload/src/config/client.ts @@ -43,6 +43,27 @@ export type ClientConfig = { globals: ClientGlobalConfig[] } & Omit +const serverOnlyConfigProperties: readonly Partial[] = [ + 'endpoints', + 'db', + 'editor', + 'plugins', + 'sharp', + 'onInit', + 'secret', + 'hooks', + 'bin', + 'typescript', + 'cors', + 'csrf', + 'email', + 'custom', + 'graphQL', + // `admin`, `onInit`, `localization`, `collections`, and `globals` are all handled separately +] + +const serverOnlyAdminProperties: readonly Partial[] = ['components'] + export const createClientConfig = async ({ config, t, @@ -53,49 +74,28 @@ export const createClientConfig = async ({ }): Promise => { const clientConfig: ClientConfig = { ...config } - const serverOnlyConfigProperties: Partial[] = [ - 'endpoints', - 'db', - 'editor', - 'plugins', - 'sharp', - 'onInit', - 'secret', - 'hooks', - 'bin', - 'typescript', - 'cors', - 'csrf', - 'email', - 'custom', - 'graphQL', - // `admin`, `onInit`, `localization`, `collections`, and `globals` are all handled separately - ] - - serverOnlyConfigProperties.forEach((key) => { + for (const key of serverOnlyConfigProperties) { if (key in clientConfig) { delete clientConfig[key] } - }) + } if ('localization' in clientConfig && clientConfig.localization) { clientConfig.localization = { ...clientConfig.localization } - clientConfig.localization.locales.forEach((locale) => { + for (const locale of clientConfig.localization.locales) { delete locale.toString - }) + } } if ('admin' in clientConfig) { clientConfig.admin = { ...clientConfig.admin } - const serverOnlyAdminProperties: Partial[] = ['components'] - - serverOnlyAdminProperties.forEach((key) => { + for (const key of serverOnlyAdminProperties) { if (key in clientConfig.admin) { delete clientConfig.admin[key] } - }) + } if ('livePreview' in clientConfig.admin) { clientConfig.admin.livePreview = { ...clientConfig.admin.livePreview } diff --git a/packages/payload/src/config/types.ts b/packages/payload/src/config/types.ts index f7477d822..3ac995bbf 100644 --- a/packages/payload/src/config/types.ts +++ b/packages/payload/src/config/types.ts @@ -453,16 +453,15 @@ export type CORSConfig = { export type Config = { /** Configure admin dashboard */ admin?: { - /** Automatically log in as a user when visiting the admin dashboard. */ + /** Automatically log in as a user */ autoLogin?: | { /** * The email address of the user to login as - * */ email?: string - /** The password of the user to login as */ - password: string + /** The password of the user to login as. This is only needed if `prefillOnly` is set to true */ + password?: string /** * If set to true, the login credentials will be prefilled but the user will still need to click the login button. * @@ -473,9 +472,9 @@ export type Config = { username?: string } | false + /** Set account profile picture. Options: gravatar, default or a custom React component. */ avatar?: 'default' | 'gravatar' | React.ComponentType - /** * Add extra and/or replace built-in components with custom components * diff --git a/packages/ui/src/providers/Auth/index.tsx b/packages/ui/src/providers/Auth/index.tsx index 26d469e12..f60c8081b 100644 --- a/packages/ui/src/providers/Auth/index.tsx +++ b/packages/ui/src/providers/Auth/index.tsx @@ -12,7 +12,6 @@ import { useDebounce } from '../../hooks/useDebounce.js' import { useTranslation } from '../../providers/Translation/index.js' import { requests } from '../../utilities/api.js' import { useConfig } from '../Config/index.js' -import { useSearchParams } from '../SearchParams/index.js' export type AuthContext = { fetchFullUser: () => Promise @@ -34,11 +33,9 @@ const Context = createContext({} as AuthContext) const maxTimeoutTime = 2147483647 export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const { searchParams } = useSearchParams() const [user, setUser] = useState() const [tokenInMemory, setTokenInMemory] = useState() const [tokenExpiration, setTokenExpiration] = useState() - const [strategy, setStrategy] = useState() const pathname = usePathname() const router = useRouter() // const { code } = useLocale() @@ -48,9 +45,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children const { admin: { - autoLogin, routes: { inactivity: logoutInactivityRoute }, - routes: { login: loginRoute }, user: userSlug, }, routes: { admin, api }, @@ -79,7 +74,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children const revokeTokenAndExpire = useCallback(() => { setTokenInMemory(undefined) setTokenExpiration(undefined) - setStrategy(undefined) }, []) const setTokenAndExpiration = useCallback( @@ -88,7 +82,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children if (token && json?.exp) { setTokenInMemory(token) setTokenExpiration(json.exp) - if (json.strategy) setStrategy(json.strategy) } else { revokeTokenAndExpire() } @@ -215,36 +208,6 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children if (json?.token) { setTokenAndExpiration(json) } - } else if (autoLogin && autoLogin.prefillOnly !== true) { - // auto log-in with the provided autoLogin credentials. This is used in dev mode - // so you don't have to log in over and over again - const autoLoginResult = await requests.post( - `${serverURL}${api}/${userSlug}${loginRoute}`, - { - body: JSON.stringify({ - email: autoLogin.email, - password: autoLogin.password, - username: autoLogin.username, - }), - headers: { - 'Accept-Language': i18n.language, - 'Content-Type': 'application/json', - }, - }, - ) - if (autoLoginResult.status === 200) { - const autoLoginJson = await autoLoginResult.json() - setUser(autoLoginJson.user) - if (autoLoginJson?.token) { - setTokenAndExpiration(autoLoginJson) - } - router.replace( - typeof searchParams['redirect'] === 'string' ? searchParams['redirect'] : admin, - ) - } else { - setUser(null) - revokeTokenAndExpire() - } } else { setUser(null) revokeTokenAndExpire() @@ -253,21 +216,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children } catch (e) { toast.error(`Fetching user failed: ${e.message}`) } - }, [ - serverURL, - api, - userSlug, - i18n.language, - autoLogin, - setTokenAndExpiration, - router, - searchParams, - admin, - revokeTokenAndExpire, - strategy, - tokenExpiration, - loginRoute, - ]) + }, [serverURL, api, userSlug, i18n.language, setTokenAndExpiration, revokeTokenAndExpire]) // On mount, get user and set useEffect(() => { diff --git a/test/_community/e2e.spec.ts b/test/_community/e2e.spec.ts index ecff243e6..35e1fb60d 100644 --- a/test/_community/e2e.spec.ts +++ b/test/_community/e2e.spec.ts @@ -4,7 +4,7 @@ import { expect, test } from '@playwright/test' import * as path from 'path' import { fileURLToPath } from 'url' -import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -25,7 +25,7 @@ test.describe('Admin Panel', () => { const context = await browser.newContext() page = await context.newPage() initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('example test', async () => { diff --git a/test/_community/payload-types.ts b/test/_community/payload-types.ts index a36155c54..bf1368e08 100644 --- a/test/_community/payload-types.ts +++ b/test/_community/payload-types.ts @@ -16,6 +16,9 @@ export interface Config { 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; }; + db: { + defaultIDType: string; + }; globals: { menu: Menu; 'custom-ts': CustomT; @@ -30,13 +33,16 @@ export interface UserAuthOperations { email: string; }; login: { - password: string; email: string; + password: string; }; registerFirstUser: { email: string; password: string; }; + unlock: { + email: string; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/access-control/e2e.spec.ts b/test/access-control/e2e.spec.ts index 6723042be..9a2d35628 100644 --- a/test/access-control/e2e.spec.ts +++ b/test/access-control/e2e.spec.ts @@ -16,7 +16,7 @@ import type { import { closeNav, - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, getAdminRoutes, initPageConsoleErrorCatch, @@ -92,7 +92,7 @@ describe('access control', () => { initPageConsoleErrorCatch(page) await login({ page, serverURL }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) const { admin: { diff --git a/test/admin/e2e/1/e2e.spec.ts b/test/admin/e2e/1/e2e.spec.ts index 81b92f1f4..b858b5093 100644 --- a/test/admin/e2e/1/e2e.spec.ts +++ b/test/admin/e2e/1/e2e.spec.ts @@ -8,7 +8,7 @@ import type { Config, Geo, Post } from '../../payload-types.js' import { checkBreadcrumb, checkPageTitle, - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, getAdminRoutes, initPageConsoleErrorCatch, @@ -103,7 +103,7 @@ describe('admin1', () => { snapshotKey: 'adminTests1', }) - await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL }) + await ensureCompilationIsDone({ customAdminRoutes, page, serverURL }) adminRoutes = getAdminRoutes({ customAdminRoutes }) @@ -115,7 +115,7 @@ describe('admin1', () => { snapshotKey: 'adminTests1', }) - await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL }) + await ensureCompilationIsDone({ customAdminRoutes, page, serverURL }) }) describe('metadata', () => { @@ -294,14 +294,6 @@ describe('admin1', () => { await expect(() => expect(page.url()).not.toContain(loginURL)).toPass({ timeout: POLL_TOPASS_TIMEOUT, }) - - // Ensure auto-login logged the user back in - - await expect(() => expect(page.url()).toBe(`${serverURL}${adminRoutes.routes.admin}`)).toPass( - { - timeout: POLL_TOPASS_TIMEOUT, - }, - ) }) }) diff --git a/test/admin/e2e/2/e2e.spec.ts b/test/admin/e2e/2/e2e.spec.ts index 0a1e50f84..c0b7db8db 100644 --- a/test/admin/e2e/2/e2e.spec.ts +++ b/test/admin/e2e/2/e2e.spec.ts @@ -8,7 +8,7 @@ import * as qs from 'qs-esm' import type { Config, Geo, Post } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, getAdminRoutes, initPageConsoleErrorCatch, @@ -67,7 +67,7 @@ describe('admin2', () => { snapshotKey: 'adminTests2', }) - await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL }) + await ensureCompilationIsDone({ customAdminRoutes, page, serverURL }) adminRoutes = getAdminRoutes({ customAdminRoutes }) }) @@ -77,7 +77,7 @@ describe('admin2', () => { snapshotKey: 'adminTests2', }) - await ensureAutoLoginAndCompilationIsDone({ customAdminRoutes, page, serverURL }) + await ensureCompilationIsDone({ customAdminRoutes, page, serverURL }) }) describe('custom CSS', () => { diff --git a/test/admin/payload-types.ts b/test/admin/payload-types.ts index d846d1db6..d13e67114 100644 --- a/test/admin/payload-types.ts +++ b/test/admin/payload-types.ts @@ -30,6 +30,9 @@ export interface Config { 'payload-preferences': PayloadPreference; 'payload-migrations': PayloadMigration; }; + db: { + defaultIDType: string; + }; globals: { 'hidden-global': HiddenGlobal; 'global-no-api-view': GlobalNoApiView; @@ -49,13 +52,16 @@ export interface UserAuthOperations { email: string; }; login: { - password: string; email: string; + password: string; }; registerFirstUser: { email: string; password: string; }; + unlock: { + email: string; + }; } /** * This interface was referenced by `Config`'s JSON-Schema diff --git a/test/auth/e2e.spec.ts b/test/auth/e2e.spec.ts index f56137bf1..4f46b329b 100644 --- a/test/auth/e2e.spec.ts +++ b/test/auth/e2e.spec.ts @@ -12,7 +12,7 @@ import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config } from './payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, getAdminRoutes, initPageConsoleErrorCatch, saveDocAndAssert, @@ -105,7 +105,7 @@ describe('auth', () => { enableAPIKey: true, }, }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) describe('authenticated users', () => { diff --git a/test/buildConfigWithDefaults.ts b/test/buildConfigWithDefaults.ts index 03da180f0..de7e0cd84 100644 --- a/test/buildConfigWithDefaults.ts +++ b/test/buildConfigWithDefaults.ts @@ -179,15 +179,16 @@ export async function buildConfigWithDefaults( }, } - config.admin = { - autoLogin: + if (!config.admin) { + config.admin = {} + } + if (config.admin.autoLogin === undefined) { + config.admin.autoLogin = process.env.PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN === 'true' ? false : { email: 'dev@payloadcms.com', - password: 'test', - }, - ...(config.admin || {}), + } } if (process.env.PAYLOAD_DISABLE_ADMIN === 'true') { diff --git a/test/field-error-states/e2e.spec.ts b/test/field-error-states/e2e.spec.ts index 3db45402e..616270901 100644 --- a/test/field-error-states/e2e.spec.ts +++ b/test/field-error-states/e2e.spec.ts @@ -5,11 +5,7 @@ import { AdminUrlUtil } from 'helpers/adminUrlUtil.js' import path from 'path' import { fileURLToPath } from 'url' -import { - ensureAutoLoginAndCompilationIsDone, - initPageConsoleErrorCatch, - saveDocAndAssert, -} from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' import { slugs } from './shared.js' @@ -35,7 +31,7 @@ describe('field error states', () => { page = await context.newPage() initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('Remove row should remove error states from parent fields', async () => { diff --git a/test/fields-relationship/e2e.spec.ts b/test/fields-relationship/e2e.spec.ts index 2f3cc781f..efe892afb 100644 --- a/test/fields-relationship/e2e.spec.ts +++ b/test/fields-relationship/e2e.spec.ts @@ -16,7 +16,7 @@ import type { } from './payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, openCreateDocDrawer, openDocControls, @@ -67,7 +67,7 @@ describe('fields - relationship', () => { page = await context.newPage() initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { @@ -137,7 +137,7 @@ describe('fields - relationship', () => { }, })) as any - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should create relationship', async () => { diff --git a/test/fields/collections/Array/e2e.spec.ts b/test/fields/collections/Array/e2e.spec.ts index 4c46ecd26..3e31bc581 100644 --- a/test/fields/collections/Array/e2e.spec.ts +++ b/test/fields/collections/Array/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -48,7 +48,7 @@ describe('Array', () => { snapshotKey: 'fieldsArrayTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -63,7 +63,7 @@ describe('Array', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) let url: AdminUrlUtil diff --git a/test/fields/collections/Blocks/e2e.spec.ts b/test/fields/collections/Blocks/e2e.spec.ts index 1e299a308..db9e356c0 100644 --- a/test/fields/collections/Blocks/e2e.spec.ts +++ b/test/fields/collections/Blocks/e2e.spec.ts @@ -5,7 +5,7 @@ import path from 'path' import { fileURLToPath } from 'url' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -43,7 +43,7 @@ describe('Block fields', () => { snapshotKey: 'blockFieldsTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -58,7 +58,7 @@ describe('Block fields', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) let url: AdminUrlUtil diff --git a/test/fields/collections/Date/e2e.spec.ts b/test/fields/collections/Date/e2e.spec.ts index 0f8b223c9..cbfa4a68e 100644 --- a/test/fields/collections/Date/e2e.spec.ts +++ b/test/fields/collections/Date/e2e.spec.ts @@ -8,7 +8,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -50,7 +50,7 @@ describe('Date', () => { snapshotKey: 'fieldsDateTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -65,7 +65,7 @@ describe('Date', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should display formatted date in list view table cell', async () => { diff --git a/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts b/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts index 3c9df3cef..3b0dfdf7f 100644 --- a/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts +++ b/test/fields/collections/Lexical/e2e/blocks/e2e.spec.ts @@ -11,7 +11,7 @@ import type { PayloadTestSDK } from '../../../../../helpers/sdk/index.js' import type { Config, LexicalField, Upload } from '../../../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../../../helpers.js' @@ -74,7 +74,7 @@ describe('lexicalBlocks', () => { snapshotKey: 'fieldsLexicalBlocksTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { /*await throttleTest({ diff --git a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts b/test/fields/collections/Lexical/e2e/main/e2e.spec.ts index 9368698c5..63018010b 100644 --- a/test/fields/collections/Lexical/e2e/main/e2e.spec.ts +++ b/test/fields/collections/Lexical/e2e/main/e2e.spec.ts @@ -10,7 +10,7 @@ import type { PayloadTestSDK } from '../../../../../helpers/sdk/index.js' import type { Config, LexicalField } from '../../../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../../../helpers.js' @@ -73,7 +73,7 @@ describe('lexicalMain', () => { snapshotKey: 'fieldsLexicalMainTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { /*await throttleTest({ diff --git a/test/fields/collections/Number/e2e.spec.ts b/test/fields/collections/Number/e2e.spec.ts index 432cad6c6..8a1d7d716 100644 --- a/test/fields/collections/Number/e2e.spec.ts +++ b/test/fields/collections/Number/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -51,7 +51,7 @@ describe('Number', () => { snapshotKey: 'fieldsNumberTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -66,7 +66,7 @@ describe('Number', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should display field in list view', async () => { diff --git a/test/fields/collections/Point/e2e.spec.ts b/test/fields/collections/Point/e2e.spec.ts index 598ade559..82a9b8fdc 100644 --- a/test/fields/collections/Point/e2e.spec.ts +++ b/test/fields/collections/Point/e2e.spec.ts @@ -8,7 +8,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -51,7 +51,7 @@ describe('Point', () => { snapshotKey: 'fieldsPointTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -66,7 +66,7 @@ describe('Point', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) filledGroupPoint = await payload.create({ collection: pointFieldsSlug, diff --git a/test/fields/collections/Relationship/e2e.spec.ts b/test/fields/collections/Relationship/e2e.spec.ts index 59c4d982a..53b39d2f9 100644 --- a/test/fields/collections/Relationship/e2e.spec.ts +++ b/test/fields/collections/Relationship/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config, RelationshipField, TextField } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, initPageConsoleErrorCatch, openCreateDocDrawer, @@ -50,7 +50,7 @@ describe('relationship', () => { snapshotKey: 'fieldsRelationshipTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -65,7 +65,7 @@ describe('relationship', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) let url: AdminUrlUtil diff --git a/test/fields/collections/RichText/e2e.spec.ts b/test/fields/collections/RichText/e2e.spec.ts index 3dbad0b93..39e6fd120 100644 --- a/test/fields/collections/RichText/e2e.spec.ts +++ b/test/fields/collections/RichText/e2e.spec.ts @@ -6,7 +6,7 @@ import { wait } from 'payload/shared' import { fileURLToPath } from 'url' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert, } from '../../../helpers.js' @@ -43,7 +43,7 @@ describe('Rich Text', () => { snapshotKey: 'fieldsRichTextTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -58,7 +58,7 @@ describe('Rich Text', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) async function navigateToRichTextFields() { diff --git a/test/fields/collections/Tabs/e2e.spec.ts b/test/fields/collections/Tabs/e2e.spec.ts index 23f2325f8..549bbfd02 100644 --- a/test/fields/collections/Tabs/e2e.spec.ts +++ b/test/fields/collections/Tabs/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, navigateToListCellLink, saveDocAndAssert, @@ -53,7 +53,7 @@ describe('Tabs', () => { snapshotKey: 'fieldsTabsTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -68,7 +68,7 @@ describe('Tabs', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should fill and retain a new value within a tab while switching tabs', async () => { diff --git a/test/fields/collections/Text/e2e.spec.ts b/test/fields/collections/Text/e2e.spec.ts index a6e7bed27..36ec866e4 100644 --- a/test/fields/collections/Text/e2e.spec.ts +++ b/test/fields/collections/Text/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, initPageConsoleErrorCatch, saveDocAndAssert, @@ -53,7 +53,7 @@ describe('Text', () => { snapshotKey: 'fieldsTextTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -68,7 +68,7 @@ describe('Text', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should display field in list view', async () => { diff --git a/test/fields/collections/Upload/e2e.spec.ts b/test/fields/collections/Upload/e2e.spec.ts index 77d679014..0db10bbf0 100644 --- a/test/fields/collections/Upload/e2e.spec.ts +++ b/test/fields/collections/Upload/e2e.spec.ts @@ -9,7 +9,7 @@ import type { PayloadTestSDK } from '../../../helpers/sdk/index.js' import type { Config } from '../../payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, openDocDrawer, saveDocAndAssert, @@ -52,7 +52,7 @@ describe('Upload', () => { snapshotKey: 'fieldsUploadTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -67,7 +67,7 @@ describe('Upload', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) async function uploadImage() { diff --git a/test/fields/e2e.spec.ts b/test/fields/e2e.spec.ts index 782b669a7..a013bab6f 100644 --- a/test/fields/e2e.spec.ts +++ b/test/fields/e2e.spec.ts @@ -8,11 +8,7 @@ import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config } from './payload-types.js' -import { - ensureAutoLoginAndCompilationIsDone, - initPageConsoleErrorCatch, - saveDocAndAssert, -} from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { reInitializeDB } from '../helpers/reInitializeDB.js' @@ -53,7 +49,7 @@ describe('fields', () => { snapshotKey: 'fieldsTest', uploadsDir: path.resolve(dirname, './collections/Upload/uploads'), }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -68,7 +64,7 @@ describe('fields', () => { client = new RESTClient(null, { defaultSlug: 'users', serverURL }) await client.login() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) describe('indexed', () => { diff --git a/test/fields/payload-types.ts b/test/fields/payload-types.ts index 39e97d820..48b322536 100644 --- a/test/fields/payload-types.ts +++ b/test/fields/payload-types.ts @@ -12,1433 +12,1459 @@ */ export type BlockColumns = | { - text?: string | null + text?: string | null; subArray?: | { - requiredText: string - id?: string | null + requiredText: string; + id?: string | null; }[] - | null - id?: string | null + | null; + id?: string | null; }[] - | null + | null; export interface Config { + auth: { + users: UserAuthOperations; + }; collections: { - 'lexical-fields': LexicalField - 'lexical-migrate-fields': LexicalMigrateField - 'lexical-localized-fields': LexicalLocalizedField - users: User - 'array-fields': ArrayField - 'block-fields': BlockField - 'checkbox-fields': CheckboxField - 'code-fields': CodeField - 'collapsible-fields': CollapsibleField - 'conditional-logic': ConditionalLogic - 'date-fields': DateField - 'radio-fields': RadioField - 'group-fields': GroupField - 'row-fields': RowField - 'indexed-fields': IndexedField - 'json-fields': JsonField - 'number-fields': NumberField - 'point-fields': PointField - 'relationship-fields': RelationshipField - 'rich-text-fields': RichTextField - 'select-fields': SelectField - 'tabs-fields-2': TabsFields2 - 'tabs-fields': TabsField - 'text-fields': TextField - uploads: Upload - uploads2: Uploads2 - uploads3: Uploads3 - 'ui-fields': UiField - 'payload-preferences': PayloadPreference - 'payload-migrations': PayloadMigration - } + 'lexical-fields': LexicalField; + 'lexical-migrate-fields': LexicalMigrateField; + 'lexical-localized-fields': LexicalLocalizedField; + users: User; + 'array-fields': ArrayField; + 'block-fields': BlockField; + 'checkbox-fields': CheckboxField; + 'code-fields': CodeField; + 'collapsible-fields': CollapsibleField; + 'conditional-logic': ConditionalLogic; + 'date-fields': DateField; + 'radio-fields': RadioField; + 'group-fields': GroupField; + 'row-fields': RowField; + 'indexed-fields': IndexedField; + 'json-fields': JsonField; + 'number-fields': NumberField; + 'point-fields': PointField; + 'relationship-fields': RelationshipField; + 'rich-text-fields': RichTextField; + 'select-fields': SelectField; + 'tabs-fields-2': TabsFields2; + 'tabs-fields': TabsField; + 'text-fields': TextField; + uploads: Upload; + uploads2: Uploads2; + uploads3: Uploads3; + 'ui-fields': UiField; + 'payload-preferences': PayloadPreference; + 'payload-migrations': PayloadMigration; + }; + db: { + defaultIDType: string; + }; globals: { - tabsWithRichText: TabsWithRichText - } - locale: 'en' | 'es' + tabsWithRichText: TabsWithRichText; + }; + locale: 'en' | 'es'; user: User & { - collection: 'users' - } + collection: 'users'; + }; +} +export interface UserAuthOperations { + forgotPassword: { + email: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + }; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "lexical-fields". */ export interface LexicalField { - id: string - title: string + id: string; + title: string; lexicalSimple?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; lexicalWithBlocks: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } - lexicalWithBlocks_markdown?: string | null - updatedAt: string - createdAt: string + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + }; + lexicalWithBlocks_markdown?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "lexical-migrate-fields". */ export interface LexicalMigrateField { - id: string - title: string + id: string; + title: string; lexicalWithLexicalPluginData?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; lexicalWithSlateData?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; lexicalSimple?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - lexicalSimple_html?: string | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalSimple_html?: string | null; groupWithLexicalField?: { lexicalInGroupField?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - lexicalInGroupField_html?: string | null - } + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalInGroupField_html?: string | null; + }; arrayWithLexicalField?: | { lexicalInArrayField?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - lexicalInArrayField_html?: string | null - id?: string | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + lexicalInArrayField_html?: string | null; + id?: string | null; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "lexical-localized-fields". */ export interface LexicalLocalizedField { - id: string - title: string + id: string; + title: string; lexicalBlocksSubLocalized?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; lexicalBlocksLocalized?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - updatedAt: string - createdAt: string + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". */ export interface User { - id: string - canViewConditionalField?: boolean | null - updatedAt: string - createdAt: string - email: string - resetPasswordToken?: string | null - resetPasswordExpiration?: string | null - salt?: string | null - hash?: string | null - loginAttempts?: number | null - lockUntil?: string | null - password?: string | null + id: string; + canViewConditionalField?: boolean | null; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "array-fields". */ export interface ArrayField { - id: string - title?: string | null + id: string; + title?: string | null; items: { - text: string - localizedText?: string | null + text: string; + localizedText?: string | null; subArray?: | { - text?: string | null - id?: string | null + text?: string | null; + id?: string | null; }[] - | null - id?: string | null - }[] + | null; + id?: string | null; + }[]; collapsedArray?: | { - text: string - id?: string | null + text: string; + id?: string | null; }[] - | null + | null; localized: { - text: string - id?: string | null - }[] + text: string; + id?: string | null; + }[]; readOnly?: | { - text?: string | null - id?: string | null + text?: string | null; + id?: string | null; }[] - | null + | null; potentiallyEmptyArray?: | { - text?: string | null + text?: string | null; groupInRow?: { - textInGroupInRow?: string | null - } - id?: string | null + textInGroupInRow?: string | null; + }; + id?: string | null; }[] - | null + | null; rowLabelAsComponent?: | { - title?: string | null - id?: string | null + title?: string | null; + id?: string | null; }[] - | null + | null; arrayWithMinRows?: | { - text?: string | null - id?: string | null + text?: string | null; + id?: string | null; }[] - | null + | null; disableSort?: | { - text: string - id?: string | null + text: string; + id?: string | null; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "block-fields". */ export interface BlockField { - id: string + id: string; blocks: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'content' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'content'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'subBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'subBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'tabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'tabs'; } - )[] + )[]; duplicate: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'content' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'content'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'subBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'subBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'tabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'tabs'; } - )[] + )[]; collapsedByDefaultBlocks: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedContent' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedContent'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'localizedNumber' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'localizedNumber'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedSubBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedSubBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'localizedTabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedTabs'; } - )[] + )[]; disableSort: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedContent' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedContent'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'localizedNumber' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'localizedNumber'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedSubBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedSubBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'localizedTabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedTabs'; } - )[] + )[]; localizedBlocks: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedContent' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedContent'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'localizedNumber' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'localizedNumber'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'localizedSubBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedSubBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'localizedTabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'localizedTabs'; } - )[] + )[]; i18nBlocks?: | { - text?: string | null - id?: string | null - blockName?: string | null - blockType: 'text' + text?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'text'; }[] - | null + | null; blocksWithSimilarConfigs?: | ( | { items?: | { - title: string - id?: string | null + title: string; + id?: string | null; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'block-a' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'block-a'; } | { items?: | { - title2: string - id?: string | null + title2: string; + id?: string | null; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'block-b' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'block-b'; } | { group?: { - text?: string | null - } - id?: string | null - blockName?: string | null - blockType: 'group-block' + text?: string | null; + }; + id?: string | null; + blockName?: string | null; + blockType: 'group-block'; } )[] - | null + | null; blocksWithSimilarGroup?: | ( | { group?: { - text?: string | null - } - id?: string | null - blockName?: string | null - blockType: 'group-block' + text?: string | null; + }; + id?: string | null; + blockName?: string | null; + blockType: 'group-block'; } | { items?: | { - title2: string - id?: string | null + title2: string; + id?: string | null; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'block-b' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'block-b'; } )[] - | null + | null; blocksWithMinRows?: | { - blockTitle?: string | null - id?: string | null - blockName?: string | null - blockType: 'block' + blockTitle?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'block'; }[] - | null + | null; customBlocks?: | ( | { - block1Title?: string | null - id?: string | null - blockName?: string | null - blockType: 'block-1' + block1Title?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'block-1'; } | { - block2Title?: string | null - id?: string | null - blockName?: string | null - blockType: 'block-2' + block2Title?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'block-2'; } )[] - | null + | null; relationshipBlocks?: | { - relationship?: (string | null) | TextField - id?: string | null - blockName?: string | null - blockType: 'relationships' + relationship?: (string | null) | TextField; + id?: string | null; + blockName?: string | null; + blockType: 'relationships'; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "text-fields". */ export interface TextField { - id: string - text: string - localizedText?: string | null - i18nText?: string | null - defaultString?: string | null - defaultEmptyString?: string | null - defaultFunction?: string | null - defaultAsync?: string | null - overrideLength?: string | null - fieldWithDefaultValue?: string | null - dependentOnFieldWithDefaultValue?: string | null - customLabel?: string | null - customError?: string | null - beforeAndAfterInput?: string | null - hasMany?: string[] | null - validatesHasMany?: string[] | null - localizedHasMany?: string[] | null - withMinRows?: string[] | null - withMaxRows?: string[] | null - disableListColumnText?: string | null - disableListFilterText?: string | null - updatedAt: string - createdAt: string + id: string; + text: string; + localizedText?: string | null; + i18nText?: string | null; + defaultString?: string | null; + defaultEmptyString?: string | null; + defaultFunction?: string | null; + defaultAsync?: string | null; + overrideLength?: string | null; + fieldWithDefaultValue?: string | null; + dependentOnFieldWithDefaultValue?: string | null; + customLabel?: string | null; + customError?: string | null; + beforeAndAfterInput?: string | null; + hasMany?: string[] | null; + validatesHasMany?: string[] | null; + localizedHasMany?: string[] | null; + withMinRows?: string[] | null; + withMaxRows?: string[] | null; + disableListColumnText?: string | null; + disableListFilterText?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "checkbox-fields". */ export interface CheckboxField { - id: string - checkbox: boolean - updatedAt: string - createdAt: string + id: string; + checkbox: boolean; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "code-fields". */ export interface CodeField { - id: string - javascript?: string | null - typescript?: string | null - json?: string | null - html?: string | null - css?: string | null - updatedAt: string - createdAt: string + id: string; + javascript?: string | null; + typescript?: string | null; + json?: string | null; + html?: string | null; + css?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "collapsible-fields". */ export interface CollapsibleField { - id: string - text: string + id: string; + text: string; group?: { - textWithinGroup?: string | null + textWithinGroup?: string | null; subGroup?: { - textWithinSubGroup?: string | null - } - } - someText?: string | null + textWithinSubGroup?: string | null; + }; + }; + someText?: string | null; group2?: { - textWithinGroup?: string | null + textWithinGroup?: string | null; subGroup?: { - textWithinSubGroup?: string | null - } - } - functionTitleField?: string | null - componentTitleField?: string | null - nestedTitle?: string | null + textWithinSubGroup?: string | null; + }; + }; + functionTitleField?: string | null; + componentTitleField?: string | null; + nestedTitle?: string | null; arrayWithCollapsibles?: | { - innerCollapsible?: string | null - id?: string | null + innerCollapsible?: string | null; + id?: string | null; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "conditional-logic". */ export interface ConditionalLogic { - id: string - text: string - toggleField?: boolean | null - fieldToToggle?: string | null - userConditional?: string | null + id: string; + text: string; + toggleField?: boolean | null; + fieldToToggle?: string | null; + userConditional?: string | null; parentGroup?: { - enableParentGroupFields?: boolean | null - siblingField?: string | null - } - reliesOnParentGroup?: string | null - groupSelection?: ('group1' | 'group2') | null + enableParentGroupFields?: boolean | null; + siblingField?: string | null; + }; + reliesOnParentGroup?: string | null; + groupSelection?: ('group1' | 'group2') | null; group1?: { - group1Field?: string | null - } + group1Field?: string | null; + }; group2?: { - group2Field?: string | null - } - updatedAt: string - createdAt: string + group2Field?: string | null; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "date-fields". */ export interface DateField { - id: string - default: string - timeOnly?: string | null - timeOnlyWithCustomFormat?: string | null - dayOnly?: string | null - dayAndTime?: string | null - monthOnly?: string | null - updatedAt: string - createdAt: string + id: string; + default: string; + timeOnly?: string | null; + timeOnlyWithCustomFormat?: string | null; + dayOnly?: string | null; + dayAndTime?: string | null; + monthOnly?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "radio-fields". */ export interface RadioField { - id: string - radio?: ('one' | 'two' | 'three') | null - updatedAt: string - createdAt: string + id: string; + radio?: ('one' | 'two' | 'three') | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "group-fields". */ export interface GroupField { - id: string + id: string; group: { - text: string - defaultParent?: string | null - defaultChild?: string | null + text: string; + defaultParent?: string | null; + defaultChild?: string | null; subGroup?: { - textWithinGroup?: string | null + textWithinGroup?: string | null; arrayWithinGroup?: | { - textWithinArray?: string | null - id?: string | null + textWithinArray?: string | null; + id?: string | null; }[] - | null - } - } + | null; + }; + }; arrayOfGroups?: | { groupItem?: { - text?: string | null - } - id?: string | null + text?: string | null; + }; + id?: string | null; }[] - | null + | null; localizedGroup?: { - text?: string | null - } + text?: string | null; + }; potentiallyEmptyGroup?: { - text?: string | null - } + text?: string | null; + }; groupInRow?: { - field?: string | null - secondField?: string | null - thirdField?: string | null - } + field?: string | null; + secondField?: string | null; + thirdField?: string | null; + }; secondGroupInRow?: { - field?: string | null + field?: string | null; nestedGroup?: { - nestedField?: string | null - } - } + nestedField?: string | null; + }; + }; groups?: { groupInRow?: { - field?: string | null - secondField?: string | null - thirdField?: string | null - } + field?: string | null; + secondField?: string | null; + thirdField?: string | null; + }; secondGroupInRow?: { - field?: string | null + field?: string | null; nestedGroup?: { - nestedField?: string | null - } - } - } - updatedAt: string - createdAt: string + nestedField?: string | null; + }; + }; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "row-fields". */ export interface RowField { - id: string - title: string - field_with_width_a?: string | null - field_with_width_b?: string | null - field_within_collapsible_a?: string | null - field_within_collapsible_b?: string | null - updatedAt: string - createdAt: string + id: string; + title: string; + field_with_width_a?: string | null; + field_with_width_b?: string | null; + field_within_collapsible_a?: string | null; + field_within_collapsible_b?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "indexed-fields". */ export interface IndexedField { - id: string - text: string - uniqueText?: string | null - uniqueRequiredText: string - localizedUniqueRequiredText: string + id: string; + text: string; + uniqueText?: string | null; + uniqueRequiredText: string; + localizedUniqueRequiredText: string; /** * @minItems 2 * @maxItems 2 */ - point?: [number, number] | null + point?: [number, number] | null; group?: { - localizedUnique?: string | null - unique?: string | null + localizedUnique?: string | null; + unique?: string | null; /** * @minItems 2 * @maxItems 2 */ - point?: [number, number] | null - } - collapsibleLocalizedUnique?: string | null - collapsibleTextUnique?: string | null - updatedAt: string - createdAt: string + point?: [number, number] | null; + }; + collapsibleLocalizedUnique?: string | null; + collapsibleTextUnique?: string | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "json-fields". */ export interface JsonField { - id: string - json?: - | { - [k: string]: unknown - } - | unknown[] - | string - | number - | boolean - | null + id: string; + json?: { + foo?: 'bar' | 'foobar'; + number?: 10 | 5; + [k: string]: unknown; + }; group?: { jsonWithinGroup?: | { - [k: string]: unknown + [k: string]: unknown; } | unknown[] | string | number | boolean - | null - } - updatedAt: string - createdAt: string + | null; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "number-fields". */ export interface NumberField { - id: string - number?: number | null - min?: number | null - max?: number | null - positiveNumber?: number | null - negativeNumber?: number | null - decimalMin?: number | null - decimalMax?: number | null - defaultNumber?: number | null - hasMany?: number[] | null - validatesHasMany?: number[] | null - localizedHasMany?: number[] | null - withMinRows?: number[] | null - updatedAt: string - createdAt: string + id: string; + number?: number | null; + min?: number | null; + max?: number | null; + positiveNumber?: number | null; + negativeNumber?: number | null; + decimalMin?: number | null; + decimalMax?: number | null; + defaultNumber?: number | null; + hasMany?: number[] | null; + validatesHasMany?: number[] | null; + localizedHasMany?: number[] | null; + withMinRows?: number[] | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "point-fields". */ export interface PointField { - id: string + id: string; /** * @minItems 2 * @maxItems 2 */ - point: [number, number] + point: [number, number]; /** * @minItems 2 * @maxItems 2 */ - localized?: [number, number] | null + localized?: [number, number] | null; group?: { /** * @minItems 2 * @maxItems 2 */ - point?: [number, number] | null - } - updatedAt: string - createdAt: string + point?: [number, number] | null; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "relationship-fields". */ export interface RelationshipField { - id: string - text?: string | null + id: string; + text?: string | null; relationship: | { - relationTo: 'text-fields' - value: string | TextField + relationTo: 'text-fields'; + value: string | TextField; } | { - relationTo: 'array-fields' - value: string | ArrayField - } + relationTo: 'array-fields'; + value: string | ArrayField; + }; relationHasManyPolymorphic?: | ( | { - relationTo: 'text-fields' - value: string | TextField + relationTo: 'text-fields'; + value: string | TextField; } | { - relationTo: 'array-fields' - value: string | ArrayField + relationTo: 'array-fields'; + value: string | ArrayField; } )[] - | null - relationToSelf?: (string | null) | RelationshipField - relationToSelfSelectOnly?: (string | null) | RelationshipField - relationWithDynamicDefault?: (string | null) | User + | null; + relationToSelf?: (string | null) | RelationshipField; + relationToSelfSelectOnly?: (string | null) | RelationshipField; + relationWithDynamicDefault?: (string | null) | User; relationHasManyWithDynamicDefault?: { - relationTo: 'users' - value: string | User - } | null - relationshipWithMin?: (string | TextField)[] | null - relationshipWithMax?: (string | TextField)[] | null - relationshipHasMany?: (string | TextField)[] | null + relationTo: 'users'; + value: string | User; + } | null; + relationshipWithMin?: (string | TextField)[] | null; + relationshipWithMax?: (string | TextField)[] | null; + relationshipHasMany?: (string | TextField)[] | null; array?: | { - relationship?: (string | null) | TextField - id?: string | null + relationship?: (string | null) | TextField; + id?: string | null; }[] - | null + | null; relationshipWithMinRows?: | { - relationTo: 'text-fields' - value: string | TextField + relationTo: 'text-fields'; + value: string | TextField; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "rich-text-fields". */ export interface RichTextField { - id: string - title: string + id: string; + title: string; lexicalCustomFields: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } - lexicalCustomFields_html?: string | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + }; + lexicalCustomFields_html?: string | null; lexical?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null; richText: { - [k: string]: unknown - }[] + [k: string]: unknown; + }[]; richTextCustomFields?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null + | null; richTextReadOnly?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null + | null; blocks?: | ( | { - text?: string | null - id?: string | null - blockName?: string | null - blockType: 'textBlock' + text?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'textBlock'; } | { text?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'richTextBlock' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'richTextBlock'; } )[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "select-fields". */ export interface SelectField { - id: string - select?: ('one' | 'two' | 'three') | null - selectReadOnly?: ('one' | 'two' | 'three') | null - selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null - selectHasManyLocalized?: ('one' | 'two')[] | null - selectI18n?: ('one' | 'two' | 'three') | null - simple?: ('One' | 'Two' | 'Three') | null + id: string; + select?: ('one' | 'two' | 'three') | null; + selectReadOnly?: ('one' | 'two' | 'three') | null; + selectHasMany?: ('one' | 'two' | 'three' | 'four' | 'five' | 'six')[] | null; + selectHasManyLocalized?: ('one' | 'two')[] | null; + selectI18n?: ('one' | 'two' | 'three') | null; + simple?: ('One' | 'Two' | 'Three') | null; settings?: { - category?: ('a' | 'b')[] | null - } - updatedAt: string - createdAt: string + category?: ('a' | 'b')[] | null; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "tabs-fields-2". */ export interface TabsFields2 { - id: string + id: string; tabsInArray?: | { - text?: string | null + text?: string | null; tab2?: { - text2?: string | null - } - id?: string | null + text2?: string | null; + }; + id?: string | null; }[] - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "tabs-fields". */ export interface TabsField { - id: string - sidebarField?: string | null + id: string; + sidebarField?: string | null; array: { - text: string - id?: string | null - }[] + text: string; + id?: string | null; + }[]; blocks: ( | { - text: string + text: string; richText?: | { - [k: string]: unknown + [k: string]: unknown; }[] - | null - id?: string | null - blockName?: string | null - blockType: 'content' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'content'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } | { subBlocks?: | ( | { - text: string - id?: string | null - blockName?: string | null - blockType: 'text' + text: string; + id?: string | null; + blockName?: string | null; + blockType: 'text'; } | { - number: number - id?: string | null - blockName?: string | null - blockType: 'number' + number: number; + id?: string | null; + blockName?: string | null; + blockType: 'number'; } )[] - | null - id?: string | null - blockName?: string | null - blockType: 'subBlocks' + | null; + id?: string | null; + blockName?: string | null; + blockType: 'subBlocks'; } | { - textInCollapsible?: string | null - textInRow?: string | null - id?: string | null - blockName?: string | null - blockType: 'tabs' + textInCollapsible?: string | null; + textInRow?: string | null; + id?: string | null; + blockName?: string | null; + blockType: 'tabs'; } - )[] + )[]; group: { - number: number - } - textInRow: string - numberInRow: number + number: number; + }; + textInRow: string; + numberInRow: number; json?: | { - [k: string]: unknown + [k: string]: unknown; } | unknown[] | string | number | boolean - | null + | null; tab: { array: { - text: string - id?: string | null - }[] - text?: string | null - defaultValue?: string | null + text: string; + id?: string | null; + }[]; + text?: string | null; + defaultValue?: string | null; arrayInRow?: | { - textInArrayInRow?: string | null - id?: string | null + textInArrayInRow?: string | null; + id?: string | null; }[] - | null - } + | null; + }; namedTabWithDefaultValue?: { - defaultValue?: string | null - } + defaultValue?: string | null; + }; localizedTab?: { - text?: string | null - } + text?: string | null; + }; accessControlTab?: { - text?: string | null - } + text?: string | null; + }; hooksTab?: { - beforeValidate?: boolean | null - beforeChange?: boolean | null - afterChange?: boolean | null - afterRead?: boolean | null - } - textarea?: string | null - anotherText: string + beforeValidate?: boolean | null; + beforeChange?: boolean | null; + afterChange?: boolean | null; + afterRead?: boolean | null; + }; + textarea?: string | null; + anotherText: string; nestedTab?: { - text?: string | null - } - updatedAt: string - createdAt: string + text?: string | null; + }; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "uploads". */ export interface Upload { - id: string - text?: string | null - media?: string | Upload | null + id: string; + text?: string | null; + media?: string | Upload | null; richText?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - updatedAt: string - createdAt: string - url?: string | null - thumbnailURL?: string | null - filename?: string | null - mimeType?: string | null - filesize?: number | null - width?: number | null - height?: number | null - focalX?: number | null - focalY?: number | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "uploads2". */ export interface Uploads2 { - id: string - text?: string | null - media?: string | Uploads2 | null - updatedAt: string - createdAt: string - url?: string | null - thumbnailURL?: string | null - filename?: string | null - mimeType?: string | null - filesize?: number | null - width?: number | null - height?: number | null - focalX?: number | null - focalY?: number | null + id: string; + text?: string | null; + media?: string | Uploads2 | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "uploads3". */ export interface Uploads3 { - id: string - media?: string | Uploads3 | null + id: string; + media?: string | Uploads3 | null; richText?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - updatedAt: string - createdAt: string - url?: string | null - thumbnailURL?: string | null - filename?: string | null - mimeType?: string | null - filesize?: number | null - width?: number | null - height?: number | null - focalX?: number | null - focalY?: number | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + updatedAt: string; + createdAt: string; + url?: string | null; + thumbnailURL?: string | null; + filename?: string | null; + mimeType?: string | null; + filesize?: number | null; + width?: number | null; + height?: number | null; + focalX?: number | null; + focalY?: number | null; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "ui-fields". */ export interface UiField { - id: string - text: string - updatedAt: string - createdAt: string + id: string; + text: string; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: string + id: string; user: { - relationTo: 'users' - value: string | User - } - key?: string | null + relationTo: 'users'; + value: string | User; + }; + key?: string | null; value?: | { - [k: string]: unknown + [k: string]: unknown; } | unknown[] | string | number | boolean - | null - updatedAt: string - createdAt: string + | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: string - name?: string | null - batch?: number | null - updatedAt: string - createdAt: string + id: string; + name?: string | null; + batch?: number | null; + updatedAt: string; + createdAt: string; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "tabsWithRichText". */ export interface TabsWithRichText { - id: string + id: string; tab1?: { rt1?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - } + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + }; tab2?: { rt2?: { root: { - type: string + type: string; children: { - type: string - version: number - [k: string]: unknown - }[] - direction: ('ltr' | 'rtl') | null - format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '' - indent: number - version: number - } - [k: string]: unknown - } | null - } - updatedAt?: string | null - createdAt?: string | null + type: string; + version: number; + [k: string]: unknown; + }[]; + direction: ('ltr' | 'rtl') | null; + format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | ''; + indent: number; + version: number; + }; + [k: string]: unknown; + } | null; + }; + updatedAt?: string | null; + createdAt?: string | null; } /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "LexicalBlocksRadioButtonsBlock". */ export interface LexicalBlocksRadioButtonsBlock { - radioButtons?: ('option1' | 'option2' | 'option3') | null - id?: string | null - blockName?: string | null - blockType: 'radioButtons' + radioButtons?: ('option1' | 'option2' | 'option3') | null; + id?: string | null; + blockName?: string | null; + blockType: 'radioButtons'; +} +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "auth". + */ +export interface Auth { + [k: string]: unknown; } + declare module 'payload' { - // @ts-ignore + // @ts-ignore export interface GeneratedTypes extends Config {} -} +} \ No newline at end of file diff --git a/test/helpers.ts b/test/helpers.ts index 268c00562..b259b7852 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -48,11 +48,11 @@ const networkConditions = { } /** - * Load admin panel and make sure autologin has passed before running tests + * Ensure admin panel is loaded before running tests * @param page * @param serverURL */ -export async function ensureAutoLoginAndCompilationIsDone({ +export async function ensureCompilationIsDone({ customAdminRoutes, customRoutes, page, @@ -64,9 +64,6 @@ export async function ensureAutoLoginAndCompilationIsDone({ serverURL: string }): Promise { const { - admin: { - routes: { createFirstUser: createFirstUserRoute, login: loginRoute }, - }, routes: { admin: adminRoute }, } = getAdminRoutes({ customAdminRoutes, customRoutes }) @@ -79,16 +76,6 @@ export async function ensureAutoLoginAndCompilationIsDone({ timeout: POLL_TOPASS_TIMEOUT, }) - await expect(() => expect(page.url()).not.toContain(`${adminRoute}${loginRoute}`)).toPass({ - timeout: POLL_TOPASS_TIMEOUT, - }) - - await expect(() => - expect(page.url()).not.toContain(`${adminRoute}${createFirstUserRoute}`), - ).toPass({ - timeout: POLL_TOPASS_TIMEOUT, - }) - await expect(page.locator('.dashboard__label').first()).toBeVisible() } diff --git a/test/helpers/NextRESTClient.ts b/test/helpers/NextRESTClient.ts index 891ed5eb5..c885e8b20 100644 --- a/test/helpers/NextRESTClient.ts +++ b/test/helpers/NextRESTClient.ts @@ -85,6 +85,9 @@ export class NextRESTClient { if (options.auth !== false && this.token) { headers.set('Authorization', `JWT ${this.token}`) } + if (options.auth === false) { + headers.set('DisableAutologin', 'true') + } return headers } diff --git a/test/i18n/e2e.spec.ts b/test/i18n/e2e.spec.ts index 81023efae..3f9bf8ec8 100644 --- a/test/i18n/e2e.spec.ts +++ b/test/i18n/e2e.spec.ts @@ -9,7 +9,7 @@ const { beforeAll, beforeEach, describe } = test import path from 'path' import { fileURLToPath } from 'url' -import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { reInitializeDB } from '../helpers/reInitializeDB.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -39,7 +39,7 @@ describe('i18n', () => { serverURL, snapshotKey: 'i18nTests', }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) beforeEach(async () => { await reInitializeDB({ @@ -47,7 +47,7 @@ describe('i18n', () => { snapshotKey: 'i18nTests', }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('ensure i18n labels and useTranslation hooks display correct translation', async () => { diff --git a/test/live-preview/e2e.spec.ts b/test/live-preview/e2e.spec.ts index f6c738c28..cec551bad 100644 --- a/test/live-preview/e2e.spec.ts +++ b/test/live-preview/e2e.spec.ts @@ -5,7 +5,7 @@ import path from 'path' import { fileURLToPath } from 'url' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, initPageConsoleErrorCatch, saveDocAndAssert, @@ -57,7 +57,7 @@ describe('Live Preview', () => { initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('collection — has tab', async () => { diff --git a/test/localization/e2e.spec.ts b/test/localization/e2e.spec.ts index c35339fa8..530c703c8 100644 --- a/test/localization/e2e.spec.ts +++ b/test/localization/e2e.spec.ts @@ -10,7 +10,7 @@ import type { Config, LocalizedPost } from './payload-types.js' import { changeLocale, - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, openDocControls, saveDocAndAssert, @@ -63,7 +63,7 @@ describe('Localization', () => { initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) describe('localized text', () => { diff --git a/test/package.json b/test/package.json index 5deb66bd2..d5c623ffb 100644 --- a/test/package.json +++ b/test/package.json @@ -11,6 +11,16 @@ "test:int": "pnpm -C \"../\" run test:int", "typecheck": "pnpm turbo build --filter test && tsc --project tsconfig.typecheck.json" }, + "lint-staged": { + "**/package.json": "sort-package-json", + "*.{md,mdx,yml,json}": "prettier --write", + "*.{js,jsx,ts,tsx}": [ + "prettier --write", + "eslint --cache --fix" + ], + "templates/website/**/*": "sh -c \"cd templates/website; pnpm install --ignore-workspace --frozen-lockfile; pnpm run lint --fix\"", + "tsconfig.json": "node scripts/reset-tsconfig.js" + }, "devDependencies": { "@aws-sdk/client-s3": "^3.525.0", "@lexical/headless": "0.16.1", diff --git a/test/plugin-cloud-storage/e2e.spec.ts b/test/plugin-cloud-storage/e2e.spec.ts index 2f9b692b7..ecae889a0 100644 --- a/test/plugin-cloud-storage/e2e.spec.ts +++ b/test/plugin-cloud-storage/e2e.spec.ts @@ -4,7 +4,7 @@ import { expect, test } from '@playwright/test' import * as path from 'path' import { fileURLToPath } from 'url' -import { ensureAutoLoginAndCompilationIsDone, saveDocAndAssert } from '../helpers.js' +import { ensureCompilationIsDone, saveDocAndAssert } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -24,7 +24,7 @@ test.describe('Admin Panel', () => { const context = await browser.newContext() page = await context.newPage() - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should create file upload', async () => { diff --git a/test/plugin-form-builder/e2e.spec.ts b/test/plugin-form-builder/e2e.spec.ts index 1af13e00c..9b3ca7af1 100644 --- a/test/plugin-form-builder/e2e.spec.ts +++ b/test/plugin-form-builder/e2e.spec.ts @@ -7,7 +7,7 @@ import { fileURLToPath } from 'url' import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config } from './payload-types.js' -import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { POLL_TOPASS_TIMEOUT, TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -35,7 +35,7 @@ test.describe('Form Builder', () => { page = await context.newPage() initPageConsoleErrorCatch(page) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test.describe('Forms collection', () => { diff --git a/test/plugin-nested-docs/e2e.spec.ts b/test/plugin-nested-docs/e2e.spec.ts index 2047432f0..5ade24e7a 100644 --- a/test/plugin-nested-docs/e2e.spec.ts +++ b/test/plugin-nested-docs/e2e.spec.ts @@ -6,7 +6,7 @@ import { fileURLToPath } from 'url' import type { Config, Page as PayloadPage } from './payload-types.js' -import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -69,7 +69,7 @@ describe('Nested Docs Plugin', () => { }) draftChildId = draftChildPage.id - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) describe('Core functionality', () => { diff --git a/test/plugin-seo/e2e.spec.ts b/test/plugin-seo/e2e.spec.ts index be196cd45..86d688cc5 100644 --- a/test/plugin-seo/e2e.spec.ts +++ b/test/plugin-seo/e2e.spec.ts @@ -8,7 +8,7 @@ import { fileURLToPath } from 'url' import type { Config, Page as PayloadPage } from './payload-types.js' -import { ensureAutoLoginAndCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' +import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js' import { AdminUrlUtil } from '../helpers/adminUrlUtil.js' import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js' import { TEST_TIMEOUT_LONG } from '../playwright.config.js' @@ -57,7 +57,7 @@ describe('SEO Plugin', () => { })) as unknown as PayloadPage id = createdPage.id - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) describe('Core functionality', () => { diff --git a/test/uploads/e2e.spec.ts b/test/uploads/e2e.spec.ts index d83d1e95d..a4fff3e1b 100644 --- a/test/uploads/e2e.spec.ts +++ b/test/uploads/e2e.spec.ts @@ -10,7 +10,7 @@ import type { PayloadTestSDK } from '../helpers/sdk/index.js' import type { Config, Media } from './payload-types.js' import { - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, initPageConsoleErrorCatch, openDocDrawer, saveDocAndAssert, @@ -89,7 +89,7 @@ describe('uploads', () => { audioDoc = findAudio.docs[0] as unknown as Media - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) }) test('should see upload filename in relation list', async () => { diff --git a/test/versions/e2e.spec.ts b/test/versions/e2e.spec.ts index f444e352a..d34fbab9a 100644 --- a/test/versions/e2e.spec.ts +++ b/test/versions/e2e.spec.ts @@ -35,7 +35,7 @@ import type { Config } from './payload-types.js' import { globalSlug } from '../admin/slugs.js' import { changeLocale, - ensureAutoLoginAndCompilationIsDone, + ensureCompilationIsDone, exactText, findTableCell, initPageConsoleErrorCatch, @@ -113,7 +113,7 @@ describe('versions', () => { snapshotKey: 'versionsTest', }) - await ensureAutoLoginAndCompilationIsDone({ page, serverURL }) + await ensureCompilationIsDone({ page, serverURL }) //await clearAndSeedEverything(payload) })