* chore(richtext-lexical): Add int test which reproduces the issue
* chore: Remove unnecessary await in core afterRead promise
* fix(richtext-lexical): re-use recurseNestedFields from payload instead of using own recurseNestedFields
* chore(richtext-lexical): pass in missing properties which are available in the core afterRead hook
* chore: remove unnecessary block
* chore(richtext-lexical): Add a hint that the slash menu exists to the user
* Update LexicalEditor.tsx
---------
Co-authored-by: Alessio Gravili <70709113+AlessioGr@users.noreply.github.com>
* fix(richtext-lexical): make sure block fields are wrapped in a uniquely-named group
* chore: remove redundant hook
* chore(richtext-lexical): attempt to fix unnecessary unsaved changes warning regression
* cleanup everything
* chore: more cleanup
* debug
* looks like properly cloning the formdata for setting initial state fixes the issue where the old formdata is updated even if node.setFields is not called
* chore: fix e2e tests
* chore: fix e2e tests (a selector has changed)
* chore: fix int tests (due to new blocks data format)
* chore: fix incorrect insert block commands in drawer
* chore: add new e2e test
* chore: fail e2e tests when there are browser console errors
* fix(breaking): beforeInput and afterInput: fix missing key errors, consistent typing and cases in name
* chore: new lexical int tests and working test structure
* chore: more int tests, and better lexical collection structure
* fix(richtext-lexical): Blocks: unnecessary saving node value when initially opening a document
* feat(richtext-lexical): 'bottom' position value for plugins
* feat: TestRecorderFeature
* chore: restructuring to seed and clear db before each test
* chore: make sure all tests pass
* chore: make sure indexes are created in seed.ts - this fixes one erroring test
* chore: speed up test runs through db snapshots
* chore: support drizzle when resetting db
* chore: simplify seeding process, by moving boilerplate db reset / snapshot logic into a wrapper function
* chore: add new seeding process to admin test suite
* chore(deps): upgrade jest and playwright
* chore: make sure mongoose-specific tests are not skipped
* chore: fix point test, which was depending on another test (that's bad!)
* chore: fix incorrect import
* chore: remove unnecessary comments
* chore: clearly label lexicalE2E test file as todo
* chore: simplify seed logic
* chore: move versions test suite to new seed system
Fixes#3904
* fix(db-mongodb): improve find query performance
* fix: add optimization to other operations which use pagination: findGlobalVersions, findVersions, queryDrafts
* fix: index createdAt field by default
* feat(live-preview): another oen
* wip: changelog script
* wippppp
* chore: this worked
* wip: changelog working
* chore(script): working changelog gen
* chore(script): update changelog during release
* chore(richtext-lexical): add jsdocs for afterReadPromise in GraphQL
* feat(richtext-lexical): HTML Serializer
* chore(richtext-lexical): adjust comment
* chore(richtext-lexical): change the way the html serializer works
* chore: working html converter field, improve various exports
* feat: link and heading html serializers
* fix: populationPromises not being added properly
* feat: allow html serializers to be async
* feat: upload html serializer
* feat: text format => html
* feat: lists => html
* feat: Quote => html
* chore: improve Checklist => html conversion, by passing in the full parent to converters
* feat: pass collection, global and field props to collection, global and field hooks - where applicable
* fix: initial request context not set for all operations
* chore: add tests which check the collection prop for collection hooks
* feat: add context to props of global hooks
* chore: add global tests for global and field props
* chore: int tests: use JSON instead of object hashes
* Fix generate:types bug #3697
generateEntityDeclarations function creates mismatched type names. We'll simply use the existing Config type instead.
* code cleanup
* fix(bundler-webpack): better node_modules resolution
* chore: see if retries are affecting new webpack changes
* chore: reinstate retries
This reverts commit 96989295ba.
* chore: default to process.cwd() if cannot find node_modules path
Specified that you don't need to provide any credentials when using a correct IAM Role. IAM Roles are recommended by AWS over direct credentials due to superior security.
without default value, it gives error in payload admin page (in console of browser)
caught SyntaxError: "undefined" is not valid JSON
at JSON.parse (<anonymous>)
at ./src/payload.config.ts
as envs are not availabe in payload admin GCS_CREDENTIALS gives undefined
resulting JSON.parse(undefined) raises this error
description:Please add a link to a reproduction. See the fork [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
description:Want us to look into your issue faster? Follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
validations:
required:false
- type:textarea
attributes:
label:Describe the Bug
validations:
required:true
- type:textarea
@@ -19,11 +24,6 @@ body:
description:Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required:true
- type:textarea
attributes:
label:Describe the Bug
validations:
required:true
- type:input
id:version
attributes:
@@ -31,6 +31,11 @@ body:
description:What version of Payload are you running?
validations:
required:true
- type:input
id:adapters-plugins
attributes:
label:Adapters and Plugins
description:What adapters and plugins are you using? ie. db-mongodb, db-postgres, bundler-webpack, etc.
- type:markdown
attributes:
value:Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
1. [fork](https://github.com/payloadcms/payload/fork) this repo
2.run `yarn` to install dependencies
3.open up the `test/_community` directory
4.add any necessary `collections/globals/fields` in this directory to recreate the issue you are experiencing
5.run `yarn dev _community` to start the admin panel
1. [Fork](https://github.com/payloadcms/payload/fork) this repo
2.Optionally, create a new branch for your reproduction
3.Run `pnpm install` to install dependencies
4.Open up the `test/_community` directory
5.Add any necessary `collections/globals/fields` in this directory to recreate the issue you are experiencing
6. Run `pnpm dev _community` to start the admin panel
**NOTE:** The goal is to isolate the problem by reducing the number of `collections/globals/fields` you add to the `test/_community` folder. This folder is _not_ meant for you to copy your project into, but rather recreate the issue you are experiencing with minimal config.
@@ -21,7 +22,7 @@
-`config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example
-`int.spec.ts` [Optional] - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix.
-`e2e.spec.ts` [Optional] - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests.
-`payload-types.ts` - Generated types from `config.ts`. Generate this file by running `yarn dev:generate-types _community`.
-`payload-types.ts` - Generated types from `config.ts`. Generate this file by running `pnpm dev:generate-types _community`.
The directory split up in this way specifically to reduce friction when creating tests and to add the ability to boot up Payload with that specific config. You should modify the files in `test/_community` to get started.
@@ -44,7 +45,7 @@ There are a couple ways run integration tests:
- **Manually** - you can run all int tests in the `/test/_community/int.spec.ts` file by running the following command:
* add serbian (latin and cyrillic) translations ([#4268](https://github.com/payloadcms/payload/issues/4268)) ([40c8909](https://github.com/payloadcms/payload/commit/40c8909ee0003d45a1afa4524ade557268d01067))
* **db-mongodb:** search for migrations dir intelligently ([530c825](https://github.com/payloadcms/payload/commit/530c825f806708df8672e66c8e9c559c5e625e5e))
* **db-postgres:** search for migrations dir intelligently ([308979f](https://github.com/payloadcms/payload/commit/308979f31d27979955a52f32be4ea33849b48f30))
* **live-preview:** batches api requests ([#4315](https://github.com/payloadcms/payload/issues/4315)) ([d49bb43](https://github.com/payloadcms/payload/commit/d49bb4351f22f17f68477c3145594abbb60fab05))
* support migrations with js files ([2122242](https://github.com/payloadcms/payload/commit/21222421929ae19728c31bdccc84995ce3951224))
* support OAuth 2.0 format Authorization: Bearer tokens in headers ([c1eb9d1](https://github.com/payloadcms/payload/commit/c1eb9d1727daf96375e73943882621127b78e593))
* **db-postgres:** allow for nested block fields to be queried ([#4237](https://github.com/payloadcms/payload/issues/4237)) ([cd07873](https://github.com/payloadcms/payload/commit/cd07873fc544766b4aeeff873dfb8d6e3e97e9dc))
* **db-postgres:** error saving nested arrays with versions ([#4302](https://github.com/payloadcms/payload/issues/4302)) ([3514bfb](https://github.com/payloadcms/payload/commit/3514bfbdaee99341ae739d03591cb63bd9415fe3))
* duplicate documents with required localized fields ([#4236](https://github.com/payloadcms/payload/issues/4236)) ([9da9b1f](https://github.com/payloadcms/payload/commit/9da9b1fc5050d4f29bcf6dce2f22027834aaf698))
* incorrect key property in Tabs field component ([#4311](https://github.com/payloadcms/payload/issues/4311)) ([3502ce7](https://github.com/payloadcms/payload/commit/3502ce720b3020eed5fc733884b525303faa4c15)), closes [#4282](https://github.com/payloadcms/payload/issues/4282)
* **live-preview-react:** removes payload from peer deps ([7e1052f](https://github.com/payloadcms/payload/commit/7e1052fd98c88a4d68af08f98ccc8936edb8ebf6))
* properly sets tabs key in fieldSchemaToJSON ([#4317](https://github.com/payloadcms/payload/issues/4317)) ([9cc88bb](https://github.com/payloadcms/payload/commit/9cc88bb47443ecdf525f4c99d9f13d81c141c471))
* **richtext-lexical:** HTML Converter field not working inside of tabs ([#4293](https://github.com/payloadcms/payload/issues/4293)) ([5bf6493](https://github.com/payloadcms/payload/commit/5bf64933b4b99a0ac8ef7d1d91d0165a16636a9f))
* **richtext-lexical:** re-use payload population logic to fix population-related issues ([#4291](https://github.com/payloadcms/payload/issues/4291)) ([094d02c](https://github.com/payloadcms/payload/commit/094d02ce1d85106470a1a8c6ffe9050873f2e57a))
* **richtext-slate:** add use client to top of tsx files importing from payload core ([#4312](https://github.com/payloadcms/payload/issues/4312)) ([d4f28b1](https://github.com/payloadcms/payload/commit/d4f28b16b4d42f224e9c5e4254f9ec55107a2f97))
### BREAKING CHANGES
### ⚠️ @payloadcms/richtext-lexical
The `SlashMenuGroup` and `SlashMenuOption` classes have changed. If you have any custom lexical Features which are adding new slash menu entries, this will be a breaking change for you. If not, no action is required from your side.
Here are the breaking changes and how to migrate:
1. The `SlashMenuOption`'s first argument is now used as a `key` and not as a display name. Additionally, a new, optional `displayName` property is added which will serve as the display name. Make sure your `key` does not contain any spaces or special characters.
2. The `title` property of `SlashMenuGroup` has been replaced by a new, mandatory `key` and an optional `displayName` property. To migrate, you will have to remove the `title` property and add a `key` property instead - make sure you do not use spaces or special characters in the `key`.
3. Additionally, if you have custom styles targeting elements inside of slash or floating-select-toolbar menus, you will have to adjust those too, as the CSS classes changed
* **i18n:** adds Korean translation ([#4258](https://github.com/payloadcms/payload/issues/4258)) ([1401718](https://github.com/payloadcms/payload/commit/1401718b3b549ce1454389a982474dbe159eb61f))
### Bug Fixes
* number field validation ([#4233](https://github.com/payloadcms/payload/issues/4233)) ([19fcfc2](https://github.com/payloadcms/payload/commit/19fcfc27af2ecb68ff989dcaed19b7b7d041a322))
* passes date options to the react-datepicker in filter UI, removes duplicate options from operators select ([#4225](https://github.com/payloadcms/payload/issues/4225)) ([3d2b62b](https://github.com/payloadcms/payload/commit/3d2b62b2100e36a54adc6a675257a4d671fdd469))
* prevent json data getting reset when switching tabs ([#4123](https://github.com/payloadcms/payload/issues/4123)) ([1dcd3a2](https://github.com/payloadcms/payload/commit/1dcd3a27825ed9d276b997a66f84bb2c05e87955))
* transactions broken within doc access ([443847e](https://github.com/payloadcms/payload/commit/443847ec716a3b87032d9d1904b6c90aadd47197))
* typo in polish translations ([#4234](https://github.com/payloadcms/payload/issues/4234)) ([56a4692](https://github.com/payloadcms/payload/commit/56a469266207ef83053b0c9176d1be4fc26087e6))
* make outputSchema optional on richtext config ([#4230](https://github.com/payloadcms/payload/issues/4230)) ([3a784a0](https://github.com/payloadcms/payload/commit/3a784a06cc6c42c96b8d6cf023d942e6661be7b5))
* allow richtext adapters to control type generation, improve generated lexical types ([#4036](https://github.com/payloadcms/payload/issues/4036)) ([989c10e](https://github.com/payloadcms/payload/commit/989c10e0e0b36a8c34822263b19f5cb4b9ed6e72))
* hide publish button based on permissions ([#4203](https://github.com/payloadcms/payload/issues/4203)) ([de02490](https://github.com/payloadcms/payload/commit/de02490231fbc8936973c1b81ac87add39878d8b))
* **richtext-lexical:** Add new position: 'top' property for plugins ([eed4f43](https://github.com/payloadcms/payload/commit/eed4f4361cd012adf4e777820adbe7ad330ffef6))
### Bug Fixes
* fully define the define property for esbuild string replacement ([#4099](https://github.com/payloadcms/payload/issues/4099)) ([e22b95b](https://github.com/payloadcms/payload/commit/e22b95bdf3b2911ae67a07a76ec109c76416ea56))
* improves live preview breakpoints and zoom options in dark mode ([#4090](https://github.com/payloadcms/payload/issues/4090)) ([b91711a](https://github.com/payloadcms/payload/commit/b91711a74ad9379ed820b6675060209626b1c2d0))
* **plugin-nested-docs:** await populate breadcrumbs on resaveChildren ([#4226](https://github.com/payloadcms/payload/issues/4226)) ([4e41dd1](https://github.com/payloadcms/payload/commit/4e41dd1bf2706001fa03130adb1c69403795ac96))
* **richtext-lexical:** Blocks: Array row data is not removed ([#4209](https://github.com/payloadcms/payload/issues/4209)) ([0af9c4d](https://github.com/payloadcms/payload/commit/0af9c4d3985a6c46a071ef5ac28c8359cb320571))
* **richtext-lexical:** Blocks: fields without fulfilled condition are now skipped for validation ([50fab90](https://github.com/payloadcms/payload/commit/50fab902bd7baa1702ae0d995b4f58c1f5fca374))
* **richtext-lexical:** Blocks: make sure fields are wrapped in a uniquely-named group, change block node data format, fix react key error ([#3995](https://github.com/payloadcms/payload/issues/3995)) ([c068a87](https://github.com/payloadcms/payload/commit/c068a8784ec5780dbdca5416b25ba654afd05458))
* **richtext-lexical:** Blocks: z-index issue, e.g. select field dropdown in blocks hidden behind blocks below, or slash menu inside nested editor hidden behind blocks below ([09f17f4](https://github.com/payloadcms/payload/commit/09f17f44508539cfcb8722f7f462ef40d9ed54fd))
* **richtext-lexical:** Floating Select Toolbar: Buttons and Dropdown Buttons not clickable in nested editors ([615702b](https://github.com/payloadcms/payload/commit/615702b858e76994a174159cb69f034ef811e016)), closes [#4025](https://github.com/payloadcms/payload/issues/4025)
* **richtext-lexical:** incorrect caret positioning when selecting second line of multi-line paragraph ([#4165](https://github.com/payloadcms/payload/issues/4165)) ([b210af4](https://github.com/payloadcms/payload/commit/b210af46968b77d96ffd6ef60adc3b8d8bdc9376))
* **richtext-lexical:** make lexicalHTML() function work for globals ([dbfc835](https://github.com/payloadcms/payload/commit/dbfc83520ca8b5e55198a3c4b517ae3a80f9cac6))
* **richtext-lexical:** nested editor may lose focus when writing ([#4139](https://github.com/payloadcms/payload/issues/4139)) ([859c2f4](https://github.com/payloadcms/payload/commit/859c2f4a6d299a42e572133502b3841a74a11002))
* **richtext-lexical:** remove optional chaining after `this` as transpilers are not handling it well ([#4145](https://github.com/payloadcms/payload/issues/4145)) ([2c8d34d](https://github.com/payloadcms/payload/commit/2c8d34d2aadf2fcaf0655c0abef233f341d9945f))
* **richtext-lexical:** visual bug after rearranging blocks ([a6b4860](https://github.com/payloadcms/payload/commit/a6b486007dc26195adc5d576d937e35471c2868f))
* simplifies block/array/hasMany-number field validations ([#4052](https://github.com/payloadcms/payload/issues/4052)) ([803a37e](https://github.com/payloadcms/payload/commit/803a37eaa947397fa0a93b9f4f7d702c6b94ceaa))
* thread locale through to access routes from admin panel ([#4183](https://github.com/payloadcms/payload/issues/4183)) ([05f3169](https://github.com/payloadcms/payload/commit/05f3169a75b3b62962e7fe7842fbb6df6699433d))
* transactionID isolation for GraphQL ([#4095](https://github.com/payloadcms/payload/issues/4095)) ([195a952](https://github.com/payloadcms/payload/commit/195a952c4314e0d53fd579517035373b49d6ccae))
* upload fit not accounted for when editing focal point or crop ([#4142](https://github.com/payloadcms/payload/issues/4142)) ([45e9a55](https://github.com/payloadcms/payload/commit/45e9a559bbb16b2171465c8a439044011cebf102))
* conditionally hide dot menu in DocumentControls ([#4075](https://github.com/payloadcms/payload/issues/4075)) ([cef4cbb](https://github.com/payloadcms/payload/commit/cef4cbb0ee59e1b0b806808d79b402dce114755f))
* disable editing option for svg image types ([#4071](https://github.com/payloadcms/payload/issues/4071)) ([949e265](https://github.com/payloadcms/payload/commit/949e265cd9c95b7d4063336dde86177008d54839))
* fixes creation of related documents within a transaction if filterOptions is used ([#4087](https://github.com/payloadcms/payload/issues/4087)) ([acad288](https://github.com/payloadcms/payload/commit/acad2888cd9a13d5fb9e4c686b2267ea69454eaf))
* hide empty image sizes from the preview drawer ([#3946](https://github.com/payloadcms/payload/issues/3946)) ([687f485](https://github.com/payloadcms/payload/commit/687f4850acf073df0a649ef6182bfc8387857173))
* **live-preview:** ensures field schema exists before traversing fields ([#4074](https://github.com/payloadcms/payload/issues/4074)) ([7059a71](https://github.com/payloadcms/payload/commit/7059a71243a8f98dcc89af0bfe502247db9e4123))
* **live-preview:** field recursion and relationship population ([#4045](https://github.com/payloadcms/payload/issues/4045)) ([2ad7340](https://github.com/payloadcms/payload/commit/2ad73401546ef6608fd67d1f00b537f149640d6a))
* possible issue with access control not using req ([#4086](https://github.com/payloadcms/payload/issues/4086)) ([348a70c](https://github.com/payloadcms/payload/commit/348a70cc33409b0b48aff3acd2b94c2df5d88f3b))
* **richtext-lexical:** Blocks: unnecessary saving node value when initially opening a document & new lexical tests ([#4059](https://github.com/payloadcms/payload/issues/4059)) ([fff377a](https://github.com/payloadcms/payload/commit/fff377ad22cce3b26142cde8f4125fcee95aa072))
* **richtext-lexical:** floating select toolbar caret not positioned correctly if first line is selected ([#4062](https://github.com/payloadcms/payload/issues/4062)) ([c462df3](https://github.com/payloadcms/payload/commit/c462df38f65b155e131e6a7b46b2bb16cd090e45))
* add internationalization (i18n) to locales ([#4005](https://github.com/payloadcms/payload/issues/4005)) ([6a0a859](https://github.com/payloadcms/payload/commit/6a0a859563ed9e742260ea51a1839a1ef0f61fce))
* Custom Error, Label, and before/after field components ([#3747](https://github.com/payloadcms/payload/issues/3747)) ([266c327](https://github.com/payloadcms/payload/commit/266c3274d03e4fd52c692eeef1ee9248dcf66189))
### Bug Fixes
* error on graphql multiple queries ([#3985](https://github.com/payloadcms/payload/issues/3985)) ([57da3c9](https://github.com/payloadcms/payload/commit/57da3c99a7e4ce5d3d1e17315e3691815f363704))
* focal and cropping issues, adds test ([#4039](https://github.com/payloadcms/payload/issues/4039)) ([acba5e4](https://github.com/payloadcms/payload/commit/acba5e482b7ddc6e3dc6ba9b7736022770d69a55))
* handle invalid tokens in refresh token operation ([#3647](https://github.com/payloadcms/payload/issues/3647)) ([131d89c](https://github.com/payloadcms/payload/commit/131d89c3f50c237e1ab2d7cd32d7a8226a9f8ce3))
* hasMany number and select fields unable to save within arrays ([#4047](https://github.com/payloadcms/payload/issues/4047)) ([182c57b](https://github.com/payloadcms/payload/commit/182c57b191010ce3dcf659f39c1dc2f7cf80662e))
* injects array and block ids into fieldSchemaToJSON ([#4043](https://github.com/payloadcms/payload/issues/4043)) ([d068ef7](https://github.com/payloadcms/payload/commit/d068ef7e2483d49dc41bdd7735042ddcaa0a684c))
* parse predefined migrations via file arg or name prefix ([#4001](https://github.com/payloadcms/payload/issues/4001)) ([eb42c03](https://github.com/payloadcms/payload/commit/eb42c031ef980558ed051d4163925aa28d6ab090))
* polymorphic hasMany relationships missing in postgres admin ([#4053](https://github.com/payloadcms/payload/issues/4053)) ([7a9af44](https://github.com/payloadcms/payload/commit/7a9af4417a56c621f01195f9a2904b9adffaad7a))
* resets list filter row when the filter on field is changed ([#3956](https://github.com/payloadcms/payload/issues/3956)) ([8d14c21](https://github.com/payloadcms/payload/commit/8d14c213c878a1afda2b3bf03431fed5aa2a44e3))
* Update API Views ([b008b6c](https://github.com/payloadcms/payload/commit/b008b6c6463c9dc3d8e61eaa0a9210aa1a189442))
* vite not replacing env vars correctly when building ([67b3baa](https://github.com/payloadcms/payload/commit/67b3baaa445a13246be8178d57eaeba92888bef1))
* do not display field if read permission is false - admin panel ui ([#3949](https://github.com/payloadcms/payload/issues/3949)) ([cdc10be](https://github.com/payloadcms/payload/commit/cdc10be1a241c6a9ac09feab77bcd58d23ff3dd9))
* ensures dataloader does not run requests in parallel ([4607dbf](https://github.com/payloadcms/payload/commit/4607dbf97694bc899e597e9c7df50b6c878874f5))
* exclude files from dev bundle if aliased ([#3957](https://github.com/payloadcms/payload/issues/3957)) ([7966692](https://github.com/payloadcms/payload/commit/796669279afb8fe23723ce36e6e47a44b7088b09))
* field paths being mutated if they ended with the req.locale ([#3936](https://github.com/payloadcms/payload/issues/3936)) ([36576f1](https://github.com/payloadcms/payload/commit/36576f152ace41edd8b353703db2598d04deae44))
* passes correct data to buildStateFromSchema on account page ([#3984](https://github.com/payloadcms/payload/issues/3984)) ([c7a315a](https://github.com/payloadcms/payload/commit/c7a315a7d1075361a7ee432a449769397c12185e))
* prevent sort from saving a new version in version list view ([#3944](https://github.com/payloadcms/payload/issues/3944)) ([900a9ea](https://github.com/payloadcms/payload/commit/900a9eafeb51b1e5130518d4f71034a2bf9e4c5b))
* properly load temp files into buffer ([#3996](https://github.com/payloadcms/payload/issues/3996)) ([d1a0822](https://github.com/payloadcms/payload/commit/d1a0822f8044a3f65416f4fe608e91a4ceea6b56))
* sort document tabs by order ([#3968](https://github.com/payloadcms/payload/issues/3968)) ([06cd52b](https://github.com/payloadcms/payload/commit/06cd52b622723503896af6262907d31b258d0a5e))
* vertical alignment in step nav when using larger logos ([#3955](https://github.com/payloadcms/payload/issues/3955)) ([b6d9a20](https://github.com/payloadcms/payload/commit/b6d9a2021fafea594353329fd304553bf7f2d091))
* adds null to non-required field unions ([#3870](https://github.com/payloadcms/payload/issues/3870)) ([7e919aa](https://github.com/payloadcms/payload/commit/7e919aa87c0116c41bf41d75dcd91ff96576a46f))
* checks for user before accessing properties in preferences update operation([#3844](https://github.com/payloadcms/payload/issues/3844)) ([24eab3a](https://github.com/payloadcms/payload/commit/24eab3af1da3b08debe0580cce8ece08a86039a4))
* disable webpack hot reload on production ([#3891](https://github.com/payloadcms/payload/issues/3891)) ([422c803](https://github.com/payloadcms/payload/commit/422c803da67982a063a028508c44009b9577646e))
* duplicate document copying to incorrect locale ([#3874](https://github.com/payloadcms/payload/issues/3874)) ([89f273b](https://github.com/payloadcms/payload/commit/89f273bf894512b69e8647be4cf4496bff37c99b))
* ensure serverURL has string value for getBaseUploadFields function ([#3900](https://github.com/payloadcms/payload/issues/3900)) ([c564a83](https://github.com/payloadcms/payload/commit/c564a83ab61b672d9a2bcc875ab890b0fede5462))
* ensures compare-version select field cannot be cleared ([#3901](https://github.com/payloadcms/payload/issues/3901)) ([42d8d11](https://github.com/payloadcms/payload/commit/42d8d11fd7e5792b119f69f17dc1100c85cfa491))
* error handling when duplicating documents fails ([#3873](https://github.com/payloadcms/payload/issues/3873)) ([435eb62](https://github.com/payloadcms/payload/commit/435eb6204e550e898a81033f794fcf568e3b017c))
* generate new block ids on create ([#3871](https://github.com/payloadcms/payload/issues/3871)) ([3404bab](https://github.com/payloadcms/payload/commit/3404bab83f1112713675eb504870a4a1786c3822))
* global permissions for live preview ([#3854](https://github.com/payloadcms/payload/issues/3854)) ([3032e0b](https://github.com/payloadcms/payload/commit/3032e0b5a239db0762abd120b2db95f30ed5ca65))
* handles null & undefined relationship field values in versions view ([#3609](https://github.com/payloadcms/payload/issues/3609)) ([115e592](https://github.com/payloadcms/payload/commit/115e592b54d9174f316daa3cff31bcc801eaf92f))
* incorrect duplication of data in admin ui ([#3907](https://github.com/payloadcms/payload/issues/3907)) ([46fc41c](https://github.com/payloadcms/payload/commit/46fc41cbd9615c58248b4d2c44d24905dd676171))
* only apply focal manipulation when necessary ([#3902](https://github.com/payloadcms/payload/issues/3902)) ([a4f36aa](https://github.com/payloadcms/payload/commit/a4f36aa8a009e9c0156924320bbcf1d04b697223))
* removes conditional return of formattedEmails in sendEmail hook [#26](https://github.com/payloadcms/payload/issues/26) ([#28](https://github.com/payloadcms/payload/issues/28)) ([e8458f8](https://github.com/payloadcms/payload/commit/e8458f84bcd5bad74b189479931fbb7faea74900))
* resize image if no aspect ratio change ([#3859](https://github.com/payloadcms/payload/issues/3859)) ([f53b713](https://github.com/payloadcms/payload/commit/f53b7131548dbe9071c65ba110f7f0d206bb33b5))
* **richtext-*:** type issues with typescript strict mode enabled ([dac9514](https://github.com/payloadcms/payload/commit/dac9514eb00b99a3caeb9f217695b2b89368f7c9))
* **richtext-lexical:** Blocks node incorrectly marked as client module ([35f00fa](https://github.com/payloadcms/payload/commit/35f00fa83d2a90967e0707ca0fd960c5608a3bf3))
* set date to 12UTC for default, dayOnly and monthOnly fields ([#3887](https://github.com/payloadcms/payload/issues/3887)) ([d393225](https://github.com/payloadcms/payload/commit/d3932252891bb8721a5abc97e204dbb6a7f3fda2))
* store resized image on req or tempFilePath ([#3883](https://github.com/payloadcms/payload/issues/3883)) ([6c5d525](https://github.com/payloadcms/payload/commit/6c5d525d8e1267eebdffeb9f31b2ef3a4df1132d))
* unique field error handling ([#3888](https://github.com/payloadcms/payload/issues/3888)) ([4d8d4c2](https://github.com/payloadcms/payload/commit/4d8d4c214ab12571e9dc71e406117c4b19f63c6b))
* adjusts props to accept components for before and after fields instead of functions ([#3820](https://github.com/payloadcms/payload/issues/3820)) ([c476d01](https://github.com/payloadcms/payload/commit/c476d01f4e5016f9c2bc338103ef2c778139a536))
* alignment of collapsible within row ([#3822](https://github.com/payloadcms/payload/issues/3822)) ([eaef0e7](https://github.com/payloadcms/payload/commit/eaef0e739546b4411d971da21170977ba73695f8))
* named tabs not appearing in the gql mutation input type ([#3835](https://github.com/payloadcms/payload/issues/3835)) ([a0019d0](https://github.com/payloadcms/payload/commit/a0019d0a78504b5c4d6aeec4823d7a0e224f1d6b))
* only parses live preview ready message when same origin ([#3791](https://github.com/payloadcms/payload/issues/3791)) ([e8f2377](https://github.com/payloadcms/payload/commit/e8f237783b9f48edf80b1d8c61142aeb2edb1c0b))
* prevent storing duplicate user preferences ([#3833](https://github.com/payloadcms/payload/issues/3833)) ([7eee0ec](https://github.com/payloadcms/payload/commit/7eee0ec3558c8b65afc38df7377073f042402ee3))
* prevents document sidebar from collapsing ([71a3e5b](https://github.com/payloadcms/payload/commit/71a3e5ba1037fe447dccad4a490fdfb1623ba0b0))
* renders live preview for globals ([#3801](https://github.com/payloadcms/payload/issues/3801)) ([a13ec2e](https://github.com/payloadcms/payload/commit/a13ec2ebc4858029c643f4530daa4ed49a7b024e))
* collection, global and field props for hooks, fix request context initialization, add context to global hooks ([#3780](https://github.com/payloadcms/payload/pull/3780))
* **richtext-lexical:** HTML Serializer ([#3685](https://github.com/payloadcms/payload/pull/3685))
### Bug Fixes
* remove duplicate removal of temp upload file ([#3818](https://github.com/payloadcms/payload/pull/3818))
* simplify how the search input and query params are connected ([#3797](https://github.com/payloadcms/payload/pull/3797))
* standardizes layout of document fields ([#3798](https://github.com/payloadcms/payload/pull/3798))
* issue where dragging unsortable item would crash the page ([#3789](https://github.com/payloadcms/payload/pull/3789))
* **richtext-lexical:** defaultValue property didn't fit into field schema ([b5c7bbed9](https://github.com/payloadcms/payload/commit/b5c7bbed93b532ec54a9c73537f4cb1290122a66))
* **richtext-*:** hasMany relationships not populated correctly ([e197e0316](https://github.com/payloadcms/payload/commit/e197e0316f9c01f945dc7f6d21ac28f9f0420f1d))
* filesRequired is optional for uploads ([#3668](https://github.com/payloadcms/payload/pull/3668)) ([48de897](https://github.com/payloadcms/payload/commit/48de89794b2c5d94183090b0830fd355d8d6c6f3))
### Bug Fixes
* Register first user verify update missing transaction id / req ([#3665](https://github.com/payloadcms/payload/pull/3665)) ([68c5a5751](https://github.com/payloadcms/payload/commit/68c5a57515ffbba37c9194a75d0f672bdb10d96b))
* allows filterOptions to return null ([c4cac99](https://github.com/payloadcms/payload/commit/c4cac998752730e7084598c92c77789da8c82e0d))
* **live-preview:** caches field schema ([#3711](https://github.com/payloadcms/payload/issues/3711)) ([dd0ac06](https://github.com/payloadcms/payload/commit/dd0ac066ce2ed88b85025309303610a95b6089e1))
### Bug Fixes
* autosave time shown minutes only ([#3492](https://github.com/payloadcms/payload/issues/3492)) ([e311e8f](https://github.com/payloadcms/payload/commit/e311e8fff9cd4264d7a71903f63c4fa825a3564d))
* blocks within groups in postgres ([45a62ba](https://github.com/payloadcms/payload/commit/45a62ba949aca33b25e0808773a5c2f1cf4adf82))
* bug with seeding ecommerce ([993568a](https://github.com/payloadcms/payload/commit/993568a1959ea10f960e35e4ed7a8e06af672a72))
* corrects add block index ([#3681](https://github.com/payloadcms/payload/issues/3681)) ([3c50443](https://github.com/payloadcms/payload/commit/3c5044368d5b30c76a2ff20c25b9234ef89dc205))
* misc upload crop/focal point updates ([#3580](https://github.com/payloadcms/payload/issues/3580)) ([d616772](https://github.com/payloadcms/payload/commit/d6167727401a01282345e63636560e029ae8e0f3))
* renders mobile document controls ([#3695](https://github.com/payloadcms/payload/issues/3695)) ([1625ff2](https://github.com/payloadcms/payload/commit/1625ff244e6e81e6edc0357037c3abc1a3bf8ba7))
* some local operations missing req.transactionID ([#3651](https://github.com/payloadcms/payload/issues/3651)) ([150799e](https://github.com/payloadcms/payload/commit/150799e10e580281d1af49388eb142ee9639a002))
* **richtext-*:** extra fields not being iterated correctly ([#3693](https://github.com/payloadcms/payload/issues/3693)) ([b8a5866](https://github.com/payloadcms/payload/commit/b8a58666e70f604af1e1cf349bcb4f9add0147e7))
* **richtext-*:** link drawer form receiving incorrect field schema ([#3696](https://github.com/payloadcms/payload/issues/3696)) ([cb39354](https://github.com/payloadcms/payload/commit/cb39354a9de3d20960110e453f62c4aa166d8448))
* **templates:** user access control ([#3712](https://github.com/payloadcms/payload/issues/3712)) ([8b8ceab](https://github.com/payloadcms/payload/commit/8b8ceabbdd6354761e7d744cacb1192cac3a2427))
* login form clearing out and field spacing ([#3633](https://github.com/payloadcms/payload/issues/3633)) ([4bd01df](https://github.com/payloadcms/payload/commit/4bd01df411e4ad2ccacdcd6de0fb21a8145c3964))
* sidebar field permissions ([#3629](https://github.com/payloadcms/payload/issues/3629)) ([c956a85](https://github.com/payloadcms/payload/commit/c956a85252bc7de1686925cc783694383c0ac9be))
* properly renders custom buttons for globals ([#3616](https://github.com/payloadcms/payload/issues/3616)) ([05cc287](https://github.com/payloadcms/payload/commit/05cc2873b4a19e2bd46be778f3610643d3e15d09))
* minor type issue in richText validate function ([06a51b3](https://github.com/payloadcms/payload/commit/06a51b3c9b9045b23051807aa03b222b542b46f5))
* live preview device size ([#3606](https://github.com/payloadcms/payload/issues/3606)) ([8bbac60](https://github.com/payloadcms/payload/commit/8bbac60e60a6dbe4dc0c7b05edbca7f6f2d1c569))
* properly handles nested routes for live preview ([#3586](https://github.com/payloadcms/payload/issues/3586)) ([6486468](https://github.com/payloadcms/payload/commit/64864686c418f9822bf61c45ece078a39e81b4cb))
* various stepnav related issues ([#3599](https://github.com/payloadcms/payload/issues/3599)) ([aaf8839](https://github.com/payloadcms/payload/commit/aaf883909c588bae1145ddddc5291a98740c2c03))
* postgres select fields within groups ([#3570](https://github.com/payloadcms/payload/issues/3570)) ([06e2fa9](https://github.com/payloadcms/payload/commit/06e2fa9d111c18fad3422953082266db9329fc91))
* [#3511](https://github.com/payloadcms/payload/issues/3511), documents don't delete their versions ([#3520](https://github.com/payloadcms/payload/issues/3520)) ([e3c7765](https://github.com/payloadcms/payload/commit/e3c776523a64da03a4756ee5ae8a84175090979f))
### Documentation
- updates building your own live preview hook ([#3604](https://github.com/payloadcms/payload/issues/3604)) ([15c7f0dbf](https://github.com/payloadcms/payload/commit/15c7f0dbf3ebf5c6a2bb011970dda515a15acb56))
- API tab breadcrumbs and results indentation ([#3564](https://github.com/payloadcms/payload/issues/3564)) ([e0afeec](https://github.com/payloadcms/payload/commit/e0afeeca974d0a0cac7aca8e40f9436449c902b5))
- sidebar width when fields have long descriptions ([#3562](https://github.com/payloadcms/payload/issues/3562)) ([cfc78ed](https://github.com/payloadcms/payload/commit/cfc78ed4f58647769f651da5a952fed20cfb217f))
- row field margins ([#3558](https://github.com/payloadcms/payload/issues/3558)) ([6d9353b](https://github.com/payloadcms/payload/commit/6d9353b53f4197bae2b15ca95298a87d784c7e76))
- removes nested array field configs from array value ([#3549](https://github.com/payloadcms/payload/issues/3549)) ([af892ec](https://github.com/payloadcms/payload/commit/af892ecb0e67777a97206bb5fccf489387ce68fc))
- renders global label as page title ([#3532](https://github.com/payloadcms/payload/issues/3532)) ([ace3e57](https://github.com/payloadcms/payload/commit/ace3e577f6b1cbeb12860dc936c578c2a1f68570))
- increases document controls popup list button hitbox ([#3529](https://github.com/payloadcms/payload/issues/3529)) ([f009593](https://github.com/payloadcms/payload/commit/f0095937bafdd85c53c99bcc1d29d3361aa07238))
- adds build your own plugin page ([#3184](https://github.com/payloadcms/payload/pull/3184)) ([15f650afd](https://github.com/payloadcms/payload/commit/15f650afdef717d62c162846fec77aa0f326bb43))
- webpack export default was not found [#3494](https://github.com/payloadcms/payload/issues/3494) ([be049ce](https://github.com/payloadcms/payload/commit/be049cea0029cf497822e337777b8a86b7d38bed))
- postgres generated type id [#3504](https://github.com/payloadcms/payload/issues/3504) ([c90d1fa](https://github.com/payloadcms/payload/commit/c90d1faa7fedd5d902949089fd457c56eed4643d))
- hasMany relationships unable to be cleared [#3513](https://github.com/payloadcms/payload/issues/3513) ([5d9384f](https://github.com/payloadcms/payload/commit/5d9384f53052c96403d8c07ae9d05edf3676c4ef))
### Documentation
- move payload script mention to top of migrations ([26967fb92](https://github.com/payloadcms/payload/commit/26967fb92))
- payload script in package.json ([2f86c196e](https://github.com/payloadcms/payload/commit/2f86c196e))
- updates required node version ([70e068b18](https://github.com/payloadcms/payload/commit/70e068b18))
These new properties are all now required for Payload to function, and you will have to install each separate adapter that you use. Feel free to swap out any of the adapters with your choice (Lexical, Postgres, Vite, etc.)
Make sure to install the packages that you need. In the above example, you would need to install the following:
Adjust the `PAYLOAD_CONFIG_PATH` to point to your Payload config file if necessary.
**2. Create a migration, using the new Payload migration API**
```bash
npm run payload migrate:create --file @payloadcms/db-mongodb/versions-v1-v2
@@ -63,7 +446,7 @@ npm run payload migrate:create --file @payloadcms/db-mongodb/versions-v1-v2
The above command will output a migration file into your `./src/migrations` folder (default migrations location). It contains a migration script to automatically add a `latest: true` flag to each of your newest drafts, for all draft-enabled collections. It works out of the box!
**2. Run migrations**
**3. Run migrations**
From there, you need to run migrations. Run the following command to execute your new migration:
@@ -103,6 +486,12 @@ This means that in some fringe cases, if you are creating a doc and then instant
To avoid any issues, you can pass the `req.transactionID` through to your Local API calls, so that your Local API calls are included as part of the parent transaction.
### ⚠️ Locales now have more functionality, and in some places, you might need to update custom code
Payload's locales have become more powerful and now allow you to customize more aspects per locale such as a human-friendly label and if the locale is RTL or not.
This means that certain functions now return a different shape, such as `useLocale`. This hook used to return a string of the locale code you are currently editing, but it now returns an object with type of `Locale`.
### ⚠️ Admin panel CSS classes may have changed
The revisions we've made in 2.0 required changes to both HTML and CSS within the admin panel. For this reason, if you were loading custom CSS into the admin panel to customize the look and feel, your stylesheets may need to be updated. If your CSS is targeting elements on the page using HTML selectors or class names, you may need to update these selectors based on the current markup. It may also be necessary to update your style definitions if the core Payload component you are targeting has undergone significant change.
@@ -89,3 +89,14 @@ If you are committing to [templates](./templates) or [examples](./examples), use
## Pull Requests
For all Pull Requests, you should be extremely descriptive about both your problem and proposed solution. If there are any affected open or closed issues, please leave the issue number in your PR message.
## Previewing docs
This is how you can preview changes you made locally to the docs:
3. Duplicate the `.env.example` file and rename it to `.env`
4. Add a `DOCS_DIR` environment variable to the `.env` file which points to the absolute path of your modified docs folder. For example `DOCS_DIR=/Users/yourname/Documents/GitHub/payload/docs`
5. Run `yarn run fetchDocs:local`. If this was successful, you should see no error messages and the following output: *Docs successfully written to /.../website/src/app/docs.json*. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it
6. You're done! Now you can start the website locally using `yarn run dev` and preview the docs under [http://localhost:3000/docs/](http://localhost:3000/docs/)
> 🎉 <strong>Payload 2.0 is now available!</strong> Read more in the <a target="_blank" href="https://payloadcms.com/blog/payload-2-0" rel="dofollow"><strong>announcement post</strong></a>.
<h3>Benefits over a regular CMS</h3>
<ul>
<li>Don’t hit some third-party SaaS API, hit your own API</li>
@@ -47,7 +41,7 @@ Create a cloud account, connect your GitHub, and [deploy in minutes](https://pay
Before beginning to work with Payload, make sure you have all of the [required software](https://payloadcms.com/docs/getting-started/installation).
```text
npx create-payload-app
npx create-payload-app@latest
```
Alternatively, it only takes about five minutes to [create an app from scratch](https://payloadcms.com/docs/getting-started/installation#from-scratch).
@@ -95,6 +89,8 @@ We're constantly adding more templates to our [Templates Directory](https://gith
Check out the [Payload website](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.
Migrating from v1 to v2? Check out the [2.0 Release Notes](https://github.com/payloadcms/payload/releases/tag/v2.0.0) on how to do it.
## 🙋 Contributing
If you want to add contributions to this repository, please follow the instructions in [contributing.md](./CONTRIBUTING.md).
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views that can be overridden:
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views dy default, all of which can be overridden:
@@ -84,6 +84,7 @@ To swap out any of these views, simply pass in your custom component to the `adm
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
@@ -95,7 +96,7 @@ To swap out any of these views, simply pass in your custom component to the `adm
}
```
For more granular control, pass a configuration object instead. Payload exposes all of the properties of `<Route />` component in [React Router v5](https://v5.reactrouter.com):
For more granular control, pass a configuration object instead. Each view corresponds to its own `<Route />` component in [React Router v5](https://v5.reactrouter.com). Payload exposes all of the properties of React Router:
@@ -114,6 +115,7 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
@@ -127,11 +129,19 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
}
```
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/master/test/admin/components)._ For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
<Banner type="warning">
<strong>Note:</strong>
<br />
Routes are cascading. This means that unless explicitly given the `exact` property, they will match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all routes in your application. Alternatively, you could define your nested route _before_ your parent route.
</Banner>
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component).
### Collections
You can override components on a collection-by-collection basis via their `admin` property.
You can override components on a collection-by-collection basis via the `admin.components` property.
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default that can be overridden:
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views dy default, all of which can be overridden:
| **`Edit`** | The Edit view is used to edit a single document for a given Collection. |
| **`List`** | The List view is used to show a list of documents for a given Collection. |
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
| **`List`** | The List view is used to show a list of documents for a given collection. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
To swap or add new _tabs_ to the `Edit` view, you can use the `admin.components.views.Edit` property on the collection's config. See the [Custom Tabs](#custom-tabs) section for more information. For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
To swap specific _nested_ views within the parent `Edit` view, you can use the `admin.components.views.Edit` property on the globals's config. This will only replace the nested view, leaving the page breadcrumbs, title, tabs, etc intact.
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: MyCustomDefaultTab,
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Globals
As with Collections, you can override components on a global-by-global basis via their `admin` property.
As with Collections, you can override components on a global-by-global basis via the `admin.components` property.
| **`edit.SaveButton`** | Replace the default `Save` button with a custom component. Drafts must be disabled |
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a custom component. Drafts must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default `Publish` button with a custom component. Drafts must be enabled. |
| **`edit.PreviewButton`** | Replace the default `Preview` button with a custom component. |
| **`elements.SaveButton`** | Replace the default `Save` button with a custom component. Drafts must be disabled |
| **`elements.SaveDraftButton`** | Replace the default `Save Draft` button with a custom component. Drafts must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default `Publish` button with a custom component. Drafts must be enabled. |
| **`elements.PreviewButton`** | Replace the default `Preview` button with a custom component. |
| **`views`** | Override or create new views within the Payload Admin UI. [More](#global-views) |
#### Global views
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default that you can override:
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views dy default, all of which can be overridden:
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
To swap or add new _tabs_ to the `Edit` view, you can use the `admin.components.views.Edit` property on the collection's config. See the [Custom Tabs](#custom-tabs) section for more information. For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
To swap specific _nested_ views within the parent `Edit` view, you can use the `admin.components.views.Edit` property on the globals's config. This will only replace the nested view, leaving the page breadcrumbs, title, and tabs intact.
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: MyCustomDefaultTab,
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Custom Tabs
To can swap collection or global tabs, pass an _object_ to the `admin.components.views.Edit` property on any collection or global config. Payload renders the following views by default which can be overridden:
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views dy default, all of which can be overridden:
To add a _new_ tab to the `Edit` view, simply add another key to the `views.Edit` object with at least a `path` and `Component` property. For example:
To add a _new_ tab to the `Edit` view, simply add another key to `components.views.Edit[key]` with at least a `path` and `Component` property. For example:
// You an swap the entire tab component out for your own
Tab: MyCustomTab
},
AnotherCustomView: {
Component: AnotherCustomView,
path: '/another-custom-view',
// Or you can use the default tab component and just pass in your own label and href
Tab: {
label: 'Another Custom View',
href: '/another-custom-view',
}
},
},
},
@@ -343,12 +405,12 @@ Your custom view components will be given all the props that a React Router `<Ro
#### Example
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/master/test/admin/components/views). There, you'll find two custom views:
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/main/test/admin/components/views). There, you'll find two custom views:
1. A custom view that uses the `DefaultTemplate`, which is the built-in Payload template that displays the sidebar and "eyebrow nav"
1. A custom view that uses the `MinimalTemplate` - which is just a centered template used for things like logging in or out
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/master/test/admin/config.ts).
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/main/test/admin/config.ts).
### Fields
@@ -370,6 +432,15 @@ All Payload fields support the ability to swap in your own React components. So,
| **`Cell`** | Used in the `List` view's table to represent a table-based preview of the data stored in the field. [More](#cell-component) |
| **`Field`** | Swap out the field itself within all `Edit` views. [More](#field-component) |
As an alternative to replacing the entire Field component, you may want to keep the majority of the default Field component and only swap components within. This allows you to replace the **`Label`** or **`Error`** within a field component or add additional components inside the field with **`beforeInput`** or **`afterInput`**. **`beforeInput`** and **`afterInput`** are allowed in any fields that don't contain other fields, except [UI](/docs/fields/ui) and [Rich Text](/docs/fields/rich-text).
| **`showError`** | A boolean value that represents if the error should be shown. |
#### Example
```tsx
import React from 'react'
type Props = {
message: string
showError?: boolean
}
const CustomError: React.FC<Props> = (props) => {
const { message, showError } = props
if (showError) {
return <p style={{color: 'red'}}>{message}</p>
} else return null;
}
```
## afterInput and beforeInput
With these properties you can add multiple components before and after the input element. For example, you can add an absolutely positioned button to clear the current field value.
As your admin customizations gets more complex you may want to share state between fields or other components. You can add custom providers to do add your own context to any Payload app for use in other custom components within the admin panel. Within your config add `admin.components.providers`, these can be used to share context or provide other custom functionality. Read the [React context](https://reactjs.org/docs/context.html) docs to learn more.
TODO: expand on this and make sure it looks nice, talk about how if you use a `process.env.SERVER_URL`, it might not be usable in your Payload config in your admin UI, but it needs to be, so it should be prefixed like `process.env.PAYLOAD_PUBLIC_SERVER_URL` to work in both places
desc: Learn how to exclude server-only code from the Payload Admin UI bundle
---
### Aliasing server-only modules
Because the Admin Panel browser bundle includes your Payload Config file, files using server-only modules need to be excluded.
It's common for your config to rely on server only modules to perform logic in access control functions, hooks, and other contexts.
Any file that imports a server-only module such as `fs`, `stripe`, `authorizenet`, `nodemailer`, etc. **cannot** be included in the browser bundle.
#### Let's Look at an example
#### Example Scenario
Say we have a collection called `Subscriptions` that has a `beforeChange` hook that creates a Stripe subscription whenever a Subscription document is created in Payload.
@@ -93,14 +91,34 @@ This way when your bundler goes to import a file that contains server-only modul
To remove files that contain server-only modules from your bundle, you can use an `alias`.
First create new file that exports an empty object:
```js
// mocks/emptyObject.js
In the Subscriptions config file above, we are importing the hook like so:
export default {}
```ts
// collections/Subscriptions/index.ts
import createStripeSubscription from './hooks/createStripeSubscription'
```
Then, in your Payload config, you can alias the file containing the server-only module to the mock module. For example, here's how you'd do this in Webpack:
By default the browser bundle will now include all the code from that file and any files down the tree. We know that the file imports `stripe`.
To fix this, we need to alias the `createStripeSubscription` file to a different file that can safely be included in the browser bundle.
First, we will create a mock file to replace the server-only file when bundling:
```js
// mocks/modules.js
export default {}
/**
* NOTE: if you are destructuring an import
* the mock file will need to export matching
* variables as the destructured object.
*
* export const namedExport = {}
*/
```
Aliasing with [Webpack](/docs/admin/webpack) can be done by:
```ts
// payload.config.ts
@@ -108,10 +126,16 @@ Then, in your Payload config, you can alias the file containing the server-only
import { buildConfig } from 'payload/config'
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { Subscriptions } from './collections/Subscriptions'
The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following:
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
**Example:**
```tsx
import { useDocumentEvents } from 'payload/components/hooks'
const ListenForUpdates: React.FC = () => {
const { mostRecentUpdate } = useDocumentEvents()
return (
<span>
{JSON.stringify(mostRecentUpdate)}
</span>
)
}
```
<Banner type="info">
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future it will track more document-related events as needed, such as document creation, deletion, etc.
| `bundler` | The bundler that you would like to use to bundle the admin panel. Officially supported bundlers: [Webpack](/docs/admin/webpack) and [Vite](/docs/admin/vite). |
| `user` | The `slug` of a Collection that you want be used to log in to the Admin dashboard. [More](/docs/admin/overview#the-admin-user-collection) |
| `buildPath` | Specify an absolute path for where to store the built Admin panel bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `meta` | Base meta data to use for the Admin panel. Included properties are `titleSuffix`, `ogImage`, and `favicon`. |
@@ -44,9 +45,8 @@ All options for the Admin panel are defined in your base Payload config file.
| `components` | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components) |
| `webpack` | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack) |
| `vite` | Customize the Vite config that's used to generate the Admin panel. [More](/docs/admin/vite) |
| **`bundler`** | The bundler that you would like to use to bundle the admin panel. Officially supported bundlers: [Webpack](/docs/admin/webpack) and [Vite](/docs/admin/vite). |
| **`logoutRoute`** | The route for the `logout` page. |
| **`inactivityRoute`** | The route for the `logout` inactivity page. |
| `logoutRoute` | The route for the `logout` page. |
| `inactivityRoute` | The route for the `logout` inactivity page. |
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
</Banner>
Payload has a Vite bundler that you can install and bundle the Admin Panel with. This is an alternative to the [Webpack](/docs/admin/webpack) bundler and might give some performance boosts to your development workflow.
To use Vite as your bundler, first you need to install the package:
@@ -13,9 +17,19 @@ To use Vite as your bundler, first you need to install the package:
yarn add @payloadcms/bundler-vite
```
<Banner>
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love to hear if you find any bugs or issues!
</Banner>
Then you will need to add the [bundler](/docs/admin/bundlers) to your Payload config:
```ts
import { buildConfig } from '@payloadcms/config'
import viteBundler from '@payloadcms/bundler-vite'
export default buildConfig({
collections: [],
admin: {
bundler: viteBundler(),
}
})
```
Vite works fundamentally differently than Webpack. In development mode, it will first pre-bundle any of your dependencies that are CommonJS-only, and then it'll leverage ESM directly in your browser for a better HMR experience.
@@ -31,8 +45,51 @@ Here are the main differences between how Vite aliases work and how Webpack alia
**Vite aliases do not work with absolute paths.**
In Vite, an alias will only match if the `find` property _exactly matches_ how you are importing your server-only file. So if you are importing a file with a relative path, i.e. `'../../my-module'`, and your alias is absolute, your alias will not work.
In Vite, alias keys must <strong>exactly match</strong> a import paths. If you have 2 files that import the same server-only module, but have different import paths, you would need to add 2 aliases to support both import paths.
```ts
// File A
import serverOnlyModule from '../server-only-module'
// File B
import serverOnlyModule from '../../server-only-module'
// payload.config.ts
// You would need to add 2 aliases to support both import paths
@@ -58,7 +116,7 @@ This will effectively alias the entire plugin and work with Vite. If the plugin
### Extending the Vite config
The Payload config supports a new property for plugins to be able to extend the Vite config specifically. That property exists on the main Payload config under `admin.vite`.
The Payload config supports a new property for plugins to be able to extend the Vite config specifically. That property exists on the main Payload config under `admin.vite`. You can check out the [Vite docs](https://vitejs.dev/config/shared-options.html) for more information on what you can do with the Vite config.
It's a function that takes a Vite config, and returns an updated Vite config. Here's an example:
@@ -66,17 +124,38 @@ It's a function that takes a Vite config, and returns an updated Vite config. He
Learn more about [aliasing server-only modules](https://payloadcms.com/docs/admin/excluding-server-code#aliasing-server-only-modules).
Even though there is a new property for Vite configs specifically, we have implemented some "compatibility" between Webpack and Vite out-of-the-box.
If your config specifies Webpack aliases, we attempt to leverage them automatically within the Vite config. They are merged into the Vite alias configuration seamlessly and may work out-of-the-box.
@@ -82,7 +82,7 @@ Once enabled, each document that is created within the Collection can be thought
### Token-based auth
Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization` header, Payload will automatically identify the user and add its user JWT data to the Express `req`, which is available throughout Payload including within access control, hooks, and more.
Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization: JWT` or `Authorization: Bearer` header, Payload will automatically identify the user and add its user JWT data to the Express `req`, which is available throughout Payload including within access control, hooks, and more.
You can specify what data gets encoded to the JWT token by setting `saveToJWT` to true in your auth collection fields. If you wish to use a different key other than the field `name`, you can provide it to `saveToJWT` as a string. It is also possible to use `saveToJWT` on fields that are nested in inside groups and tabs. If a group has a `saveToJWT` set it will include the object with all sub-fields in the token. You can set `saveToJWT: false` for any fields you wish to omit. If a field inside a group has `saveToJWT` set, but the group does not, the field will be included at the top level of the token.
@@ -29,7 +29,6 @@ It's often best practice to write your Collections in separate files and then im
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`defaultSort`** | Pass a top-level field to sort by default in the collection List view. Prefix the name of the field with a minus symbol ("-") to sort in descending order. |
| **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
You can find an [example Global config](https://github.com/payloadcms/public-demo/blob/master/src/globals/MainMenu.ts) in the Public Demo source code on GitHub.
You can find an [example Global config](https://github.com/payloadcms/public-demo/blob/master/src/payload/globals/MainMenu.ts) in the Public Demo source code on GitHub.
| `admin` \* | Base Payload admin configuration. Specify bundler*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
| `admin` | Base Payload admin configuration. Specify custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). |
| `editor` | Default richText editor which will be used by richText fields. |
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
@@ -46,21 +47,25 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
| `custom` | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
#### Simple example
```ts
import { buildConfig } from 'payload/config'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { postgresAdapter } from '@payloadcms/db-postgres'
import { postgresAdapter } from '@payloadcms/db-postgres' // beta
import { viteBundler } from '@payloadcms/bundler-vite'
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import { lexicalEditor } from '@payloadcms/richtext-lexical' // beta
import { slateEditor } from '@payloadcms/richtext-slate'
export default buildConfig({
bundler: webpackBundler() // or viteBundler(),
admin: {
bundler: webpackBundler(), // or viteBundler()
},
db: mongooseAdapter({}) // or postgresAdapter({}),
editor: lexicalEditor({}) // or slateEditor({})
collections: [
@@ -103,7 +108,7 @@ export default buildConfig({
#### Full example config
You can see a full [example config](https://github.com/payloadcms/public-demo/blob/master/src/payload.config.ts) in the Public Demo source code on GitHub.
You can see a full [example config](https://github.com/payloadcms/public-demo/blob/master/src/payload/payload.config.ts) in the Public Demo source code on GitHub.
desc: Payload features first-party database migrations all done in TypeScript.
---
## Migrations
Payload exposes a full suite of migration controls available for your use. Migration commands are accessible via the `npm run payload` command in your project directory.
Ensure you have an npm script called "payload" in your `package.json` file.
Note that you need to run Payload migrations through the package manager that you are using, because Payload should not be globally installed on your system.
Each DB adapter has an optional property `migrationDir` where you can override where you want your migrations to be stored/read. If this is not specified, Payload will check the default and possibly make a best effort to find your migrations directory by searching in common locations ie. `./src/migrations`, `./dist/igrations`, `./migrations`, etc.
All database adapters should implement similar migration patterns, but there will be small differences based on the adapter and its specific needs. Below is a list of all migration commands that should be supported by your database adapter.
## Commands
### Migrate
The `migrate` command will run any migrations that have not yet been run.
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
| `migrationDir` | Customize the directory that migrations are stored. |
@@ -55,6 +55,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
| **`date.maxDate`** \* | Max date value to allow. |
| **`date.minTime`** \* | Min time value to allow. |
| **`date.maxTime`** \* | Max date value to allow. |
| **`date.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IDiffEditorConstructionOptions.html). |
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/typedoc/variables/editor.EditorOptions.html). |
@@ -70,6 +70,43 @@ Set to `true` if you'd like this field to be sortable within the Admin UI using
Set to `false` if you'd like to disable the ability to create new documents from within the relationship field (hides the "Add new" button in the admin UI).
**`sortOptions`**
The `sortOptions` property allows you to define a default sorting order for the options within a Relationship field's dropdown. This can be particularly useful for ensuring that the most relevant options are presented first to the user.
You can specify `sortOptions` in two ways:
**As a string:**
Provide a string to define a global default sort field for all relationship field dropdowns across different collections. You can prefix the field name with a minus symbol ("-") to sort in descending order.
Example:
```ts
sortOptions: 'fieldName',
```
This configuration will sort all relationship field dropdowns by `"fieldName"` in ascending order.
**As an object :**
Specify an object where keys are collection slugs and values are strings representing the field names to sort by. This allows for different sorting fields for each collection's relationship dropdown.
Example:
```ts
sortOptions: {
"pages": "fieldName1",
"posts": "-fieldName2",
"categories": "fieldName3"
}
```
In this configuration:
- Dropdowns related to `pages` will be sorted by `"fieldName1"` in ascending order.
- Dropdowns for `posts` will use `"fieldName2"` for sorting in descending order (noted by the "-" prefix).
- Dropdowns associated with `categories` will sort based on `"fieldName3"` in ascending order.
Note: If `sortOptions` is not defined, the default sorting behavior of the Relationship field dropdown will be used.
### Filtering relationship options
Options can be dynamically limited by supplying a [query constraint](/docs/queries/overview), which will be used both for validating input and filtering available relationships in the UI.
@@ -267,3 +304,27 @@ Relationship fields with `hasMany` set to more than one kind of collections save
Querying is done in the same way as the earlier Polymorphic example:
#### Querying and Filtering Polymorphic Relationships
Polymorphic and non-polymorphic relationships must be queried differently because of how the related data is stored and may be inconsistent across different collections. Because of this, filtering polymorphic relationship fields from the Collection List admin UI is limited to the `id` value.
For a polymorphic relationship, the response will always be an array of objects. Each object will contain the `relationTo` and `value` properties.
The data can be queried by the related document ID:
- Any [compatible database](/docs/database/overview) (MongoDB or Postgres)
<Banner type="warning">
Before proceeding any further, please ensure that you have the above requirements met.
@@ -23,7 +23,7 @@ Payload requires the following software:
To quickly scaffold a new Payload app in the fastest way possible, you can use [create-payload-app](https://npmjs.com/package/create-payload-app). To do so, run the following command:
```
npx create-payload-app
npx create-payload-app@latest
```
Then just follow the prompts! You'll get set up with a new folder and a functioning Payload app inside.
Here is a list of all properties available to pass through `payload.init`:
##### `secret`
##### secret
**Required**. This is a secure string that will be used to authenticate with Payload. It can be random but should be at least 14 characters and be very difficult to guess.
Payload uses this secret key to generate secure user tokens (JWT). Behind the scenes, we do not use your secret key to encrypt directly - instead, we first take the secret key and create an encrypted string using the SHA-256 hash function. Then, we reduce the encrypted string to its first 32 characters. This final value is what Payload uses for encryption.
##### `config`
##### config
Allows you to pass your config directly to the onInit function. The config passed here should match the payload.config file.
##### `disableOnInit`
##### disableOnInit
A boolean that disables running your `onInit` function when Payload starts up.
##### `disableDBConnect`
##### disableDBConnect
A boolean that disables the database connection when Payload starts up.
##### `email`
##### email
An object used to configure SMTP. [Read more](/docs/email/overview).
##### `express`
##### express
This is your Express app as shown above. Payload will tie into your existing `app` and scope all of its functionalities to sub-routers. By default, Payload will add an `/admin` router and an `/api` router, but you can customize these paths.
##### `local`
##### local
A boolean that when set to `true` tells Payload to start in local-only mode which will bypass setting up API routes. When set to `true`, `express` is not required. This is useful when running scripts that need to use Payload's [local-api](/docs/local-api/overview).
##### `loggerDestination`
##### loggerDestination
Specify destination stream for the built-in Pino logger that Payload uses for internal logging. See [Pino Docs](https://getpino.io/#/docs/api?id=pino-destination) for more info on what is available.
##### `loggerOptions`
##### loggerOptions
Specify options for the built-in Pino logger that Payload uses for internal logging. See [Pino Docs](https://getpino.io/#/docs/api?id=options) for more info on what is available.
##### `onInit`
##### onInit
A function that is called immediately following startup that receives the Payload instance as it's only argument.
When working with GraphQL it is useful to have the schema for development of other projects that need to call on your GraphQL endpoint. In Payload the schema is controlled by your collections and globals and is made available to the developer or third parties, it is not necessary for developers using Payload to write schema types manually.
### Schema generatation script
### Schema generation script
Run the following command in a Payload project to generate your project's GraphQL schema from Payload:
@@ -10,13 +10,14 @@ While using Live Preview, the Admin panel emits a new `window.postMessage` event
Wiring your front-end into Live Preview is easy. If your front-end application is built with React or Next.js, use the [`useLivePreview`](#react) React hook that Payload provides. In the future, all other major frameworks like Vue, Svelte, etc will be officially supported. If you are using any of these frameworks today, you can still integrate with Live Preview yourself using the underlying tooling that Payload provides. See [building your own hook](#building-your-own-hook) for more information.
### Relationships and/or uploads are not populating
If you are using relationships or uploads in your front-end application, and your front-end application runs on a different domain than your Payload server, you may need to configure [CORS](../configuration/overview) to allow requests to be made between the two domains. This includes sites that are running on a different port or subdomain. Similarly, if you are protecting resources behind user authentication, you may also need to configure [CSRF](../authentication/overview#csrf-protection) to allow cookies to be sent between the two domains. For example:
```ts
// payload.config.ts
{
// ...
// If your site is running on a different domain than your Payload server,
// This will allows requests to be made between the two domains
cors: {
[
'http://localhost:3001' // Your front-end application
],
},
// If you are protecting resources behind user authentication,
// This will allow cookies to be sent between the two domains
csrf: {
[
'http://localhost:3001' // Your front-end application
],
},
}
```
### Relationships and/or uploads disappear after editing a document
It is possible that either you are setting an improper [`depth`](../getting-started/concepts#depth) in your initial request and/or your `useLivePreview` hook, or they're mismatched. Ensure that the `depth` parameter is set to the correct value, and that it matches exactly in both places. For example:
```tsx
// Your initial request
const { docs } = await payload.find({
collection: 'pages',
depth: 1, // Ensure this is set to the proper depth for your application
where: {
slug: {
equals: 'home',
}
}
})
```
```tsx
// Your hook
const { data } = useLivePreview<PageType>({
initialData: initialPage,
serverURL: PAYLOAD_SERVER_URL,
depth: 1, // Ensure this matches the depth of your initial request
@@ -8,10 +8,14 @@ keywords: live preview, preview, live, iframe, iframe preview, visual editing, d
**With Live Preview you can render your front-end application directly within the Admin panel. As you type, your changes take effect in real-time. No need to save a draft or publish your changes.**
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin panel communicates with your app through `window.postMessage` events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin panel communicates with your app through [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
{/* IMAGE OF LIVE PREVIEW HERE */}
<Banner type="warning">
Live Preview is currently in beta. You may use this feature in production, but please be aware that it is subject to change and may not be fully stable for all use cases. If you encounter any issues, please [report them](https://github.com/payloadcms/payload/issues/new?assignees=jacobsfletch&labels=possible-bug&projects=&title=Live%20Preview&template=1.bug_report.yml) with as much detail as possible.
</Banner>
## Setup
Setting up Live Preview is easy. You first need to enable it through the `admin.livePreview` property of your Payload config. It takes the following options:
@@ -84,8 +88,8 @@ Here is an example of using a function that returns a dynamic URL:
The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL within Node, directly on your server. Here, you don't need to deal with server latency or network speed whatsoever and can interact directly with your database.
The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL
within Node, directly on your server. Here, you don't need to deal with server latency or network speed whatsoever and
can interact directly with your database.
<Banner type="success">
<strong>Tip:</strong>
@@ -30,7 +32,9 @@ You can gain access to the currently running `payload` object via two ways:
##### Importing it
You can import or require `payload` into your own files after it's been initialized, but you need to make sure that your `import` / `require` statements come **after** you call `payload.init()`—otherwise Payload won't have been initialized yet. That might be obvious. To us, it's usually not.
You can import or require `payload` into your own files after it's been initialized, but you need to make sure that
your `import` / `require` statements come **after** you call `payload.init()`—otherwise Payload won't have been
initialized yet. That might be obvious. To us, it's usually not.
TODO: talk about how plugins need to ensure compatibility with both Vite and Webpack
- It's best practice to alias your plugin to an admin-only version, so if you have admin-only changes, put them in the admin plugin, and then leave the full plugin, complete with server code, to be installed on the server side
<Banner type="success">
COMING SOON: This page is a work in progress. Check back soon for more information.
Building your own plugin is easy, and if you're already familiar with Payload then you'll have everything you need to get started. You can either start from scratch or use the Payload plugin template to get up and running quickly.
<Banner type="success">
To use the template, run `npx create-payload-app@latest -t plugin -n my-new-plugin` directly in your terminal or [clone the template directly from GitHub](https://github.com/payloadcms/payload-plugin-template).
</Banner>
Our plugin template includes everything you need to build a full life-cycle plugin:
* Example files and functions for extending the payload config
* A local dev environment to develop the plugin
* Test suite with integrated GitHub workflow
By abstracting your code into a plugin, you'll be able to reuse your feature across multiple projects and make it available for other developers to use.
### Plugins Recap
Here is a brief recap of how to integrate plugins with Payload, to learn more head back to the [plugin overview page](https://payloadcms.com/docs/plugins/overview).
#### How to install a plugin
To install any plugin, simply add it to your Payload config in the plugins array.
```
import samplePlugin from 'sample-plugin';
const config = buildConfig({
plugins: [
// Add plugins here
samplePlugin({
enabled: true,
}),
],
});
export default config;
```
#### Initialization
The initialization process goes in the following order:
1. Incoming config is validated
2. Plugins execute
3. Default options are integrated
4. Sanitization cleans and validates data
5. Final config gets initialized
### Plugin Template
In the [Payload plugin template](https://github.com/payloadcms/payload-plugin-template), you will see a common file structure that is used across plugins:
1. root folder - general configuration
2. /src folder - everything related to the plugin
3. /dev folder - sanitized test project for development
#### Root
In the root folder, you will see various files related to the configuration of the plugin. We set up our environment in a similar manner in Payload core and across other projects. The only two files you need to modify are:
* **README**.md - This contains instructions on how to use the template. When you are ready, update this to contain instructions on how to use your Plugin.
* **package**.json - Contains necessary scripts and dependencies. Overwrite the metadata in this file to describe your Plugin.
#### Dev
The purpose of the **dev** folder is to provide a sanitized local Payload project. so you can run and test your plugin while you are actively developing it.
Do **not** store any of the plugin functionality in this folder - it is purely an environment to _assist_ you with developing the plugin.
If you're starting from scratch, you can easily setup a dev environment like this:
```
mkdir dev
cd dev
npx create-payload-app@latest
```
If you're using the plugin template, the dev folder is built out for you and the `samplePlugin` has already been installed in `dev/payload.config()`.
```
plugins: [
// when you rename the plugin or add options, make sure to update it here
samplePlugin({
enabled: false,
})
]
```
You can add to the `dev/payload.config` and build out the dev project as needed to test your plugin.
When you're ready to start development, navigate into this folder with `cd dev`
And then start the project with `yarn dev` and pull up `http://localhost:3000` in your browser.
### Testing
Another benefit of the dev folder is that you have the perfect environment established for testing.
A good test suite is essential to ensure quality and stability in your plugin. Payload typically uses [Jest](https://jestjs.io/); a popular testing framework, widely used for testing JavaScript and particularly for applications built with React.
Jest organizes tests into test suites and cases. We recommend creating tests based on the expected behavior of your plugin from start to finish. Read more about tests in the [Jest documentation.](https://jestjs.io/)
The plugin template provides a stubbed out test suite at `dev/plugin.spec.ts` which is ready to go - just add in your own test conditions and you're all set!
```
import payload from 'payload'
describe('Plugin tests', () => {
// Example test to check for seeded data
it('seeds data accordingly', async () => {
const newCollectionQuery = await payload.find({
collection: 'newCollection',
sort: 'createdAt',
})
newCollection = newCollectionQuery.docs
expect(newCollectionQuery.totalDocs).toEqual(1)
})
})
```
### Seeding data
For development and testing, you will likely need some data to work with. You can streamline this process by seeding and dropping your database - instead of manually entering data.
In the plugin template, you can navigate to `dev/src/server.ts` and see an example seed function.
```
if (process.env.PAYLOAD_SEED === 'true') {
await seed(payload)
}
```
A sample seed function has been created for you at `dev/src/seed`, update this file with additional data as needed.
Now that we have our environment setup and dev project ready to go - it's time to build the plugin!
**index.ts**
First up, the `src/index.ts` file - this is where the plugin should be imported from. It is best practice not to build the plugin directly in this file, instead we use this to export the plugin and types from their respective files.
**Plugin.ts**
To reiterate, the essence of a payload plugin is simply to extend the Payload config - and that is exactly what we are doing in this file.
```
export const samplePlugin =
(pluginOptions: PluginTypes) =>
(incomingConfig: Config): Config => {
let config = { ...incomingConfig }
// do something cool with the config here
return config
}
```
1. First, you need to receive the existing Payload config along with any plugin options.
2. Then set the variable `config` to be equal to a copy of the existing config.
3. From here, you can extend the config however you like!
4. Finally, return the config and you're all set.
### Spread Syntax
[Spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) (or the spread operator) is a feature in JavaScript that uses the dot notation **(...)** to spread elements from arrays, strings, or objects into various contexts.
We are going to use spread syntax to allow us to add data to existing arrays without losing the existing data. It is crucial to spread the existing data correctly, else this can cause adverse behavior and conflicts with Payload config and other plugins.
Let's say you want to build a plugin that adds a new collection:
```
config.collections = [
...(config.collections || []),
newCollection,
// Add additional collections here
]
```
First, you need to spread the `config.collections` to ensure that we don't lose the existing collections. Then you can add any additional collections, just as you would in a regular payload config.
This same logic is applied to other properties like admin, globals, hooks:
```
config.globals = [
...(config.globals || []),
// Add additional globals here
]
config.hooks = {
...(config.hooks || {}),
// Add additional hooks here
}
```
Some properties will be slightly different to extend, for instance the `onInit` property:
```
config.onInit = async payload => {
if (incomingConfig.onInit) await incomingConfig.onInit(payload)
// Add additional onInit code by using the onInitExtension function
onInitExtension(pluginOptions, payload)
}
```
If you wish to add to the `onInit`, you must include the async/await. We don't use spread syntax in this case, instead you must await the existing `onInit` before running additional functionality.
In the template, we have stubbed out a basic `onInitExtension` file that you can use, if not needed feel free to delete it.
### Webpack
If any of your files use server only packages such as fs, stripe, nodemailer, etc, they will need to be removed from the browser bundle. To do that, you can [alias the file imports with webpack](https://payloadcms.com/docs/admin/webpack#aliasing-server-only-modules).
When files are bundled for the browser, the import paths are essentially crawled to determine what files to include in the bundle. To prevent the server only files from making it into the bundle, we can alias their import paths to a file that can be included in the browser. This will short-circuit the import path crawling and ensure browser only code is bundled.
Webpack is another part of the Payload config that can be a little more tricky to extend. To help here, the template includes a helper function `extendWebpackConfig()` which takes care of spreading the existing webpack, so you can just add your new stuff:
```
config.admin = {
...(config.admin || {}),
// Add your aliases to the helper function below
webpack: extendWebpackConfig(incomingConfig)
}
```
### Types
If your plugin has options, you should define and provide types for these options in a separate file which gets exported from the main `index.ts`.
```
export interface PluginTypes {
/**
* Enable or disable plugin
* @default false
*/
enabled?: boolean
}
```
If possible, include [JSDoc comments](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#types-1) to describe the options and their types. This allows a developer to see details about the options in their editor.
### Best practices
In addition to the setup covered above, here are other best practices to follow:
##### Providing an enable / disable option:
For a better user experience, provide a way to disable the plugin without uninstalling it. This is especially important if your plugin adds additional webpack aliases, this will allow you to still let the webpack run to prevent errors.
##### Include tests in your GitHub CI workflow:
If you've configured tests for your package, integrate them into your workflow to run the tests each time you commit to the plugin repository. Learn more about [how to configure tests into your GitHub CI workflow.](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs)
##### Publish your finished plugin to NPM:
The best way to share and allow others to use your plugin once it is complete is to publish an NPM package. This process is straightforward and well documented, find out more about [creating and publishing a NPM package here](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/).
##### Add payload-plugin topic tag:
Apply the tag **payload-plugin** to your GitHub repository. This will boost the visibility of your plugin and ensure it gets listed with [existing payload plugins](https://github.com/topics/payload-plugin).
##### Use [Semantic Versioning](https://semver.org/) (SemVar):
With the SemVar system you release version numbers that reflect the nature of changes (major, minor, patch). Ensure all major versions reference their Payload compatibility.
@@ -158,9 +158,20 @@ DigitalOcean provides extremely helpful documentation that can walk you through
1. [Create a new MongoDB and user](https://medium.com/@mhagemann/how-to-add-a-new-user-to-a-mongodb-database-d896776b5362)
1. [Set up Node for production](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04)
### Swap Space
Swap refers to a section of storage on the hard drive that is reserved to temporarily store data that can no longer fit within RAM. This allows for the expansion of your server's working memory, with some limitations. Swap space comes into play when available RAM can no longer accommodate actively used application data, enabling the system to continue functioning.
Insufficient space can lead to deployment errors and memory-related issues, resulting in application crashes, sluggish performance, or an unresponsive server.
Common deployment error due to **space limitations** (as reported by users):
- `Error: Command failed with exit code 1`
To configure swap, we recommend following this tutorial on [How To Add Swap Space](https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-22-04).
## Docker
This is an example of a multi-stage docker build of Payload for production. Ensure you are setting your environment variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `MONGODB_URI` if needed.
This is an example of a multi-stage docker build of Payload for production. Ensure you are setting your environment variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `DATABASE_URI` if needed.
| `limit` | Limits the number of documents returned |
| `page` | Get a specific page number |
### Disabling pagination within Local API
For `find` operations within the Local API, you can disable pagination to retrieve all documents from a collection by passing `pagination: false` to the `find` local operation. This is not supported in REST or GraphQL, however, because it could potentially lead to malicious activity.
You can also override Lexical settings on a field-by-field basis as follows:
```ts
import { CollectionConfig } from 'payload/types'
import type { CollectionConfig } from 'payload/types'
import {
lexicalEditor
} from '@payloadcms/richtext-lexical'
export const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'content',
type: 'richText',
// Pass the Lexical editor here and override base settings as necessary
editor: lexicalEditor({})
}
]
}
```
## Extending the lexical editor with Features
Lexical has been designed with extensibility in mind. Whether you're aiming to introduce new functionalities or tweak the existing ones, Lexical makes it seamless for you to bring those changes to life.
### Features: The Building Blocks
At the heart of Lexical's customization potential are "features". While Lexical ships with a set of default features we believe are essential for most use cases, the true power lies in your ability to redefine, expand, or prune these as needed.
If you remove all the default features, you're left with a blank editor. You can then add in only the features you need, or you can build your own custom features from scratch.
### Integrating New Features
To weave in your custom features, utilize the `features` prop when initializing the Lexical Editor. Here's a basic example of how this is done:
```ts
import {
BlocksFeature,
LinkFeature,
@@ -55,13 +87,7 @@ import {
import { Banner } from '../blocks/Banner'
import { CallToAction } from '../blocks/CallToAction'
export const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'content',
type: 'richText',
// Pass the Lexical editor here and override base settings as necessary
| **`BoldTextFeature`** | Yes | Handles the bold text format |
| **`ItalicTextFeature`** | Yes | Handles the italic text format |
| **`UnderlineTextFeature`** | Yes | Handles the underline text format |
| **`StrikethroughTextFeature`** | Yes | Handles the strikethrough text format |
| **`SubscriptTextFeature`** | Yes | Handles the subscript text format |
| **`SuperscriptTextFeature`** | Yes | Handles the superscript text format |
| **`InlineCodeTextFeature`** | Yes | Handles the inline-code text format |
| **`ParagraphFeature`** | Yes | Handles paragraphs. Since they are already a key feature of lexical itself, this Feature mainly handles the Slash and Add-Block menu entries for paragraphs |
| **`HeadingFeature`** | Yes | Adds Heading Nodes (by default, H1 - H6, but that can be customized) |
| **`AlignFeature`** | Yes | Allows you to align text left, centered and right |
| **`IndentFeature`** | Yes | Allows you to indent text with the tab key |
| **`LinkFeature`** | Yes | Allows you to create internal and external links |
| **`RelationshipFeature`** | Yes | Allows you to create block-level (not inline) relationships to other documents |
| **`BlockQuoteFeature`** | Yes | Allows you to create block-level quotes |
| **`UploadFeature`** | Yes | Allows you to create block-level upload nodes - this supports all kinds of uploads, not just images |
| **`BlocksFeature`** | No | Allows you to use Payload's [Blocks Field](/docs/fields/blocks) directly inside your editor. In the feature props, you can specify the allowed blocks - just like in the Blocks field. |
| **`TreeViewFeature`** | No | Adds a debug box under the editor, which allows you to see the current editor state live, the dom, as well as time travel. Very useful for debugging |
## Creating your own, custom Feature
Creating your own custom feature requires deep knowledge of the Lexical editor. We recommend you take a look at the [Lexical documentation](https://lexical.dev/docs/intro) first - especially the "concepts" section.
Next, take a look at the [features we've already built](https://github.com/payloadcms/payload/tree/main/packages/richtext-lexical/src/field/features) - understanding how they work will help you understand how to create your own. There is no difference between the features included by default and the ones you create yourself - since those features are all isolated from the "core", you have access to the same APIs, whether the feature is part of payload or not!
## Converters
### Lexical => HTML
Lexical saves data in JSON, but can also generate its HTML representation via two main methods:
1. **Outputting HTML from the Collection:** Create a new field in your collection to convert saved JSON content to HTML. Payload generates and outputs the HTML for use in your frontend.
2. **Generating HTML on the Frontend:** Convert JSON to HTML on-demand, either in your frontend or elsewhere.
The editor comes with built-in HTML serializers, simplifying the process of converting JSON to HTML.
#### Outputting HTML from the Collection
To add HTML generation directly within the collection, follow the example below:
```ts
import type { CollectionConfig } from 'payload/types'
import {
HTMLConverterFeature,
lexicalEditor,
lexicalHTML
} from '@payloadcms/richtext-lexical'
const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'nameOfYourRichTextField',
type: 'richText',
editor: lexicalEditor({
features: ({ defaultFeatures }) => [
...defaultFeatures,
// The HTMLConverter Feature is the feature which manages the HTML serializers. If you do not pass any arguments to it, it will use the default serializers.
The `lexicalHTML()` function creates a new field that automatically converts the referenced lexical richText field into HTML through an afterRead hook.
#### Generating HTML in the Frontend:
If you wish to convert JSON to HTML ad-hoc, use this code snippet:
```ts
import type { SerializedEditorState } from 'lexical'
import {
type SanitizedEditorConfig,
convertLexicalToHTML,
consolidateHTMLConverters,
} from '@payloadcms/richtext-lexical'
async function lexicalToHTML(editorData: SerializedEditorState, editorConfig: SanitizedEditorConfig) {
This method employs `convertLexicalToHTML` from `@payloadcms/richtext-lexical`, which converts the serialized editor state into HTML.
Because every `Feature` is able to provide html converters, and because the `htmlFeature` can modify those or provide their own, we need to consolidate them with the default html Converters using the `consolidateHTMLConverters` function.
#### Creating your own HTML Converter
HTML Converters are typed as `HTMLConverter`, which contains the node type it should handle, and a function that accepts the serialized node from the lexical editor, and outputs the HTML string. Here's the HTML Converter of the Upload node as an example:
```ts
import type { HTMLConverter } from '@payloadcms/richtext-lexical'
nodeTypes: [UploadNode.getType()], // This is the type of the lexical node that this converter can handle. Instead of hardcoding 'upload' we can get the node type directly from the UploadNode, since it's static.
}
```
As you can see, we have access to all the information saved in the node (for the Upload node, this is `value`and `relationTo`) and we can use that to generate the HTML.
The `convertLexicalToHTML` is part of `@payloadcms/richtext-lexical` automatically handles traversing the editor state and calling the correct converter for each node.
#### Embedding the HTML Converter in your Feature
You can embed your HTML Converter directly within your custom `Feature`, allowing it to be handled automatically by the `consolidateHTMLConverters` function. Here is an example:
As you can see, you need to provide an editor config in order to create a headless editor. This is because the editor config is used to determine which nodes & features are enabled, and which converters are used.
To get the editor config, simply import the default editor config and adjust it - just like you did inside of the `editor: lexicalEditor({})` property:
```ts
import { defaultEditorConfig, defaultEditorFeatures } from '@payloadcms/richtext-lexical' // <= make sure this package is installed
const yourEditorConfig = defaultEditorConfig
// If you made changes to the features of the field's editor config, you should also make those changes here:
yourEditorConfig.features = [
...defaultEditorFeatures,
// Add your custom features here
]
```
### HTML => Lexical
Once you have your headless editor instance, you can use it to convert HTML to Lexical:
```ts
import { $generateNodesFromDOM } from '@lexical/html'
import { $getRoot,$getSelection } from 'lexical'
import { JSDOM } from 'jsdom';
headlessEditor.update(() => {
// In a headless environment you can use a package such as JSDom to parse the HTML string.
const dom = new JSDOM(htmlString)
// Once you have the DOM instance it's easy to generate LexicalNodes.
Functions prefixed with a `$` can only be run inside of an `editor.update()` or `editorState.read()` callback.
This has been taken from the [lexical serialization & deserialization docs](https://lexical.dev/docs/concepts/serialization#html---lexical).
<Banner type="success">
<strong>Note:</strong>
<br />
Using the <code>discrete: true</code> flag ensures instant updates to the editor state. If immediate reading of the updated state isn't necessary, you can omit the flag.
</Banner>
### Markdown => Lexical
Convert markdown content to the Lexical editor format with the following:
```ts
import { $convertFromMarkdownString } from '@lexical/markdown'
import { sanitizeEditorConfig } from '@payloadcms/richtext-lexical'
const yourSanitizedEditorConfig = sanitizeEditorConfig(yourEditorConfig) // <= your editor config here
The `.setEditorState()` function immediately updates your editor state. Thus, there's no need for the `discrete: true` flag when reading the state afterward.
### Lexical => Plain Text
Export content from the Lexical editor into plain text using these steps:
1. Import your current editor state into the headless editor.
2. Convert and fetch the resulting plain text string.
Here's the code for it:
```ts
import type { SerializedEditorState } from "lexical"
import { $getRoot } from "lexical"
const yourEditorState: SerializedEditorState // <= your current editor state here
// Import editor state into your headless editor
try {
headlessEditor.setEditorState(headlessEditor.parseEditorState(yourEditorState)) // This should commit the editor state immediately
} catch (e) {
logger.error({ err: e }, 'ERROR parsing editor state')
While both Slate and Lexical save the editor state in JSON, the structure of the JSON is different.
### Migration via SlateToLexicalFeature
One way to handle this is to just give your lexical editor the ability to read the slate JSON.
Simply add the `SlateToLexicalFeature` to your editor:
```ts
import type { CollectionConfig } from 'payload/types'
import {
SlateToLexicalFeature,
lexicalEditor,
} from '@payloadcms/richtext-lexical'
const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'nameOfYourRichTextField',
type: 'richText',
editor: lexicalEditor({
features: ({ defaultFeatures }) => [
...defaultFeatures,
SlateToLexicalFeature({})
],
}),
},
],
}
```
and done! Now, everytime this lexical editor is initialized, it converts the slate date to lexical on-the-fly. If the data is already in lexical format, it will just pass it through.
This is by far the easiest way to migrate from Slate to Lexical, although it does come with a few caveats:
- There is a performance hit when initializing the lexical editor
- The editor will still output the Slate data in the output JSON, as the on-the-fly converter only runs for the admin panel
The easy way to solve this: Just save the document! This overrides the slate data with the lexical data, and the next time the document is loaded, the lexical data will be used. This solves both the performance and the output issue for that specific document.
### Migration via migration script
The method described above does not solve the issue for all documents, though. If you want to convert all your documents to lexical, you can use a migration script. Here's a simple example:
```ts
import type { Payload } from 'payload'
import type { YourDocumentType } from 'payload/generated-types'
import {
cloneDeep,
convertSlateToLexical,
defaultSlateConverters,
} from '@payloadcms/richtext-lexical'
import { AnotherCustomConverter } from './lexicalFeatures/converters/AnotherCustomConverter'
export async function convertAll(payload: Payload, collectionName: string, fieldName: string) {
const docs: YourDocumentType[] = await payload.db.collections[collectionName].find({}).exec() // Use MongoDB models directly to query all documents at once
if (richText && Array.isArray(richText) && !('root' in richText)) { // It's Slate data - skip already-converted data
const converted = convertSlateToLexical({
converters: converters,
slateData: richText,
})
await payload.update({
id: doc.id,
collection: collectionName as any,
data: {
[fieldName]: converted,
},
})
}
})
// Wait for all promises in the batch to complete. Resolving batches of 20 asynchronously is faster than waiting for each doc to update individually
await Promise.all(promises)
// Update the count of processed docs
processed += batch.length
console.log(`Converted ${processed} of ${docs.length}`)
}
}
```
The `convertSlateToLexical` is the same method used in the `SlateToLexicalFeature` - it handles traversing the Slate JSON for you.
Do note that this script might require adjustment depending on your document structure, especially if you have nested richText fields or localization enabled.
### Converting custom Slate nodes
If you have custom Slate nodes, create a custom converter for them. Here's the Upload converter as an example:
```ts
import type { SerializedUploadNode } from '../uploadNode.'
import type { SlateNodeConverter } from '@payloadcms/richtext-lexical'
It's pretty simple: You get a Slate node as input, and you return the lexical node. The `nodeTypes` array is used to determine which Slate nodes this converter can handle.
When using a migration script, you can add your custom converters to the `converters` property of the `convertSlateToLexical` props, as seen in the example above
When using the `SlateToLexicalFeature`, you can add your custom converters to the `converters` property of the `SlateToLexicalFeature` props:
```ts
import type { CollectionConfig } from 'payload/types'
import {
SlateToLexicalFeature,
lexicalEditor,
defaultSlateConverters
} from '@payloadcms/richtext-lexical'
import { YourCustomConverter } from '../converters/YourCustomConverter'
const Pages: CollectionConfig = {
slug: 'pages',
fields: [
{
name: 'nameOfYourRichTextField',
type: 'richText',
editor: lexicalEditor({
features: ({ defaultFeatures }) => [
...defaultFeatures,
SlateToLexicalFeature({
converters: [
...defaultSlateConverters,
YourCustomConverter
]
}),
],
}),
},
],
}
```
## Migrating from payload-plugin-lexical
Migrating from [payload-plugin-lexical](https://github.com/AlessioGr/payload-plugin-lexical) works similar to migrating from Slate.
Instead of a `SlateToLexicalFeature` there is a `LexicalPluginToLexicalFeature` you can use. And instead of `convertSlateToLexical` you can use `convertLexicalPluginToLexical`.
## Coming Soon
Lots more documentation will be coming soon, which will show in detail how to create your own custom features within Lexical.
For now, take a look at the TypeScript interfaces and let us know if you need a hand. Much more will be coming from the Payload team on this topic soon.
You can run this command whenever you need to regenerate your types, and then you can use these types in your Payload code directly.
### Disable declare statement
By default, `generate:types` will add a `declare` statement to your types file, which automatically enables type inference within Payload.
If you are using your `payload-types.ts` file in other repos, though, it might be better to disable this `declare` statement, so that you don't get any TS errors in projects that use your Payload types, but do not have Payload installed.
```ts
// payload.config.ts
{
// ...
typescript: {
declare: false, // defaults to true if not set
},
}
```
If you do disable the `declare` pattern, you'll need to manually add a `declare` statement to your code in order for Payload types to be recognized. Here's an example showing how to declare your types in your `payload.config.ts` file:
```ts
import { Config } from './payload-types'
declare module 'payload' {
export interface GeneratedTypes extends Config {}
}
```
### Custom output file path
You can specify where you want your types to be generated by adding a property to your Payload config:
Payload supports TypeScript natively, and not only that, the entirety of the CMS is built with TypeScript. To get started developing with Payload and TypeScript, you can use one of Payload's built-in boilerplates in one line via `create-payload-app`:
```
npx create-payload-app
npx create-payload-app@latest
```
Pick a TypeScript project type to get started easily.
@@ -52,8 +52,9 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
| **`handlers`** | Array of Express request handlers to execute before the built-in Payload static middleware executes. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
| **`staticOptions`** | Set options for `express.static` to use while serving your static files. [More](http://expressjs.com/en/resources/middleware/serve-static.html) format) |
| **`staticOptions`** | Set options for `express.static` to use while serving your static files. [More](http://expressjs.com/en/resources/middleware/serve-static.html) |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
_An asterisk denotes that a property above is required._
@@ -147,6 +148,23 @@ All auto-resized images are exposed to be re-used in hooks and similar via an ob
The object will have keys for each size generated, and each key will be set equal to a buffer containing the file data.
##### Handling Image Enlargement
When an uploaded image is smaller than the defined image size, we have 3 options:
`withoutEnlargement: undefined | false | true`
1.`undefined` [default]: uploading images with smaller width AND height than the image size will return null
2. `false`: always enlarge images to the image size
3. `true`: if the image is smaller than the image size, return the original image
<Banner type="error">
<strong>Note:</strong>
<br />
By default, the image size will return NULL when the uploaded image is smaller than the defined image size.
Use the `withoutEnlargement` prop to change this.
</Banner>
### Crop and Focal Point Selector
This feature is only available for image file types.
| `interval` | Define an `interval` in milliseconds to automatically save progress while documents are edited. Document updates are "debounced" at this interval. Defaults to `2000`. |
| `interval` | Define an `interval` in milliseconds to automatically save progress while documents are edited. Document updates are "debounced" at this interval. Defaults to `800`. |
**Example config with versions, drafts, and autosave enabled:**
@@ -66,7 +66,7 @@ When `autosave` is enabled, all `update` operations within Payload expose a new
#### How autosaves are stored
If we created a new version for each autosave, you'd quickly find a ton of autosaves that clutter up your `_versions` collection within the database. That would be messy quick because `autosave` is typically set to save a document every ~2000ms or so.
If we created a new version for each autosave, you'd quickly find a ton of autosaves that clutter up your `_versions` collection within the database. That would be messy quick because `autosave` is typically set to save a document at ~800ms intervals.
<Banner type="success">
Instead of creating a new version each time a document is autosaved, Payload smartly only creates{' '}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.