diff --git a/.release-it.beta.json b/.release-it.canary.json similarity index 89% rename from .release-it.beta.json rename to .release-it.canary.json index 5dff68cbd7..f65c00ec61 100644 --- a/.release-it.beta.json +++ b/.release-it.canary.json @@ -1,5 +1,5 @@ { - "preReleaseId": "beta", + "preReleaseId": "canary", "git": { "requireCleanWorkingDir": false, "commit": false, @@ -11,7 +11,7 @@ }, "npm": { "skipChecks": true, - "tag": "beta" + "tag": "canary" }, "hooks": { "before:init": ["yarn", "yarn clean", "yarn test"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 95326c9e3b..fca8a67b59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ +## [1.5.7](https://github.com/payloadcms/payload/compare/v1.5.6...v1.5.7) (2023-01-12) + + +### Bug Fixes + +* ensures find with draft=true does not improperly exclude draft ids ([69026c5](https://github.com/payloadcms/payload/commit/69026c577914ba029f2c45423d9f621b605a3ca0)) +* ensures querying with drafts works on both published and non-published posts ([f018fc0](https://github.com/payloadcms/payload/commit/f018fc04b02f70d0e6ea545d5eb36ea860206964)) + +## [1.5.6](https://github.com/payloadcms/payload/compare/v1.5.5...v1.5.6) (2023-01-11) + + +### Bug Fixes + +* ensures that find with draft=true returns ids with drafts ([3f30b2f](https://github.com/payloadcms/payload/commit/3f30b2f4894258d67e9a9a79e2213f9d5f69f856)) + +## [1.5.5](https://github.com/payloadcms/payload/compare/v1.5.4...v1.5.5) (2023-01-11) + + +### Bug Fixes + +* [#1808](https://github.com/payloadcms/payload/issues/1808), arrays and blocks now save localized nested field data upon reordering rows ([ee54c14](https://github.com/payloadcms/payload/commit/ee54c1481cdb8d6669864f20584fa6ef072c9097)) +* bug when clearing relationship field without hasMany: true ([#1829](https://github.com/payloadcms/payload/issues/1829)) ([ed7cfff](https://github.com/payloadcms/payload/commit/ed7cfff45c262206495580509a77adb72a646ddb)) +* ensures upload file data is available for conditions ([d40e136](https://github.com/payloadcms/payload/commit/d40e1369472f212b5f85bfc72fac01dc708aa507)) +* fix miss typo in Thai translation ([25e5ab7](https://github.com/payloadcms/payload/commit/25e5ab7ceebfb36960b6969db543a2b4ae7127d2)) +* formats date when useAsTitle ([086117d](https://github.com/payloadcms/payload/commit/086117d7039b2b68ab2789b57cac97e2735819cf)) +* prevents uploads drawer from crashing when no uploads are enabled ([84e1417](https://github.com/payloadcms/payload/commit/84e1417b711e0823753f0b9174c145e40b68e0be)) +* rte link element initial state [#1848](https://github.com/payloadcms/payload/issues/1848) ([1cde647](https://github.com/payloadcms/payload/commit/1cde647a2a86df21312229b8beec0a6b75df22c3)) +* updatesmargin for group field within a row ([1c3a257](https://github.com/payloadcms/payload/commit/1c3a257244e322c04164f6630772a40baf256da7)) +* upload field filterOptions ([9483ccb](https://github.com/payloadcms/payload/commit/9483ccb1208a91c1376ac4bd5186037f909aa45d)) +* wrong translation and punctuation spacing ([bf1242a](https://github.com/payloadcms/payload/commit/bf1242aafa3fa7e72e81af10284f4ddade28c4a0)) + + +### Features + +* adds translations for fallbackToDefaultLocale ([c247f31](https://github.com/payloadcms/payload/commit/c247f3130cf03d1dc12d456886b04db028161800)) +* ensures compatibility with azure cosmos and aws documentdb ([73af283](https://github.com/payloadcms/payload/commit/73af283e1c24befc2797e2bc9766a22d26e3c288)) + ## [1.5.4](https://github.com/payloadcms/payload/compare/v1.5.3...v1.5.4) (2023-01-06) diff --git a/docs/authentication/using-middleware.mdx b/docs/authentication/using-middleware.mdx index 607d493faf..e26b924e04 100644 --- a/docs/authentication/using-middleware.mdx +++ b/docs/authentication/using-middleware.mdx @@ -25,25 +25,24 @@ payload.init({ secret: 'PAYLOAD_SECRET_KEY', mongoURL: 'mongodb://localhost/payload', express: app, - onInit: async () => { - const router = express.Router(); +}); - router.use(payload.authenticate); // highlight-line +const router = express.Router(); - router.get('/', (req, res) => { - if (req.user) { - return res.send(`Authenticated successfully as ${req.user.email}.`); - } +router.use(payload.authenticate); // highlight-line - return res.send('Not authenticated'); - }); +router.get('/', (req, res) => { + if (req.user) { + return res.send(`Authenticated successfully as ${req.user.email}.`); + } - app.use('/some-route-here', router); + return res.send('Not authenticated'); +}); - app.listen(3000, async () => { - payload.logger.info(`listening on ${3000}...`); - }); - }, +app.use('/some-route-here', router); + +app.listen(3000, async () => { + payload.logger.info(`listening on ${3000}...`); }); ``` diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index a0a8499fc3..cc2dcecac2 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -66,7 +66,7 @@ app.listen(3000, async () => { }); ``` -This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its `init()` method, which accepts a small set of arguments to tell it how to operate. For a full list of `init` arguments, please consult the [main configuration](/docs/configuration/overview) docs. +This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its `init()` method, which accepts a small set of arguments to tell it how to operate. For a full list of `init` arguments, please consult the [main configuration](/docs/configuration/overview#init) docs. To initialize Payload, update your `server.js` file to reflect the following code: @@ -80,13 +80,12 @@ payload.init({ secret: 'SECRET_KEY', mongoURL: 'mongodb://localhost/payload', express: app, - onInit: () => { - app.listen(3000, async () => { - console.log('Express is now listening for incoming connections on port 3000.') - }); - } }) +app.listen(3000, async () => { + console.log('Express is now listening for incoming connections on port 3000.') +}); + ``` Here is a list of all properties available to pass through `payload.init`: diff --git a/package.json b/package.json index dd29aed36a..6988fb38bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload", - "version": "1.5.4", + "version": "1.5.7", "description": "Node, React and MongoDB Headless CMS and Application Framework", "license": "MIT", "engines": { diff --git a/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx b/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx index c1d97f20f0..f21c376876 100644 --- a/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx +++ b/src/admin/components/forms/field-types/RichText/elements/link/Button/index.tsx @@ -1,7 +1,7 @@ import React, { Fragment, useId, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactEditor, useSlate } from 'slate-react'; -import { Transforms, Range } from 'slate'; +import { Transforms, Range, Editor } from 'slate'; import { useModal } from '@faceless-ui/modal'; import ElementButton from '../../Button'; import LinkIcon from '../../../../../../icons/Link'; @@ -15,6 +15,10 @@ import { getBaseFields } from '../LinkDrawer/baseFields'; import { LinkDrawer } from '../LinkDrawer'; import { Field } from '../../../../../../../../fields/config/types'; import { Props as RichTextFieldProps } from '../../../types'; +import buildStateFromSchema from '../../../../../Form/buildStateFromSchema'; +import { useAuth } from '../../../../../../utilities/Auth'; +import { Fields } from '../../../../../Form/types'; +import { useLocale } from '../../../../../../utilities/Locale'; const insertLink = (editor, fields) => { const isCollapsed = editor.selection && Range.isCollapsed(editor.selection); @@ -56,6 +60,9 @@ export const LinkButton: React.FC<{ fieldProps: RichTextFieldProps }> = ({ fieldProps }) => { const customFieldSchema = fieldProps?.admin?.link?.fields; + const { user } = useAuth(); + const locale = useLocale(); + const [initialState, setInitialState] = useState({}); const { t } = useTranslation(['upload', 'general']); const editor = useSlate(); @@ -99,11 +106,22 @@ export const LinkButton: React.FC<{ format="link" tooltip={t('fields:addLink')} className="link" - onClick={() => { + onClick={async () => { if (isElementActive(editor, 'link')) { unwrapLink(editor); } else { openModal(drawerSlug); + + const isCollapsed = editor.selection && Range.isCollapsed(editor.selection); + + if (!isCollapsed) { + const data = { + text: editor.selection ? Editor.string(editor, editor.selection) : '', + }; + + const state = await buildStateFromSchema({ fieldSchema, data, user, operation: 'create', locale, t }); + setInitialState(state); + } } }} > @@ -115,6 +133,7 @@ export const LinkButton: React.FC<{ insertLink(editor, fields); closeModal(drawerSlug); }} + initialState={initialState} fieldSchema={fieldSchema} handleClose={() => { closeModal(drawerSlug); diff --git a/src/auth/operations/local/forgotPassword.ts b/src/auth/operations/local/forgotPassword.ts index 612889267a..eafb8331f5 100644 --- a/src/auth/operations/local/forgotPassword.ts +++ b/src/auth/operations/local/forgotPassword.ts @@ -3,6 +3,7 @@ import forgotPassword, { Result } from '../forgotPassword'; import { Payload } from '../../..'; import { getDataLoader } from '../../../collections/dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -25,6 +26,10 @@ async function localForgotPassword(payload: Payload, options: Options): Promise< const collection = payload.collections[collectionSlug]; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.i18n = i18n(payload.config.i18n); diff --git a/src/auth/operations/local/login.ts b/src/auth/operations/local/login.ts index ef92235c08..f1921ea9ea 100644 --- a/src/auth/operations/local/login.ts +++ b/src/auth/operations/local/login.ts @@ -5,6 +5,7 @@ import { TypeWithID } from '../../../collections/config/types'; import { Payload } from '../../..'; import { getDataLoader } from '../../../collections/dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -21,7 +22,7 @@ export type Options = { showHiddenFields?: boolean } -async function localLogin(payload: Payload, options: Options): Promise { +async function localLogin(payload: Payload, options: Options): Promise { const { collection: collectionSlug, req = {} as PayloadRequest, @@ -36,6 +37,10 @@ async function localLogin(payload: Payload, options: const collection = payload.collections[collectionSlug]; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.payload = payload; req.i18n = i18n(payload.config.i18n); diff --git a/src/auth/operations/local/resetPassword.ts b/src/auth/operations/local/resetPassword.ts index 55f3541159..969850d9de 100644 --- a/src/auth/operations/local/resetPassword.ts +++ b/src/auth/operations/local/resetPassword.ts @@ -3,6 +3,7 @@ import resetPassword, { Result } from '../resetPassword'; import { PayloadRequest } from '../../../express/types'; import { getDataLoader } from '../../../collections/dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -24,6 +25,10 @@ async function localResetPassword(payload: Payload, options: Options): Promise const collection = payload.collections[collectionSlug]; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payload = payload; req.payloadAPI = 'local'; req.i18n = i18n(payload.config.i18n); diff --git a/src/auth/operations/local/verifyEmail.ts b/src/auth/operations/local/verifyEmail.ts index 22228d5ac4..c4466bbc95 100644 --- a/src/auth/operations/local/verifyEmail.ts +++ b/src/auth/operations/local/verifyEmail.ts @@ -1,3 +1,4 @@ +import { APIError } from '../../../errors'; import { Payload } from '../../../index'; import verifyEmail from '../verifyEmail'; @@ -14,6 +15,10 @@ async function localVerifyEmail(payload: Payload, options: Options): Promise { +export function generateGraphQLSchema(): void { const logger = Logger(); const config = loadConfig(); - await payload.init({ + payload.init({ secret: '--unused--', mongoURL: false, local: true, diff --git a/src/collections/operations/local/create.ts b/src/collections/operations/local/create.ts index e32a58e710..cab886b689 100644 --- a/src/collections/operations/local/create.ts +++ b/src/collections/operations/local/create.ts @@ -7,6 +7,7 @@ import create from '../create'; import { getDataLoader } from '../../dataloader'; import { File } from '../../../uploads/types'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -46,6 +47,10 @@ export default async function createLocal(payload: Payload, options: Op const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.locale = locale ?? req?.locale ?? defaultLocale; req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale; diff --git a/src/collections/operations/local/delete.ts b/src/collections/operations/local/delete.ts index 0b8a0188a8..386c1e797e 100644 --- a/src/collections/operations/local/delete.ts +++ b/src/collections/operations/local/delete.ts @@ -5,6 +5,7 @@ import { Payload } from '../../../index'; import deleteOperation from '../delete'; import { getDataLoader } from '../../dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -32,6 +33,11 @@ export default async function deleteLocal(payload: P const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/collections/operations/local/find.ts b/src/collections/operations/local/find.ts index 342a91dcb6..cea2105c98 100644 --- a/src/collections/operations/local/find.ts +++ b/src/collections/operations/local/find.ts @@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types'; import find from '../find'; import { getDataLoader } from '../../dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -50,6 +51,10 @@ export default async function findLocal(payload: Pay const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.locale = locale ?? req?.locale ?? defaultLocale; req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale; diff --git a/src/collections/operations/local/findByID.ts b/src/collections/operations/local/findByID.ts index ba3addeb1d..9f013b041a 100644 --- a/src/collections/operations/local/findByID.ts +++ b/src/collections/operations/local/findByID.ts @@ -5,6 +5,7 @@ import findByID from '../findByID'; import { Payload } from '../../..'; import { getDataLoader } from '../../dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -41,6 +42,10 @@ export default async function findByIDLocal(payload: const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.locale = locale ?? req?.locale ?? defaultLocale; req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale; diff --git a/src/collections/operations/local/findVersionByID.ts b/src/collections/operations/local/findVersionByID.ts index 240ce53bd8..e19eba9dd0 100644 --- a/src/collections/operations/local/findVersionByID.ts +++ b/src/collections/operations/local/findVersionByID.ts @@ -5,6 +5,7 @@ import { TypeWithVersion } from '../../../versions/types'; import findVersionByID from '../findVersionByID'; import { getDataLoader } from '../../dataloader'; import i18n from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -35,6 +36,10 @@ export default async function findVersionByIDLocal const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + req.payloadAPI = 'local'; req.locale = locale ?? req?.locale ?? defaultLocale; req.fallbackLocale = fallbackLocale ?? req?.fallbackLocale ?? defaultLocale; diff --git a/src/collections/operations/local/findVersions.ts b/src/collections/operations/local/findVersions.ts index 6d833cf976..e7f1000218 100644 --- a/src/collections/operations/local/findVersions.ts +++ b/src/collections/operations/local/findVersions.ts @@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types'; import findVersions from '../findVersions'; import { getDataLoader } from '../../dataloader'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -39,6 +40,10 @@ export default async function findVersionsLocal = a const collection = payload.collections[collectionSlug]; const defaultLocale = payload?.config?.localization ? payload?.config?.localization?.defaultLocale : null; + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + const i18n = i18nInit(payload.config.i18n); const req = { user, diff --git a/src/collections/operations/local/restoreVersion.ts b/src/collections/operations/local/restoreVersion.ts index f016468740..67d3ee6bbc 100644 --- a/src/collections/operations/local/restoreVersion.ts +++ b/src/collections/operations/local/restoreVersion.ts @@ -5,6 +5,7 @@ import { TypeWithVersion } from '../../../versions/types'; import { getDataLoader } from '../../dataloader'; import restoreVersion from '../restoreVersion'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -30,6 +31,11 @@ export default async function restoreVersionLocal = } = options; const collection = payload.collections[collectionSlug]; + + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + const i18n = i18nInit(payload.config.i18n); const req = { user, diff --git a/src/collections/operations/local/update.ts b/src/collections/operations/local/update.ts index 57fd71a7ff..a4e86c80b6 100644 --- a/src/collections/operations/local/update.ts +++ b/src/collections/operations/local/update.ts @@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types'; import { getDataLoader } from '../../dataloader'; import { File } from '../../../uploads/types'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { collection: string @@ -43,6 +44,11 @@ export default async function updateLocal(payload: Payload, options: Op } = options; const collection = payload.collections[collectionSlug]; + + if (!collection) { + throw new APIError(`The collection with slug ${collectionSlug} can't be found.`); + } + const i18n = i18nInit(payload.config.i18n); const defaultLocale = payload.config.localization ? payload.config.localization?.defaultLocale : null; diff --git a/src/globals/operations/local/findOne.ts b/src/globals/operations/local/findOne.ts index 8d9f04cab7..60f9d196e6 100644 --- a/src/globals/operations/local/findOne.ts +++ b/src/globals/operations/local/findOne.ts @@ -5,6 +5,7 @@ import { Document } from '../../../types'; import { TypeWithID } from '../../config/types'; import findOne from '../findOne'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { slug: string @@ -32,6 +33,11 @@ export default async function findOneLocal(payload: const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug); const i18n = i18nInit(payload.config.i18n); + + if (!globalConfig) { + throw new APIError(`The global with slug ${globalSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/globals/operations/local/findVersionByID.ts b/src/globals/operations/local/findVersionByID.ts index 8d9cf748a2..6e14dd948e 100644 --- a/src/globals/operations/local/findVersionByID.ts +++ b/src/globals/operations/local/findVersionByID.ts @@ -5,6 +5,7 @@ import { Document } from '../../../types'; import { TypeWithVersion } from '../../../versions/types'; import findVersionByID from '../findVersionByID'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { slug: string @@ -34,6 +35,10 @@ export default async function findVersionByIDLocal const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug); const i18n = i18nInit(payload.config.i18n); + if (!globalConfig) { + throw new APIError(`The global with slug ${globalSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/globals/operations/local/findVersions.ts b/src/globals/operations/local/findVersions.ts index 321b153173..b53f334ddf 100644 --- a/src/globals/operations/local/findVersions.ts +++ b/src/globals/operations/local/findVersions.ts @@ -6,6 +6,7 @@ import { PayloadRequest } from '../../../express/types'; import findVersions from '../findVersions'; import { getDataLoader } from '../../../collections/dataloader'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { slug: string @@ -39,6 +40,10 @@ export default async function findVersionsLocal = a const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug); const i18n = i18nInit(payload.config.i18n); + if (!globalConfig) { + throw new APIError(`The global with slug ${globalSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/globals/operations/local/restoreVersion.ts b/src/globals/operations/local/restoreVersion.ts index 97a83bd03e..4bd185d578 100644 --- a/src/globals/operations/local/restoreVersion.ts +++ b/src/globals/operations/local/restoreVersion.ts @@ -5,6 +5,7 @@ import { Document } from '../../../types'; import { TypeWithVersion } from '../../../versions/types'; import restoreVersion from '../restoreVersion'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { slug: string @@ -32,6 +33,10 @@ export default async function restoreVersionLocal = const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug); const i18n = i18nInit(payload.config.i18n); + if (!globalConfig) { + throw new APIError(`The global with slug ${globalSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/globals/operations/local/update.ts b/src/globals/operations/local/update.ts index 264235f1b9..169f7d74c1 100644 --- a/src/globals/operations/local/update.ts +++ b/src/globals/operations/local/update.ts @@ -5,6 +5,7 @@ import { TypeWithID } from '../../config/types'; import update from '../update'; import { getDataLoader } from '../../../collections/dataloader'; import i18nInit from '../../../translations/init'; +import { APIError } from '../../../errors'; export type Options = { slug: string @@ -34,6 +35,10 @@ export default async function updateLocal(payload: P const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug); const i18n = i18nInit(payload.config.i18n); + if (!globalConfig) { + throw new APIError(`The global with slug ${globalSlug} can't be found.`); + } + const req = { user, payloadAPI: 'local', diff --git a/src/index.ts b/src/index.ts index 1d31742b03..319a5e9fc5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,7 +44,7 @@ import { Result as ResetPasswordResult } from './auth/operations/resetPassword'; import { Result as LoginResult } from './auth/operations/login'; import { Options as FindGlobalOptions } from './globals/operations/local/findOne'; import { Options as UpdateGlobalOptions } from './globals/operations/local/update'; -import { initPayload } from './init'; +import { initSync, initAsync } from './init'; require('isomorphic-fetch'); @@ -121,8 +121,12 @@ export class Payload { * @description Initializes Payload * @param options */ - async init(options: InitOptions): Promise { - await initPayload(this, options); + init(options: InitOptions): void { + initSync(this, options); + } + + async initAsync(options: InitOptions): Promise { + await initAsync(this, options); } getAdminURL = (): string => `${this.config.serverURL}${this.config.routes.admin}`; diff --git a/src/init.ts b/src/init.ts index 5f87c76d2d..fb1f2e61e5 100644 --- a/src/init.ts +++ b/src/init.ts @@ -33,15 +33,7 @@ import mountEndpoints from './express/mountEndpoints'; import PreferencesModel from './preferences/model'; import findConfig from './config/find'; -export const initPayload = async (payload: Payload, options: InitOptions): Promise => { - payload.logger = Logger('payload', options.loggerOptions); - payload.mongoURL = options.mongoURL; - - if (payload.mongoURL) { - mongoose.set('strictQuery', false); - payload.mongoMemoryServer = await connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger); - } - +export const init = (payload: Payload, options: InitOptions): void => { payload.logger.info('Starting Payload...'); if (!options.secret) { throw new Error( @@ -153,7 +145,34 @@ export const initPayload = async (payload: Payload, options: InitOptions): Promi } serverInitTelemetry(payload); +}; + +export const initAsync = async (payload: Payload, options: InitOptions): Promise => { + payload.logger = Logger('payload', options.loggerOptions); + payload.mongoURL = options.mongoURL; + + if (payload.mongoURL) { + mongoose.set('strictQuery', false); + payload.mongoMemoryServer = await connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger); + } + + init(payload, options); if (typeof options.onInit === 'function') await options.onInit(payload); if (typeof payload.config.onInit === 'function') await payload.config.onInit(payload); }; + +export const initSync = (payload: Payload, options: InitOptions): void => { + payload.logger = Logger('payload', options.loggerOptions); + payload.mongoURL = options.mongoURL; + + if (payload.mongoURL) { + mongoose.set('strictQuery', false); + connectMongoose(payload.mongoURL, options.mongoOptions, payload.logger); + } + + init(payload, options); + + if (typeof options.onInit === 'function') options.onInit(payload); + if (typeof payload.config.onInit === 'function') payload.config.onInit(payload); +}; diff --git a/src/versions/drafts/mergeDrafts.ts b/src/versions/drafts/mergeDrafts.ts index 28eee8e67c..2ec040de5d 100644 --- a/src/versions/drafts/mergeDrafts.ts +++ b/src/versions/drafts/mergeDrafts.ts @@ -5,7 +5,6 @@ import { PaginatedDocs } from '../../mongoose/types'; import { Collection, CollectionModel, TypeWithID } from '../../collections/config/types'; import { hasWhereAccessResult } from '../../auth'; import { appendVersionToQueryKey } from './appendVersionToQueryKey'; -import sanitizeInternalFields from '../../utilities/sanitizeInternalFields'; import replaceWithDraftIfAvailable from './replaceWithDraftIfAvailable'; type AggregateVersion = { @@ -100,6 +99,28 @@ export const mergeDrafts = async ({ createdAt: { $first: '$createdAt' }, }, }, + { + $addFields: { + id: { + $toObjectId: '$_id', + }, + }, + }, + { + $lookup: { + from: collection.config.slug, + localField: 'id', + foreignField: '_id', + as: 'parent', + }, + }, + { + $match: { + parent: { + $size: 1, + }, + }, + }, { $match: versionQuery }, { $limit: paginationOptions.limit }, ]).then((res) => res.reduce>((map, { _id, updatedAt, createdAt, version }) => { @@ -125,6 +146,9 @@ export const mergeDrafts = async ({ updatedAt: { $gt: parentDocUpdatedAt, }, + parent: { + $eq: parentDocID, + }, }, {}, { limit: 1 }).lean(); // If there are, @@ -152,8 +176,8 @@ export const mergeDrafts = async ({ finalQueryToBuild.where.and.push(accessResult); } - if (where) { - finalQueryToBuild.where.and[0].or.push(where); + if (incomingWhere) { + finalQueryToBuild.where.and[0].or.push(incomingWhere); } if (includedParentIDs.length > 0) { @@ -165,7 +189,7 @@ export const mergeDrafts = async ({ } if (excludedParentIDs.length > 0) { - finalQueryToBuild.where.and[0].or.push({ + finalQueryToBuild.where.and.push({ id: { not_in: excludedParentIDs, }, @@ -179,15 +203,11 @@ export const mergeDrafts = async ({ result = { ...result, docs: await Promise.all(result.docs.map(async (doc) => { - let sanitizedDoc = JSON.parse(JSON.stringify(doc)); - sanitizedDoc.id = sanitizedDoc._id; - sanitizedDoc = sanitizeInternalFields(sanitizedDoc); + const matchedVersion = versionCollectionMatchMap[doc.id]; - const matchedVersion = versionCollectionMatchMap[sanitizedDoc.id]; - - if (matchedVersion) { + if (matchedVersion && matchedVersion.updatedAt > doc.updatedAt) { return { - ...sanitizedDoc, + ...doc, ...matchedVersion.version, createdAt: matchedVersion.createdAt, updatedAt: matchedVersion.updatedAt, @@ -199,7 +219,7 @@ export const mergeDrafts = async ({ payload, entity: collection.config, entityType: 'collection', - doc: sanitizedDoc, + doc, locale, }); })), diff --git a/test/devServer.ts b/test/devServer.ts index 49138309ba..02c9b8778a 100644 --- a/test/devServer.ts +++ b/test/devServer.ts @@ -4,8 +4,9 @@ import { v4 as uuid } from 'uuid'; import payload from '../src'; const expressApp = express(); + const init = async () => { - await payload.init({ + await payload.initAsync({ secret: uuid(), mongoURL: process.env.MONGO_URL || 'mongodb://localhost/payload', express: expressApp, diff --git a/test/fields/e2e.spec.ts b/test/fields/e2e.spec.ts index c29416f81a..ad291c6b50 100644 --- a/test/fields/e2e.spec.ts +++ b/test/fields/e2e.spec.ts @@ -364,12 +364,16 @@ describe('fields', () => { await expect(popup).toBeVisible(); await expect(popup.locator('a')).toHaveAttribute('href', 'https://payloadcms.com'); - // Open link edit modal + // Open the drawer await popup.locator('.rich-text-link__link-edit').click(); - const editLinkModal = page.locator('.rich-text-link-edit-modal__template'); + const editLinkModal = page.locator('[id^=drawer_1_rich-text-link-]'); await expect(editLinkModal).toBeVisible(); - // Close link edit modal + // Check the drawer values + const textField = await editLinkModal.locator('#field-text'); + await expect(textField).toHaveValue('render links'); + + // Close the drawer await editLinkModal.locator('button[type="submit"]').click(); await expect(editLinkModal).not.toBeVisible(); }); @@ -383,15 +387,36 @@ describe('fields', () => { await expect(popup).toBeVisible(); await expect(popup.locator('a')).toHaveAttribute('href', /\/admin\/collections\/array-fields\/.*/); - // Open link edit modal + // Open the drawer await popup.locator('.rich-text-link__link-edit').click(); - const editLinkModal = page.locator('.rich-text-link-edit-modal__template'); + const editLinkModal = page.locator('[id^=drawer_1_rich-text-link-]'); await expect(editLinkModal).toBeVisible(); - // Close link edit modal + // Check the drawer values + const textField = await editLinkModal.locator('#field-text'); + await expect(textField).toHaveValue('link to relationships'); + + // Close the drawer await editLinkModal.locator('button[type="submit"]').click(); await expect(editLinkModal).not.toBeVisible(); }); + + test('should populate new links', async () => { + navigateToRichTextFields(); + + // Highlight existing text + const headingElement = await page.locator('#field-richText h1 >> text="Hello, I\'m a rich text field."'); + await headingElement.selectText(); + + // click the toolbar link button + await page.locator('.rich-text__toolbar button:not([disabled]) .link').click(); + + // find the drawer and confirm the values + const editLinkModal = await page.locator('[id^=drawer_1_rich-text-link-]'); + await expect(editLinkModal).toBeVisible(); + const textField = await editLinkModal.locator('#field-text'); + await expect(textField).toHaveValue('Hello, I\'m a rich text field.'); + }); }); }); diff --git a/test/helpers/configHelpers.ts b/test/helpers/configHelpers.ts index bd1d30e5cc..3144a8921e 100644 --- a/test/helpers/configHelpers.ts +++ b/test/helpers/configHelpers.ts @@ -40,7 +40,7 @@ export async function initPayloadTest(options: Options): Promise<{ serverURL: st initOptions.express = express(); } - await payload.init(initOptions); + await payload.initAsync(initOptions); if (initOptions.express) { initOptions.express.listen(port);