Compare commits
13 Commits
postgres-d
...
fix/config
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4eb75d9db | ||
|
|
e5eed336ff | ||
|
|
73a8a1836d | ||
|
|
a9d0b31f3f | ||
|
|
c82d130fd7 | ||
|
|
7a815f7e51 | ||
|
|
f212870f82 | ||
|
|
1d07fba5cb | ||
|
|
a5c995445b | ||
|
|
9bac0398d7 | ||
|
|
7af16bd1a7 | ||
|
|
00f27bba16 | ||
|
|
ceda0ad028 |
34
.github/CODEOWNERS
vendored
34
.github/CODEOWNERS
vendored
@@ -1,34 +0,0 @@
|
||||
# Order matters. The last matching pattern takes precedence
|
||||
|
||||
## Package Exports
|
||||
|
||||
**/exports/ @denolfe @DanRibbens
|
||||
|
||||
## Packages
|
||||
|
||||
/packages/create-payload-app/src/ @denolfe
|
||||
/packages/email-*/src/ @denolfe
|
||||
/packages/eslint-*/ @denolfe @AlessioGr
|
||||
/packages/plugin-cloud-storage/src/ @denolfe
|
||||
/packages/plugin-multi-tenant/src/ @JarrodMFlesch
|
||||
/packages/richtext-*/src/ @AlessioGr
|
||||
/packages/storage-*/src/ @denolfe
|
||||
/packages/ui/src/ @jacobsfletch @AlessioGr @JarrodMFlesch
|
||||
|
||||
## Templates
|
||||
|
||||
/templates/_data/ @denolfe
|
||||
/templates/_template/ @denolfe
|
||||
|
||||
## Build Files
|
||||
|
||||
**/jest.config.js @denolfe @AlessioGr
|
||||
**/tsconfig*.json @denolfe @AlessioGr
|
||||
|
||||
## Root
|
||||
|
||||
/.github/ @denolfe
|
||||
/.husky/ @denolfe
|
||||
/.vscode/ @denolfe @AlessioGr
|
||||
/package.json @denolfe
|
||||
/tools/ @denolfe
|
||||
6
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
6
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
@@ -43,7 +43,6 @@ body:
|
||||
- 'plugin: cloud'
|
||||
- 'plugin: cloud-storage'
|
||||
- 'plugin: form-builder'
|
||||
- 'plugin: multi-tenant'
|
||||
- 'plugin: nested-docs'
|
||||
- 'plugin: richtext-lexical'
|
||||
- 'plugin: richtext-slate'
|
||||
@@ -60,7 +59,10 @@ body:
|
||||
label: Environment Info
|
||||
description: Paste output from `pnpm payload info` _or_ Payload, Node.js, and Next.js versions. Please avoid using "latest"—specific version numbers help us accurately diagnose and resolve issues.
|
||||
render: text
|
||||
placeholder: Run `pnpm payload info` in your terminal and paste the output here.
|
||||
placeholder: |
|
||||
Payload:
|
||||
Node.js:
|
||||
Next.js:
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
||||
63
.github/actions/setup/action.yml
vendored
63
.github/actions/setup/action.yml
vendored
@@ -4,17 +4,24 @@ description: |
|
||||
|
||||
inputs:
|
||||
node-version:
|
||||
description: Node.js version override
|
||||
description: Node.js version
|
||||
required: true
|
||||
default: 22.6.0
|
||||
pnpm-version:
|
||||
description: Pnpm version override
|
||||
description: Pnpm version
|
||||
required: true
|
||||
default: 9.7.1
|
||||
pnpm-run-install:
|
||||
description: Whether to run pnpm install
|
||||
required: false
|
||||
default: true
|
||||
pnpm-restore-cache:
|
||||
description: Whether to restore cache
|
||||
required: false
|
||||
default: true
|
||||
pnpm-install-cache-key:
|
||||
description: The cache key override for the pnpm install cache
|
||||
description: The cache key for the pnpm install cache
|
||||
default: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
outputs:
|
||||
pnpm-store-path:
|
||||
@@ -30,44 +37,15 @@ runs:
|
||||
shell: bash
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Get versions from .tool-versions or use overrides
|
||||
shell: bash
|
||||
run: |
|
||||
# if node-version input is provided, use it; otherwise, read from .tool-versions
|
||||
if [ "${{ inputs.node-version }}" ]; then
|
||||
echo "Node version override provided: ${{ inputs.node-version }}"
|
||||
echo "NODE_VERSION=${{ inputs.node-version }}" >> $GITHUB_ENV
|
||||
elif [ -f .tool-versions ]; then
|
||||
NODE_VERSION=$(grep '^nodejs ' .tool-versions | awk '{print $2}')
|
||||
echo "NODE_VERSION=$NODE_VERSION" >> $GITHUB_ENV
|
||||
echo "Node version resolved to: $NODE_VERSION"
|
||||
else
|
||||
echo "No .tool-versions file found and no node-version input provided. Invalid configuration."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# if pnpm-version input is provided, use it; otherwise, read from .tool-versions
|
||||
if [ "${{ inputs.pnpm-version }}" ]; then
|
||||
echo "Pnpm version override provided: ${{ inputs.pnpm-version }}"
|
||||
echo "PNPM_VERSION=${{ inputs.pnpm-version }}" >> $GITHUB_ENV
|
||||
elif [ -f .tool-versions ]; then
|
||||
PNPM_VERSION=$(grep '^pnpm ' .tool-versions | awk '{print $2}')
|
||||
echo "PNPM_VERSION=$PNPM_VERSION" >> $GITHUB_ENV
|
||||
echo "Pnpm version resolved to: $PNPM_VERSION"
|
||||
else
|
||||
echo "No .tool-versions file found and no pnpm-version input provided. Invalid configuration."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node@${{ inputs.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: ${{ env.PNPM_VERSION }}
|
||||
version: ${{ inputs.pnpm-version }}
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store path
|
||||
@@ -77,25 +55,14 @@ runs:
|
||||
echo "STORE_PATH=$STORE_PATH" >> $GITHUB_ENV
|
||||
echo "Pnpm store path resolved to: $STORE_PATH"
|
||||
|
||||
- name: Compute Cache Key
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "${{ inputs.pnpm-install-cache-key }}" ]; then
|
||||
PNPM_INSTALL_CACHE_KEY="${{ inputs.pnpm-install-cache-key }}"
|
||||
else
|
||||
PNPM_INSTALL_CACHE_KEY="pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}"
|
||||
fi
|
||||
echo "Computed PNPM_INSTALL_CACHE_KEY: $PNPM_INSTALL_CACHE_KEY"
|
||||
echo "PNPM_INSTALL_CACHE_KEY=$PNPM_INSTALL_CACHE_KEY" >> $GITHUB_ENV
|
||||
|
||||
- name: Restore pnpm install cache
|
||||
if: ${{ inputs.pnpm-restore-cache == 'true' }}
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ env.PNPM_INSTALL_CACHE_KEY }}
|
||||
key: ${{ inputs.pnpm-install-cache-key }}
|
||||
restore-keys: |
|
||||
pnpm-store-${{ env.PNPM_VERSION }}-
|
||||
pnpm-store-${{ inputs.pnpm-version }}-
|
||||
pnpm-store-
|
||||
|
||||
- name: Run pnpm install
|
||||
@@ -105,5 +72,5 @@ runs:
|
||||
|
||||
# Set the cache key output
|
||||
- run: |
|
||||
echo "pnpm-install-cache-key=${{ env.PNPM_INSTALL_CACHE_KEY }}" >> $GITHUB_OUTPUT
|
||||
echo "pnpm-install-cache-key=${{ inputs.pnpm-install-cache-key }}" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
4
.github/reproduction-guide.md
vendored
4
.github/reproduction-guide.md
vendored
@@ -40,7 +40,7 @@ There are a couple ways run integration tests:
|
||||
|
||||
- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/.github/assets/int-debug.png" />
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/assets/images/github/int-debug.png" />
|
||||
|
||||
- **Manually** - you can run all int tests in the `/test/_community/int.spec.ts` file by running the following command:
|
||||
|
||||
@@ -57,7 +57,7 @@ The easiest way to run E2E tests is to install
|
||||
|
||||
Once they are installed you can open the `testing` tab in vscode sidebar and drill down to the test you want to run, i.e. `/test/_community/e2e.spec.ts`
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/.github/assets/e2e-debug.png" />
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/assets/images/github/e2e-debug.png" />
|
||||
|
||||
#### Notes
|
||||
|
||||
|
||||
30
.github/workflows/audit-dependencies.sh
vendored
30
.github/workflows/audit-dependencies.sh
vendored
@@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
severity=${1:-"critical"}
|
||||
audit_json=$(pnpm audit --prod --json)
|
||||
output_file="audit_output.json"
|
||||
|
||||
echo "Auditing for ${severity} vulnerabilities..."
|
||||
|
||||
echo "${audit_json}" | jq --arg severity "${severity}" '
|
||||
.advisories | to_entries |
|
||||
map(select(.value.patched_versions != "<0.0.0" and .value.severity == $severity) |
|
||||
{
|
||||
package: .value.module_name,
|
||||
vulnerable: .value.vulnerable_versions,
|
||||
fixed_in: .value.patched_versions
|
||||
}
|
||||
)
|
||||
' >$output_file
|
||||
|
||||
audit_length=$(jq 'length' $output_file)
|
||||
|
||||
if [[ "${audit_length}" -gt "0" ]]; then
|
||||
echo "Actionable vulnerabilities found in the following packages:"
|
||||
jq -r '.[] | "\u001b[1m\(.package)\u001b[0m vulnerable in \u001b[31m\(.vulnerable)\u001b[0m fixed in \u001b[32m\(.fixed_in)\u001b[0m"' $output_file | while read -r line; do echo -e "$line"; done
|
||||
echo "Output written to ${output_file}"
|
||||
exit 1
|
||||
else
|
||||
echo "No actionable vulnerabilities"
|
||||
exit 0
|
||||
fi
|
||||
53
.github/workflows/audit-dependencies.yml
vendored
53
.github/workflows/audit-dependencies.yml
vendored
@@ -1,53 +0,0 @@
|
||||
name: audit-dependencies
|
||||
|
||||
on:
|
||||
# Sundays at 2am EST
|
||||
schedule:
|
||||
- cron: '0 7 * * 0'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
audit-level:
|
||||
description: The level of audit to run (low, moderate, high, critical)
|
||||
required: false
|
||||
default: critical
|
||||
debug:
|
||||
description: Enable debug logging
|
||||
required: false
|
||||
default: false
|
||||
|
||||
env:
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Run audit dependencies script
|
||||
id: audit_dependencies
|
||||
run: ./.github/workflows/audit-dependencies.sh ${{ inputs.audit-level }}
|
||||
|
||||
- name: Slack notification on failure
|
||||
if: failure()
|
||||
uses: slackapi/slack-github-action@v2.1.0
|
||||
with:
|
||||
webhook: ${{ inputs.debug == 'true' && secrets.SLACK_TEST_WEBHOOK_URL || secrets.SLACK_WEBHOOK_URL }}
|
||||
webhook-type: incoming-webhook
|
||||
payload: |
|
||||
{
|
||||
"username": "GitHub Actions Bot",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "🚨 Actionable vulnerabilities found: <https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Details>"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
274
.github/workflows/main.yml
vendored
274
.github/workflows/main.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: ci
|
||||
name: build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -6,7 +6,6 @@ on:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
- labeled
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
@@ -17,6 +16,8 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
NODE_VERSION: 22.6.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
@@ -61,6 +62,12 @@ jobs:
|
||||
echo "templates: ${{ steps.filter.outputs.templates }}"
|
||||
|
||||
lint:
|
||||
# Follows same github's ci skip: [skip lint], [lint skip], [no lint]
|
||||
if: >
|
||||
github.event_name == 'pull_request' &&
|
||||
!contains(github.event.pull_request.title, '[skip lint]') &&
|
||||
!contains(github.event.pull_request.title, '[lint skip]') &&
|
||||
!contains(github.event.pull_request.title, '[no lint]')
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -69,9 +76,15 @@ jobs:
|
||||
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint -- --quiet
|
||||
- name: Lint staged
|
||||
run: |
|
||||
git diff --name-only --diff-filter=d origin/${GITHUB_BASE_REF}...${GITHUB_SHA}
|
||||
npx lint-staged --diff="origin/${GITHUB_BASE_REF}...${GITHUB_SHA}"
|
||||
|
||||
build:
|
||||
needs: changes
|
||||
@@ -83,6 +96,10 @@ jobs:
|
||||
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- run: pnpm run build:all
|
||||
env:
|
||||
@@ -104,8 +121,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -128,8 +148,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -147,7 +170,6 @@ jobs:
|
||||
needs: [changes, build]
|
||||
if: ${{ needs.changes.outputs.needs_tests == 'true' }}
|
||||
name: int-${{ matrix.database }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -159,7 +181,6 @@ jobs:
|
||||
- supabase
|
||||
- sqlite
|
||||
- sqlite-uuid
|
||||
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@@ -171,8 +192,7 @@ jobs:
|
||||
|
||||
services:
|
||||
postgres:
|
||||
# Custom postgres 17 docker image that supports both pg-vector and postgis: https://github.com/payloadcms/postgis-vector
|
||||
image: ${{ (startsWith(matrix.database, 'postgres') ) && 'ghcr.io/payloadcms/postgis-vector:latest' || '' }}
|
||||
image: ${{ (startsWith(matrix.database, 'postgres') ) && 'postgis/postgis:16-3.4' || '' }}
|
||||
env:
|
||||
# must specify password for PG Docker container image, see: https://registry.hub.docker.com/_/postgres?tab=description&page=1&name=10
|
||||
POSTGRES_USER: ${{ env.POSTGRES_USER }}
|
||||
@@ -189,8 +209,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -242,7 +265,6 @@ jobs:
|
||||
needs: [changes, build]
|
||||
if: ${{ needs.changes.outputs.needs_tests == 'true' }}
|
||||
name: e2e-${{ matrix.suite }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -297,141 +319,6 @@ jobs:
|
||||
- plugin-cloud-storage
|
||||
- plugin-form-builder
|
||||
- plugin-import-export
|
||||
- plugin-multi-tenant
|
||||
- plugin-nested-docs
|
||||
- plugin-seo
|
||||
- sort
|
||||
- versions
|
||||
- uploads
|
||||
env:
|
||||
SUITE_NAME: ${{ matrix.suite }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Start LocalStack
|
||||
run: pnpm docker:start
|
||||
if: ${{ matrix.suite == 'plugin-cloud-storage' }}
|
||||
|
||||
- name: Store Playwright's Version
|
||||
run: |
|
||||
# Extract the version number using a more targeted regex pattern with awk
|
||||
PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --depth=0 | awk '/@playwright\/test/ {print $2}')
|
||||
echo "Playwright's Version: $PLAYWRIGHT_VERSION"
|
||||
echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache Playwright Browsers for Playwright's Version
|
||||
id: cache-playwright-browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }}
|
||||
|
||||
- name: Setup Playwright - Browsers and Dependencies
|
||||
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
|
||||
run: pnpm exec playwright install --with-deps chromium
|
||||
|
||||
- name: Setup Playwright - Dependencies-only
|
||||
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
|
||||
run: pnpm exec playwright install-deps chromium
|
||||
|
||||
- name: E2E Tests
|
||||
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci:noturbo ${{ matrix.suite }}
|
||||
env:
|
||||
PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results-${{ matrix.suite }}
|
||||
path: test/test-results/
|
||||
if-no-files-found: ignore
|
||||
retention-days: 1
|
||||
|
||||
# Disabled until this is fixed: https://github.com/daun/playwright-report-summary/issues/156
|
||||
# - uses: daun/playwright-report-summary@v3
|
||||
# with:
|
||||
# report-file: results_${{ matrix.suite }}.json
|
||||
# report-tag: ${{ matrix.suite }}
|
||||
# job-summary: true
|
||||
|
||||
tests-e2e-turbo:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [changes, build]
|
||||
if: >-
|
||||
needs.changes.outputs.needs_tests == 'true' &&
|
||||
(
|
||||
contains(github.event.pull_request.labels.*.name, 'run-e2e-turbo') ||
|
||||
github.event.label.name == 'run-e2e-turbo'
|
||||
)
|
||||
name: e2e-turbo-${{ matrix.suite }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# find test -type f -name 'e2e.spec.ts' | sort | xargs dirname | xargs -I {} basename {}
|
||||
suite:
|
||||
- _community
|
||||
- access-control
|
||||
- admin__e2e__general
|
||||
- admin__e2e__list-view
|
||||
- admin__e2e__document-view
|
||||
- admin-bar
|
||||
- admin-root
|
||||
- auth
|
||||
- auth-basic
|
||||
- bulk-edit
|
||||
- joins
|
||||
- field-error-states
|
||||
- fields-relationship
|
||||
- fields__collections__Array
|
||||
- fields__collections__Blocks
|
||||
- fields__collections__Blocks#config.blockreferences.ts
|
||||
- fields__collections__Checkbox
|
||||
- fields__collections__Collapsible
|
||||
- fields__collections__ConditionalLogic
|
||||
- fields__collections__CustomID
|
||||
- fields__collections__Date
|
||||
- fields__collections__Email
|
||||
- fields__collections__Indexed
|
||||
- fields__collections__JSON
|
||||
- fields__collections__Number
|
||||
- fields__collections__Point
|
||||
- fields__collections__Radio
|
||||
- fields__collections__Relationship
|
||||
- fields__collections__Row
|
||||
- fields__collections__Select
|
||||
- fields__collections__Tabs
|
||||
- fields__collections__Tabs2
|
||||
- fields__collections__Text
|
||||
- fields__collections__UI
|
||||
- fields__collections__Upload
|
||||
- hooks
|
||||
- lexical__collections__Lexical__e2e__main
|
||||
- lexical__collections__Lexical__e2e__blocks
|
||||
- lexical__collections__Lexical__e2e__blocks#config.blockreferences.ts
|
||||
- lexical__collections__RichText
|
||||
- query-presets
|
||||
- form-state
|
||||
- live-preview
|
||||
- localization
|
||||
- locked-documents
|
||||
- i18n
|
||||
- plugin-cloud-storage
|
||||
- plugin-form-builder
|
||||
- plugin-import-export
|
||||
- plugin-multi-tenant
|
||||
- plugin-nested-docs
|
||||
- plugin-seo
|
||||
- sort
|
||||
@@ -445,8 +332,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -489,7 +379,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results-turbo${{ matrix.suite }}
|
||||
name: test-results-${{ matrix.suite }}
|
||||
path: test/test-results/
|
||||
if-no-files-found: ignore
|
||||
retention-days: 1
|
||||
@@ -501,32 +391,24 @@ jobs:
|
||||
# report-tag: ${{ matrix.suite }}
|
||||
# job-summary: true
|
||||
|
||||
# Build listed templates with packed local packages and then runs their int and e2e tests
|
||||
build-and-test-templates:
|
||||
# Build listed templates with packed local packages
|
||||
build-templates:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [changes, build]
|
||||
if: ${{ needs.changes.outputs.needs_build == 'true' }}
|
||||
name: build-template-${{ matrix.template }}-${{ matrix.database }}
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- template: blank
|
||||
database: mongodb
|
||||
|
||||
- template: website
|
||||
database: mongodb
|
||||
|
||||
- template: with-payload-cloud
|
||||
database: mongodb
|
||||
|
||||
- template: with-vercel-mongodb
|
||||
database: mongodb
|
||||
|
||||
# Postgres
|
||||
- template: with-postgres
|
||||
database: postgres
|
||||
|
||||
- template: with-vercel-postgres
|
||||
database: postgres
|
||||
|
||||
@@ -536,6 +418,8 @@ jobs:
|
||||
# - template: with-vercel-website
|
||||
# database: postgres
|
||||
|
||||
name: ${{ matrix.template }}-${{ matrix.database }}
|
||||
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@@ -548,8 +432,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -596,45 +483,6 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8096
|
||||
|
||||
- name: Store Playwright's Version
|
||||
run: |
|
||||
# Extract the version number using a more targeted regex pattern with awk
|
||||
PLAYWRIGHT_VERSION=$(pnpm ls @playwright/test --depth=0 | awk '/@playwright\/test/ {print $2}')
|
||||
echo "Playwright's Version: $PLAYWRIGHT_VERSION"
|
||||
echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache Playwright Browsers for Playwright's Version
|
||||
id: cache-playwright-browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-${{ env.PLAYWRIGHT_VERSION }}
|
||||
|
||||
- name: Setup Playwright - Browsers and Dependencies
|
||||
if: steps.cache-playwright-browsers.outputs.cache-hit != 'true'
|
||||
run: pnpm exec playwright install --with-deps chromium
|
||||
|
||||
- name: Setup Playwright - Dependencies-only
|
||||
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
|
||||
run: pnpm exec playwright install-deps chromium
|
||||
|
||||
- name: Runs Template Int Tests
|
||||
run: pnpm --filter ${{ matrix.template }} run test:int
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8096
|
||||
PAYLOAD_DATABASE: ${{ matrix.database }}
|
||||
POSTGRES_URL: ${{ env.POSTGRES_URL }}
|
||||
MONGODB_URL: mongodb://localhost:27017/payloadtests
|
||||
|
||||
- name: Runs Template E2E Tests
|
||||
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.template }}.json pnpm --filter ${{ matrix.template }} test:e2e
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8096
|
||||
PAYLOAD_DATABASE: ${{ matrix.database }}
|
||||
POSTGRES_URL: ${{ env.POSTGRES_URL }}
|
||||
MONGODB_URL: mongodb://localhost:27017/payloadtests
|
||||
NEXT_TELEMETRY_DISABLED: 1
|
||||
|
||||
tests-type-generation:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [changes, build]
|
||||
@@ -645,8 +493,11 @@ jobs:
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
pnpm-install-cache-key: pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
@@ -667,7 +518,7 @@ jobs:
|
||||
needs:
|
||||
- lint
|
||||
- build
|
||||
- build-and-test-templates
|
||||
- build-templates
|
||||
- tests-unit
|
||||
- tests-int
|
||||
- tests-e2e
|
||||
@@ -690,34 +541,3 @@ jobs:
|
||||
- run: |
|
||||
echo github.ref: ${{ github.ref }}
|
||||
echo isV3: ${{ github.ref == 'refs/heads/main' }}
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes, build]
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read # for checkout repository
|
||||
actions: read # for fetching base branch bundle stats
|
||||
pull-requests: write # for comments
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Node setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
pnpm-run-install: false
|
||||
pnpm-restore-cache: false # Full build is restored below
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- run: pnpm run build:bundle-for-analysis # Esbuild packages that haven't already been built in the build step for the purpose of analyzing bundle size
|
||||
env:
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
|
||||
- name: Analyze esbuild bundle size
|
||||
uses: exoego/esbuild-bundle-analyzer@v1
|
||||
with:
|
||||
metafiles: 'packages/payload/meta_index.json,packages/payload/meta_shared.json,packages/ui/meta_client.json,packages/ui/meta_shared.json,packages/next/meta_index.json,packages/richtext-lexical/meta_client.json'
|
||||
|
||||
10
.github/workflows/post-release-templates.yml
vendored
10
.github/workflows/post-release-templates.yml
vendored
@@ -7,6 +7,8 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
NODE_VERSION: 22.6.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
@@ -58,6 +60,9 @@ jobs:
|
||||
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
|
||||
- name: Start PostgreSQL
|
||||
uses: CasperWA/postgresql-action@v1.2
|
||||
@@ -82,11 +87,6 @@ jobs:
|
||||
with:
|
||||
mongodb-version: 6.0
|
||||
|
||||
# The template generation script runs import map generation which needs the built payload bin scripts
|
||||
- run: pnpm run build:all
|
||||
env:
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
|
||||
- name: Update template lockfiles and migrations
|
||||
run: pnpm script:gen-templates
|
||||
|
||||
|
||||
2
.github/workflows/post-release.yml
vendored
2
.github/workflows/post-release.yml
vendored
@@ -12,6 +12,8 @@ on:
|
||||
default: ''
|
||||
|
||||
env:
|
||||
NODE_VERSION: 22.6.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
|
||||
5
.github/workflows/publish-prerelease.yml
vendored
5
.github/workflows/publish-prerelease.yml
vendored
@@ -7,6 +7,8 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
NODE_VERSION: 22.6.0
|
||||
PNPM_VERSION: 9.7.1
|
||||
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
|
||||
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
|
||||
|
||||
@@ -21,6 +23,9 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup
|
||||
uses: ./.github/actions/setup
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
- name: Load npm token
|
||||
run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
|
||||
env:
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -3,7 +3,6 @@ package-lock.json
|
||||
dist
|
||||
/.idea/*
|
||||
!/.idea/runConfigurations
|
||||
/.idea/runConfigurations/_template*
|
||||
!/.idea/payload.iml
|
||||
|
||||
# Custom actions
|
||||
@@ -22,13 +21,6 @@ meta_server.json
|
||||
meta_index.json
|
||||
meta_shared.json
|
||||
|
||||
packages/payload/esbuild
|
||||
packages/ui/esbuild
|
||||
packages/next/esbuild
|
||||
packages/richtext-lexical/esbuild
|
||||
|
||||
audit_output.json
|
||||
|
||||
.turbo
|
||||
|
||||
# Ignore test directory media folder/files
|
||||
|
||||
9
.idea/runConfigurations/_template__of_JavaScriptTestRunnerJest.xml
generated
Normal file
9
.idea/runConfigurations/_template__of_JavaScriptTestRunnerJest.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="true" type="JavaScriptTestRunnerJest">
|
||||
<node-interpreter value="project" />
|
||||
<node-options value="--no-deprecation" />
|
||||
<envs />
|
||||
<scope-kind value="ALL" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1 +1 @@
|
||||
v23.11.0
|
||||
v22.6.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
pnpm 9.7.1
|
||||
nodejs 23.11.0
|
||||
nodejs 22.6.0
|
||||
|
||||
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -63,13 +63,6 @@
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm tsx --no-deprecation test/dev.ts query-presets",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Query Presets",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm tsx --no-deprecation test/dev.ts login-with-username",
|
||||
"cwd": "${workspaceFolder}",
|
||||
@@ -118,13 +111,6 @@
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm tsx --no-deprecation test/dev.ts folder-view",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Folder View",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm tsx --no-deprecation test/dev.ts localization",
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
||||
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@@ -6,9 +6,10 @@
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"editor.formatOnSaveMode": "file",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"eslint.rules.customizations": [
|
||||
// Defaultt all ESLint errors to 'warn' to differentate from TypeScript's 'error' level
|
||||
{ "rule": "*", "severity": "warn" },
|
||||
|
||||
// Silence some warnings that will get auto-fixed
|
||||
{ "rule": "perfectionist/*", "severity": "off", "fixable": true },
|
||||
{ "rule": "curly", "severity": "off", "fixable": true },
|
||||
@@ -23,8 +24,5 @@
|
||||
"runtimeArgs": ["--no-deprecation"]
|
||||
},
|
||||
// Essentially disables bun test buttons
|
||||
"bun.test.filePattern": "bun.test.ts",
|
||||
"playwright.env": {
|
||||
"NODE_OPTIONS": "--no-deprecation --no-experimental-strip-types"
|
||||
}
|
||||
"bun.test.filePattern": "bun.test.ts"
|
||||
}
|
||||
|
||||
@@ -77,13 +77,9 @@ If you wish to use your own MongoDB database for the `test` directory instead of
|
||||
|
||||
### Using Postgres
|
||||
|
||||
Our test suites supports automatic PostgreSQL + PostGIS setup using Docker. No local PostgreSQL installation required. By default, mongodb is used.
|
||||
If you have postgres installed on your system, you can also run the test suites using postgres. By default, mongodb is used.
|
||||
|
||||
To use postgres, simply set the `PAYLOAD_DATABASE` environment variable to `postgres`.
|
||||
|
||||
```bash
|
||||
PAYLOAD_DATABASE=postgres pnpm dev {suite}
|
||||
```
|
||||
To do that, simply set the `PAYLOAD_DATABASE` environment variable to `postgres`.
|
||||
|
||||
### Running the e2e and int tests
|
||||
|
||||
@@ -91,43 +87,41 @@ You can run the entire test suite using `pnpm test`. If you wish to only run e2e
|
||||
|
||||
By default, `pnpm test:int` will only run int test against MongoDB. To run int tests against postgres, you can use `pnpm test:int:postgres`. You will have to have postgres installed on your system for this to work.
|
||||
|
||||
### Pull Requests
|
||||
### Commits
|
||||
|
||||
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 description.
|
||||
We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for our commit messages. Please follow this format when creating commits. Here are some examples:
|
||||
|
||||
All commits within a PR are squashed when merged, using the PR title as the commit message. For that reason, please use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) for your PR titles.
|
||||
- `feat: adds new feature`
|
||||
- `fix: fixes bug`
|
||||
- `docs: adds documentation`
|
||||
- `chore: does chore`
|
||||
|
||||
Here are some examples:
|
||||
Here's a breakdown of the format. At the top-level, we use the following types to categorize our commits:
|
||||
|
||||
- `feat: add new feature`
|
||||
- `fix: fix bug`
|
||||
- `docs: add documentation`
|
||||
- `test: add/fix tests`
|
||||
- `refactor: refactor code`
|
||||
- `chore: anything that does not fit into the above categories`
|
||||
|
||||
If applicable, you must indicate the affected packages in parentheses to "scope" the changes. Changes to the payload chore package do not require scoping.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- `feat(ui): add new feature`
|
||||
- `fix(richtext-lexical): fix bug`
|
||||
- `feat`: new feature that adds functionality. These are automatically added to the changelog when creating new releases.
|
||||
- `fix`: a fix to an existing feature. These are automatically added to the changelog when creating new releases.
|
||||
- `docs`: changes to [docs](./docs) only. These do not appear in the changelog.
|
||||
- `chore`: changes to code that is neither a fix nor a feature (e.g. refactoring, adding tests, etc.). These do not appear in the changelog.
|
||||
|
||||
If you are committing to [templates](./templates) or [examples](./examples), use the `chore` type with the proper scope, like this:
|
||||
|
||||
- `chore(templates): adds feature to template`
|
||||
- `chore(examples): fixes bug in example`
|
||||
|
||||
## 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:
|
||||
|
||||
1. Clone our [website repository](https://github.com/payloadcms/website)
|
||||
2. Run `pnpm install`
|
||||
2. Run `yarn install`
|
||||
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 `pnpm 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 `pnpm dev` and preview the docs under [http://localhost:3000/docs/local](http://localhost:3000/docs/local)
|
||||
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/)
|
||||
|
||||
## Internationalization (i18n)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ There are a couple ways to do this:
|
||||
|
||||
- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/.github/assets/int-debug.png" />
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/assets/images/github/int-debug.png" />
|
||||
|
||||
- **Manually** - you can run all int tests in the `/test/_community/int.spec.ts` file by running the following command:
|
||||
|
||||
@@ -62,7 +62,7 @@ The easiest way to run E2E tests is to install
|
||||
|
||||
Once they are installed you can open the `testing` tab in vscode sidebar and drill down to the test you want to run, i.e. `/test/_community/e2e.spec.ts`
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/.github/assets/e2e-debug.png" />
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/assets/images/github/e2e-debug.png" />
|
||||
|
||||
#### Notes
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ const GlobalWithAccessControl: GlobalConfig = {
|
||||
update: ({ req: { user } }) => {...},
|
||||
|
||||
// Version-enabled Globals only
|
||||
readVersions: () => {...},
|
||||
readVersion: () => {...},
|
||||
},
|
||||
// highlight-end
|
||||
}
|
||||
@@ -64,7 +64,7 @@ If a Global supports [Versions](../versions/overview), the following additional
|
||||
|
||||
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can read this global based on its current properties.
|
||||
|
||||
To add read Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):
|
||||
To add read Access Control to a [Global](../configuration/globals), use the `read` property in the [Global Config](../configuration/globals):
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload'
|
||||
@@ -72,7 +72,7 @@ import { GlobalConfig } from 'payload'
|
||||
const Header: GlobalConfig = {
|
||||
// ...
|
||||
// highlight-start
|
||||
access: {
|
||||
read: {
|
||||
read: ({ req: { user } }) => {
|
||||
return Boolean(user)
|
||||
},
|
||||
|
||||
@@ -32,18 +32,18 @@ The Admin Panel serves as the entire HTTP layer for Payload, providing a full CR
|
||||
Once you [install Payload](../getting-started/installation), the following files and directories will be created in your app:
|
||||
|
||||
```plaintext
|
||||
app
|
||||
├─ (payload)
|
||||
├── admin
|
||||
├─── [[...segments]]
|
||||
app/
|
||||
├─ (payload)/
|
||||
├── admin/
|
||||
├─── [[...segments]]/
|
||||
├──── page.tsx
|
||||
├──── not-found.tsx
|
||||
├── api
|
||||
├─── [...slug]
|
||||
├── api/
|
||||
├─── [...slug]/
|
||||
├──── route.ts
|
||||
├── graphql
|
||||
├── graphql/
|
||||
├──── route.ts
|
||||
├── graphql-playground
|
||||
├── graphql-playground/
|
||||
├──── route.ts
|
||||
├── custom.scss
|
||||
├── layout.tsx
|
||||
@@ -84,30 +84,30 @@ import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
admin: {
|
||||
// highlight-line
|
||||
// ...
|
||||
},
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| `autoLogin` | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
|
||||
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](../custom-components/overview). |
|
||||
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
|
||||
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| `meta` | Base metadata to use for the Admin Panel. [More details](./metadata). |
|
||||
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
|
||||
| `suppressHydrationWarning` | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
|
||||
| `theme` | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
|
||||
| `timezones` | Configure the timezone settings for the admin panel. [More details](#timezones) |
|
||||
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
|
||||
| Option | Description |
|
||||
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`avatar`** | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| **`autoLogin`** | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
|
||||
| **`buildPath`** | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
|
||||
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](../custom-components/overview). |
|
||||
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
|
||||
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| **`meta`** | Base metadata to use for the Admin Panel. [More details](./metadata). |
|
||||
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
|
||||
| **`suppressHydrationWarning`** | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
|
||||
| **`theme`** | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
|
||||
| **`timezones`** | Configure the timezone settings for the admin panel. [More details](#timezones) |
|
||||
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
|
||||
|
||||
<Banner type="success">
|
||||
**Reminder:** These are the _root-level_ options for the Admin Panel. You can
|
||||
@@ -187,12 +187,6 @@ The following options are available:
|
||||
| `graphQL` | `/graphql` | The [GraphQL API](../graphql/overview) base path. |
|
||||
| `graphQLPlayground` | `/graphql-playground` | The GraphQL Playground. |
|
||||
|
||||
<Banner type="warning">
|
||||
**Important:** Changing Root-level Routes also requires a change to [Project
|
||||
Structure](#project-structure) to match the new route. [More
|
||||
details](#customizing-root-level-routes).
|
||||
</Banner>
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** You can easily add _new_ routes to the Admin Panel through [Custom
|
||||
Endpoints](../rest-api/overview#custom-endpoints) and [Custom
|
||||
@@ -203,29 +197,13 @@ The following options are available:
|
||||
|
||||
You can change the Root-level Routes as needed, such as to mount the Admin Panel at the root of your application.
|
||||
|
||||
This change, however, also requires a change to your [Project Structure](#project-structure) to match the new route.
|
||||
|
||||
For example, if you set `routes.admin` to `/`:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
routes: {
|
||||
admin: '/', // highlight-line
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Then you would need to completely remove the `admin` directory from the project structure:
|
||||
Changing Root-level Routes also requires a change to [Project Structure](#project-structure) to match the new route. For example, if you set `routes.admin` to `/`, you would need to completely remove the `admin` directory from the project structure:
|
||||
|
||||
```plaintext
|
||||
app
|
||||
├─ (payload)
|
||||
├── [[...segments]]
|
||||
app/
|
||||
├─ (payload)/
|
||||
├── [[...segments]]/
|
||||
├──── ...
|
||||
├── layout.tsx
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
|
||||
@@ -65,7 +65,7 @@ preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlig
|
||||
|
||||
The Preview feature can be used to achieve "Draft Preview". After clicking the preview button from the Admin Panel, you can enter into "draft mode" within your front-end application. This will allow you to adjust your page queries to include the `draft: true` param. When this param is present on the request, Payload will send back a draft document as opposed to a published one based on the document's `_status` field.
|
||||
|
||||
To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that draft mode is enabled. This is framework specific, so the mechanisms here vary from framework to framework although the underlying concept is the same.
|
||||
To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that draft mode is enabled. This is framework specific, so the mechanisms here very from framework to framework although the underlying concept is the same.
|
||||
|
||||
### Next.js
|
||||
|
||||
|
||||
@@ -114,12 +114,7 @@ const MyComponent: React.FC = () => {
|
||||
|
||||
## useAllFormFields
|
||||
|
||||
**To retrieve more than one field**, you can use the `useAllFormFields` hook. Unlike the `useFormFields` hook, this hook does not accept a "selector", and it always returns an array with type of `[fields: Fields, dispatch: React.Dispatch<Action>]]`.
|
||||
|
||||
<Banner type="warning">
|
||||
**Warning:** Your component will re-render when _any_ field changes, so use
|
||||
this hook only if you absolutely need to.
|
||||
</Banner>
|
||||
**To retrieve more than one field**, you can use the `useAllFormFields` hook. Your component will re-render when _any_ field changes, so use this hook only if you absolutely need to. Unlike the `useFormFields` hook, this hook does not accept a "selector", and it always returns an array with type of `[fields: Fields, dispatch: React.Dispatch<Action>]]`.
|
||||
|
||||
You can do lots of powerful stuff by retrieving the full form state, like using built-in helper functions to reduce field state to values only, or to retrieve sibling data by path.
|
||||
|
||||
@@ -610,7 +605,7 @@ return (
|
||||
textField: {
|
||||
initialValue: 'Updated text',
|
||||
valid: true,
|
||||
value: 'Updated text',
|
||||
value: 'Upddated text',
|
||||
},
|
||||
},
|
||||
// blockType: "yourBlockSlug",
|
||||
@@ -880,7 +875,7 @@ Useful to retrieve info about the currently logged in user as well as methods fo
|
||||
| **`refreshCookie`** | A method to trigger the silent refreshing of a user's auth token |
|
||||
| **`setToken`** | Set the token of the user, to be decoded and used to reset the user and token in memory |
|
||||
| **`token`** | The logged in user's token (useful for creating preview links, etc.) |
|
||||
| **`refreshPermissions`** | Load new permissions (useful when content that affects permissions has been changed) |
|
||||
| **`refreshPermissions`** | Load new permissions (useful when content that effects permissions has been changed) |
|
||||
| **`permissions`** | The permissions of the current user |
|
||||
|
||||
```tsx
|
||||
@@ -986,15 +981,7 @@ const MyComponent: React.FC = () => {
|
||||
|
||||
## useTableColumns
|
||||
|
||||
Returns properties and methods to manipulate table columns:
|
||||
| Property | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------ |
|
||||
| **`columns`** | The current state of columns including their active status and configuration |
|
||||
| **`LinkedCellOverride`** | A component override for linked cells in the table |
|
||||
| **`moveColumn`** | A method to reorder columns. Accepts `{ fromIndex: number, toIndex: number }` as arguments |
|
||||
| **`resetColumnsState`** | A method to reset columns back to their default configuration as defined in the collection config |
|
||||
| **`setActiveColumns`** | A method to set specific columns to active state while preserving the existing column order. Accepts an array of column names to activate |
|
||||
| **`toggleColumn`** | A method to toggle a single column's visibility. Accepts a column name as string |
|
||||
Returns methods to manipulate table columns
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
@@ -1002,30 +989,17 @@ import { useTableColumns } from '@payloadcms/ui'
|
||||
|
||||
const MyComponent: React.FC = () => {
|
||||
// highlight-start
|
||||
const { setActiveColumns, resetColumnsState } = useTableColumns()
|
||||
const { setActiveColumns } = useTableColumns()
|
||||
|
||||
const activateSpecificColumns = () => {
|
||||
// Only activates the id and createdAt columns
|
||||
// Other columns retain their current active/inactive state
|
||||
// The original column order is preserved
|
||||
setActiveColumns(['id', 'createdAt'])
|
||||
}
|
||||
|
||||
const resetToDefaults = () => {
|
||||
// Resets to the default columns defined in the collection config
|
||||
resetColumnsState()
|
||||
const resetColumns = () => {
|
||||
setActiveColumns(['id', 'createdAt', 'updatedAt'])
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button type="button" onClick={activateSpecificColumns}>
|
||||
Activate Specific Columns
|
||||
</button>
|
||||
<button type="button" onClick={resetToDefaults}>
|
||||
Reset To Defaults
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" onClick={resetColumns}>
|
||||
Reset columns
|
||||
</button>
|
||||
)
|
||||
}
|
||||
```
|
||||
@@ -1169,7 +1143,7 @@ This is useful for scenarios where you need to trigger another fetch regardless
|
||||
|
||||
Route transitions are useful in showing immediate visual feedback to the user when navigating between pages. This is especially useful on slow networks when navigating to data heavy or process intensive pages.
|
||||
|
||||
By default, any instances of `Link` from `@payloadcms/ui` will trigger route transitions by default.
|
||||
By default, any instances of `Link` from `@payloadcms/ui` will trigger route transitions dy default.
|
||||
|
||||
```tsx
|
||||
import { Link } from '@payloadcms/ui'
|
||||
|
||||
@@ -62,7 +62,7 @@ In this scenario, if your cookie was still valid, malicious-intent.com would be
|
||||
|
||||
### CSRF Prevention
|
||||
|
||||
Define domains that you trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
|
||||
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
@@ -102,8 +102,8 @@ If option 1 isn't possible, then you can get around this limitation by [configur
|
||||
|
||||
```
|
||||
SameSite: None // allows the cookie to cross domains
|
||||
Secure: true // ensures it's sent over HTTPS only
|
||||
HttpOnly: true // ensures it's not accessible via client side JavaScript
|
||||
Secure: true // ensures its sent over HTTPS only
|
||||
HttpOnly: true // ensures its not accessible via client side JavaScript
|
||||
```
|
||||
|
||||
Configuration example:
|
||||
|
||||
@@ -25,12 +25,11 @@ A strategy is made up of the following:
|
||||
|
||||
The `authenticate` function is passed the following arguments:
|
||||
|
||||
| Argument | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`canSetHeaders`** \* | Whether or not the strategy is being executed from a context where response headers can be set. Default is `false`. |
|
||||
| **`headers`** \* | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
|
||||
| **`payload`** \* | The Payload class. Useful for authenticating the identifiable information against Payload. |
|
||||
| **`isGraphQL`** | Whether or not the strategy is being executed within the GraphQL endpoint. Default is `false`. |
|
||||
| Argument | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| **`headers`** \* | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
|
||||
| **`payload`** \* | The Payload class. Useful for authenticating the identifiable information against Payload. |
|
||||
| **`isGraphQL`** | Whether or not the request was made from a GraphQL endpoint. Default is `false`. |
|
||||
|
||||
### Example Strategy
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ export const Customers: CollectionConfig = {
|
||||
|
||||
#### generateEmailSubject
|
||||
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function arguments are the same but you can only return a string - not HTML.
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
@@ -178,7 +178,7 @@ The following arguments are passed to the `generateEmailHTML` function:
|
||||
|
||||
#### generateEmailSubject
|
||||
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function arguments are the same but you can only return a string - not HTML.
|
||||
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
@@ -23,9 +23,6 @@ Example:
|
||||
```ts
|
||||
const user = await fetch('http://localhost:3000/api/users/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: 'dev@payloadcms.com',
|
||||
password: 'password',
|
||||
@@ -41,7 +38,7 @@ const request = await fetch('http://localhost:3000', {
|
||||
|
||||
### Omitting The Token
|
||||
|
||||
In some cases you may want to prevent the token from being returned from the auth operations. You can do that by setting `removeTokenFromResponses` to `true` like so:
|
||||
In some cases you may want to prevent the token from being returned from the auth operations. You can do that by setting `removeTokenFromResponse` to `true` like so:
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
@@ -49,7 +46,7 @@ import type { CollectionConfig } from 'payload'
|
||||
export const UsersWithoutJWTs: CollectionConfig = {
|
||||
slug: 'users-without-jwts',
|
||||
auth: {
|
||||
removeTokenFromResponses: true, // highlight-line
|
||||
removeTokenFromResponse: true, // highlight-line
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -67,7 +67,7 @@ query {
|
||||
}
|
||||
```
|
||||
|
||||
Document access can also be queried on a collection/global basis. Access on a global can be queried like `http://localhost:3000/api/global-slug/access`, Collection document access can be queried like `http://localhost:3000/api/collection-slug/access/:id`.
|
||||
Document access can also be queried on a collection/global basis. Access on a global can queried like `http://localhost:3000/api/global-slug/access`, Collection document access can be queried like `http://localhost:3000/api/collection-slug/access/:id`.
|
||||
|
||||
## Me
|
||||
|
||||
@@ -180,22 +180,19 @@ As Payload sets HTTP-only cookies, logging out cannot be done by just removing a
|
||||
**Example REST API logout**:
|
||||
|
||||
```ts
|
||||
const res = await fetch(
|
||||
'http://localhost:3000/api/[collection-slug]/logout?allSessions=false',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
const res = await fetch('http://localhost:3000/api/[collection-slug]/logout', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
)
|
||||
})
|
||||
```
|
||||
|
||||
**Example GraphQL Mutation**:
|
||||
|
||||
```
|
||||
mutation {
|
||||
logoutUser(allSessions: false)
|
||||
logout[collection-singular-label]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -206,10 +203,6 @@ mutation {
|
||||
docs](../local-api/server-functions#reusable-payload-server-functions).
|
||||
</Banner>
|
||||
|
||||
#### Logging out with sessions enabled
|
||||
|
||||
By default, logging out will only end the session pertaining to the JWT that was used to log out with. However, you can pass `allSessions: true` to the logout operation in order to end all sessions for the user logging out.
|
||||
|
||||
## Refresh
|
||||
|
||||
Allows for "refreshing" JWTs. If your user has a token that is about to expire, but the user is still active and using the app, you might want to use the `refresh` operation to receive a new token by executing this operation via the authenticated user.
|
||||
|
||||
@@ -71,7 +71,7 @@ export const Admins: CollectionConfig = {
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** Auth-enabled Collections will be automatically injected with the
|
||||
**Note:** Auth-enabled Collections with be automatically injected with the
|
||||
`hash`, `salt`, and `email` fields. [More
|
||||
details](../fields/overview#field-names).
|
||||
</Banner>
|
||||
@@ -91,7 +91,6 @@ The following options are available:
|
||||
| **`strategies`** | Advanced - an array of custom authentication strategies to extend this collection's authentication with. [More details](./custom-strategies). |
|
||||
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
|
||||
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |
|
||||
| **`useSessions`** | True by default. Set to `false` to use stateless JWTs for authentication instead of sessions. |
|
||||
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More details](./email#email-verification). |
|
||||
|
||||
### Login With Username
|
||||
@@ -143,17 +142,14 @@ import { buildConfig } from 'payload'
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
admin: {
|
||||
autoLogin:
|
||||
process.env.NODE_ENV === 'development'
|
||||
? {
|
||||
email: 'test@example.com',
|
||||
password: 'test',
|
||||
prefillOnly: true,
|
||||
}
|
||||
: false,
|
||||
},
|
||||
|
||||
autoLogin:
|
||||
process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true'
|
||||
? {
|
||||
email: 'test@example.com',
|
||||
password: 'test',
|
||||
prefillOnly: true,
|
||||
}
|
||||
: false,
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
@@ -179,7 +175,7 @@ All auth-related operations are available via Payload's REST, Local, and GraphQL
|
||||
|
||||
## Strategies
|
||||
|
||||
Out of the box Payload ships with three powerful Authentication strategies:
|
||||
Out of the box Payload ships with a three powerful Authentication strategies:
|
||||
|
||||
- [HTTP-Only Cookies](./cookies)
|
||||
- [JSON Web Tokens (JWT)](./jwt)
|
||||
@@ -202,43 +198,3 @@ API Keys can be enabled on auth collections. These are particularly useful when
|
||||
### Custom Strategies
|
||||
|
||||
There are cases where these may not be enough for your application. Payload is extendable by design so you can wire up your own strategy when you need to. [More details](./custom-strategies).
|
||||
|
||||
### Access Control
|
||||
|
||||
Default auth fields including `email`, `username`, and `password` can be overridden by defining a custom field with the same name in your collection config. This allows you to customize the field — including access control — while preserving the underlying auth functionality. For example, you might want to restrict the `email` field from being updated once it is created, or only allow it to be read by certain user roles. You can achieve this by redefining the field and setting access rules accordingly.
|
||||
|
||||
Here's an example of how to restrict access to default auth fields:
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const Auth: CollectionConfig = {
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'email', // or 'username'
|
||||
type: 'text',
|
||||
access: {
|
||||
create: () => true,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'password', // this will be applied to all password-related fields including new password, confirm password.
|
||||
type: 'text',
|
||||
hidden: true, // needed only for the password field to prevent duplication in the Admin panel
|
||||
access: {
|
||||
update: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
**Note:**
|
||||
|
||||
- Access functions will apply across the application — I.e. if `read` access is disabled on `email`, it will not appear in the Admin panel UI or API.
|
||||
- Restricting `read` on the `email` or `username` disables the **Unlock** action in the Admin panel as this function requires access to a user-identifying field.
|
||||
- When overriding the `password` field, you may need to include `hidden: true` to prevent duplicate fields being displayed in the Admin panel.
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: authentication, config, configuration, documentation, Content Manageme
|
||||
|
||||
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appended to the request for you.
|
||||
|
||||
### Defining Token Data
|
||||
### Definining Token Data
|
||||
|
||||
You can specify what data gets encoded to the Cookie/JWT-Token by setting `saveToJWT` property on fields within your auth collection.
|
||||
|
||||
|
||||
@@ -60,32 +60,31 @@ export const Posts: CollectionConfig = {
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
|
||||
| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
|
||||
| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
|
||||
| `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. Multiple fields can be specified by using a string array. |
|
||||
| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
|
||||
| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
|
||||
| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) |
|
||||
| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
|
||||
| `orderable` | If true, enables custom ordering for the collection, and documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. |
|
||||
| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||
| `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). |
|
||||
| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
|
||||
| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||
| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
|
||||
| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
|
||||
| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
|
||||
| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
|
||||
| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. [More details](../database/indexes#compound-indexes). |
|
||||
| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks |
|
||||
| `disableBulkEdit` | Disable the bulk edit operation for the collection in the admin panel and the REST API |
|
||||
| Option | Description |
|
||||
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
|
||||
| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
|
||||
| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
|
||||
| `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. Multiple fields can be specified by using a string array. |
|
||||
| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
|
||||
| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
|
||||
| `fields` \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
|
||||
| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) |
|
||||
| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
|
||||
| `orderable` | If true, enables custom ordering for the collection, and documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. |
|
||||
| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||
| `enableQueryPresets` | Enable query presets for this Collection. [More details](../query-presets/overview). |
|
||||
| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
|
||||
| `slug` \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||
| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
|
||||
| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
|
||||
| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
|
||||
| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
|
||||
| `indexes` | Define compound indexes for this collection. This can be used to either speed up querying/sorting by 2 or more fields at the same time or to ensure uniqueness between several fields. |
|
||||
| `forceSelect` | Specify which fields should be selected always, regardless of the `select` query which can be useful that the field exists for access control / hooks |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -121,33 +120,25 @@ export const MyCollection: CollectionConfig = {
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `group` | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
|
||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
|
||||
| `hooks` | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
|
||||
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. |
|
||||
| `description` | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#custom-components). |
|
||||
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this Collection's List View. |
|
||||
| `disableCopyToLocale` | Disables the "Copy to Locale" button while editing documents within this Collection. Only applicable when localization is enabled. |
|
||||
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this Collection. |
|
||||
| `enableRichTextLink` | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `enableRichTextRelationship` | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `folders` | A boolean to enable folders for a given collection. Defaults to `false`. [More details](../folders/overview). |
|
||||
| `meta` | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](../admin/metadata). |
|
||||
| `preview` | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](../admin/preview). |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| `components` | Swap in your own React components to be used within this Collection. [More details](#custom-components). |
|
||||
| `listSearchableFields` | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
|
||||
| `pagination` | Set pagination-specific options for this Collection. [More details](#pagination). |
|
||||
| `baseListFilter` | You can define a default base filter for this collection's List view, which will be merged into any filters that the user performs. |
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** If you set `useAsTitle` to a relationship or join field, it will use
|
||||
only the ID of the related document(s) as the title. To display a specific
|
||||
field (i.e. title) from the related document instead, create a virtual field
|
||||
that extracts the desired data, and set `useAsTitle` to that virtual field.
|
||||
</Banner>
|
||||
| Option | Description |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `group` | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
|
||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
|
||||
| `hooks` | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
|
||||
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. A field with `virtual: true` cannot be used as the title, unless it's linked to a relationship'. |
|
||||
| `description` | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#custom-components). |
|
||||
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this Collection's List View. |
|
||||
| `disableCopyToLocale` | Disables the "Copy to Locale" button while editing documents within this Collection. Only applicable when localization is enabled. |
|
||||
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this Collection. |
|
||||
| `enableRichTextLink` | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `enableRichTextRelationship` | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `meta` | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](../admin/metadata). |
|
||||
| `preview` | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](../admin/preview). |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
|
||||
| `components` | Swap in your own React components to be used within this Collection. [More details](#custom-components). |
|
||||
| `listSearchableFields` | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
|
||||
| `pagination` | Set pagination-specific options for this Collection. [More details](#pagination). |
|
||||
| `baseListFilter` | You can define a default base filter for this collection's List view, which will be merged into any filters that the user performs. |
|
||||
|
||||
### Custom Components
|
||||
|
||||
@@ -185,7 +176,7 @@ The following options are available:
|
||||
#### Edit View Options
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
import type { CollectionCOnfig } from 'payload'
|
||||
|
||||
export const MyCollection: CollectionConfig = {
|
||||
// ...
|
||||
@@ -202,15 +193,13 @@ export const MyCollection: CollectionConfig = {
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `beforeDocumentControls` | Inject custom components before the Save / Publish buttons. [More details](../custom-components/edit-view#beforedocumentcontrols). |
|
||||
| `editMenuItems` | Inject custom components within the 3-dot menu dropdown located in the document controls bar. [More details](../custom-components/edit-view#editmenuitems). |
|
||||
| `SaveButton` | Replace the default Save Button within the Edit View. [Drafts](../versions/drafts) must be disabled. [More details](../custom-components/edit-view#savebutton). |
|
||||
| `SaveDraftButton` | Replace the default Save Draft Button within the Edit View. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. [More details](../custom-components/edit-view#savedraftbutton). |
|
||||
| `PublishButton` | Replace the default Publish Button within the Edit View. [Drafts](../versions/drafts) must be enabled. [More details](../custom-components/edit-view#publishbutton). |
|
||||
| `PreviewButton` | Replace the default Preview Button within the Edit View. [Preview](../admin/preview) must be enabled. [More details](../custom-components/edit-view#previewbutton). |
|
||||
| `Upload` | Replace the default Upload component within the Edit View. [Upload](../upload/overview) must be enabled. [More details](../custom-components/edit-view#upload). |
|
||||
| Option | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `SaveButton` | Replace the default Save Button within the Edit View. [Drafts](../versions/drafts) must be disabled. [More details](../custom-components/edit-view#savebutton). |
|
||||
| `SaveDraftButton` | Replace the default Save Draft Button within the Edit View. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. [More details](../custom-components/edit-view#savedraftbutton). |
|
||||
| `PublishButton` | Replace the default Publish Button within the Edit View. [Drafts](../versions/drafts) must be enabled. [More details](../custom-components/edit-view#publishbutton). |
|
||||
| `PreviewButton` | Replace the default Preview Button within the Edit View. [Preview](../admin/preview) must be enabled. [More details](../custom-components/edit-view#previewbutton). |
|
||||
| `Upload` | Replace the default Upload component within the Edit View. [Upload](../upload/overview) must be enabled. [More details](../custom-components/edit-view#upload). |
|
||||
|
||||
<Banner type="success">
|
||||
**Note:** For details on how to build Custom Components, see [Building Custom
|
||||
@@ -285,7 +274,7 @@ You can also pass an object to the collection's `graphQL` property, which allows
|
||||
|
||||
## TypeScript
|
||||
|
||||
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizedCollectionConfig`.
|
||||
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizeCollectionConfig`.
|
||||
|
||||
The `CollectionConfig` type represents a raw Collection Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedCollectionConfig` type represents a Collection Config after it has been fully sanitized. Generally, this is only used internally by Payload.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Environment Variables
|
||||
label: Environment Variables
|
||||
order: 60
|
||||
order: 100
|
||||
desc: Learn how to use Environment Variables in your Payload project
|
||||
---
|
||||
|
||||
@@ -72,7 +72,7 @@ const MyClientComponent = () => {
|
||||
}
|
||||
```
|
||||
|
||||
For more information, check out the [Next.js documentation](https://nextjs.org/docs/app/building-your-application/configuring/environment-variables).
|
||||
For more information, check out the [Next.js Documentation](https://nextjs.org/docs/app/building-your-application/configuring/environment-variables).
|
||||
|
||||
## Outside of Next.js
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ You can also pass an object to the global's `graphQL` property, which allows you
|
||||
|
||||
## TypeScript
|
||||
|
||||
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizedGlobalConfig`.
|
||||
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizeGlobalConfig`.
|
||||
|
||||
The `GlobalConfig` type represents a raw Global Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedGlobalConfig` type represents a Global Config after it has been fully sanitized. Generally, this is only used internally by Payload.
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ The following options are available:
|
||||
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/cookies#csrf-attacks). |
|
||||
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
|
||||
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
|
||||
| `folders` | An optional object to configure global folder settings. [More details](../folders/overview). |
|
||||
| `queryPresets` | An object that to configure Collection Query Presets. [More details](../query-presets/overview). |
|
||||
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
|
||||
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
@@ -110,7 +109,7 @@ _\* An asterisk denotes that a property is required._
|
||||
details](../custom-components/overview#accessing-the-payload-config).
|
||||
</Banner>
|
||||
|
||||
### TypeScript Config
|
||||
### Typescript Config
|
||||
|
||||
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](./collections) and [Globals](./globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
|
||||
|
||||
@@ -121,11 +120,10 @@ import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
typescript: {
|
||||
// highlight-line
|
||||
// ...
|
||||
},
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
@@ -214,7 +212,7 @@ For more information about what we track, take a look at our [privacy policy](/p
|
||||
|
||||
## Cross-origin resource sharing (CORS)#cors
|
||||
|
||||
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or an object with the following properties:
|
||||
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or a object with the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -228,9 +226,7 @@ import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
cors: '*',
|
||||
// highlight-end
|
||||
cors: '*', // highlight-line
|
||||
})
|
||||
```
|
||||
|
||||
@@ -295,7 +291,7 @@ export const script = async (config: SanitizedConfig) => {
|
||||
collection: 'pages',
|
||||
data: { title: 'my title' },
|
||||
})
|
||||
payload.logger.info('Successfully seeded!')
|
||||
payload.logger.info('Succesffully seeded!')
|
||||
process.exit(0)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ For more granular control, pass a configuration object instead. Payload exposes
|
||||
| Property | Description |
|
||||
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Component` \* | Pass in the component path that should be rendered when a user navigates to this route. |
|
||||
| `path` \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. Must begin with a forward slash (`/`). |
|
||||
| `path` \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
|
||||
| `exact` | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
|
||||
| `strict` | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
|
||||
| `sensitive` | When true, will match if the path is case sensitive. |
|
||||
|
||||
@@ -30,6 +30,7 @@ export const MyCollectionOrGlobalConfig: CollectionConfig = {
|
||||
// - api
|
||||
// - versions
|
||||
// - version
|
||||
// - livePreview
|
||||
// - [key: string]
|
||||
// See below for more details
|
||||
},
|
||||
@@ -58,7 +59,7 @@ _For details on how to build Custom Views, including all available props, see [B
|
||||
|
||||
### Document Root
|
||||
|
||||
The Document Root is mounted on the top-level route for a Document. Setting this property will completely take over the entire Document View layout, including the title, [Document Tabs](#document-tabs), _and all other nested Document Views_ including the [Edit View](./edit-view), API View, etc.
|
||||
The Document Root is mounted on the top-level route for a Document. Setting this property will completely take over the entire Document View layout, including the title, [Document Tabs](#ocument-tabs), _and all other nested Document Views_ including the [Edit View](./edit-view), API View, etc.
|
||||
|
||||
When setting a Document Root, you are responsible for rendering all necessary components and controls, as no document controls or tabs would be rendered. To replace only the Edit View precisely, use the `edit.default` key instead.
|
||||
|
||||
@@ -87,7 +88,7 @@ export const MyCollection: CollectionConfig = {
|
||||
|
||||
### Edit View
|
||||
|
||||
The Edit View is where users interact with individual Collection and Global Documents. This is where they can view, edit, and save their content. The Edit View is keyed under the `default` property in the `views.edit` object.
|
||||
The Edit View is where users interact with individual Collection and Global Documents. This is where they can view, edit, and save their content. the Edit View is keyed under the `default` property in the `views.edit` object.
|
||||
|
||||
For more information on customizing the Edit View, see the [Edit View](./edit-view) documentation.
|
||||
|
||||
@@ -106,8 +107,8 @@ export const MyCollection: CollectionConfig = {
|
||||
components: {
|
||||
views: {
|
||||
edit: {
|
||||
myCustomView: {
|
||||
Component: '/path/to/MyCustomView',
|
||||
myCustomTab: {
|
||||
Component: '/path/to/MyCustomTab',
|
||||
path: '/my-custom-tab',
|
||||
// highlight-start
|
||||
tab: {
|
||||
@@ -115,14 +116,13 @@ export const MyCollection: CollectionConfig = {
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
anotherCustomView: {
|
||||
anotherCustomTab: {
|
||||
Component: '/path/to/AnotherCustomView',
|
||||
path: '/another-custom-view',
|
||||
// highlight-start
|
||||
tab: {
|
||||
label: 'Another Custom View',
|
||||
href: '/another-custom-view',
|
||||
order: '100',
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
@@ -143,7 +143,6 @@ The following options are available for tabs:
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `label` | The label to display in the tab. |
|
||||
| `href` | The URL to navigate to when the tab is clicked. This is optional and defaults to the tab's `path`. |
|
||||
| `order` | The order in which the tab appears in the navigation. Can be set on default and custom tabs. |
|
||||
| `Component` | The component to render in the tab. This can be a Server or Client component. [More details](#tab-components) |
|
||||
|
||||
### Tab Components
|
||||
|
||||
@@ -101,16 +101,15 @@ export const MyCollection: CollectionConfig = {
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Path | Description |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `beforeDocumentControls` | Inject custom components before the Save / Publish buttons. [More details](#beforedocumentcontrols). |
|
||||
| `editMenuItems` | Inject custom components within the 3-dot menu dropdown located in the document control bar. [More details](#editmenuitems). |
|
||||
| `SaveButton` | A button that saves the current document. [More details](#savebutton). |
|
||||
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#savedraftbutton). |
|
||||
| `PublishButton` | A button that publishes the current document. [More details](#publishbutton). |
|
||||
| `PreviewButton` | A button that previews the current document. [More details](#previewbutton). |
|
||||
| `Description` | A description of the Collection. [More details](#description). |
|
||||
| `Upload` | A file upload component. [More details](#upload). |
|
||||
| Path | Description |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
|
||||
| `beforeDocumentControls` | Inject custom components before the Save / Publish buttons. [More details](#beforedocumentcontrols). |
|
||||
| `SaveButton` | A button that saves the current document. [More details](#savebutton). |
|
||||
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#savedraftbutton). |
|
||||
| `PublishButton` | A button that publishes the current document. [More details](#publishbutton). |
|
||||
| `PreviewButton` | A button that previews the current document. [More details](#previewbutton). |
|
||||
| `Description` | A description of the Collection. [More details](#description). |
|
||||
| `Upload` | A file upload component. [More details](#upload). |
|
||||
|
||||
#### Globals
|
||||
|
||||
@@ -135,15 +134,14 @@ export const MyGlobal: GlobalConfig = {
|
||||
|
||||
The following options are available:
|
||||
|
||||
| Path | Description |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `beforeDocumentControls` | Inject custom components before the Save / Publish buttons. [More details](#beforedocumentcontrols). |
|
||||
| `editMenuItems` | Inject custom components within the 3-dot menu dropdown located in the document control bar. [More details](#editmenuitems). |
|
||||
| `SaveButton` | A button that saves the current document. [More details](#savebutton). |
|
||||
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#savedraftbutton). |
|
||||
| `PublishButton` | A button that publishes the current document. [More details](#publishbutton). |
|
||||
| `PreviewButton` | A button that previews the current document. [More details](#previewbutton). |
|
||||
| `Description` | A description of the Global. [More details](#description). |
|
||||
| Path | Description |
|
||||
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
|
||||
| `beforeDocumentControls` | Inject custom components before the Save / Publish buttons. [More details](#beforedocumentcontrols). |
|
||||
| `SaveButton` | A button that saves the current document. [More details](#savebutton). |
|
||||
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#savedraftbutton). |
|
||||
| `PublishButton` | A button that publishes the current document. [More details](#publishbutton). |
|
||||
| `PreviewButton` | A button that previews the current document. [More details](#previewbutton). |
|
||||
| `Description` | A description of the Global. [More details](#description). |
|
||||
|
||||
### SaveButton
|
||||
|
||||
@@ -262,92 +260,6 @@ export function MyCustomDocumentControlButton(
|
||||
}
|
||||
```
|
||||
|
||||
### editMenuItems
|
||||
|
||||
The `editMenuItems` property allows you to inject custom components into the 3-dot menu dropdown located in the document controls bar. This dropdown contains default options including `Create New`, `Duplicate`, `Delete`, and other options when additional features are enabled. Any custom components you add will appear below these default items.
|
||||
|
||||
To add `editMenuItems`, use the `components.edit.editMenuItems` property in your [Collection Config](../configuration/collections):
|
||||
|
||||
#### Config Example
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
components: {
|
||||
edit: {
|
||||
// highlight-start
|
||||
editMenuItems: ['/path/to/CustomEditMenuItem'],
|
||||
// highlight-end
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Here's an example of a custom `editMenuItems` component:
|
||||
|
||||
#### Server Component
|
||||
|
||||
```tsx
|
||||
import React from 'react'
|
||||
import { PopupList } from '@payloadcms/ui'
|
||||
|
||||
import type { EditMenuItemsServerProps } from 'payload'
|
||||
|
||||
export const EditMenuItems = async (props: EditMenuItemsServerProps) => {
|
||||
const href = `/custom-action?id=${props.id}`
|
||||
|
||||
return (
|
||||
<PopupList.ButtonGroup>
|
||||
<PopupList.Button href={href}>Custom Edit Menu Item</PopupList.Button>
|
||||
<PopupList.Button href={href}>
|
||||
Another Custom Edit Menu Item - add as many as you need!
|
||||
</PopupList.Button>
|
||||
</PopupList.ButtonGroup>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Client Component
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
import { PopupList } from '@payloadcms/ui'
|
||||
|
||||
import type { EditViewMenuItemClientProps } from 'payload'
|
||||
|
||||
export const EditMenuItems = (props: EditViewMenuItemClientProps) => {
|
||||
const handleClick = () => {
|
||||
console.log('Custom button clicked!')
|
||||
}
|
||||
|
||||
return (
|
||||
<PopupList.ButtonGroup>
|
||||
<PopupList.Button onClick={handleClick}>
|
||||
Custom Edit Menu Item
|
||||
</PopupList.Button>
|
||||
<PopupList.Button onClick={handleClick}>
|
||||
Another Custom Edit Menu Item - add as many as you need!
|
||||
</PopupList.Button>
|
||||
</PopupList.ButtonGroup>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="info">
|
||||
**Styling:** Use Payload's built-in `PopupList.Button` to ensure your menu
|
||||
items automatically match the default dropdown styles. If you want a different
|
||||
look, you can customize the appearance by passing your own `className` to
|
||||
`PopupList.Button`, or use a completely custom button built with a standard
|
||||
HTML `button` element or any other component that fits your design
|
||||
preferences.
|
||||
</Banner>
|
||||
|
||||
### SaveDraftButton
|
||||
|
||||
The `SaveDraftButton` property allows you to render a custom Save Draft Button in the Edit View.
|
||||
|
||||
@@ -94,7 +94,6 @@ The following options are available:
|
||||
| `beforeListTable` | An array of custom components to inject before the table of documents in the List View. [More details](#beforelisttable). |
|
||||
| `afterList` | An array of custom components to inject after the list of documents in the List View. [More details](#afterlist). |
|
||||
| `afterListTable` | An array of custom components to inject after the table of documents in the List View. [More details](#afterlisttable). |
|
||||
| `listMenuItems` | An array of components to render within a menu next to the List Controls (after the Columns and Filters options) |
|
||||
| `Description` | A component to render a description of the Collection. [More details](#description). |
|
||||
|
||||
### beforeList
|
||||
|
||||
@@ -505,51 +505,3 @@ Payload also exports its [SCSS](https://sass-lang.com) library for reuse which i
|
||||
**Note:** You can also drill into Payload's own component styles, or easily
|
||||
apply global, app-wide CSS. More on that [here](../admin/customizing-css).
|
||||
</Banner>
|
||||
|
||||
## Performance
|
||||
|
||||
An often overlooked aspect of Custom Components is performance. If unchecked, Custom Components can lead to slow load times of the Admin Panel and ultimately a poor user experience.
|
||||
|
||||
This is different from front-end performance of your public-facing site.
|
||||
|
||||
<Banner type="success">
|
||||
For more performance tips, see the [Performance
|
||||
documentation](../performance/overview).
|
||||
</Banner>
|
||||
|
||||
### Follow React and Next.js best practices
|
||||
|
||||
All Custom Components are built using [React](https://react.dev). For this reason, it is important to follow React best practices. This includes using memoization, streaming, caching, optimizing renders, using hooks appropriately, and more.
|
||||
|
||||
To learn more, see the [React documentation](https://react.dev/learn).
|
||||
|
||||
The Admin Panel itself is a [Next.js](https://nextjs.org) application. For this reason, it is _also_ important to follow Next.js best practices. This includes bundling, when to use layouts vs pages, where to place the server/client boundary, and more.
|
||||
|
||||
To learn more, see the [Next.js documentation](https://nextjs.org/docs).
|
||||
|
||||
### Reducing initial HTML size
|
||||
|
||||
With Server Components, be aware of what is being sent to through the server/client boundary. All props are serialized and sent through the network. This can lead to large HTML sizes and slow initial load times if too much data is being sent to the client.
|
||||
|
||||
To minimize this, you must be explicit about what props are sent to the client. Prefer server components and only send the necessary props to the client. This will also offset some of the JS execution to the server.
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** Use [React Suspense](https://react.dev/reference/react/Suspense) to
|
||||
progressively load components and improve perceived performance.
|
||||
</Banner>
|
||||
|
||||
### Prevent unnecessary re-renders
|
||||
|
||||
If subscribing your component to form state, it may be re-rendering more often than necessary.
|
||||
|
||||
To do this, use the [`useFormFields`](../admin/react-hooks) hook instead of `useFields` when you only need to access specific fields.
|
||||
|
||||
```ts
|
||||
'use client'
|
||||
import { useFormFields } from '@payloadcms/ui'
|
||||
|
||||
const MyComponent: TextFieldClientComponent = ({ path }) => {
|
||||
const value = useFormFields(([fields, dispatch]) => fields[path])
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -40,7 +40,7 @@ The following options are available:
|
||||
| `beforeDashboard` | An array of Custom Components to inject into the built-in Dashboard, _before_ the default dashboard contents. [More details](#beforedashboard). |
|
||||
| `beforeLogin` | An array of Custom Components to inject into the built-in Login, _before_ the default login form. [More details](#beforelogin). |
|
||||
| `beforeNavLinks` | An array of Custom Components to inject into the built-in Nav, _before_ the links themselves. [More details](#beforenavlinks). |
|
||||
| `graphics.Icon` | The simplified logo used in contexts like the `Nav` component. [More details](#graphicsicon). |
|
||||
| `graphics.Icon` | The simplified logo used in contexts like the the `Nav` component. [More details](#graphicsicon). |
|
||||
| `graphics.Logo` | The full logo used in contexts like the `Login` view. [More details](#graphicslogo). |
|
||||
| `header` | An array of Custom Components to be injected above the Payload header. [More details](#header). |
|
||||
| `logout.Button` | The button displayed in the sidebar that logs the user out. [More details](#logoutbutton). |
|
||||
@@ -345,7 +345,7 @@ export default function MyCustomIcon() {
|
||||
|
||||
The `Logo` property is the full logo used in contexts like the `Login` view. This is typically a larger, more detailed representation of your brand.
|
||||
|
||||
To add a custom logo, use the `admin.components.graphics.Logo` property in your Payload Config:
|
||||
To add a custom logo, use the `admin.components.graphic.Logo` property in your Payload Config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
@@ -372,13 +372,13 @@ export default function MyCustomLogo() {
|
||||
}
|
||||
```
|
||||
|
||||
### header
|
||||
### Header
|
||||
|
||||
The `header` property allows you to inject Custom Components above the Payload header.
|
||||
The `Header` property allows you to inject Custom Components above the Payload header.
|
||||
|
||||
Examples of a custom header components might include an announcements banner, a notifications bar, or anything else you'd like to display at the top of the Admin Panel in a prominent location.
|
||||
|
||||
To add `header` components, use the `admin.components.header` property in your Payload Config:
|
||||
To add `Header` components, use the `admin.components.header` property in your Payload Config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
@@ -388,14 +388,14 @@ export default buildConfig({
|
||||
admin: {
|
||||
// highlight-start
|
||||
components: {
|
||||
header: ['/path/to/your/component'],
|
||||
Header: ['/path/to/your/component'],
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Here is an example of a simple `header` component:
|
||||
Here is an example of a simple `Header` component:
|
||||
|
||||
```tsx
|
||||
export default function MyCustomHeader() {
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
---
|
||||
title: Indexes
|
||||
label: Indexes
|
||||
order: 40
|
||||
keywords: database, indexes
|
||||
desc: Index fields to produce faster queries.
|
||||
---
|
||||
|
||||
Database indexes are a way to optimize the performance of your database by allowing it to quickly locate and retrieve data. If you have a field that you frequently query or sort by, adding an index to that field can significantly improve the speed of those operations.
|
||||
|
||||
When your query runs, the database will not scan the entire document to find that one field, but will instead use the index to quickly locate the data.
|
||||
|
||||
To index a field, set the `index` option to `true` in your field's config:
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export MyCollection: CollectionConfig = {
|
||||
// ...
|
||||
fields: [
|
||||
// ...
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
// highlight-start
|
||||
index: true,
|
||||
// highlight-end
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="info">
|
||||
**Note:** The `id`, `createdAt`, and `updatedAt` fields are indexed by
|
||||
default.
|
||||
</Banner>
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** If you're using MongoDB, you can use [MongoDB
|
||||
Compass](https://www.mongodb.com/products/compass) to visualize and manage
|
||||
your indexes.
|
||||
</Banner>
|
||||
|
||||
## Compound Indexes
|
||||
|
||||
In addition to indexing single fields, you can also create compound indexes that index multiple fields together. This can be useful for optimizing queries that filter or sort by multiple fields.
|
||||
|
||||
To create a compound index, use the `indexes` option in your [Collection Config](../configuration/collections):
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const MyCollection: CollectionConfig = {
|
||||
// ...
|
||||
fields: [
|
||||
// ...
|
||||
],
|
||||
indexes: [
|
||||
{
|
||||
fields: ['title', 'createdAt'],
|
||||
unique: true, // Optional, if you want the combination of fields to be unique
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
@@ -183,13 +183,13 @@ Depending on which Database Adapter you use, your migration workflow might diffe
|
||||
|
||||
In relational databases, migrations will be **required** for non-development database environments. But with MongoDB, you might only need to run migrations once in a while (or never even need them).
|
||||
|
||||
#### MongoDB#mongodb-migrations
|
||||
#### MongoDB
|
||||
|
||||
In MongoDB, you'll only ever really need to run migrations for times where you change your database shape, and you have lots of existing data that you'd like to transform from Shape A to Shape B.
|
||||
|
||||
In this case, you can create a migration by running `pnpm payload migrate:create`, and then write the logic that you need to perform to migrate your documents to their new shape. You can then either run your migrations in CI before you build / deploy, or you can run them locally, against your production database, by using your production database connection string on your local computer and running the `pnpm payload migrate` command.
|
||||
|
||||
#### Postgres#postgres-migrations
|
||||
#### Postgres
|
||||
|
||||
In relational databases like Postgres, migrations are a bit more important, because each time you add a new field or a new collection, you'll need to update the shape of your database to match your Payload Config (otherwise you'll see errors upon trying to read / write your data).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: MongoDB
|
||||
label: MongoDB
|
||||
order: 50
|
||||
order: 40
|
||||
desc: Payload has supported MongoDB natively since we started. The flexible nature of MongoDB lends itself well to Payload's powerful fields.
|
||||
keywords: MongoDB, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
@@ -41,7 +41,6 @@ export default buildConfig({
|
||||
| `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). |
|
||||
| `allowAdditionalKeys` | By default, Payload strips all additional keys from MongoDB data that don't exist in the Payload schema. If you have some data that you want to include to the result but it doesn't exist in Payload, you can set this to `true`. Be careful as Payload access control _won't_ work for this data. |
|
||||
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
|
||||
| `disableFallbackSort` | Set to `true` to disable the adapter adding a fallback sort when sorting by non-unique fields, this can affect performance in some cases but it ensures a consistent order of results. |
|
||||
|
||||
## Access to Mongoose models
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Postgres
|
||||
label: Postgres
|
||||
order: 60
|
||||
order: 50
|
||||
desc: Payload supports Postgres through an officially supported Drizzle Database Adapter.
|
||||
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
@@ -39,7 +39,7 @@ export default buildConfig({
|
||||
import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres'
|
||||
|
||||
export default buildConfig({
|
||||
// Automatically uses process.env.POSTGRES_URL if no options are provided.
|
||||
// Automatically uses proces.env.POSTGRES_URL if no options are provided.
|
||||
db: vercelPostgresAdapter(),
|
||||
// Optionally, can accept the same options as the @vercel/postgres package.
|
||||
db: vercelPostgresAdapter({
|
||||
@@ -80,8 +80,6 @@ export default buildConfig({
|
||||
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
|
||||
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
|
||||
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
|
||||
| `readReplicas` | An array of DB read replicas connection strings, can be used to offload read-heavy traffic. |
|
||||
| `blocksAsJSON` | Store blocks as a JSON column instead of using the relational structure which can improve performance with a large amount of blocks |
|
||||
|
||||
## Access to Drizzle
|
||||
|
||||
@@ -226,7 +224,7 @@ Make sure Payload doesn't overlap table names with its collections. For example,
|
||||
### afterSchemaInit
|
||||
|
||||
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
|
||||
To extend a table, Payload exposes `extendTable` utility to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
|
||||
|
||||
```ts
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: SQLite
|
||||
label: SQLite
|
||||
order: 70
|
||||
order: 60
|
||||
desc: Payload supports SQLite through an officially supported Drizzle Database Adapter.
|
||||
keywords: SQLite, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
@@ -50,7 +50,6 @@ export default buildConfig({
|
||||
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
|
||||
| `autoIncrement` | Pass `true` to enable SQLite [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for primary keys to ensure the same ID cannot be reused from deleted rows |
|
||||
| `allowIDOnCreate` | Set to `true` to use the `id` passed in data on the create API operations without using a custom ID field. |
|
||||
| `blocksAsJSON` | Store blocks as a JSON column instead of using the relational structure which can improve performance with a large amount of blocks |
|
||||
|
||||
## Access to Drizzle
|
||||
|
||||
@@ -190,7 +189,7 @@ Make sure Payload doesn't overlap table names with its collections. For example,
|
||||
### afterSchemaInit
|
||||
|
||||
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
|
||||
To extend a table, Payload exposes `extendTable` utility to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
|
||||
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
|
||||
|
||||
```ts
|
||||
|
||||
@@ -41,17 +41,17 @@ export const MyArrayField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as the heading in the [Admin Panel](../admin/overview) or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`fields`** \* | Array of field types to correspond to each row of the Array. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
|
||||
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide an array of row data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide an array of row data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Array will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`labels`** | Customize the row labels appearing in the Admin dashboard. |
|
||||
@@ -80,7 +80,7 @@ export const MyArrayField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Array Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Array Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -41,17 +41,17 @@ export const MyBlocksField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as the heading in the Admin Panel or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`blocks`** \* | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
|
||||
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API response or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide an array of block data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide an array of block data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this field will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`labels`** | Customize the block row labels appearing in the Admin dashboard. |
|
||||
@@ -78,7 +78,7 @@ export const MyBlocksField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Blocks Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Blocks Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------------- |
|
||||
|
||||
@@ -30,15 +30,15 @@ export const MyCheckboxField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value, will default to false if field is also `required`. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value, will default to false if field is also `required`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](./overview#admin-options). |
|
||||
|
||||
@@ -31,18 +31,18 @@ export const MyBlocksField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
|
||||
@@ -68,7 +68,7 @@ export const MyCodeField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Code Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Code Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -58,7 +58,7 @@ export const MyCollapsibleField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Collapsible Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Collapsible Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------- |
|
||||
|
||||
@@ -30,15 +30,15 @@ export const MyDateField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -65,7 +65,7 @@ export const MyDateField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Date Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Date Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -30,16 +30,16 @@ export const MyEmailField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -65,7 +65,7 @@ export const MyEmailField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Email Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Email Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------- |
|
||||
|
||||
@@ -35,15 +35,15 @@ export const MyGroupField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`fields`** \* | Array of field types to nest within this Group. |
|
||||
| **`label`** | Used as a heading in the Admin Panel and to name the generated GraphQL type. Defaults to the field name, if defined. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`label`** | Used as a heading in the Admin Panel and to name the generated GraphQL type. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide an object of data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide an object of data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Group will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
@@ -69,7 +69,7 @@ export const MyGroupField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Group Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Group Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
@@ -86,7 +86,7 @@ export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'pageMeta',
|
||||
name: 'pageMeta', // required
|
||||
type: 'group', // required
|
||||
interfaceName: 'Meta', // optional
|
||||
fields: [
|
||||
@@ -110,37 +110,3 @@ export const ExampleCollection: CollectionConfig = {
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## Presentational group fields
|
||||
|
||||
You can also use the Group field to only visually group fields without affecting the data structure. Not defining a label will render just the grouped fields.
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
label: 'Page meta',
|
||||
type: 'group', // required
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
minLength: 20,
|
||||
maxLength: 100,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
minLength: 40,
|
||||
maxLength: 160,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ powerful Admin UI.
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when retrieved from the database. [More details](./overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when retrieved from the database. [More](./overview#field-names) |
|
||||
| **`collection`** \* | The `slug`s having the relationship field or an array of collection slugs. |
|
||||
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. If `collection` is an array, this field must exist for all specified collections |
|
||||
| **`orderable`** | If true, enables custom ordering and joined documents can be reordered via drag and drop. Uses [fractional indexing](https://observablehq.com/@dgreensp/implementing-fractional-indexing) for efficient reordering. |
|
||||
|
||||
@@ -31,17 +31,17 @@ export const MyJSONField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -67,7 +67,7 @@ export const MyJSONField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The JSON Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The JSON Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -30,7 +30,7 @@ export const MyNumberField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`min`** | Minimum value accepted. Used in the default `validation` function. |
|
||||
| **`max`** | Maximum value accepted. Used in the default `validation` function. |
|
||||
@@ -38,13 +38,13 @@ export const MyNumberField: Field = {
|
||||
| **`minRows`** | Minimum number of numbers in the numbers array, if `hasMany` is set to true. |
|
||||
| **`maxRows`** | Maximum number of numbers in the numbers array, if `hasMany` is set to true. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -70,7 +70,7 @@ export const MyNumberField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Number Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Number Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -100,7 +100,7 @@ Here are the available Presentational Fields:
|
||||
|
||||
### Virtual Fields
|
||||
|
||||
Virtual fields are used to display data that is not stored in the database. They are useful for displaying computed values that populate within the API response through hooks, etc.
|
||||
Virtual fields are used to display data that is not stored in the database. They are useful for displaying computed values that populate within the APi response through hooks, etc.
|
||||
|
||||
Here are the available Virtual Fields:
|
||||
|
||||
@@ -303,24 +303,7 @@ The following additional properties are provided in the `ctx` object:
|
||||
| `path` | The full path to the field in the schema, represented as an array of string segments, including array indexes. I.e `['group', 'myArray', '1', 'textField']`. |
|
||||
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation. |
|
||||
| `req` | The current HTTP request object. Contains `payload`, `user`, etc. |
|
||||
| `event` | Either `onChange` or `submit` depending on the current action. Used as a performance opt-in. [More details](#validation-performance). |
|
||||
|
||||
#### Localized and Built-in Error Messages
|
||||
|
||||
You can return localized error messages by utilizing the translation function provided in the `req` object:
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload'
|
||||
|
||||
export const MyField: Field = {
|
||||
type: 'text',
|
||||
name: 'myField',
|
||||
validate: (value, { req: { t } }) =>
|
||||
Boolean(value) || t('validation:required'), // highlight-line
|
||||
}
|
||||
```
|
||||
|
||||
This way you can use [Custom Translations](https://payloadcms.com/docs/configuration/i18n#custom-translations) as well as Payload's built in error messages (like `validation:required` used in the example above). For a full list of available translation strings, see the [english translation file](https://github.com/payloadcms/payload/blob/main/packages/translations/src/languages/en.ts) of Payload.
|
||||
| `event` | Either `onChange` or `submit` depending on the current action. Used as a performance opt-in. [More details](#async-field-validations). |
|
||||
|
||||
#### Reusing Default Field Validations
|
||||
|
||||
@@ -351,6 +334,7 @@ import {
|
||||
code,
|
||||
date,
|
||||
email,
|
||||
group,
|
||||
json,
|
||||
number,
|
||||
point,
|
||||
@@ -365,11 +349,11 @@ import {
|
||||
} from 'payload/shared'
|
||||
```
|
||||
|
||||
#### Validation Performance
|
||||
#### Async Field Validations
|
||||
|
||||
When writing async or computationally heavy validation functions, it is important to consider the performance implications. Within the Admin Panel, validations are executed on every change to the field, so they should be as lightweight as possible and only run when necessary.
|
||||
Custom validation functions can also be asynchronous depending on your needs. This makes it possible to make requests to external services or perform other miscellaneous asynchronous logic.
|
||||
|
||||
If you need to perform expensive validations, such as querying the database, consider using the `event` property in the `ctx` object to only run that particular validation on form submission.
|
||||
When writing async validation functions, it is important to consider the performance implications. Validations are executed on every change to the field, so they should be as lightweight as possible. If you need to perform expensive validations, such as querying the database, consider using the `event` property in the `ctx` object to only run the validation on form submission.
|
||||
|
||||
To write asynchronous validation functions, use the `async` keyword to define your function:
|
||||
|
||||
@@ -403,11 +387,6 @@ export const Orders: CollectionConfig = {
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
For more performance tips, see the [Performance
|
||||
documentation](../performance/overview).
|
||||
</Banner>
|
||||
|
||||
## Custom ID Fields
|
||||
|
||||
All [Collections](../configuration/collections) automatically generate their own ID field. If needed, you can override this behavior by providing an explicit ID field to your config. This field should either be required or have a hook to generate the ID dynamically.
|
||||
|
||||
@@ -34,16 +34,16 @@ export const MyPointField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Used as a field label in the Admin Panel and to name the generated GraphQL type. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](./overview#admin-options). |
|
||||
|
||||
@@ -35,16 +35,16 @@ export const MyRadioField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. The default value must exist within provided values in `options`. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. The default value must exist within provided values in `options`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -82,7 +82,7 @@ export const MyRadioField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Radio Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Radio Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -39,22 +39,22 @@ export const MyRelationshipField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`relationTo`** \* | Provide one or many collection `slug`s to be able to assign relationships to. |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More details](#filtering-relationship-options). |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-relationship-options). |
|
||||
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many relations instead of only one. |
|
||||
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. Used with `hasMany`. |
|
||||
| **`maxRows`** | A number for the most allowed items during validation when a value is present. Used with `hasMany`. |
|
||||
| **`maxDepth`** | Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/queries/depth#max-depth) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -86,14 +86,14 @@ export const MyRelationshipField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Relationship Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Relationship Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`isSortable`** | Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany` is set to `true`). |
|
||||
| **`allowCreate`** | Set to `false` if you'd like to disable the ability to create new documents from within the relationship field. |
|
||||
| **`allowEdit`** | Set to `false` if you'd like to disable the ability to edit documents from within the relationship field. |
|
||||
| **`sortOptions`** | Define a default sorting order for the options within a Relationship field's dropdown. [More details](#sort-options) |
|
||||
| **`sortOptions`** | Define a default sorting order for the options within a Relationship field's dropdown. [More](#sort-options) |
|
||||
| **`placeholder`** | Define a custom text or function to replace the generic default placeholder |
|
||||
| **`appearance`** | Set to `drawer` or `select` to change the behavior of the field. Defaults to `select`. |
|
||||
|
||||
|
||||
@@ -23,14 +23,14 @@ Instead, you can invest your time and effort into learning the underlying open-s
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](./overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](./overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](./overview#validation). |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](./overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](../authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](./overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](./overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](../configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
|
||||
@@ -35,18 +35,18 @@ export const MySelectField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
|
||||
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-options) for more details. |
|
||||
@@ -54,7 +54,6 @@ export const MySelectField: Field = {
|
||||
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`filterOptions`** | Dynamically filter which options are available based on the user, data, etc. [More details](#filteroptions) |
|
||||
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
|
||||
| **`virtual`** | Provide `true` to disable field in the database, or provide a string path to [link the field with a relationship](/docs/fields/relationship#linking-virtual-fields-with-relationships). See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
|
||||
|
||||
@@ -68,61 +67,6 @@ _\* An asterisk denotes that a property is required._
|
||||
used as a GraphQL enum.
|
||||
</Banner>
|
||||
|
||||
### filterOptions
|
||||
|
||||
Used to dynamically filter which options are available based on the current user, document data, or other criteria.
|
||||
|
||||
Some examples of this might include:
|
||||
|
||||
- Restricting options based on a user's role, e.g. admin-only options
|
||||
- Displaying different options based on the value of another field, e.g. a city/state selector
|
||||
|
||||
The result of `filterOptions` will determine:
|
||||
|
||||
- Which options are displayed in the Admin Panel
|
||||
- Which options can be saved to the database
|
||||
|
||||
To do this, use the `filterOptions` property in your [Field Config](./overview):
|
||||
|
||||
```ts
|
||||
import type { Field } from 'payload'
|
||||
|
||||
export const MySelectField: Field = {
|
||||
// ...
|
||||
// highlight-start
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: 'One',
|
||||
value: 'one',
|
||||
},
|
||||
{
|
||||
label: 'Two',
|
||||
value: 'two',
|
||||
},
|
||||
{
|
||||
label: 'Three',
|
||||
value: 'three',
|
||||
},
|
||||
],
|
||||
filterOptions: ({ options, data }) =>
|
||||
data.disallowOption1
|
||||
? options.filter(
|
||||
(option) =>
|
||||
(typeof option === 'string' ? options : option.value) !== 'one',
|
||||
)
|
||||
: options,
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** This property is similar to `filterOptions` in
|
||||
[Relationship](./relationship) or [Upload](./upload) fields, except that the
|
||||
return value of this function is simply an array of options, not a query
|
||||
constraint.
|
||||
</Banner>
|
||||
|
||||
## Admin Options
|
||||
|
||||
To customize the appearance and behavior of the Select Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
|
||||
@@ -139,7 +83,7 @@ export const MySelectField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Select Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Select Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -45,7 +45,7 @@ Each tab must have either a `name` or `label` and the required `fields` array. Y
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** | Groups field data into an object when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** | Groups field data into an object when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | The label to render on the tab itself. Required when name is undefined, defaults to name converted to words. |
|
||||
| **`fields`** \* | The fields to render within this tab. |
|
||||
| **`description`** | Optionally render a description within this tab to describe the contents of the tab itself. |
|
||||
|
||||
@@ -30,18 +30,18 @@ export const MyTextField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -70,7 +70,7 @@ export const MyTextField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Text Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Text Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -30,18 +30,18 @@ export const MyTextareaField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
|
||||
@@ -67,7 +67,7 @@ export const MyTextareaField: Field = {
|
||||
}
|
||||
```
|
||||
|
||||
The Textarea Field inherits all of the default admin options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
The Textarea Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
@@ -32,8 +32,8 @@ export const MyUIField: Field = {
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | A unique identifier for this field. |
|
||||
| **`label`** | Human-readable label for this UI field. |
|
||||
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit View. [More details](./overview#field). |
|
||||
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More details](./overview#cell). |
|
||||
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit View. [More](./overview#field) |
|
||||
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](./overview#cell) |
|
||||
| **`admin.disableListColumn`** | Set `disableListColumn` to `true` to prevent the UI field from appearing in the list view column selector. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
|
||||
@@ -46,23 +46,23 @@ export const MyUploadField: Field = {
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More details](/docs/fields/overview#field-names). |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. **Note: the related collection must be configured to support Uploads.** |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More details](#filtering-upload-options). |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
|
||||
| **`hasMany`** | Boolean which, if set to true, allows this field to have many relations instead of only one. |
|
||||
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. Used with hasMany. |
|
||||
| **`maxRows`** | A number for the most allowed items during validation when a value is present. Used with hasMany. |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](../queries/depth) |
|
||||
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More details](/docs/fields/overview#validation). |
|
||||
| **`index`** | Build an [index](../database/indexes) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
|
||||
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More details](/docs/fields/overview#default-values). |
|
||||
| **`displayPreview`** | Enable displaying preview of the uploaded file. Overrides related Collection's `displayPreview` option. [More details](/docs/upload/overview#collection-upload-options). |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`displayPreview`** | Enable displaying preview of the uploaded file. Overrides related Collection's `displayPreview` option. [More](/docs/upload/overview#collection-upload-options). |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. [Admin Options](./overview#admin-options). |
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
---
|
||||
title: Folders
|
||||
label: Overview
|
||||
order: 10
|
||||
desc: Folders allow you to group documents across collections, and are a great way to organize your content.
|
||||
keywords: folders, folder, content organization
|
||||
---
|
||||
|
||||
Folders allow you to group documents across collections, and are a great way to organize your content. Folders are built on top of relationship fields, when you enable folders on a collection, Payload adds a hidden relationship field `folders`, that relates to a folder — or no folder. Folders also have the `folder` field, allowing folders to be nested within other folders.
|
||||
|
||||
The configuration for folders is done in two places, the collection config and the Payload config. The collection config is where you enable folders, and the Payload config is where you configure the global folder settings.
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** The Folders feature is currently in beta and may be subject to
|
||||
change in minor versions updates prior to being stable.
|
||||
</Banner>
|
||||
|
||||
## Folder Configuration
|
||||
|
||||
On the payload config, you can configure the following settings under the `folders` property:
|
||||
|
||||
```ts
|
||||
// Type definition
|
||||
|
||||
type RootFoldersConfiguration = {
|
||||
/**
|
||||
* If true, the browse by folder view will be enabled
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
browseByFolder?: boolean
|
||||
/**
|
||||
* An array of functions to be ran when the folder collection is initialized
|
||||
* This allows plugins to modify the collection configuration
|
||||
*/
|
||||
collectionOverrides?: (({
|
||||
collection,
|
||||
}: {
|
||||
collection: CollectionConfig
|
||||
}) => CollectionConfig | Promise<CollectionConfig>)[]
|
||||
/**
|
||||
* Ability to view hidden fields and collections related to folders
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
debug?: boolean
|
||||
/**
|
||||
* The Folder field name
|
||||
*
|
||||
* @default "folder"
|
||||
*/
|
||||
fieldName?: string
|
||||
/**
|
||||
* Slug for the folder collection
|
||||
*
|
||||
* @default "payload-folders"
|
||||
*/
|
||||
slug?: string
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// Example usage
|
||||
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
folders: {
|
||||
// highlight-start
|
||||
debug: true, // optional
|
||||
collectionOverrides: [
|
||||
async ({ collection }) => {
|
||||
return collection
|
||||
},
|
||||
], // optional
|
||||
fieldName: 'folder', // optional
|
||||
slug: 'payload-folders', // optional
|
||||
// highlight-end
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Collection Configuration
|
||||
|
||||
To enable folders on a collection, you need to set the `admin.folders` property to `true` on the collection config. This will add a hidden relationship field to the collection that relates to a folder — or no folder.
|
||||
|
||||
```ts
|
||||
// Type definition
|
||||
|
||||
type CollectionFoldersConfiguration =
|
||||
| boolean
|
||||
| {
|
||||
/**
|
||||
* If true, the collection will be included in the browse by folder view
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
browseByFolder?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// Example usage
|
||||
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
collections: [
|
||||
{
|
||||
slug: 'pages',
|
||||
// highlight-start
|
||||
folders: true, // defaults to false
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
@@ -81,7 +81,7 @@ To install a Database Adapter, you can run **one** of the following commands:
|
||||
|
||||
#### 2. Copy Payload files into your Next.js app folder
|
||||
|
||||
Payload installs directly in your Next.js `/app` folder, and you'll need to place some files into that folder for Payload to run. You can copy these files from the [Blank Template](<https://github.com/payloadcms/payload/tree/main/templates/blank/src/app/(payload)>) on GitHub. Once you have the required Payload files in place in your `/app` folder, you should have something like this:
|
||||
Payload installs directly in your Next.js `/app` folder, and you'll need to place some files into that folder for Payload to run. You can copy these files from the [Blank Template](https://github.com/payloadcms/payload/tree/main/templates/blank/src/app/(payload)) on GitHub. Once you have the required Payload files in place in your `/app` folder, you should have something like this:
|
||||
|
||||
```plaintext
|
||||
app/
|
||||
|
||||
@@ -16,15 +16,14 @@ The labels you provide for your Collections and Globals are used to name the Gra
|
||||
|
||||
At the top of your Payload Config you can define all the options to manage GraphQL.
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) |
|
||||
| `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground in production environments, defaults to true. [More](/docs/graphql/overview#graphql-playground) |
|
||||
| `disableIntrospectionInProduction` | A boolean that if false will enable the GraphQL introspection in production environments, defaults to true. |
|
||||
| `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. |
|
||||
| `validationRules` | A function that takes the ExecutionArgs and returns an array of ValidationRules. |
|
||||
| Option | Description |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) |
|
||||
| `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground, defaults to true. [More](/docs/graphql/overview#graphql-playground) |
|
||||
| `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. |
|
||||
| `validationRules` | A function that takes the ExecutionArgs and returns an array of ValidationRules. |
|
||||
|
||||
## Collections
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ The following arguments are provided to the `beforeValidate` hook:
|
||||
|
||||
### beforeChange
|
||||
|
||||
Immediately before validation, beforeChange hooks will run during create and update operations. At this stage, the data should be treated as unvalidated user input. There is no guarantee that required fields exist or that fields are in the correct format. As such, using this data for side effects requires manual validation. You can optionally modify the shape of the data to be saved.
|
||||
Immediately following validation, `beforeChange` hooks will run within `create` and `update` operations. At this stage, you can be confident that the data that will be saved to the document is valid in accordance to your field validations. You can optionally modify the shape of data to be saved.
|
||||
|
||||
```ts
|
||||
import type { CollectionBeforeChangeHook } from 'payload'
|
||||
@@ -160,7 +160,6 @@ The following arguments are provided to the `afterChange` hook:
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`operation`** | The name of the operation that this hook is running within. |
|
||||
| **`previousDoc`** | The Document before changes were applied. |
|
||||
|
||||
@@ -23,7 +23,7 @@ Let's see examples on how context can be used in the first two scenarios mention
|
||||
|
||||
### Passing Data Between Hooks
|
||||
|
||||
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it in the context of a later hook.
|
||||
To pass data between hooks, you can assign values to context in an earlier hook in the lifecycle of a request and expect it the context in a later hook.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -128,18 +128,20 @@ const MyCollection: CollectionConfig = {
|
||||
|
||||
## TypeScript
|
||||
|
||||
The default TypeScript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare module` syntax.
|
||||
The default TypeScript interface for `context` is `{ [key: string]: unknown }`. If you prefer a more strict typing in your project or when authoring plugins for others, you can override this using the `declare` syntax.
|
||||
|
||||
This is known as [module augmentation / declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation), a TypeScript feature which allows us to add properties to existing types. Simply put this in any `.ts` or `.d.ts` file:
|
||||
This is known as "type augmentation", a TypeScript feature which allows us to add types to existing types. Simply put this in any `.ts` or `.d.ts` file:
|
||||
|
||||
```ts
|
||||
import { RequestContext as OriginalRequestContext } from 'payload'
|
||||
|
||||
declare module 'payload' {
|
||||
// Augment the RequestContext interface to include your custom properties
|
||||
export interface RequestContext {
|
||||
// Create a new interface that merges your additional fields with the original one
|
||||
export interface RequestContext extends OriginalRequestContext {
|
||||
myObject?: string
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will add the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as module augmentation can mess up your types if you do it wrong.
|
||||
This will add the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
|
||||
|
||||
@@ -128,7 +128,6 @@ The following arguments are provided to the `afterChange` hook:
|
||||
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
|
||||
| **`context`** | Custom context passed between hooks. [More details](./context). |
|
||||
| **`data`** | The incoming data passed through the operation. |
|
||||
| **`doc`** | The resulting Document after changes are applied. |
|
||||
| **`previousDoc`** | The Document before changes were applied. |
|
||||
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
|
||||
|
||||
@@ -93,108 +93,12 @@ All Hooks can be written as either synchronous or asynchronous functions. Choosi
|
||||
|
||||
#### Asynchronous
|
||||
|
||||
If the Hook should modify data before a Document is updated or created, and it relies on asynchronous actions such as fetching data from a third party, it might make sense to define your Hook as an asynchronous function. This way you can be sure that your Hook completes before the operation's lifecycle continues.
|
||||
|
||||
Async hooks are run in series - so if you have two async hooks defined, the second hook will wait for the first to complete before it starts.
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** If your hook executes a long-running task that doesn't affect the
|
||||
response in any way, consider [offloading it to the job
|
||||
queue](#offloading-long-running-tasks). That will free up the request to
|
||||
continue processing without waiting for the task to complete.
|
||||
</Banner>
|
||||
If the Hook should modify data before a Document is updated or created, and it relies on asynchronous actions such as fetching data from a third party, it might make sense to define your Hook as an asynchronous function. This way you can be sure that your Hook completes before the operation's lifecycle continues. Async hooks are run in series - so if you have two async hooks defined, the second hook will wait for the first to complete before it starts.
|
||||
|
||||
#### Synchronous
|
||||
|
||||
If your Hook simply performs a side-effect, such as mutating document data, it might be okay to define it synchronously, so the Payload operation does not have to wait for your hook to complete.
|
||||
If your Hook simply performs a side-effect, such as updating a CRM, it might be okay to define it synchronously, so the Payload operation does not have to wait for your hook to complete.
|
||||
|
||||
## Server-only Execution
|
||||
|
||||
Hooks are only triggered on the server and are automatically excluded from the client-side bundle. This means that you can safely use sensitive business logic in your Hooks without worrying about exposing it to the client.
|
||||
|
||||
## Performance
|
||||
|
||||
Hooks are a powerful way to customize the behavior of your APIs, but some hooks are run very often and can add significant overhead to your requests if not optimized.
|
||||
|
||||
When building hooks, combine together as many of these strategies as possible to ensure your hooks are as performant as they can be.
|
||||
|
||||
<Banner type="success">
|
||||
For more performance tips, see the [Performance
|
||||
documentation](../performance/overview).
|
||||
</Banner>
|
||||
|
||||
### Writing efficient hooks
|
||||
|
||||
Consider when hooks are run. One common pitfall is putting expensive logic in hooks that run very often.
|
||||
|
||||
For example, the `read` operation runs on every read request, so avoid putting expensive logic in a `beforeRead` or `afterRead` hook.
|
||||
|
||||
```ts
|
||||
{
|
||||
hooks: {
|
||||
beforeRead: [
|
||||
async () => {
|
||||
// This runs on every read request - avoid expensive logic here
|
||||
await doSomethingExpensive()
|
||||
return data
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Instead, you might want to use a `beforeChange` or `afterChange` hook, which only runs when a document is created or updated.
|
||||
|
||||
```ts
|
||||
{
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ context }) => {
|
||||
// This is more acceptable here, although still should be mindful of performance
|
||||
await doSomethingExpensive()
|
||||
// ...
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Using Hook Context
|
||||
|
||||
Use [Hook Context](./context) avoid prevent infinite loops or avoid repeating expensive operations across multiple hooks in the same request.
|
||||
|
||||
```ts
|
||||
{
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
async ({ context }) => {
|
||||
const somethingExpensive = await doSomethingExpensive()
|
||||
context.somethingExpensive = somethingExpensive
|
||||
// ...
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
To learn more, see the [Hook Context documentation](./context).
|
||||
|
||||
### Offloading to the jobs queue
|
||||
|
||||
If your hooks perform any long-running tasks that don't direct affect request lifecycle, consider offloading them to the [jobs queue](../jobs-queue/overview). This will free up the request to continue processing without waiting for the task to complete.
|
||||
|
||||
```ts
|
||||
{
|
||||
hooks: {
|
||||
afterChange: [
|
||||
async ({ doc, req }) => {
|
||||
// Offload to job queue
|
||||
await req.payload.jobs.queue(...)
|
||||
// ...
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
To learn more, see the [Job Queue documentation](../jobs-queue/overview).
|
||||
|
||||
@@ -63,50 +63,19 @@ const config = buildConfig({
|
||||
export default config
|
||||
```
|
||||
|
||||
## Enabling Content Source Maps
|
||||
|
||||
Now in your Next.js app, you need to add the `encodeSourceMaps` query parameter to your API requests. This will tell Payload to include the Content Source Maps in the API response.
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** For performance reasons, this should only be done when in draft mode
|
||||
or on preview deployments.
|
||||
</Banner>
|
||||
|
||||
#### REST API
|
||||
|
||||
If you're using the REST API, include the `?encodeSourceMaps=true` search parameter.
|
||||
Now in your Next.js app, include the `?encodeSourceMaps=true` parameter in any of your API requests. For performance reasons, this should only be done when in draft mode or on preview deployments.
|
||||
|
||||
```ts
|
||||
if (isDraftMode || process.env.VERCEL_ENV === 'preview') {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_PAYLOAD_CMS_URL}/api/pages?encodeSourceMaps=true&where[slug][equals]=${slug}`,
|
||||
`${process.env.NEXT_PUBLIC_PAYLOAD_CMS_URL}/api/pages?where[slug][equals]=${slug}&encodeSourceMaps=true`,
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Local API
|
||||
|
||||
If you're using the Local API, include the `encodeSourceMaps` via the `context` property.
|
||||
|
||||
```ts
|
||||
if (isDraftMode || process.env.VERCEL_ENV === 'preview') {
|
||||
const res = await payload.find({
|
||||
collection: 'pages',
|
||||
where: {
|
||||
slug: {
|
||||
equals: slug,
|
||||
},
|
||||
},
|
||||
context: {
|
||||
encodeSourceMaps: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! You are now ready to enter Edit Mode and begin visually editing your content.
|
||||
|
||||
## Edit Mode
|
||||
#### Edit Mode
|
||||
|
||||
To see Content Link on your site, you first need to visit any preview deployment on Vercel and login using the Vercel Toolbar. When Content Source Maps are detected on the page, a pencil icon will appear in the toolbar. Clicking this icon will enable Edit Mode, highlighting all editable fields on the page in blue.
|
||||
|
||||
@@ -125,9 +94,7 @@ const { cleaned, encoded } = vercelStegaSplit(text)
|
||||
|
||||
### Blocks and array fields
|
||||
|
||||
All `blocks` and `array` fields by definition do not have plain text strings to encode. For this reason, they are automatically given an additional `_encodedSourceMap` property, which you can use to enable Content Link on entire _sections_ of your site.
|
||||
|
||||
You can then specify the editing container by adding the `data-vercel-edit-target` HTML attribute to any top-level element of your block.
|
||||
All `blocks` and `array` fields by definition do not have plain text strings to encode. For this reason, they are given an additional `_encodedSourceMap` property, which you can use to enable Content Link on entire _sections_ of your site. You can then specify the editing container by adding the `data-vercel-edit-target` HTML attribute to any top-level element of your block.
|
||||
|
||||
```ts
|
||||
<div data-vercel-edit-target>
|
||||
|
||||
@@ -68,26 +68,3 @@ Here's a quick overview:
|
||||
- Workflows are groupings of specific tasks which should be run in-order, and can be retried from a specific point of failure
|
||||
- A Job is an instance of a single task or workflow which will be executed
|
||||
- A Queue is a way to segment your jobs into different "groups" - for example, some to run nightly, and others to run every 10 minutes
|
||||
|
||||
### Visualizing Jobs in the Admin UI
|
||||
|
||||
By default, the internal `payload-jobs` collection is hidden from the Payload Admin Panel. To make this collection visible for debugging or inspection purposes, you can override its configuration using `jobsCollectionOverrides`.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
export default buildConfig({
|
||||
// ... other config
|
||||
jobs: {
|
||||
// ... other job settings
|
||||
jobsCollectionOverrides: ({ defaultJobsCollection }) => {
|
||||
if (!defaultJobsCollection.admin) {
|
||||
defaultJobsCollection.admin = {}
|
||||
}
|
||||
|
||||
defaultJobsCollection.admin.hidden = false
|
||||
return defaultJobsCollection
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -30,9 +30,7 @@ As mentioned above, you can queue jobs, but the jobs won't run unless a worker p
|
||||
|
||||
### Cron jobs
|
||||
|
||||
The `jobs.autoRun` property allows you to configure cron jobs that automatically run queued jobs at specified intervals. Note that this does not _queue_ new jobs - only _runs_ jobs that are already in the specified queue.
|
||||
|
||||
**Example**:
|
||||
You can use the `jobs.autoRun` property to configure cron jobs:
|
||||
|
||||
```ts
|
||||
export default buildConfig({
|
||||
@@ -82,12 +80,6 @@ await fetch('/api/payload-jobs/run?limit=100&queue=nightly', {
|
||||
|
||||
This endpoint is automatically mounted for you and is helpful in conjunction with serverless platforms like Vercel, where you might want to use Vercel Cron to invoke a serverless function that executes your jobs.
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `limit`: The maximum number of jobs to run in this invocation (default: 10).
|
||||
- `queue`: The name of the queue to run jobs from. If not specified, jobs will be run from the `default` queue.
|
||||
- `allQueues`: If set to `true`, all jobs from all queues will be run. This will ignore the `queue` parameter.
|
||||
|
||||
**Vercel Cron Example**
|
||||
|
||||
If you're deploying on Vercel, you can add a `vercel.json` file in the root of your project that configures Vercel Cron to invoke the `run` endpoint on a cron schedule.
|
||||
@@ -145,15 +137,11 @@ If you want to process jobs programmatically from your server-side code, you can
|
||||
**Run all jobs:**
|
||||
|
||||
```ts
|
||||
// Run all jobs from the `default` queue - default limit is 10
|
||||
const results = await payload.jobs.run()
|
||||
|
||||
// You can customize the queue name and limit by passing them as arguments:
|
||||
await payload.jobs.run({ queue: 'nightly', limit: 100 })
|
||||
|
||||
// Run all jobs from all queues:
|
||||
await payload.jobs.run({ allQueues: true })
|
||||
|
||||
// You can provide a where clause to filter the jobs that should be run:
|
||||
await payload.jobs.run({
|
||||
where: { 'input.message': { equals: 'secret' } },
|
||||
@@ -170,22 +158,10 @@ const results = await payload.jobs.runByID({
|
||||
|
||||
### Bin script
|
||||
|
||||
Finally, you can process jobs via the bin script that comes with Payload out of the box. By default, this script will run jobs from the `default` queue, with a limit of 10 jobs per invocation:
|
||||
Finally, you can process jobs via the bin script that comes with Payload out of the box.
|
||||
|
||||
```sh
|
||||
npx payload jobs:run
|
||||
```
|
||||
|
||||
You can override the default queue and limit by passing the `--queue` and `--limit` flags:
|
||||
|
||||
```sh
|
||||
npx payload jobs:run --queue myQueue --limit 15
|
||||
```
|
||||
|
||||
If you want to run all jobs from all queues, you can pass the `--all-queues` flag:
|
||||
|
||||
```sh
|
||||
npx payload jobs:run --all-queues
|
||||
npx payload jobs:run --queue default --limit 10
|
||||
```
|
||||
|
||||
In addition, the bin script allows you to pass a `--cron` flag to the `jobs:run` command to run the jobs on a scheduled, cron basis:
|
||||
|
||||
@@ -33,7 +33,7 @@ Simply add a task to the `jobs.tasks` array in your Payload config. A task consi
|
||||
| `onSuccess` | Function to be executed if the task succeeds. |
|
||||
| `retries` | Specify the number of times that this step should be retried if it fails. If this is undefined, the task will either inherit the retries from the workflow or have no retries. If this is 0, the task will not be retried. By default, this is undefined. |
|
||||
|
||||
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks up a Job that includes this task.
|
||||
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks picks up a Job that includes this task.
|
||||
|
||||
It should return an object with an `output` key, which should contain the output of the task as you've defined.
|
||||
|
||||
@@ -213,7 +213,7 @@ export default buildConfig({
|
||||
|
||||
## Nested tasks
|
||||
|
||||
You can run sub-tasks within an existing task, by using the `tasks` or `inlineTask` arguments passed to the task `handler` function:
|
||||
You can run sub-tasks within an existing task, by using the `tasks` or `ìnlineTask` arguments passed to the task `handler` function:
|
||||
|
||||
```ts
|
||||
export default buildConfig({
|
||||
|
||||
@@ -260,7 +260,7 @@ If you are using relationships or uploads in your front-end application, and you
|
||||
{
|
||||
// ...
|
||||
// If your site is running on a different domain than your Payload server,
|
||||
// This will allow requests to be made between the two domains
|
||||
// This will allows requests to be made between the two domains
|
||||
cors: [
|
||||
'http://localhost:3001' // Your front-end application
|
||||
],
|
||||
|
||||
@@ -329,7 +329,7 @@ available:
|
||||
// responseHeaders: { ... } // returned headers from the response
|
||||
// }
|
||||
|
||||
const result = await payload.auth({ headers, canSetHeaders: false })
|
||||
const result = await payload.auth({ headers })
|
||||
```
|
||||
|
||||
### Login
|
||||
|
||||
@@ -393,7 +393,7 @@ export default function LoginForm() {
|
||||
|
||||
### Logout
|
||||
|
||||
Logs out the current user by clearing the authentication cookie and current sessions.
|
||||
Logs out the current user by clearing the authentication cookie.
|
||||
|
||||
#### Importing the `logout` function
|
||||
|
||||
@@ -401,7 +401,7 @@ Logs out the current user by clearing the authentication cookie and current sess
|
||||
import { logout } from '@payloadcms/next/auth'
|
||||
```
|
||||
|
||||
Similar to the login function, you now need to pass your Payload config to this function and this cannot be done in a client component. Use a helper server function as shown below. To ensure all sessions are cleared, set `allSessions: true` in the options, if you wish to logout but keep current sessions active, you can set this to `false` or leave it `undefined`.
|
||||
Similar to the login function, you now need to pass your Payload config to this function and this cannot be done in a client component. Use a helper server function as shown below.
|
||||
|
||||
```ts
|
||||
'use server'
|
||||
@@ -411,7 +411,7 @@ import config from '@payload-config'
|
||||
|
||||
export async function logoutAction() {
|
||||
try {
|
||||
return await logout({ allSessions: true, config })
|
||||
return await logout({ config })
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Logout failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
@@ -434,7 +434,7 @@ export default function LogoutButton() {
|
||||
|
||||
### Refresh
|
||||
|
||||
Refreshes the authentication token and current session for the logged-in user.
|
||||
Refreshes the authentication token for the logged-in user.
|
||||
|
||||
#### Importing the `refresh` function
|
||||
|
||||
@@ -453,6 +453,7 @@ import config from '@payload-config'
|
||||
export async function refreshAction() {
|
||||
try {
|
||||
return await refresh({
|
||||
collection: 'users', // pass your collection slug
|
||||
config,
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
---
|
||||
title: Performance
|
||||
label: Overview
|
||||
order: 10
|
||||
desc: Ensure your Payload app runs as quickly and efficiently as possible.
|
||||
keywords: performance, optimization, indexes, depth, select, block references, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Payload is designed with performance in mind, but its customizability means that there are many ways to configure your app that can impact performance.
|
||||
|
||||
With this in mind, Payload provides several options and best practices to help you optimize your app's specific performance needs. This includes the database, APIs, and Admin Panel.
|
||||
|
||||
Whether you're building an app or troubleshooting an existing one, follow these guidelines to ensure that it runs as quickly and efficiently as possible.
|
||||
|
||||
## Building your application
|
||||
|
||||
### Database proximity
|
||||
|
||||
The proximity of your database to your server can significantly impact performance. Ensure that your database is hosted in the same region as your server to minimize latency and improve response times.
|
||||
|
||||
### Indexing your fields
|
||||
|
||||
If a particular field is queried often, build an [Index](../database/indexes) for that field to produce faster queries.
|
||||
|
||||
When your query runs, the database will not search the entire document to find that one field, but will instead use the index to quickly locate the data.
|
||||
|
||||
To learn more, see the [Indexes](../database/indexes) docs.
|
||||
|
||||
### Querying your data
|
||||
|
||||
There are several ways to optimize your [Queries](../queries/overview). Many of these options directly impact overall database overhead, response sizes, and/or computational load and can significantly improve performance.
|
||||
|
||||
When building queries, combine as many of these options together as possible. This will ensure your queries are as efficient as they can be.
|
||||
|
||||
To learn more, see the [Query Performance](../queries/overview#performance) docs.
|
||||
|
||||
### Optimizing your APIs
|
||||
|
||||
When querying data through Payload APIs, the request lifecycle includes running hooks, access control, validations, and other operations that can add significant overhead to the request.
|
||||
|
||||
To optimize your APIs, any custom logic should be as efficient as possible. This includes writing lightweight hooks, preventing memory leaks, offloading long-running tasks, and optimizing custom validations.
|
||||
|
||||
To learn more, see the [Hooks Performance](../hooks/overview#performance) docs.
|
||||
|
||||
### Writing efficient validations
|
||||
|
||||
If your validation functions are asynchronous or computationally heavy, ensure they only run when necessary.
|
||||
|
||||
To learn more, see the [Validation Performance](../fields/overview#validation-performance) docs.
|
||||
|
||||
### Optimizing custom components
|
||||
|
||||
When building custom components in the Admin Panel, ensure that they are as efficient as possible. This includes using React best practices such as memoization, lazy loading, and avoiding unnecessary re-renders.
|
||||
|
||||
To learn more, see the [Custom Components Performance](../admin/custom-components#performance) docs.
|
||||
|
||||
## Other Best Practices
|
||||
|
||||
### Block references
|
||||
|
||||
Use [Block References](../fields/blocks#block-references) to share the same block across multiple fields without bloating the config. This will reduce the number of fields to traverse when processing permissions, etc. and can can significantly reduce the amount of data sent from the server to the client in the Admin Panel.
|
||||
|
||||
For example, if you have a block that is used in multiple fields, you can define it once and reference it in each field.
|
||||
|
||||
To do this, use the `blockReferences` option in your blocks field:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
blocks: [
|
||||
{
|
||||
slug: 'TextBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'text',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
collections: [
|
||||
{
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'content',
|
||||
type: 'blocks',
|
||||
// highlight-start
|
||||
blockReferences: ['TextBlock'],
|
||||
blocks: [], // Required to be empty, for compatibility reasons
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'pages',
|
||||
fields: [
|
||||
{
|
||||
name: 'content',
|
||||
type: 'blocks',
|
||||
// highlight-start
|
||||
blockReferences: ['TextBlock'],
|
||||
blocks: [], // Required to be empty, for compatibility reasons
|
||||
// highlight-end
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Using the cached Payload instance
|
||||
|
||||
Ensure that you do not instantiate Payload unnecessarily. Instead, Payload provides a caching mechanism to reuse the same instance across your app.
|
||||
|
||||
To do this, use the `getPayload` function to get the cached instance of Payload:
|
||||
|
||||
```ts
|
||||
import { getPayload } from 'payload'
|
||||
import config from '@payload-config'
|
||||
|
||||
const myFunction = async () => {
|
||||
const payload = await getPayload({ config })
|
||||
|
||||
// use payload here
|
||||
}
|
||||
```
|
||||
|
||||
### When to make direct-to-db calls
|
||||
|
||||
<Banner type="warning">
|
||||
**Warning:** Direct database calls bypass all hooks and validations. Only use
|
||||
this method when you are certain that the operation is safe and does not
|
||||
require any of these features.
|
||||
</Banner>
|
||||
|
||||
Making direct database calls can significantly improve performance by bypassing much of the request lifecycle such as hooks, validations, and other overhead associated with Payload APIs.
|
||||
|
||||
For example, this can be especially useful for the `update` operation, where Payload would otherwise need to make multiple API calls to fetch, update, and fetch again. Making a direct database call can reduce this to a single operation.
|
||||
|
||||
To do this, use the `payload.db` methods:
|
||||
|
||||
```ts
|
||||
await payload.db.updateOne({
|
||||
collection: 'posts',
|
||||
id: post.id,
|
||||
data: {
|
||||
title: 'New Title',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** Direct database methods do not start a
|
||||
[transaction](../database/transactions). You have to start that yourself.
|
||||
</Banner>
|
||||
|
||||
#### Returning
|
||||
|
||||
To prevent unnecessary database computation and reduce the size of the response, you can also set `returning: false` in your direct database calls if you don't need the updated document returned to you.
|
||||
|
||||
```ts
|
||||
await payload.db.updateOne({
|
||||
collection: 'posts',
|
||||
id: post.id,
|
||||
data: { title: 'New Title' }, // See note above ^ about Postgres
|
||||
// highlight-start
|
||||
returning: false,
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** The `returning` option is only available on direct-to-db methods.
|
||||
E.g. those on the `payload.db` object. It is not exposed to the Local API.
|
||||
</Banner>
|
||||
|
||||
### Avoid bundling the entire UI library in your front-end
|
||||
|
||||
If your front-end imports from `@payloadcms/ui`, ensure that you do not bundle the entire package as this can significantly increase your bundle size.
|
||||
|
||||
To do this, import using the full path to the specific component you need:
|
||||
|
||||
```ts
|
||||
import { Button } from '@payloadcms/ui/elements/Button'
|
||||
```
|
||||
|
||||
Custom components within the Admin Panel, however, do not have this same restriction and can import directly from `@payloadcms/ui`:
|
||||
|
||||
```ts
|
||||
import { Button } from '@payloadcms/ui'
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** Use
|
||||
[`@next/bundle-analyzer`](https://nextjs.org/docs/app/guides/package-bundling)
|
||||
to analyze your component tree and identify unnecessary re-renders or large
|
||||
components that could be optimized.
|
||||
</Banner>
|
||||
|
||||
## Optimizing local development
|
||||
|
||||
Everything mentioned above applies to local development as well, but there are a few additional steps you can take to optimize your local development experience.
|
||||
|
||||
### Enable Turbopack
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** In the future this will be the default. Use as your own risk.
|
||||
</Banner>
|
||||
|
||||
Add `--turbo` to your dev script to significantly speed up your local development server start time.
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "next dev --turbo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Only bundle server packages in production
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** This is enabled by default in `create-payload-app` since v3.28.0. If
|
||||
you created your app after this version, you don't need to do anything.
|
||||
</Banner>
|
||||
|
||||
By default, Next.js bundles both server and client code. However, during development, bundling certain server packages isn't necessary.
|
||||
|
||||
Payload has thousands of modules, slowing down compilation.
|
||||
|
||||
Setting this option skips bundling Payload server modules during development. Fewer files to compile means faster compilation speeds.
|
||||
|
||||
To do this, add the `devBundleServerPackages` option to `withPayload` in your `next.config.js` file:
|
||||
|
||||
```ts
|
||||
const nextConfig = {
|
||||
// your existing next config
|
||||
}
|
||||
|
||||
export default withPayload(nextConfig, { devBundleServerPackages: false })
|
||||
```
|
||||
@@ -85,7 +85,6 @@ formBuilderPlugin({
|
||||
checkbox: true,
|
||||
number: true,
|
||||
message: true,
|
||||
date: false,
|
||||
payment: false,
|
||||
},
|
||||
})
|
||||
@@ -350,18 +349,6 @@ Maps to a `checkbox` input on your front-end. Used to collect a boolean value.
|
||||
| `width` | string | The width of the field on the front-end. |
|
||||
| `required` | checkbox | Whether or not the field is required when submitted. |
|
||||
|
||||
### Date
|
||||
|
||||
Maps to a `date` input on your front-end. Used to collect a date value.
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------- | -------- | ---------------------------------------------------- |
|
||||
| `name` | string | The name of the field. |
|
||||
| `label` | string | The label of the field. |
|
||||
| `defaultValue` | date | The default value of the field. |
|
||||
| `width` | string | The width of the field on the front-end. |
|
||||
| `required` | checkbox | Whether or not the field is required when submitted. |
|
||||
|
||||
### Number
|
||||
|
||||
Maps to a `number` input on your front-end. Used to collect a number.
|
||||
@@ -434,67 +421,6 @@ formBuilderPlugin({
|
||||
})
|
||||
```
|
||||
|
||||
### Customizing the date field default value
|
||||
|
||||
You can custommise the default value of the date field and any other aspects of the date block in this way.
|
||||
Note that the end submission source will be responsible for the timezone of the date. Payload only stores the date in UTC format.
|
||||
|
||||
```ts
|
||||
import { fields as formFields } from '@payloadcms/plugin-form-builder'
|
||||
|
||||
// payload.config.ts
|
||||
formBuilderPlugin({
|
||||
fields: {
|
||||
// date: true, // just enable it without any customizations
|
||||
date: {
|
||||
...formFields.date,
|
||||
fields: [
|
||||
...(formFields.date && 'fields' in formFields.date
|
||||
? formFields.date.fields.map((field) => {
|
||||
if ('name' in field && field.name === 'defaultValue') {
|
||||
return {
|
||||
...field,
|
||||
timezone: true, // optionally enable timezone
|
||||
admin: {
|
||||
...field.admin,
|
||||
description: 'This is a date field',
|
||||
},
|
||||
}
|
||||
}
|
||||
return field
|
||||
})
|
||||
: []),
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Preventing generated schema naming conflicts
|
||||
|
||||
Plugin fields can cause GraphQL type name collisions with your own blocks or collections. This results in errors like:
|
||||
|
||||
```plaintext
|
||||
Error: Schema must contain uniquely named types but contains multiple types named "Country"
|
||||
```
|
||||
|
||||
You can resolve this by overriding:
|
||||
|
||||
- `graphQL.singularName` in your collection config (for GraphQL schema conflicts)
|
||||
- `interfaceName` in your block config
|
||||
- `interfaceName` in the plugin field config
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
formBuilderPlugin({
|
||||
fields: {
|
||||
country: {
|
||||
interfaceName: 'CountryFormBlock', // overrides the generated type name to avoid a conflict
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Email
|
||||
|
||||
This plugin relies on the [email configuration](../email/overview) defined in your Payload configuration. It will read from your config and attempt to send your emails using the credentials provided.
|
||||
|
||||
@@ -16,8 +16,8 @@ This plugin sets up multi-tenancy for your application from within your [Admin P
|
||||
If you need help, check out our [Community
|
||||
Help](https://payloadcms.com/community-help). If you think you've found a bug,
|
||||
please [open a new
|
||||
issue](https://github.com/payloadcms/payload/issues/new/choose) with as much
|
||||
detail as possible.
|
||||
issue](https://github.com/payloadcms/payload/issues/new?assignees=&labels=plugin%3A%multi-tenant&template=bug_report.md&title=plugin-multi-tenant%3A)
|
||||
with as much detail as possible.
|
||||
</Banner>
|
||||
|
||||
## Core features
|
||||
@@ -35,7 +35,7 @@ This plugin sets up multi-tenancy for your application from within your [Admin P
|
||||
By default this plugin cleans up documents when a tenant is deleted. You should ensure you have
|
||||
strong access control on your tenants collection to prevent deletions by unauthorized users.
|
||||
|
||||
You can disable this behavior by setting `cleanupAfterTenantDelete` to `false` in the plugin options.
|
||||
You can disabled this behavior by setting `cleanupAfterTenantDelete` to `false` in the plugin options.
|
||||
|
||||
</Banner>
|
||||
|
||||
|
||||
@@ -180,8 +180,8 @@ and `createBreadcrumbField` methods. They will merge your customizations overtop
|
||||
|
||||
```ts
|
||||
import type { CollectionConfig } from 'payload'
|
||||
import { createParentField } from '@payloadcms/plugin-nested-docs'
|
||||
import { createBreadcrumbsField } from '@payloadcms/plugin-nested-docs'
|
||||
import { createParentField } from '@payloadcms/plugin-nested-docs/fields'
|
||||
import { createBreadcrumbsField } from '@payloadcms/plugin-nested-docs/fields'
|
||||
|
||||
const examplePageConfig: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
|
||||
@@ -74,32 +74,16 @@ import * as Sentry from '@sentry/nextjs'
|
||||
|
||||
const config = buildConfig({
|
||||
collections: [Pages, Media],
|
||||
plugins: [sentryPlugin({ Sentry })],
|
||||
plugins: [
|
||||
sentryPlugin({
|
||||
Sentry,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
export default config
|
||||
```
|
||||
|
||||
## Instrumenting Database Queries
|
||||
|
||||
If you want Sentry to capture Postgres query performance traces, you need to inject the Sentry-patched `pg` driver into the Postgres adapter. This ensures Sentry’s instrumentation hooks into your database calls.
|
||||
|
||||
```ts
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { buildConfig } from 'payload'
|
||||
import { sentryPlugin } from '@payloadcms/plugin-sentry'
|
||||
import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
import pg from 'pg'
|
||||
|
||||
export default buildConfig({
|
||||
db: postgresAdapter({
|
||||
pool: { connectionString: process.env.DATABASE_URL },
|
||||
pg, // Inject the patched pg driver for Sentry instrumentation
|
||||
}),
|
||||
plugins: [sentryPlugin({ Sentry })],
|
||||
})
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
- `Sentry` : Sentry | **required**
|
||||
|
||||
@@ -115,7 +115,6 @@ Set the `uploadsCollection` to your application's upload-enabled collection slug
|
||||
##### `tabbedUI`
|
||||
|
||||
When the `tabbedUI` property is `true`, it appends an `SEO` tab onto your config using Payload's [Tabs Field](../fields/tabs). If your collection is not already tab-enabled, meaning the first field in your config is not of type `tabs`, then one will be created for you called `Content`. Defaults to `false`.
|
||||
Note that the order of plugins or fields in your config may affect whether or not the plugin can smartly merge tabs with your existing fields. If you have a complex structure we recommend you [make use of the fields directly](#direct-use-of-fields) instead of relying on this config option.
|
||||
|
||||
<Banner type="info">
|
||||
If you wish to continue to use top-level or sidebar fields with `tabbedUI`,
|
||||
|
||||
@@ -309,3 +309,7 @@ import {
|
||||
...
|
||||
} from '@payloadcms/plugin-stripe/types';
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
The [Templates Directory](https://github.com/payloadcms/payload/tree/main/templates) contains an official [E-commerce Template](https://github.com/payloadcms/payload/tree/main/templates/ecommerce) which demonstrates exactly how to configure this plugin in Payload and implement it on your front-end. You can also check out [How to Build An E-Commerce Site With Next.js](https://payloadcms.com/blog/how-to-build-an-e-commerce-site-with-nextjs) post for a bit more context around this template.
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
title: Building without a DB connection
|
||||
label: Building without a DB connection
|
||||
order: 10
|
||||
desc: You don't want to have a DB connection while building your Docker container? Learn how to prevent that!
|
||||
keywords: deployment, production, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
One of the most common problems when building a site for production, especially with Docker - is the DB connection requirement.
|
||||
|
||||
The important note is that Payload by itself does not have this requirement, But [Next.js' SSG ](https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation) does if any of your route segments have SSG enabled (which is default, unless you opted out or used a [Dynamic API](https://nextjs.org/docs/app/deep-dive/caching#dynamic-apis)) and use the Payload Local API.
|
||||
|
||||
Solutions:
|
||||
|
||||
## Using the experimental-build-mode Next.js build flag
|
||||
|
||||
You can run Next.js build using the `pnpm next build --experimental-build-mode compile` command to only compile the code without static generation, which does not require a DB connection. In that case, your pages will be rendered dynamically, but after that, you can still generate static pages using the `pnpm next build --experimental-build-mode generate` command when you have a DB connection.
|
||||
|
||||
When running `pnpm next build --experimental-build-mode compile`, environment variables prefixed with `NEXT_PUBLIC` will not be inlined and will be `undefined` on the client. To make these variables available, either run `pnpm next build --experimental-build-mode generate` if a DB connection is available, or use `pnpm next build --experimental-build-mode generate-env` if you do not have a DB connection.
|
||||
|
||||
[Next.js documentation](https://nextjs.org/docs/pages/api-reference/cli/next#next-build-options)
|
||||
|
||||
## Opting-out of SSG
|
||||
|
||||
You can opt out of SSG by adding this all the route segment files:
|
||||
|
||||
```ts
|
||||
export const dynamic = 'force-dynamic'
|
||||
```
|
||||
|
||||
**Note that it will disable static optimization and your site will be slower**.
|
||||
More on [Next.js documentation](https://nextjs.org/docs/app/deep-dive/caching#opting-out-2)
|
||||
@@ -150,7 +150,7 @@ Follow the docs to configure any one of these storage providers. For local devel
|
||||
## 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 `DATABASE_URI` if needed. If you don't want to have a DB connection and your build requires that, learn [here](./building-without-a-db-connection) how to prevent that.
|
||||
variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `DATABASE_URI` if needed.
|
||||
|
||||
In your Next.js config, set the `output` property `standalone`.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: query, documents, pagination, documentation, Content Management System
|
||||
|
||||
Documents in Payload can have relationships to other Documents. This is true for both [Collections](../configuration/collections) as well as [Globals](../configuration/globals). When you query a Document, you can specify the depth at which to populate any of its related Documents either as full objects, or only their IDs.
|
||||
|
||||
Since Documents can be infinitely nested or recursively related, it's important to be able to control how deep your API populates. Depth can impact the performance of your queries by affecting the load on the database and the size of the response.
|
||||
Depth will optimize the performance of your application by limiting the amount of processing made in the database and significantly reducing the amount of data returned. Since Documents can be infinitely nested or recursively related, it's important to be able to control how deep your API populates.
|
||||
|
||||
For example, when you specify a `depth` of `0`, the API response might look like this:
|
||||
|
||||
@@ -48,9 +48,7 @@ import type { Payload } from 'payload'
|
||||
const getPosts = async (payload: Payload) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
// highlight-start
|
||||
depth: 2,
|
||||
// highlight-end
|
||||
depth: 2, // highlight-line
|
||||
})
|
||||
|
||||
return posts
|
||||
@@ -67,9 +65,7 @@ const getPosts = async (payload: Payload) => {
|
||||
To specify depth in the [REST API](../rest-api/overview), you can use the `depth` parameter in your query:
|
||||
|
||||
```ts
|
||||
// highlight-start
|
||||
fetch('https://localhost:3000/api/posts?depth=2')
|
||||
// highlight-end
|
||||
fetch('https://localhost:3000/api/posts?depth=2') // highlight-line
|
||||
.then((res) => res.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
@@ -79,24 +75,6 @@ fetch('https://localhost:3000/api/posts?depth=2')
|
||||
the `/api/globals` endpoint.
|
||||
</Banner>
|
||||
|
||||
## Default Depth
|
||||
|
||||
If no depth is specified in the request, Payload will use its default depth for all requests. By default, this is set to `2`.
|
||||
|
||||
To change the default depth on the application level, you can use the `defaultDepth` option in your root Payload config:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
|
||||
export default buildConfig({
|
||||
// ...
|
||||
// highlight-start
|
||||
defaultDepth: 1,
|
||||
// highlight-end
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
## Max Depth
|
||||
|
||||
Fields like the [Relationship Field](../fields/relationship) or the [Upload Field](../fields/upload) can also set a maximum depth. If exceeded, this will limit the population depth regardless of what the depth might be on the request.
|
||||
@@ -111,9 +89,7 @@ To set a max depth for a field, use the `maxDepth` property in your field config
|
||||
name: 'author',
|
||||
type: 'relationship',
|
||||
relationTo: 'users',
|
||||
// highlight-start
|
||||
maxDepth: 2,
|
||||
// highlight-end
|
||||
maxDepth: 2, // highlight-line
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ The following operators are available for use in queries:
|
||||
<Banner type="success">
|
||||
**Tip:** If you know your users will be querying on certain fields a lot, add
|
||||
`index: true` to the Field Config. This will speed up searches using that
|
||||
field immensely. [More details](../database/indexes).
|
||||
field immensely.
|
||||
</Banner>
|
||||
|
||||
### And / Or Logic
|
||||
@@ -192,130 +192,3 @@ const getPosts = async () => {
|
||||
// Continue to handle the response below...
|
||||
}
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
There are several ways to optimize your queries. Many of these options directly impact overall database overhead, response sizes, and/or computational load and can significantly improve performance.
|
||||
|
||||
When building queries, combine as many of these strategies together as possible to ensure your queries are as performant as they can be.
|
||||
|
||||
<Banner type="success">
|
||||
For more performance tips, see the [Performance
|
||||
documentation](../performance/overview).
|
||||
</Banner>
|
||||
|
||||
### Indexes
|
||||
|
||||
Build [Indexes](../database/indexes) for fields that are often queried or sorted by.
|
||||
|
||||
When your query runs, the database will not search the entire document to find that one field, but will instead use the index to quickly locate the data.
|
||||
|
||||
This is done by adding `index: true` to the Field Config for that field:
|
||||
|
||||
```ts
|
||||
// In your collection configuration
|
||||
{
|
||||
name: 'posts',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
// highlight-start
|
||||
index: true, // Add an index to the title field
|
||||
// highlight-end
|
||||
},
|
||||
// Other fields...
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
To learn more, see the [Indexes documentation](../database/indexes).
|
||||
|
||||
### Depth
|
||||
|
||||
Set the [Depth](./depth) to only the level that you need to avoid populating unnecessary related documents.
|
||||
|
||||
Relationships will only populate down to the specified depth, and any relationships beyond that depth will only return the ID of the related document.
|
||||
|
||||
```ts
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: { ... },
|
||||
// highlight-start
|
||||
depth: 0, // Only return the IDs of related documents
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
To learn more, see the [Depth documentation](./depth).
|
||||
|
||||
### Limit
|
||||
|
||||
Set the [Limit](./pagination#limit) if you can reliably predict the number of matched documents, such as when querying on a unique field.
|
||||
|
||||
```ts
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
slug: {
|
||||
equals: 'unique-post-slug',
|
||||
},
|
||||
},
|
||||
// highlight-start
|
||||
limit: 1, // Only expect one document to be returned
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** Use in combination with `pagination: false` for best performance when
|
||||
querying by unique fields.
|
||||
</Banner>
|
||||
|
||||
To learn more, see the [Limit documentation](./pagination#limit).
|
||||
|
||||
### Select
|
||||
|
||||
Use the [Select API](./select) to only process and return the fields you need.
|
||||
|
||||
This will reduce the amount of data returned from the request, and also skip processing of any fields that are not selected, such as running their field hooks.
|
||||
|
||||
```ts
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: { ... },
|
||||
// highlight-start
|
||||
select: [{
|
||||
title: true,
|
||||
}],
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
This is a basic example, but there are many ways to use the Select API, including selecting specific fields, excluding fields, etc.
|
||||
|
||||
To learn more, see the [Select documentation](./select).
|
||||
|
||||
### Pagination
|
||||
|
||||
[Disable Pagination](./pagination#disabling-pagination) if you can reliably predict the number of matched documents, such as when querying on a unique field.
|
||||
|
||||
```ts
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
slug: {
|
||||
equals: 'unique-post-slug',
|
||||
},
|
||||
},
|
||||
// highlight-start
|
||||
pagination: false, // Return all matched documents without pagination
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** Use in combination with `limit: 1` for best performance when querying
|
||||
by unique fields.
|
||||
</Banner>
|
||||
|
||||
To learn more, see the [Pagination documentation](./pagination).
|
||||
|
||||
@@ -6,61 +6,9 @@ desc: Payload queries are equipped with automatic pagination so you create pagin
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
With Pagination you can limit the number of documents returned per page, and get a specific page of results. This is useful for creating paginated lists of documents within your application.
|
||||
All collection `find` queries are paginated automatically. Responses are returned with top-level meta data related to pagination, and returned documents are nested within a `docs` array.
|
||||
|
||||
All paginated responses include documents nested within a `docs` array, and return top-level meta data related to pagination such as `totalDocs`, `limit`, `totalPages`, `page`, and more.
|
||||
|
||||
<Banner type="success">
|
||||
**Note:** Collection `find` queries are paginated automatically.
|
||||
</Banner>
|
||||
|
||||
## Options
|
||||
|
||||
All Payload APIs support the pagination controls below. With them, you can create paginated lists of documents within your application:
|
||||
|
||||
| Control | Default | Description |
|
||||
| ------------ | ------- | ------------------------------------------------------------------------- |
|
||||
| `limit` | `10` | Limits the number of documents returned per page. [More details](#limit). |
|
||||
| `pagination` | `true` | Set to `false` to disable pagination and return all documents. |
|
||||
| `page` | `1` | Get a specific page number. |
|
||||
|
||||
## Local API
|
||||
|
||||
To specify pagination controls in the [Local API](../local-api/overview), you can use the `limit`, `page`, and `pagination` options in your query:
|
||||
|
||||
```ts
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
const getPosts = async (payload: Payload) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
// highlight-start
|
||||
limit: 10,
|
||||
page: 2,
|
||||
// highlight-end
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
## REST API
|
||||
|
||||
With the [REST API](../rest-api/overview), you can use the pagination controls below as query strings:
|
||||
|
||||
```ts
|
||||
// highlight-start
|
||||
fetch('https://localhost:3000/api/posts?limit=10&page=2')
|
||||
// highlight-end
|
||||
.then((res) => res.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
All paginated responses include documents nested within a `docs` array, and return top-level meta data related to pagination.
|
||||
|
||||
The `find` operation includes the following properties in its response:
|
||||
**`Find` response properties:**
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
@@ -103,59 +51,16 @@ The `find` operation includes the following properties in its response:
|
||||
}
|
||||
```
|
||||
|
||||
## Limit
|
||||
## Pagination controls
|
||||
|
||||
You can specify a `limit` to restrict the number of documents returned per page.
|
||||
All Payload APIs support the pagination controls below. With them, you can create paginated lists of documents within your application:
|
||||
|
||||
<Banner type="warning">
|
||||
**Reminder:** By default, any query with `limit: 0` will automatically
|
||||
[disable pagination](#disabling-pagination).
|
||||
</Banner>
|
||||
| Control | Default | Description |
|
||||
| ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `limit` | `10` | Limits the number of documents returned per page - set to `0` to show all documents, we automatically disabled pagination for you when `limit` is `0` for optimisation |
|
||||
| `pagination` | `true` | Set to `false` to disable pagination and return all documents |
|
||||
| `page` | `1` | Get a specific page number |
|
||||
|
||||
#### Performance benefits
|
||||
|
||||
If you are querying for a specific document and can reliably expect only one document to match, you can set a limit of `1` (or another low number) to reduce the number of database lookups and improve performance.
|
||||
|
||||
For example, when querying a document by a unique field such as `slug`, you can set the limit to `1` since you know there will only be one document with that slug.
|
||||
|
||||
To do this, set the `limit` option in your query:
|
||||
|
||||
```ts
|
||||
await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
slug: {
|
||||
equals: 'post-1',
|
||||
},
|
||||
},
|
||||
// highlight-start
|
||||
limit: 1,
|
||||
// highlight-end
|
||||
})
|
||||
```
|
||||
|
||||
## Disabling pagination
|
||||
|
||||
Disabling pagination can improve performance by reducing the overhead of pagination calculations and improve query speed.
|
||||
### 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.
|
||||
|
||||
To do this, set `pagination: false` in your query:
|
||||
|
||||
```ts
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
const getPost = async (payload: Payload) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
where: {
|
||||
title: { equals: 'My Post' },
|
||||
},
|
||||
// highlight-start
|
||||
pagination: false,
|
||||
// highlight-end
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
```
|
||||
|
||||
@@ -6,9 +6,9 @@ desc: Payload select determines which fields are selected to the result.
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
By default, Payload's APIs will return _all fields_ for a given collection or global. But, you may not need all of that data for all of your queries. Sometimes, you might want just a few fields from the response.
|
||||
By default, Payload's APIs will return _all fields_ for a given collection or global. But, you may not need all of that data for all of your queries. Sometimes, you might want just a few fields from the response, which can speed up the Payload API and reduce the amount of JSON that is sent to you from the API.
|
||||
|
||||
With the Select API, you can define exactly which fields you'd like to retrieve. This can impact the performance of your queries by affecting the load on the database and the size of the response.
|
||||
This is where Payload's `select` feature comes in. Here, you can define exactly which fields you'd like to retrieve from the API.
|
||||
|
||||
## Local API
|
||||
|
||||
@@ -21,7 +21,6 @@ import type { Payload } from 'payload'
|
||||
const getPosts = async (payload: Payload) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
// highlight-start
|
||||
select: {
|
||||
text: true,
|
||||
// select a specific field from group
|
||||
@@ -30,8 +29,7 @@ const getPosts = async (payload: Payload) => {
|
||||
},
|
||||
// select all fields from array
|
||||
array: true,
|
||||
},
|
||||
// highlight-end
|
||||
}, // highlight-line
|
||||
})
|
||||
|
||||
return posts
|
||||
@@ -42,14 +40,12 @@ const getPosts = async (payload: Payload) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
// Select everything except for array and group.number
|
||||
// highlight-start
|
||||
select: {
|
||||
array: false,
|
||||
group: {
|
||||
number: false,
|
||||
},
|
||||
},
|
||||
// highlight-end
|
||||
}, // highlight-line
|
||||
})
|
||||
|
||||
return posts
|
||||
@@ -71,10 +67,8 @@ To specify select in the [REST API](../rest-api/overview), you can use the `sele
|
||||
|
||||
```ts
|
||||
fetch(
|
||||
// highlight-start
|
||||
'https://localhost:3000/api/posts?select[color]=true&select[group][number]=true',
|
||||
// highlight-end
|
||||
)
|
||||
) // highlight-line
|
||||
.then((res) => res.json())
|
||||
.then((data) => console.log(data))
|
||||
```
|
||||
@@ -155,7 +149,7 @@ export const Pages: CollectionConfig<'pages'> = {
|
||||
not be able to construct the correct file URL, instead returning `url: null`.
|
||||
</Banner>
|
||||
|
||||
## Populate
|
||||
## populate
|
||||
|
||||
Setting `defaultPopulate` will enforce that each time Payload performs a "population" of a related document, only the fields specified will be queried and returned. However, you can override `defaultPopulate` with the `populate` property in the Local and REST API:
|
||||
|
||||
|
||||
@@ -6,15 +6,13 @@ desc: Payload sort allows you to order your documents by a field in ascending or
|
||||
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
|
||||
---
|
||||
|
||||
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order.
|
||||
|
||||
If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order. In Local API multiple fields can be specified by using an array of strings. In REST API multiple fields can be specified by separating fields with comma. The minus symbol can be in front of individual fields.
|
||||
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order. In Local API multiple fields can be specified by using an array of strings. In REST API multiple fields can be specified by separating fields with comma. The minus symbol can be in front of individual fields.
|
||||
|
||||
Because sorting is handled by the database, the field cannot be a [Virtual Field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) unless it's [linked with a relationship field](/docs/fields/relationship#linking-virtual-fields-with-relationships). It must be stored in the database to be searchable.
|
||||
|
||||
<Banner type="success">
|
||||
**Tip:** For performance reasons, it is recommended to enable `index: true`
|
||||
for the fields that will be sorted upon. [More details](../database/indexes).
|
||||
for the fields that will be sorted upon. [More details](../fields/overview).
|
||||
</Banner>
|
||||
|
||||
## Local API
|
||||
|
||||
@@ -46,12 +46,11 @@ const config = buildConfig({
|
||||
|
||||
The following options are available for Query Presets:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `access` | Used to define custom collection-level access control that applies to all presets. [More details](#access-control). |
|
||||
| `filterConstraints` | Used to define which constraints are available to users when managing presets. [More details](#constraint-access-control). |
|
||||
| `constraints` | Used to define custom document-level access control that apply to individual presets. [More details](#document-access-control). |
|
||||
| `labels` | Custom labels to use for the Query Presets collection. |
|
||||
| Option | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `access` | Used to define custom collection-level access control that applies to all presets. [More details](#access-control). |
|
||||
| `constraints` | Used to define custom document-level access control that apply to individual presets. [More details](#document-access-control). |
|
||||
| `labels` | Custom labels to use for the Query Presets collection. |
|
||||
|
||||
## Access Control
|
||||
|
||||
@@ -60,7 +59,7 @@ Query Presets are subject to the same [Access Control](../access-control/overvie
|
||||
Access Control for Query Presets can be customized in two ways:
|
||||
|
||||
1. [Collection Access Control](#collection-access-control): Applies to all presets. These rules are not controllable by the user and are statically defined in the config.
|
||||
2. [Document Access Control](#document-access-control): Applies to each individual preset. These rules are controllable by the user and are dynamically defined on each record in the database.
|
||||
2. [Document Access Control](#document-access-control): Applies to each individual preset. These rules are controllable by the user and are saved to the document.
|
||||
|
||||
### Collection Access Control
|
||||
|
||||
@@ -98,7 +97,7 @@ This example restricts all Query Presets to users with the role of `admin`.
|
||||
|
||||
### Document Access Control
|
||||
|
||||
You can also define access control rules that apply to each specific preset. Users have the ability to define and modify these rules on the fly as they manage presets. These are saved dynamically in the database on each record.
|
||||
You can also define access control rules that apply to each specific preset. Users have the ability to define and modify these rules on the fly as they manage presets. These are saved dynamically in the database on each document.
|
||||
|
||||
When a user manages a preset, document-level access control options will be available to them in the Admin Panel for each operation.
|
||||
|
||||
@@ -151,8 +150,8 @@ const config = buildConfig({
|
||||
}),
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
})
|
||||
```
|
||||
@@ -172,39 +171,3 @@ The following options are available for each constraint:
|
||||
| `value` | The value to store in the database when this constraint is selected. |
|
||||
| `fields` | An array of fields to render when this constraint is selected. |
|
||||
| `access` | A function that determines the access control rules for this constraint. |
|
||||
|
||||
### Constraint Access Control
|
||||
|
||||
Used to dynamically filter which constraints are available based on the current user, document data, or other criteria.
|
||||
|
||||
Some examples of this might include:
|
||||
|
||||
- Ensuring that only "admins" are allowed to make a preset available to "everyone"
|
||||
- Preventing the "onlyMe" option from being selected based on a hypothetical "disablePrivatePresets" checkbox
|
||||
|
||||
When a user lacks the permission to set a constraint, the option will either be hidden from them, or disabled if it is already saved to that preset.
|
||||
|
||||
To do this, you can use the `filterConstraints` property in your [Payload Config](../configuration/overview):
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload'
|
||||
|
||||
const config = buildConfig({
|
||||
// ...
|
||||
queryPresets: {
|
||||
// ...
|
||||
// highlight-start
|
||||
filterConstraints: ({ req, options }) =>
|
||||
!req.user?.roles?.includes('admin')
|
||||
? options.filter(
|
||||
(option) =>
|
||||
(typeof option === 'string' ? option : option.value) !==
|
||||
'everyone',
|
||||
)
|
||||
: options,
|
||||
// highlight-end
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
The `filterConstraints` function receives the same arguments as [`filterOptions`](../fields/select#filteroptions) in the [Select field](../fields/select).
|
||||
|
||||
@@ -738,7 +738,7 @@ Payload supports a method override feature that allows you to send GET requests
|
||||
|
||||
### How to Use
|
||||
|
||||
To use this feature, include the `X-Payload-HTTP-Method-Override` header set to `GET` in your POST request. The parameters should be sent in the body of the request with the `Content-Type` set to `application/x-www-form-urlencoded`.
|
||||
To use this feature, include the `X-HTTP-Method-Override` header set to `GET` in your POST request. The parameters should be sent in the body of the request with the `Content-Type` set to `application/x-www-form-urlencoded`.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -753,7 +753,7 @@ const res = await fetch(`${api}/${collectionSlug}`, {
|
||||
headers: {
|
||||
'Accept-Language': i18n.language,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'X-Payload-HTTP-Method-Override': 'GET',
|
||||
'X-HTTP-Method-Override': 'GET',
|
||||
},
|
||||
body: qs.stringify({
|
||||
depth: 1,
|
||||
|
||||
@@ -6,14 +6,14 @@ desc: Converting between lexical richtext and HTML
|
||||
keywords: lexical, richtext, html
|
||||
---
|
||||
|
||||
## Rich Text to HTML
|
||||
## Converting Rich Text to HTML
|
||||
|
||||
There are two main approaches to convert your Lexical-based rich text to HTML:
|
||||
|
||||
1. **Generate HTML on-demand (Recommended)**: Convert JSON to HTML wherever you need it, on-demand.
|
||||
2. **Generate HTML within your Collection**: Create a new field that automatically converts your saved JSON content to HTML. This is not recommended because it adds overhead to the Payload API and may not work well with live preview.
|
||||
|
||||
### On-demand
|
||||
### Generating HTML on-demand (Recommended)
|
||||
|
||||
To convert JSON to HTML on-demand, use the `convertLexicalToHTML` function from `@payloadcms/richtext-lexical/html`. Here's an example of how to use it in a React component in your frontend:
|
||||
|
||||
@@ -32,81 +32,61 @@ export const MyComponent = ({ data }: { data: SerializedEditorState }) => {
|
||||
}
|
||||
```
|
||||
|
||||
#### Dynamic Population (Advanced)
|
||||
### Converting Lexical Blocks
|
||||
|
||||
By default, `convertLexicalToHTML` expects fully populated data (e.g. uploads, links, etc.). If you need to dynamically fetch and populate those nodes, use the async variant, `convertLexicalToHTMLAsync`, from `@payloadcms/richtext-lexical/html-async`. You must provide a `populate` function:
|
||||
If your rich text includes Lexical blocks, you need to provide a way to convert them to HTML. For example:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import type { MyInlineBlock, MyTextBlock } from '@/payload-types'
|
||||
import type {
|
||||
DefaultNodeTypes,
|
||||
SerializedBlockNode,
|
||||
SerializedInlineBlockNode,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
|
||||
|
||||
import { getRestPopulateFn } from '@payloadcms/richtext-lexical/client'
|
||||
import { convertLexicalToHTMLAsync } from '@payloadcms/richtext-lexical/html-async'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
export const MyComponent = ({ data }: { data: SerializedEditorState }) => {
|
||||
const [html, setHTML] = useState<null | string>(null)
|
||||
useEffect(() => {
|
||||
async function convert() {
|
||||
const html = await convertLexicalToHTMLAsync({
|
||||
data,
|
||||
populate: getRestPopulateFn({
|
||||
apiURL: `http://localhost:3000/api`,
|
||||
}),
|
||||
})
|
||||
setHTML(html)
|
||||
}
|
||||
|
||||
void convert()
|
||||
}, [data])
|
||||
|
||||
return html && <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
```
|
||||
|
||||
Using the REST populate function will send a separate request for each node. If you need to populate a large number of nodes, this may be slow. For improved performance on the server, you can use the `getPayloadPopulateFn` function:
|
||||
|
||||
```tsx
|
||||
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
|
||||
|
||||
import { getPayloadPopulateFn } from '@payloadcms/richtext-lexical'
|
||||
import { convertLexicalToHTMLAsync } from '@payloadcms/richtext-lexical/html-async'
|
||||
import { getPayload } from 'payload'
|
||||
import {
|
||||
convertLexicalToHTML,
|
||||
type HTMLConvertersFunction,
|
||||
} from '@payloadcms/richtext-lexical/html'
|
||||
import React from 'react'
|
||||
|
||||
import config from '../../config.js'
|
||||
type NodeTypes =
|
||||
| DefaultNodeTypes
|
||||
| SerializedBlockNode<MyTextBlock>
|
||||
| SerializedInlineBlockNode<MyInlineBlock>
|
||||
|
||||
export const MyRSCComponent = async ({
|
||||
data,
|
||||
}: {
|
||||
data: SerializedEditorState
|
||||
}) => {
|
||||
const payload = await getPayload({
|
||||
config,
|
||||
})
|
||||
const htmlConverters: HTMLConvertersFunction<NodeTypes> = ({
|
||||
defaultConverters,
|
||||
}) => ({
|
||||
...defaultConverters,
|
||||
blocks: {
|
||||
// Each key should match your block's slug
|
||||
myTextBlock: ({ node, providedCSSString }) =>
|
||||
`<div style="background-color: red;${providedCSSString}">${node.fields.text}</div>`,
|
||||
},
|
||||
inlineBlocks: {
|
||||
// Each key should match your inline block's slug
|
||||
myInlineBlock: ({ node, providedStyleTag }) =>
|
||||
`<span${providedStyleTag}>${node.fields.text}</span$>`,
|
||||
},
|
||||
})
|
||||
|
||||
const html = await convertLexicalToHTMLAsync({
|
||||
export const MyComponent = ({ data }: { data: SerializedEditorState }) => {
|
||||
const html = convertLexicalToHTML({
|
||||
converters: htmlConverters,
|
||||
data,
|
||||
populate: await getPayloadPopulateFn({
|
||||
currentDepth: 0,
|
||||
depth: 1,
|
||||
payload,
|
||||
}),
|
||||
})
|
||||
|
||||
return html && <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
```
|
||||
|
||||
### HTML field
|
||||
### Outputting HTML from the Collection
|
||||
|
||||
The `lexicalHTMLField()` helper converts JSON to HTML and saves it in a field that is updated every time you read it via an `afterRead` hook. It's generally not recommended for two reasons:
|
||||
|
||||
1. It creates a column with duplicate content in another format.
|
||||
2. In [client-side live preview](/docs/live-preview/client), it makes it not "live".
|
||||
|
||||
Consider using the [on-demand HTML converter above](/docs/rich-text/converting-html#on-demand-recommended) or the [JSX converter](/docs/rich-text/converting-jsx) unless you have a good reason.
|
||||
To automatically generate HTML from the saved richText field in your Collection, use the `lexicalHTMLField()` helper. This approach converts the JSON to HTML using an `afterRead` hook. For instance:
|
||||
|
||||
```ts
|
||||
import type { HTMLConvertersFunction } from '@payloadcms/richtext-lexical/html'
|
||||
@@ -174,59 +154,74 @@ const Pages: CollectionConfig = {
|
||||
}
|
||||
```
|
||||
|
||||
## Blocks to HTML
|
||||
### Generating HTML in Your Frontend with Dynamic Population (Advanced)
|
||||
|
||||
If your rich text includes Lexical blocks, you need to provide a way to convert them to HTML. For example:
|
||||
By default, `convertLexicalToHTML` expects fully populated data (e.g. uploads, links, etc.). If you need to dynamically fetch and populate those nodes, use the async variant, `convertLexicalToHTMLAsync`, from `@payloadcms/richtext-lexical/html-async`. You must provide a `populate` function:
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import type { MyInlineBlock, MyTextBlock } from '@/payload-types'
|
||||
import type {
|
||||
DefaultNodeTypes,
|
||||
SerializedBlockNode,
|
||||
SerializedInlineBlockNode,
|
||||
} from '@payloadcms/richtext-lexical'
|
||||
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
|
||||
|
||||
import {
|
||||
convertLexicalToHTML,
|
||||
type HTMLConvertersFunction,
|
||||
} from '@payloadcms/richtext-lexical/html'
|
||||
import React from 'react'
|
||||
|
||||
type NodeTypes =
|
||||
| DefaultNodeTypes
|
||||
| SerializedBlockNode<MyTextBlock>
|
||||
| SerializedInlineBlockNode<MyInlineBlock>
|
||||
|
||||
const htmlConverters: HTMLConvertersFunction<NodeTypes> = ({
|
||||
defaultConverters,
|
||||
}) => ({
|
||||
...defaultConverters,
|
||||
blocks: {
|
||||
// Each key should match your block's slug
|
||||
myTextBlock: ({ node, providedCSSString }) =>
|
||||
`<div style="background-color: red;${providedCSSString}">${node.fields.text}</div>`,
|
||||
},
|
||||
inlineBlocks: {
|
||||
// Each key should match your inline block's slug
|
||||
myInlineBlock: ({ node, providedStyleTag }) =>
|
||||
`<span${providedStyleTag}>${node.fields.text}</span$>`,
|
||||
},
|
||||
})
|
||||
import { getRestPopulateFn } from '@payloadcms/richtext-lexical/client'
|
||||
import { convertLexicalToHTMLAsync } from '@payloadcms/richtext-lexical/html-async'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
|
||||
export const MyComponent = ({ data }: { data: SerializedEditorState }) => {
|
||||
const html = convertLexicalToHTML({
|
||||
converters: htmlConverters,
|
||||
data,
|
||||
})
|
||||
const [html, setHTML] = useState<null | string>(null)
|
||||
useEffect(() => {
|
||||
async function convert() {
|
||||
const html = await convertLexicalToHTMLAsync({
|
||||
data,
|
||||
populate: getRestPopulateFn({
|
||||
apiURL: `http://localhost:3000/api`,
|
||||
}),
|
||||
})
|
||||
setHTML(html)
|
||||
}
|
||||
|
||||
return <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
void convert()
|
||||
}, [data])
|
||||
|
||||
return html && <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
```
|
||||
|
||||
## HTML to Richtext
|
||||
Using the REST populate function will send a separate request for each node. If you need to populate a large number of nodes, this may be slow. For improved performance on the server, you can use the `getPayloadPopulateFn` function:
|
||||
|
||||
```tsx
|
||||
import type { SerializedEditorState } from '@payloadcms/richtext-lexical/lexical'
|
||||
|
||||
import { getPayloadPopulateFn } from '@payloadcms/richtext-lexical'
|
||||
import { convertLexicalToHTMLAsync } from '@payloadcms/richtext-lexical/html-async'
|
||||
import { getPayload } from 'payload'
|
||||
import React from 'react'
|
||||
|
||||
import config from '../../config.js'
|
||||
|
||||
export const MyRSCComponent = async ({
|
||||
data,
|
||||
}: {
|
||||
data: SerializedEditorState
|
||||
}) => {
|
||||
const payload = await getPayload({
|
||||
config,
|
||||
})
|
||||
|
||||
const html = await convertLexicalToHTMLAsync({
|
||||
data,
|
||||
populate: await getPayloadPopulateFn({
|
||||
currentDepth: 0,
|
||||
depth: 1,
|
||||
payload,
|
||||
}),
|
||||
})
|
||||
|
||||
return html && <div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
```
|
||||
|
||||
## Converting HTML to Richtext
|
||||
|
||||
If you need to convert raw HTML into a Lexical editor state, use `convertHTMLToLexical` from `@payloadcms/richtext-lexical`, along with the [editorConfigFactory to retrieve the editor config](/docs/rich-text/converters#retrieving-the-editor-config):
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ desc: Converting between lexical richtext and JSX
|
||||
keywords: lexical, richtext, jsx
|
||||
---
|
||||
|
||||
## Richtext to JSX
|
||||
## Converting Richtext to JSX
|
||||
|
||||
To convert richtext to JSX, import the `RichText` component from `@payloadcms/richtext-lexical/react` and pass the richtext content to it:
|
||||
|
||||
@@ -28,7 +28,7 @@ The `RichText` component includes built-in converters for common Lexical nodes.
|
||||
populated data to work correctly.
|
||||
</Banner>
|
||||
|
||||
### Internal Links
|
||||
### Converting Internal Links
|
||||
|
||||
By default, Payload doesn't know how to convert **internal** links to JSX, as it doesn't know what the corresponding URL of the internal link is. You'll notice that you get a "found internal link, but internalDocToHref is not provided" error in the console when you try to render content with internal links.
|
||||
|
||||
@@ -81,7 +81,7 @@ export const MyComponent: React.FC<{
|
||||
}
|
||||
```
|
||||
|
||||
### Lexical Blocks
|
||||
### Converting Lexical Blocks
|
||||
|
||||
If your rich text includes custom Blocks or Inline Blocks, you must supply custom converters that match each block's slug. This converter is not included by default, as Payload doesn't know how to render your custom blocks.
|
||||
|
||||
@@ -133,9 +133,9 @@ export const MyComponent: React.FC<{
|
||||
}
|
||||
```
|
||||
|
||||
### Overriding Converters
|
||||
### Overriding Default JSX Converters
|
||||
|
||||
You can override any of the default JSX converters by passing your custom converter, keyed to the node type, to the `converters` prop / the converters function.
|
||||
You can override any of the default JSX converters by passing passing your custom converter, keyed to the node type, to the `converters` prop / the converters function.
|
||||
|
||||
Example - overriding the upload node converter to use next/image:
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ desc: Converting between lexical richtext and Markdown / MDX
|
||||
keywords: lexical, richtext, markdown, md, mdx
|
||||
---
|
||||
|
||||
## Richtext to Markdown
|
||||
## Converting Richtext to Markdown
|
||||
|
||||
If you have access to the Payload Config and the [lexical editor config](/docs/rich-text/converters#retrieving-the-editor-config), you can convert the lexical editor state to Markdown with the following:
|
||||
|
||||
@@ -91,7 +91,7 @@ const Pages: CollectionConfig = {
|
||||
}
|
||||
```
|
||||
|
||||
## Markdown to Richtext
|
||||
## Converting Markdown to Richtext
|
||||
|
||||
If you have access to the Payload Config and the [lexical editor config](/docs/rich-text/converters#retrieving-the-editor-config), you can convert Markdown to the lexical editor state with the following:
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user