Compare commits
167 Commits
ci/experim
...
db-postgre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c84c58c7b4 | ||
|
|
1c1b8f3cec | ||
|
|
3f69f83180 | ||
|
|
371353f153 | ||
|
|
a92c6334b6 | ||
|
|
eb9e771a9c | ||
|
|
ee5390aaca | ||
|
|
a861311c5a | ||
|
|
74c3fe1bb2 | ||
|
|
a2be50279e | ||
|
|
403eb06acf | ||
|
|
f5c2cd74cc | ||
|
|
a6a1963ec6 | ||
|
|
0647c870f1 | ||
|
|
3b88adc7d0 | ||
|
|
82383a5b5f | ||
|
|
f9dda628b2 | ||
|
|
93eb0e4a31 | ||
|
|
2e362f44f4 | ||
|
|
775502b161 | ||
|
|
84d75ce6ca | ||
|
|
175cf229c0 | ||
|
|
bb40bd3efb | ||
|
|
3d74c133aa | ||
|
|
0f6b6ca970 | ||
|
|
8e1692ef10 | ||
|
|
1d1ee913fc | ||
|
|
beca43341f | ||
|
|
84818469ea | ||
|
|
0a259d27b5 | ||
|
|
e2e56a4d58 | ||
|
|
d0f7677d5f | ||
|
|
35956eb837 | ||
|
|
d92af295eb | ||
|
|
493fde5ccc | ||
|
|
c6bd20ef33 | ||
|
|
6d5ac1de1e | ||
|
|
fa3b3dd62d | ||
|
|
1115387744 | ||
|
|
53e8690feb | ||
|
|
4319fe1c6e | ||
|
|
2fee0c0d44 | ||
|
|
7923edd7bc | ||
|
|
5702b83e82 | ||
|
|
63e5c43fe6 | ||
|
|
04f2888135 | ||
|
|
0f69b9c2f8 | ||
|
|
f1bb2f8151 | ||
|
|
ea528b8c10 | ||
|
|
0053e40404 | ||
|
|
605c0be43c | ||
|
|
3152b4c4c5 | ||
|
|
a64b80babc | ||
|
|
5cfde542b1 | ||
|
|
772020963e | ||
|
|
5e083689d0 | ||
|
|
911764a490 | ||
|
|
e3b81d913d | ||
|
|
41b3b17911 | ||
|
|
e9860b36f3 | ||
|
|
14b39fbc85 | ||
|
|
d08e85d08c | ||
|
|
abcbf9974d | ||
|
|
d01437d212 | ||
|
|
06729a0a73 | ||
|
|
2bd7822a16 | ||
|
|
bc7daf6b49 | ||
|
|
feab679ef7 | ||
|
|
be39ed4317 | ||
|
|
570e192eb4 | ||
|
|
22f4967dd4 | ||
|
|
4873c36129 | ||
|
|
f0ec21cdda | ||
|
|
da737bdf8e | ||
|
|
40508880c1 | ||
|
|
8f420d841a | ||
|
|
9022e27308 | ||
|
|
acf2e41312 | ||
|
|
6acfae8ee7 | ||
|
|
20bdd91da4 | ||
|
|
50502834c9 | ||
|
|
2b731c1088 | ||
|
|
983733ad74 | ||
|
|
555d02769a | ||
|
|
682eca2186 | ||
|
|
6affa1c304 | ||
|
|
1d14d9f8b8 | ||
|
|
0abaddc2ef | ||
|
|
57dc93da5d | ||
|
|
21b9453cf4 | ||
|
|
136993ec2b | ||
|
|
63bc4cabe1 | ||
|
|
6a8a6e4ef4 | ||
|
|
9828772890 | ||
|
|
6116573164 | ||
|
|
cab6babd60 | ||
|
|
55399424a1 | ||
|
|
28d3f73c2a | ||
|
|
28a30120dd | ||
|
|
40a0921597 | ||
|
|
7eae86bcb3 | ||
|
|
0b80e4a403 | ||
|
|
b378532ddf | ||
|
|
d419275fb5 | ||
|
|
0fb3a9ca89 | ||
|
|
f43cf185d4 | ||
|
|
5d15955f83 | ||
|
|
2d35e06667 | ||
|
|
d2de6db449 | ||
|
|
a3e78161b5 | ||
|
|
d543665995 | ||
|
|
db7dddf1c5 | ||
|
|
3027a03ad1 | ||
|
|
85e38b7cfd | ||
|
|
9090540ece | ||
|
|
46ef284f6b | ||
|
|
0727dcd963 | ||
|
|
52f8d4f9f0 | ||
|
|
f1fa374ed1 | ||
|
|
6b691eee43 | ||
|
|
be3beabb9b | ||
|
|
1fa00cc25c | ||
|
|
f70943524b | ||
|
|
a67080a291 | ||
|
|
69a99445c9 | ||
|
|
00d8480062 | ||
|
|
7424ba9090 | ||
|
|
ec4d2f97cb | ||
|
|
9d9ac0ec28 | ||
|
|
635e7c26e8 | ||
|
|
c4a4678afb | ||
|
|
a5a91c08a9 | ||
|
|
7db58b482b | ||
|
|
1b914083c8 | ||
|
|
657d14c07b | ||
|
|
fbf8ab72a4 | ||
|
|
997f158149 | ||
|
|
c3be5d1d5e | ||
|
|
250bcd8189 | ||
|
|
a71d37b398 | ||
|
|
5c5523195c | ||
|
|
bff4cf518f | ||
|
|
8015e999cd | ||
|
|
0c905f0da7 | ||
|
|
e691a90a4c | ||
|
|
0b2da4fba7 | ||
|
|
1c6d6788a3 | ||
|
|
ecc7978184 | ||
|
|
1b9ee64a67 | ||
|
|
22b02226c3 | ||
|
|
e4102b88d8 | ||
|
|
a099f55a69 | ||
|
|
1f1445c798 | ||
|
|
741a5e3650 | ||
|
|
365047a3fb | ||
|
|
42c06acd18 | ||
|
|
f2c8ac4a9a | ||
|
|
05e8914db7 | ||
|
|
35191bdd66 | ||
|
|
98890eee1f | ||
|
|
ef43629502 | ||
|
|
c703497924 | ||
|
|
5caad706bb | ||
|
|
aa048d5409 | ||
|
|
aafd538cf8 | ||
|
|
1b42bd207d | ||
|
|
9fac2ef24e |
@@ -8,6 +8,3 @@
|
|||||||
**/dist/**
|
**/dist/**
|
||||||
**/node_modules
|
**/node_modules
|
||||||
**/temp
|
**/temp
|
||||||
playwright.config.ts
|
|
||||||
jest.config.js
|
|
||||||
test/live-preview/next-app
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
/** @type {import('eslint').Linter.Config} */
|
|
||||||
module.exports = {
|
|
||||||
extends: ['@payloadcms'],
|
|
||||||
ignorePatterns: ['README.md', 'packages/**/*.spec.ts'],
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: ['packages/**'],
|
|
||||||
plugins: ['payload'],
|
|
||||||
rules: {
|
|
||||||
'payload/no-jsx-import-statements': 'warn',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['scripts/**'],
|
|
||||||
rules: {
|
|
||||||
'@typescript-eslint/no-unused-vars': 'off',
|
|
||||||
'no-console': 'off',
|
|
||||||
'perfectionist/sort-object-types': 'off',
|
|
||||||
'perfectionist/sort-objects': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
|
||||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['packages/eslint-config-payload/**'],
|
|
||||||
rules: {
|
|
||||||
'perfectionist/sort-objects': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
files: ['package.json', 'tsconfig.json'],
|
|
||||||
rules: {
|
|
||||||
'perfectionist/sort-array-includes': 'off',
|
|
||||||
'perfectionist/sort-astro-attributes': 'off',
|
|
||||||
'perfectionist/sort-classes': 'off',
|
|
||||||
'perfectionist/sort-enums': 'off',
|
|
||||||
'perfectionist/sort-exports': 'off',
|
|
||||||
'perfectionist/sort-imports': 'off',
|
|
||||||
'perfectionist/sort-interfaces': 'off',
|
|
||||||
'perfectionist/sort-jsx-props': 'off',
|
|
||||||
'perfectionist/sort-keys': 'off',
|
|
||||||
'perfectionist/sort-maps': 'off',
|
|
||||||
'perfectionist/sort-named-exports': 'off',
|
|
||||||
'perfectionist/sort-named-imports': 'off',
|
|
||||||
'perfectionist/sort-object-types': 'off',
|
|
||||||
'perfectionist/sort-objects': 'off',
|
|
||||||
'perfectionist/sort-svelte-attributes': 'off',
|
|
||||||
'perfectionist/sort-union-types': 'off',
|
|
||||||
'perfectionist/sort-vue-attributes': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
parserOptions: {
|
|
||||||
project: ['./tsconfig.json'],
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
|
|
||||||
EXPERIMENTAL_useProjectService: true,
|
|
||||||
sourceType: 'module',
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
},
|
|
||||||
root: true,
|
|
||||||
}
|
|
||||||
38
.eslintrc.js
Normal file
38
.eslintrc.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ['@payloadcms'],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||||
|
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['packages/eslint-config-payload/**'],
|
||||||
|
rules: {
|
||||||
|
'perfectionist/sort-objects': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['package.json', 'tsconfig.json'],
|
||||||
|
rules: {
|
||||||
|
'perfectionist/sort-array-includes': 'off',
|
||||||
|
'perfectionist/sort-astro-attributes': 'off',
|
||||||
|
'perfectionist/sort-classes': 'off',
|
||||||
|
'perfectionist/sort-enums': 'off',
|
||||||
|
'perfectionist/sort-exports': 'off',
|
||||||
|
'perfectionist/sort-imports': 'off',
|
||||||
|
'perfectionist/sort-interfaces': 'off',
|
||||||
|
'perfectionist/sort-jsx-props': 'off',
|
||||||
|
'perfectionist/sort-keys': 'off',
|
||||||
|
'perfectionist/sort-maps': 'off',
|
||||||
|
'perfectionist/sort-named-exports': 'off',
|
||||||
|
'perfectionist/sort-named-imports': 'off',
|
||||||
|
'perfectionist/sort-object-types': 'off',
|
||||||
|
'perfectionist/sort-objects': 'off',
|
||||||
|
'perfectionist/sort-svelte-attributes': 'off',
|
||||||
|
'perfectionist/sort-union-types': 'off',
|
||||||
|
'perfectionist/sort-vue-attributes': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
root: true,
|
||||||
|
}
|
||||||
@@ -16,6 +16,3 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
|
|||||||
|
|
||||||
# lint and format create-payload-app
|
# lint and format create-payload-app
|
||||||
5fd3d430001efe86515262ded5e26f00c1451181
|
5fd3d430001efe86515262ded5e26f00c1451181
|
||||||
|
|
||||||
# 3.0 prettier & lint everywhere
|
|
||||||
6789e61488a1d3de56f472ac3214faf344030005
|
|
||||||
|
|||||||
13
.github/CODEOWNERS
vendored
13
.github/CODEOWNERS
vendored
@@ -1,24 +1,32 @@
|
|||||||
# Order matters. The last matching pattern takes precedence.
|
# Order matters. The last matching pattern takes precedence.
|
||||||
|
|
||||||
|
### Catch-all ###
|
||||||
|
* @denolfe @jmikrut @DanRibbens
|
||||||
|
.* @denolfe @jmikrut @DanRibbens
|
||||||
|
|
||||||
### Core ###
|
### Core ###
|
||||||
|
/packages/payload/ @denolfe @jmikrut @DanRibbens
|
||||||
/packages/payload/src/uploads/ @denolfe
|
/packages/payload/src/uploads/ @denolfe
|
||||||
/packages/payload/src/admin/ @jmikrut @jacobsfletch @JarrodMFlesch
|
/packages/payload/src/admin/ @jmikrut @jacobsfletch @JarrodMFlesch
|
||||||
|
|
||||||
### Adapters ###
|
### Adapters ###
|
||||||
|
/packages/bundler-*/ @denolfe @jmikrut @DanRibbens @JarrodMFlesch
|
||||||
/packages/db-*/ @denolfe @jmikrut @DanRibbens
|
/packages/db-*/ @denolfe @jmikrut @DanRibbens
|
||||||
/packages/richtext-*/ @denolfe @jmikrut @DanRibbens @AlessioGr
|
/packages/richtext-*/ @denolfe @jmikrut @DanRibbens @AlessioGr
|
||||||
|
|
||||||
### Plugins ###
|
### Plugins ###
|
||||||
/packages/plugin-*/ @denolfe @jmikrut @DanRibbens
|
/packages/plugin-*/ @denolfe @jmikrut @DanRibbens @jacobsfletch @JarrodMFlesch @AlessioGr
|
||||||
/packages/plugin-cloud*/ @denolfe
|
/packages/plugin-cloud*/ @denolfe
|
||||||
/packages/plugin-form-builder/ @jacobsfletch
|
/packages/plugin-form-builder/ @jacobsfletch
|
||||||
/packages/plugin-live-preview*/ @jacobsfletch
|
/packages/plugin-live-preview*/ @jacobsfletch
|
||||||
/packages/plugin-nested-docs/ @jacobsfletch
|
/packages/plugin-nested-docs/ @jacobsfletch
|
||||||
|
/packages/plugin-password-protection/ @jmikrut
|
||||||
/packages/plugin-redirects/ @jacobsfletch
|
/packages/plugin-redirects/ @jacobsfletch
|
||||||
/packages/plugin-search/ @jacobsfletch
|
/packages/plugin-search/ @jacobsfletch
|
||||||
/packages/plugin-sentry/ @JessChowdhury
|
/packages/plugin-sentry/ @JessChowdhury
|
||||||
/packages/plugin-seo/ @jacobsfletch
|
/packages/plugin-seo/ @jacobsfletch
|
||||||
/packages/plugin-stripe/ @jacobsfletch
|
/packages/plugin-stripe/ @jacobsfletch
|
||||||
|
/packages/plugin-zapier/ @JarrodMFlesch
|
||||||
|
|
||||||
### Examples ###
|
### Examples ###
|
||||||
/examples/ @jacobsfletch
|
/examples/ @jacobsfletch
|
||||||
@@ -27,7 +35,8 @@
|
|||||||
/examples/whitelabel/ @JessChowdhury
|
/examples/whitelabel/ @JessChowdhury
|
||||||
|
|
||||||
### Templates ###
|
### Templates ###
|
||||||
/templates/ @jacobsfletch @denolfe
|
/templates/ @jacobsfletch
|
||||||
|
/templates/blank/ @denolfe
|
||||||
|
|
||||||
### Misc ###
|
### Misc ###
|
||||||
/packages/create-payload-app/ @denolfe
|
/packages/create-payload-app/ @denolfe
|
||||||
|
|||||||
298
.github/workflows/main.yml
vendored
298
.github/workflows/main.yml
vendored
@@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
push:
|
push:
|
||||||
branches: ['main', 'alpha']
|
branches: ['main']
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
changes:
|
changes:
|
||||||
@@ -15,25 +15,25 @@ jobs:
|
|||||||
needs_build: ${{ steps.filter.outputs.needs_build }}
|
needs_build: ${{ steps.filter.outputs.needs_build }}
|
||||||
templates: ${{ steps.filter.outputs.templates }}
|
templates: ${{ steps.filter.outputs.templates }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 25
|
fetch-depth: 25
|
||||||
- uses: dorny/paths-filter@v3
|
- uses: dorny/paths-filter@v2
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
needs_build:
|
needs_build:
|
||||||
- '.github/workflows/**'
|
- '.github/workflows/**'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- 'test/**'
|
- 'test/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
- 'package.json'
|
- 'package.json'
|
||||||
templates:
|
templates:
|
||||||
- 'templates/**'
|
- 'templates/**'
|
||||||
- name: Log all filter results
|
- name: Log all filter results
|
||||||
run: |
|
run: |
|
||||||
echo "needs_build: ${{ steps.filter.outputs.needs_build }}"
|
echo "needs_build: ${{ steps.filter.outputs.needs_build }}"
|
||||||
echo "templates: ${{ steps.filter.outputs.templates }}"
|
echo "templates: ${{ steps.filter.outputs.templates }}"
|
||||||
|
|
||||||
core-build:
|
core-build:
|
||||||
needs: changes
|
needs: changes
|
||||||
@@ -46,12 +46,12 @@ jobs:
|
|||||||
fetch-depth: 25
|
fetch-depth: 25
|
||||||
|
|
||||||
- name: Use Node.js 18
|
- name: Use Node.js 18
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
@@ -61,7 +61,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v3
|
||||||
name: Setup pnpm cache
|
name: Setup pnpm cache
|
||||||
with:
|
with:
|
||||||
path: ${{ env.STORE_PATH }}
|
path: ${{ env.STORE_PATH }}
|
||||||
@@ -71,86 +71,246 @@ jobs:
|
|||||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm run build:core
|
- run: pnpm run build
|
||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: core-build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
database: [mongoose, postgres]
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_DB: payloadtests
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Use Node.js 18
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Restore build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ./*
|
||||||
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
- name: Start PostgreSQL
|
||||||
|
uses: CasperWA/postgresql-action@v1.2
|
||||||
|
with:
|
||||||
|
postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions
|
||||||
|
postgresql db: ${{ env.POSTGRES_DB }}
|
||||||
|
postgresql user: ${{ env.POSTGRES_USER }}
|
||||||
|
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
||||||
|
if: matrix.database == 'postgres'
|
||||||
|
|
||||||
|
- run: sleep 30
|
||||||
|
- name: Configure PostgreSQL
|
||||||
|
run: |
|
||||||
|
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;"
|
||||||
|
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();"
|
||||||
|
echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV
|
||||||
|
if: matrix.database == 'postgres'
|
||||||
|
|
||||||
|
- name: Component Tests
|
||||||
|
run: pnpm test:components
|
||||||
|
|
||||||
|
- name: Integration Tests
|
||||||
|
run: pnpm test:int
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: --max-old-space-size=8096
|
||||||
|
PAYLOAD_DATABASE: ${{ matrix.database }}
|
||||||
|
POSTGRES_URL: ${{ env.POSTGRES_URL }}
|
||||||
|
|
||||||
tests-e2e:
|
tests-e2e:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: core-build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
suite:
|
part: [1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8]
|
||||||
- _community
|
|
||||||
# Add other suites as needed
|
|
||||||
steps:
|
steps:
|
||||||
- name: Use Node.js 18
|
- name: Use Node.js 18
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v2
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 8
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
- name: Install Playwright
|
|
||||||
run: pnpm exec playwright install --with-deps
|
|
||||||
|
|
||||||
- name: E2E Tests
|
- name: E2E Tests
|
||||||
run: pnpm test:e2e ${{ matrix.suite }}
|
uses: nick-fields/retry@v2
|
||||||
|
with:
|
||||||
|
retry_on: error
|
||||||
|
max_attempts: 2
|
||||||
|
timeout_minutes: 15
|
||||||
|
command: pnpm test:e2e --part ${{ matrix.part }} --bail
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v3
|
||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: test-results-${{ matrix.suite }}
|
name: test-results
|
||||||
path: test/test-results/
|
path: test-results/
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
- name: Process and Upload Trace Files
|
tests-type-generation:
|
||||||
if: always()
|
runs-on: ubuntu-latest
|
||||||
run: |
|
needs: core-build
|
||||||
count=0
|
|
||||||
for folder in test/test-results/*; do
|
|
||||||
if [ -d "$folder" ] && [ -f "$folder/trace.zip" ]; then
|
|
||||||
((count++))
|
|
||||||
if [ "$count" -le 5 ]; then
|
|
||||||
test_name=$(basename "$folder")
|
|
||||||
|
|
||||||
echo "Processing $test_name"
|
steps:
|
||||||
|
- name: Use Node.js 18
|
||||||
new_trace_name="trace-${{ matrix.suite }}-$count.zip"
|
uses: actions/setup-node@v3
|
||||||
cp "$folder/trace.zip" "$new_trace_name"
|
|
||||||
echo "$test_name: $new_trace_name" >> map.txt
|
|
||||||
else
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
cat map.txt
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
with:
|
||||||
name: trace-${{ matrix.suite }}-1
|
node-version: 18
|
||||||
path: trace-${{ matrix.suite }}-1.zip
|
|
||||||
|
|
||||||
- name: Display Mapped Names and Links
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Restore build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ./*
|
||||||
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
- name: Generate Payload Types
|
||||||
|
run: pnpm dev:generate-types fields
|
||||||
|
|
||||||
|
- name: Generate GraphQL schema file
|
||||||
|
run: pnpm dev:generate-graphql-schema graphql-schema-gen
|
||||||
|
|
||||||
|
build-packages:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: core-build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
pkg:
|
||||||
|
- db-mongodb
|
||||||
|
- db-postgres
|
||||||
|
- bundler-webpack
|
||||||
|
- bundler-vite
|
||||||
|
- richtext-slate
|
||||||
|
- richtext-lexical
|
||||||
|
- live-preview
|
||||||
|
- live-preview-react
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Use Node.js 18
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Restore build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ./*
|
||||||
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.pkg }}
|
||||||
|
run: pnpm turbo run build --filter=${{ matrix.pkg }}
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: core-build
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
pkg:
|
||||||
|
- create-payload-app
|
||||||
|
- plugin-cloud
|
||||||
|
- plugin-cloud-storage
|
||||||
|
- plugin-form-builder
|
||||||
|
- plugin-nested-docs
|
||||||
|
- plugin-search
|
||||||
|
- plugin-sentry
|
||||||
|
- plugin-seo
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Use Node.js 18
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8
|
||||||
|
run_install: false
|
||||||
|
|
||||||
|
- name: Restore build
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ./*
|
||||||
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.pkg }}
|
||||||
|
run: pnpm turbo run build --filter=${{ matrix.pkg }}
|
||||||
|
|
||||||
|
- name: Test ${{ matrix.pkg }}
|
||||||
|
run: pnpm --filter ${{ matrix.pkg }} run test
|
||||||
|
if: matrix.pkg != 'create-payload-app' # degit doesn't work within GitHub Actions
|
||||||
|
|
||||||
|
templates:
|
||||||
|
needs: changes
|
||||||
|
if: ${{ needs.changes.outputs.templates == 'true' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
template: [blank, website, ecommerce]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 25
|
||||||
|
|
||||||
|
- name: Use Node.js 18
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
|
||||||
|
- name: Start MongoDB
|
||||||
|
uses: supercharge/mongodb-github-action@1.10.0
|
||||||
|
with:
|
||||||
|
mongodb-version: 6.0
|
||||||
|
|
||||||
|
- name: Build Template
|
||||||
run: |
|
run: |
|
||||||
while IFS= read -r line; do
|
cd templates/${{ matrix.template }}
|
||||||
IFS=': ' read -r test_name trace_name <<< "$line"
|
cp .env.example .env
|
||||||
echo "${test_name}: https://github.com/payloadcms/payload/actions/runs/${GITHUB_RUN_ID}/artifacts/${trace_name}"
|
yarn install
|
||||||
done < map.txt
|
yarn build
|
||||||
shell: bash
|
yarn generate:types
|
||||||
|
|||||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -3,21 +3,10 @@ package-lock.json
|
|||||||
dist
|
dist
|
||||||
/.idea/*
|
/.idea/*
|
||||||
!/.idea/runConfigurations
|
!/.idea/runConfigurations
|
||||||
!/.idea/payload.iml
|
|
||||||
|
|
||||||
test-results
|
test-results
|
||||||
.devcontainer
|
.devcontainer
|
||||||
.localstack
|
|
||||||
/migrations
|
/migrations
|
||||||
.localstack
|
|
||||||
.turbo
|
|
||||||
|
|
||||||
.turbo
|
|
||||||
|
|
||||||
# Ignore test directory media folder/files
|
|
||||||
/media
|
|
||||||
test/media
|
|
||||||
/versions
|
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
@@ -290,4 +279,3 @@ $RECYCLE.BIN/
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
|
|
||||||
/build
|
/build
|
||||||
.swc
|
|
||||||
|
|||||||
54
.idea/payload.iml
generated
54
.idea/payload.iml
generated
@@ -1,54 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/payload/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/payload/components" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/payload/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.swc" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/examples" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/media" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/create-payload-app/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/create-payload-app/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/db-mongodb/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/db-mongodb/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/db-postgres/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/db-postgres/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/graphql/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/graphql/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/live-preview-react/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/live-preview-react/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/live-preview/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/live-preview/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/next/.swc" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/next/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/payload/fields" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud-storage/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud-storage/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-form-builder/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-nested-docs/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-nested-docs/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-redirects/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-redirects/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-search/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-search/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-sentry/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-seo/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-seo/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-stripe/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/richtext-lexical/.turbo" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/packages/richtext-lexical/dist" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/templates" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/test/.swc" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/versions" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
5
.idea/runConfigurations/Run_Dev_Fields.xml
generated
5
.idea/runConfigurations/Run_Dev_Fields.xml
generated
@@ -1,8 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="--no-deprecation fields" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
|
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="fields" path-to-js-file="node_modules/.pnpm/nodemon@3.0.1/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||||
<envs>
|
|
||||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
|
||||||
</envs>
|
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
5
.idea/runConfigurations/Run_Dev__community.xml
generated
5
.idea/runConfigurations/Run_Dev__community.xml
generated
@@ -1,8 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="--no-deprecation _community" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
|
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="_community" path-to-js-file="node_modules/.pnpm/nodemon@3.0.1/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||||
<envs>
|
|
||||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
|
||||||
</envs>
|
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
@@ -1 +1 @@
|
|||||||
v18.19.1
|
v18.17.1
|
||||||
|
|||||||
@@ -9,4 +9,3 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
**/temp
|
**/temp
|
||||||
**/docs/**
|
**/docs/**
|
||||||
tsconfig.json
|
|
||||||
|
|||||||
16
.release-it.pre.js
Normal file
16
.release-it.pre.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module.exports = {
|
||||||
|
verbose: true,
|
||||||
|
git: {
|
||||||
|
requireCleanWorkingDir: false,
|
||||||
|
commit: false,
|
||||||
|
push: false,
|
||||||
|
tag: false,
|
||||||
|
},
|
||||||
|
npm: {
|
||||||
|
skipChecks: true,
|
||||||
|
tag: 'beta',
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
'before:init': ['pnpm install', 'pnpm clean', 'pnpm build'],
|
||||||
|
},
|
||||||
|
}
|
||||||
15
.swcrc
15
.swcrc
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://json.schemastore.org/swcrc",
|
|
||||||
"sourceMaps": "inline",
|
|
||||||
"jsc": {
|
|
||||||
"target": "esnext",
|
|
||||||
"parser": {
|
|
||||||
"syntax": "typescript",
|
|
||||||
"tsx": true,
|
|
||||||
"dts": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"module": {
|
|
||||||
"type": "es6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
@@ -1,8 +1,3 @@
|
|||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"firsttris.vscode-jest-runner",
|
|
||||||
"ms-playwright.playwright"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
.vscode/launch.json
vendored
43
.vscode/launch.json
vendored
@@ -3,33 +3,12 @@
|
|||||||
// Hover to view descriptions of existing attributes.
|
// Hover to view descriptions of existing attributes.
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"command": "pnpm generate:types",
|
"command": "pnpm run dev _community",
|
||||||
"name": "Generate Types CLI",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node-terminal",
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "node --no-deprecation test/dev.js _community",
|
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"name": "Run Dev Community",
|
"name": "Run Dev Community",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"command": "node --no-deprecation test/dev.js live-preview",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"name": "Run Dev Live Preview",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node-terminal"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "node --no-deprecation test/dev.js admin",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"name": "Run Dev Admin",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node-terminal"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"command": "pnpm run dev plugin-cloud-storage",
|
"command": "pnpm run dev plugin-cloud-storage",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@@ -41,21 +20,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "node --no-deprecation test/dev.js fields",
|
"command": "pnpm run dev fields",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"name": "Run Dev Fields",
|
"name": "Run Dev Fields",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "node --no-deprecation test/dev.js versions",
|
"command": "pnpm run dev:postgres fields",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"name": "Run Dev Postgres",
|
"name": "Run Dev Postgres",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal",
|
"type": "node-terminal"
|
||||||
"env": {
|
|
||||||
"PAYLOAD_DATABASE": "postgres"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "pnpm run dev versions",
|
"command": "pnpm run dev versions",
|
||||||
@@ -126,6 +102,17 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "ts-node ./packages/payload/src/bin/index.ts generate:types",
|
||||||
|
"env": {
|
||||||
|
"PAYLOAD_CONFIG_PATH": "test/_community/config.ts",
|
||||||
|
"DISABLE_SWC": "true" // SWC messes up debugging the bin scripts
|
||||||
|
},
|
||||||
|
"name": "Generate Types CLI",
|
||||||
|
"outputCapture": "std",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "ts-node ./packages/payload/src/bin/index.ts migrate:status",
|
"command": "ts-node ./packages/payload/src/bin/index.ts migrate:status",
|
||||||
"env": {
|
"env": {
|
||||||
|
|||||||
13
.vscode/settings.json
vendored
13
.vscode/settings.json
vendored
@@ -5,21 +5,21 @@
|
|||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[typescriptreact]": {
|
"[typescriptreact]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"source.fixAll.eslint": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"[json]": {
|
"[json]": {
|
||||||
@@ -35,10 +35,5 @@
|
|||||||
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
// Load .git-blame-ignore-revs file
|
// Load .git-blame-ignore-revs file
|
||||||
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
|
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"]
|
||||||
"[javascript][typescript][typescriptreact]": {
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll.eslint": "explicit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
114
CHANGELOG.md
114
CHANGELOG.md
@@ -1,120 +1,11 @@
|
|||||||
## [2.11.2](https://github.com/payloadcms/payload/compare/v2.11.1...v2.11.2) (2024-02-23)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **db-postgres:** configurable custom schema to use ([#5047](https://github.com/payloadcms/payload/issues/5047)) ([e8f2ca4](https://github.com/payloadcms/payload/commit/e8f2ca484ee56cd7767d5111e46ebd24752ff8de))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Add Context Provider in EditMany Component ([#5005](https://github.com/payloadcms/payload/issues/5005)) ([70e57fe](https://github.com/payloadcms/payload/commit/70e57fef184f7fcf56344ea755465f246f2253a5))
|
|
||||||
* **db-mongodb:** unique sparse for not required fields ([#5114](https://github.com/payloadcms/payload/issues/5114)) ([815bdfa](https://github.com/payloadcms/payload/commit/815bdfac0b0afbff2a20e54d5aee64b90f6b3a77))
|
|
||||||
* **db-postgres:** set _parentID for array nested localized fields ([#5117](https://github.com/payloadcms/payload/issues/5117)) ([ceca5c4](https://github.com/payloadcms/payload/commit/ceca5c4e97f53f1346797a31b6abfc0375e98215))
|
|
||||||
* disabling API Key does not remove the key ([#5145](https://github.com/payloadcms/payload/issues/5145)) ([7a7f0ed](https://github.com/payloadcms/payload/commit/7a7f0ed7e8132253be607c111c160163b84bd770))
|
|
||||||
* handle thrown errors in config-level afterError hook ([#5147](https://github.com/payloadcms/payload/issues/5147)) ([32ed95e](https://github.com/payloadcms/payload/commit/32ed95e1ee87409db234f1b7bd6d2e462fd9ed5d))
|
|
||||||
* only replace the drawer content with full edit component if it exists ([#5144](https://github.com/payloadcms/payload/issues/5144)) ([0a07f60](https://github.com/payloadcms/payload/commit/0a07f607b9fb1217ad956cd05b2a84a4042a19ca))
|
|
||||||
* transaction error from access endpoint ([#5156](https://github.com/payloadcms/payload/issues/5156)) ([ad42d54](https://github.com/payloadcms/payload/commit/ad42d541b342ed56463b81cee6d6307df6f06d7f))
|
|
||||||
|
|
||||||
## [2.11.1](https://github.com/payloadcms/payload/compare/v2.11.0...v2.11.1) (2024-02-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* **db-postgres:** adds idType to use uuid or serial id columns ([#3864](https://github.com/payloadcms/payload/issues/3864)) ([d6c2578](https://github.com/payloadcms/payload/commit/d6c25783cfa97983bf9db27ceb5ccd39a62c62f1))
|
|
||||||
* **db-postgres:** reconnect after disconnection from database ([#5086](https://github.com/payloadcms/payload/issues/5086)) ([bf942fd](https://github.com/payloadcms/payload/commit/bf942fdfa6ea9c26cf05295cc9db646bf31fa622))
|
|
||||||
* **plugin-search:** add req to beforeSync args for transactions ([#5068](https://github.com/payloadcms/payload/issues/5068)) ([98b87e2](https://github.com/payloadcms/payload/commit/98b87e22782c0a788f79326f22be05a6b176ad74))
|
|
||||||
* **richtext-lexical:** add justify aligment to AlignFeature ([#4035](https://github.com/payloadcms/payload/issues/4035)) ([#4868](https://github.com/payloadcms/payload/issues/4868)) ([6d6823c](https://github.com/payloadcms/payload/commit/6d6823c3e5609a58eeeeb8d043945a762f9463df))
|
|
||||||
* **richtext-lexical:** AddBlock handle for all nodes, even if they aren't empty paragraphs ([#5063](https://github.com/payloadcms/payload/issues/5063)) ([00fc034](https://github.com/payloadcms/payload/commit/00fc0343dabf184d5bab418d47c403b3ad11698f))
|
|
||||||
* **richtext-lexical:** Update lexical from 0.12.6 to 0.13.1, port over all useful changes from playground ([#5066](https://github.com/payloadcms/payload/issues/5066)) ([0d18822](https://github.com/payloadcms/payload/commit/0d18822062275c1826c8e2c3da2571a2b3483310))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **db-mongodb:** find versions pagination ([#5091](https://github.com/payloadcms/payload/issues/5091)) ([5d4022f](https://github.com/payloadcms/payload/commit/5d4022f1445e2809c01cb1dd599280f0a56cdc6e))
|
|
||||||
* **db-postgres:** query using blockType ([#5044](https://github.com/payloadcms/payload/issues/5044)) ([35c2a08](https://github.com/payloadcms/payload/commit/35c2a085efa6d5ad59779960874bc9728a17e3a0))
|
|
||||||
* filterOptions errors cause transaction to abort ([#5079](https://github.com/payloadcms/payload/issues/5079)) ([5f3d016](https://github.com/payloadcms/payload/commit/5f3d0169bee21e1c0963dbd7ede9fe5f1c46a5a5))
|
|
||||||
* **plugin-form-builder:** hooks do not respect transactions ([#5069](https://github.com/payloadcms/payload/issues/5069)) ([82e9d31](https://github.com/payloadcms/payload/commit/82e9d31127c8df83c5bed92a5ffdab76d331900f))
|
|
||||||
* remove collection findByID caching ([#5034](https://github.com/payloadcms/payload/issues/5034)) ([1ac943e](https://github.com/payloadcms/payload/commit/1ac943ed5e8416883b863147fdf3c23380955559))
|
|
||||||
* **richtext-lexical:** do not remove adjacent paragraph node when inserting certain nodes in empty editor ([#5061](https://github.com/payloadcms/payload/issues/5061)) ([6323965](https://github.com/payloadcms/payload/commit/6323965c652ea68dffeb716957b124d165b9ce96))
|
|
||||||
* **uploads:** account for serverURL when retrieving external file ([#5102](https://github.com/payloadcms/payload/issues/5102)) ([25cee8b](https://github.com/payloadcms/payload/commit/25cee8bb102bf80b3a4bfb4b4e46712722cc7f0d))
|
|
||||||
|
|
||||||
|
|
||||||
### ⚠ BREAKING CHANGES: @payloadcms/richtext-lexical
|
|
||||||
|
|
||||||
* **richtext-lexical:** Update lexical from 0.12.6 to 0.13.1, port over all useful changes from playground (#5066)
|
|
||||||
|
|
||||||
- You HAVE to make sure that any versions of the lexical packages (IF you have any installed) match the lexical version which richtext-lexical uses: v0.13.1. If you do not do this, you may be plagued by React useContext / "cannot find active editor state" errors
|
|
||||||
- Updates to lexical's API, e.g. the removal of INTERNAL_isPointSelection, could be breaking depending on your code. Please consult the [lexical changelog](https://github.com/facebook/lexical/blob/main/CHANGELOG.md).
|
|
||||||
|
|
||||||
## [2.11.0](https://github.com/payloadcms/payload/compare/v2.10.1...v2.11.0) (2024-02-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* exposes collapsible provider with more functionality ([#5043](https://github.com/payloadcms/payload/issues/5043)) ([df39602](https://github.com/payloadcms/payload/commit/df39602758ae8dc3765bb48e51f7a657babfa559))
|
|
||||||
|
|
||||||
## [2.10.1](https://github.com/payloadcms/payload/compare/v2.10.0...v2.10.1) (2024-02-09)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* clearable cells handle null values ([#5038](https://github.com/payloadcms/payload/issues/5038)) ([f6d7da7](https://github.com/payloadcms/payload/commit/f6d7da751039df25066b51bb91d6453e1a4efd82))
|
|
||||||
* **db-mongodb:** handle null values with exists ([#5037](https://github.com/payloadcms/payload/issues/5037)) ([cdc4cb9](https://github.com/payloadcms/payload/commit/cdc4cb971b9180ba2ed09741f5af1a3c18292828))
|
|
||||||
* **db-postgres:** handle nested docs with drafts ([#5012](https://github.com/payloadcms/payload/issues/5012)) ([da184d4](https://github.com/payloadcms/payload/commit/da184d40ece74bffb224002eb5df8f6987d65043))
|
|
||||||
* ensures docs with the same id are shown in relationship field select ([#4859](https://github.com/payloadcms/payload/issues/4859)) ([e1813fb](https://github.com/payloadcms/payload/commit/e1813fb884e0dc84203fcbab87527a99a4d3a5d7))
|
|
||||||
* query relationships by explicit id field ([#5022](https://github.com/payloadcms/payload/issues/5022)) ([a0a58e7](https://github.com/payloadcms/payload/commit/a0a58e7fd20dff54d210c968f4d5defd67441bdd))
|
|
||||||
* **richtext-lexical:** make editor reactive to initialValue changes ([#5010](https://github.com/payloadcms/payload/issues/5010)) ([2315781](https://github.com/payloadcms/payload/commit/2315781f1891ddde4b4c5f2f0cfa1c17af85b7a9))
|
|
||||||
|
|
||||||
## [2.10.0](https://github.com/payloadcms/payload/compare/v2.9.0...v2.10.0) (2024-02-06)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* add more options to addFieldStatePromise so that it can be used for field flattening ([#4799](https://github.com/payloadcms/payload/issues/4799)) ([8725d41](https://github.com/payloadcms/payload/commit/8725d411645bb0270376e235669f46be2227ecc0))
|
|
||||||
* extend transactions to cover after and beforeOperation hooks ([#4960](https://github.com/payloadcms/payload/issues/4960)) ([1e8a6b7](https://github.com/payloadcms/payload/commit/1e8a6b7899f7b1e6451cc4d777602208478b483c))
|
|
||||||
* previousValue and previousSiblingDoc args added to beforeChange field hooks ([#4958](https://github.com/payloadcms/payload/issues/4958)) ([5d934ba](https://github.com/payloadcms/payload/commit/5d934ba02d07d98f781ce983228858ee5ce5c226))
|
|
||||||
* re-use existing logger instance passed to payload.init ([#3124](https://github.com/payloadcms/payload/issues/3124)) ([471d211](https://github.com/payloadcms/payload/commit/471d2113a790dc0d54b2f8ed84e6899310efd600))
|
|
||||||
* **richtext-lexical:** Blocks: generate type definitions for blocks fields ([#4529](https://github.com/payloadcms/payload/issues/4529)) ([90d7ee3](https://github.com/payloadcms/payload/commit/90d7ee3e6535d51290fc734b284ff3811dbda1f8))
|
|
||||||
* use deletion success message from server if provided ([#4966](https://github.com/payloadcms/payload/issues/4966)) ([e3c8105](https://github.com/payloadcms/payload/commit/e3c8105cc2ed6fdf8007d97cd7b5556fc71ed724))
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* **db-postgres:** filtering relationships with drafts enabled ([#4998](https://github.com/payloadcms/payload/issues/4998)) ([c3a3942](https://github.com/payloadcms/payload/commit/c3a39429697e9d335e9be199e7caafb82eb26219))
|
|
||||||
* **db-postgres:** handle schema changes with supabase ([#4968](https://github.com/payloadcms/payload/issues/4968)) ([5d3659d](https://github.com/payloadcms/payload/commit/5d3659d48ad8bbf5d96fbcd80434d2287cab97e0))
|
|
||||||
* **db-postgres:** indexes not created for non unique field names ([#4967](https://github.com/payloadcms/payload/issues/4967)) ([64f705c](https://github.com/payloadcms/payload/commit/64f705c3c94148972f67e8175e718015760d6430))
|
|
||||||
* **db-postgres:** indexes not creating for relationships, arrays, hasmany and blocks ([#4976](https://github.com/payloadcms/payload/issues/4976)) ([47106d5](https://github.com/payloadcms/payload/commit/47106d5a1af2ebd073fbbc6e474174c3d3835e5c))
|
|
||||||
* **db-postgres:** localized field sort count ([#4997](https://github.com/payloadcms/payload/issues/4997)) ([f3876c2](https://github.com/payloadcms/payload/commit/f3876c2a39efe19a1864213306725aadcc14f130))
|
|
||||||
* ensures docPermissions fallback to collection permissions on create ([#4969](https://github.com/payloadcms/payload/issues/4969)) ([afa2b94](https://github.com/payloadcms/payload/commit/afa2b942e0aad90c55744ae13e0ffe1cefa4585d))
|
|
||||||
* **migrations:** safely create migration file when no name passed ([#4995](https://github.com/payloadcms/payload/issues/4995)) ([0740d50](https://github.com/payloadcms/payload/commit/0740d5095ee1aef13e4e37f6b174d529f0f2d993))
|
|
||||||
* **plugin-seo:** tabbedUI with email field causes duplicate field ([#4944](https://github.com/payloadcms/payload/issues/4944)) ([db22cbd](https://github.com/payloadcms/payload/commit/db22cbdf21a39ed0604ab96c57ca4242eac82ce7))
|
|
||||||
|
|
||||||
## [2.9.0](https://github.com/payloadcms/payload/compare/v2.8.2...v2.9.0) (2024-01-26)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* forceAcceptWarning migration arg added to accept prompts ([#4874](https://github.com/payloadcms/payload/issues/4874)) ([eba53ba](https://github.com/payloadcms/payload/commit/eba53ba60afd7c5d37389377ed06a9b556058d49))
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* afterLogin hook write conflicts ([#4904](https://github.com/payloadcms/payload/issues/4904)) ([3eb681e](https://github.com/payloadcms/payload/commit/3eb681e847e9c55eaaa69c22bea4f4e66c7eac36))
|
|
||||||
* **db-postgres:** migrate down error ([#4861](https://github.com/payloadcms/payload/issues/4861)) ([dfba522](https://github.com/payloadcms/payload/commit/dfba5222f3abf3f236dc9212a28e1aec7d7214d5))
|
|
||||||
* **db-postgres:** query unset relation ([#4862](https://github.com/payloadcms/payload/issues/4862)) ([8ce15c8](https://github.com/payloadcms/payload/commit/8ce15c8b07800397a50dcf790c263ed5b3cfad53))
|
|
||||||
* migrate down missing filter for latest batch ([#4860](https://github.com/payloadcms/payload/issues/4860)) ([b99d24f](https://github.com/payloadcms/payload/commit/b99d24fcfa698c493ea01c41621201abe18fabe3))
|
|
||||||
* **plugin-cloud-storage:** slow get file performance large collections ([#4927](https://github.com/payloadcms/payload/issues/4927)) ([f73d503](https://github.com/payloadcms/payload/commit/f73d503fecdfa5cefdc26ab9aad60b00563f881e))
|
|
||||||
* remove No Options dropdown from hasMany fields ([#4899](https://github.com/payloadcms/payload/issues/4899)) ([e5a7907](https://github.com/payloadcms/payload/commit/e5a7907a72c1371447ac2f71fce213ed22246092))
|
|
||||||
* upload input drawer does not show draft versions ([#4903](https://github.com/payloadcms/payload/issues/4903)) ([6930c4e](https://github.com/payloadcms/payload/commit/6930c4e9f2200853121391ad8f8df48ea66c40a4))
|
|
||||||
|
|
||||||
## [2.8.2](https://github.com/payloadcms/payload/compare/v2.8.1...v2.8.2) (2024-01-16)
|
## [2.8.2](https://github.com/payloadcms/payload/compare/v2.8.1...v2.8.2) (2024-01-16)
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* **db-postgres:** support drizzle logging config ([#4809](https://github.com/payloadcms/payload/issues/4809)) ([371353f](https://github.com/payloadcms/payload/commit/371353f1535fbab4ebd9f56fc14fd10a30eec289))
|
* **db-postgres:** support drizzle logging config ([#4809](https://github.com/payloadcms/payload/issues/4809)) ([371353f](https://github.com/payloadcms/payload/commit/371353f1535fbab4ebd9f56fc14fd10a30eec289))
|
||||||
* **plugin-form-builder:** add validation for form ID when creating a submission ([#4730](https://github.com/payloadcms/payload/pull/4730))
|
* **plugin-form-builder:** add validation for form ID when creating a submission
|
||||||
* **plugin-seo:** add support for interfaceName and fieldOverrides ([#4695](https://github.com/payloadcms/payload/pull/4695))
|
* **plugin-seo:** allow field and interface overrides
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
@@ -123,7 +14,6 @@
|
|||||||
* **db-postgres:** Remove duplicate keys from response ([#4747](https://github.com/payloadcms/payload/issues/4747)) ([eb9e771](https://github.com/payloadcms/payload/commit/eb9e771a9ca03636486d36654f215b73435574cb))
|
* **db-postgres:** Remove duplicate keys from response ([#4747](https://github.com/payloadcms/payload/issues/4747)) ([eb9e771](https://github.com/payloadcms/payload/commit/eb9e771a9ca03636486d36654f215b73435574cb))
|
||||||
* **db-postgres:** validateExistingBlockIsIdentical with arrays ([3b88adc](https://github.com/payloadcms/payload/commit/3b88adc7d0594af63ce190c40c9ee3905df67a31))
|
* **db-postgres:** validateExistingBlockIsIdentical with arrays ([3b88adc](https://github.com/payloadcms/payload/commit/3b88adc7d0594af63ce190c40c9ee3905df67a31))
|
||||||
* **db-postgres:** validateExistingBlockIsIdentical with other tables ([0647c87](https://github.com/payloadcms/payload/commit/0647c870f15dc1b122734b678c2abeb6f56377d4))
|
* **db-postgres:** validateExistingBlockIsIdentical with other tables ([0647c87](https://github.com/payloadcms/payload/commit/0647c870f15dc1b122734b678c2abeb6f56377d4))
|
||||||
* **plugin-seo:** fix missing spread operator in URL generator function ([#4723](https://github.com/payloadcms/payload/pull/4723))
|
|
||||||
* removes max-width from field-types class & correctly sets it on uploads ([#4829](https://github.com/payloadcms/payload/issues/4829)) ([ee5390a](https://github.com/payloadcms/payload/commit/ee5390aaca37a4154cde8392b60f091ec3e5175c))
|
* removes max-width from field-types class & correctly sets it on uploads ([#4829](https://github.com/payloadcms/payload/issues/4829)) ([ee5390a](https://github.com/payloadcms/payload/commit/ee5390aaca37a4154cde8392b60f091ec3e5175c))
|
||||||
|
|
||||||
## [2.8.1](https://github.com/payloadcms/payload/compare/v2.8.0...v2.8.1) (2024-01-12)
|
## [2.8.1](https://github.com/payloadcms/payload/compare/v2.8.0...v2.8.1) (2024-01-12)
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
import type { Metadata } from 'next'
|
|
||||||
|
|
||||||
import config from '@payload-config'
|
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
|
||||||
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views/NotFound/index.js'
|
|
||||||
|
|
||||||
type Args = {
|
|
||||||
params: {
|
|
||||||
segments: string[]
|
|
||||||
}
|
|
||||||
searchParams: {
|
|
||||||
[key: string]: string | string[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
|
||||||
generatePageMetadata({ config, params, searchParams })
|
|
||||||
|
|
||||||
const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })
|
|
||||||
|
|
||||||
export default NotFound
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
import type { Metadata } from 'next'
|
|
||||||
|
|
||||||
import config from '@payload-config'
|
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
|
||||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views/Root/index.js'
|
|
||||||
|
|
||||||
type Args = {
|
|
||||||
params: {
|
|
||||||
segments: string[]
|
|
||||||
}
|
|
||||||
searchParams: {
|
|
||||||
[key: string]: string | string[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
|
||||||
generatePageMetadata({ config, params, searchParams })
|
|
||||||
|
|
||||||
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
|
|
||||||
|
|
||||||
export default Page
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
|
||||||
import config from '@payload-config'
|
|
||||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes/index.js'
|
|
||||||
|
|
||||||
export const GET = REST_GET(config)
|
|
||||||
export const POST = REST_POST(config)
|
|
||||||
export const DELETE = REST_DELETE(config)
|
|
||||||
export const PATCH = REST_PATCH(config)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
|
||||||
import config from '@payload-config'
|
|
||||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes/index.js'
|
|
||||||
|
|
||||||
export const GET = GRAPHQL_PLAYGROUND_GET(config)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
|
||||||
import config from '@payload-config'
|
|
||||||
import { GRAPHQL_POST } from '@payloadcms/next/routes/index.js'
|
|
||||||
|
|
||||||
export const POST = GRAPHQL_POST(config)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
import configPromise from '@payload-config'
|
|
||||||
import { RootLayout } from '@payloadcms/next/layouts/Root/index.js'
|
|
||||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import './custom.scss'
|
|
||||||
|
|
||||||
type Args = {
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const Layout = ({ children }: Args) => <RootLayout config={configPromise}>{children}</RootLayout>
|
|
||||||
|
|
||||||
export default Layout
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page as PageType } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../_api/serverURL.js'
|
|
||||||
import { Blocks } from '../../_components/Blocks/index.js'
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { Hero } from '../../_components/Hero/index.js'
|
|
||||||
|
|
||||||
export const PageClient: React.FC<{
|
|
||||||
page: PageType
|
|
||||||
}> = ({ page: initialPage }) => {
|
|
||||||
const { data } = useLivePreview<PageType>({
|
|
||||||
depth: 2,
|
|
||||||
initialData: initialPage,
|
|
||||||
serverURL: PAYLOAD_SERVER_URL,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Gutter>
|
|
||||||
<h1 id="page-title">{data.title}</h1>
|
|
||||||
</Gutter>
|
|
||||||
<Hero {...data?.hero} />
|
|
||||||
<Blocks
|
|
||||||
blocks={[
|
|
||||||
...(data?.layout ?? []),
|
|
||||||
{
|
|
||||||
blockName: 'Relationships',
|
|
||||||
blockType: 'relationships',
|
|
||||||
data,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
disableTopPadding={
|
|
||||||
!data?.hero || data?.hero?.type === 'none' || data?.hero?.type === 'lowImpact'
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { notFound } from 'next/navigation.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { fetchDoc } from '../../_api/fetchDoc.js'
|
|
||||||
import { fetchDocs } from '../../_api/fetchDocs.js'
|
|
||||||
import { PageClient } from './page.client.js'
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-exports
|
|
||||||
export default async function Page({ params: { slug = 'home' } }) {
|
|
||||||
let page: Page | null = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
page = await fetchDoc<Page>({
|
|
||||||
slug,
|
|
||||||
collection: 'pages',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!page) {
|
|
||||||
return notFound()
|
|
||||||
}
|
|
||||||
|
|
||||||
return <PageClient page={page} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
|
||||||
try {
|
|
||||||
const pages = await fetchDocs<Page>('pages')
|
|
||||||
return pages?.map(({ slug }) => slug)
|
|
||||||
} catch (error) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Post as PostType } from '../../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
|
||||||
import { Blocks } from '../../../_components/Blocks/index.js'
|
|
||||||
import { PostHero } from '../../../_heros/PostHero/index.js'
|
|
||||||
|
|
||||||
export const PostClient: React.FC<{
|
|
||||||
post: PostType
|
|
||||||
}> = ({ post: initialPost }) => {
|
|
||||||
const { data } = useLivePreview<PostType>({
|
|
||||||
depth: 2,
|
|
||||||
initialData: initialPost,
|
|
||||||
serverURL: PAYLOAD_SERVER_URL,
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<PostHero post={data} />
|
|
||||||
<Blocks blocks={data?.layout} />
|
|
||||||
<Blocks
|
|
||||||
blocks={[
|
|
||||||
{
|
|
||||||
blockName: 'Related Posts',
|
|
||||||
blockType: 'relatedPosts',
|
|
||||||
docs: data?.relatedPosts,
|
|
||||||
introContent: [
|
|
||||||
{
|
|
||||||
type: 'h4',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Related posts',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'p',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'The posts displayed here are individually selected for this page. Admins can select any number of related posts to display here and the layout will adjust accordingly. Alternatively, you could swap this out for the "Archive" block to automatically populate posts by category complete with pagination. To manage related posts, ',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'link',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'navigate to the admin dashboard',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
url: `/admin/collections/posts/${data?.id}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
relationTo: 'posts',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
disableTopPadding
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
import { notFound } from 'next/navigation.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Post } from '../../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { fetchDoc } from '../../../_api/fetchDoc.js'
|
|
||||||
import { fetchDocs } from '../../../_api/fetchDocs.js'
|
|
||||||
import { PostClient } from './page.client.js'
|
|
||||||
|
|
||||||
export default async function Post({ params: { slug = '' } }) {
|
|
||||||
let post: Post | null = null
|
|
||||||
|
|
||||||
try {
|
|
||||||
post = await fetchDoc<Post>({
|
|
||||||
slug,
|
|
||||||
collection: 'posts',
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error) // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!post) {
|
|
||||||
notFound()
|
|
||||||
}
|
|
||||||
|
|
||||||
return <PostClient post={post} />
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
|
||||||
try {
|
|
||||||
const posts = await fetchDocs<Post>('posts')
|
|
||||||
return posts?.map(({ slug }) => slug)
|
|
||||||
} catch (error) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
import { PAYLOAD_SERVER_URL } from './serverURL.js'
|
|
||||||
|
|
||||||
export const fetchDocs = async <T>(collection: string): Promise<T[]> => {
|
|
||||||
const docs: T[] = await fetch(`${PAYLOAD_SERVER_URL}/api/${collection}?depth=0&limit=100`, {
|
|
||||||
cache: 'no-store',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'GET',
|
|
||||||
})
|
|
||||||
?.then((res) => res.json())
|
|
||||||
?.then((res) => {
|
|
||||||
if (res.errors) throw new Error(res?.errors?.[0]?.message ?? 'Error fetching docs')
|
|
||||||
|
|
||||||
return res?.docs
|
|
||||||
})
|
|
||||||
|
|
||||||
return docs
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { ArchiveBlockProps } from './types.js'
|
|
||||||
|
|
||||||
import { CollectionArchive } from '../../_components/CollectionArchive/index.js'
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const ArchiveBlock: React.FC<
|
|
||||||
ArchiveBlockProps & {
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
> = (props) => {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
categories,
|
|
||||||
introContent,
|
|
||||||
limit,
|
|
||||||
populateBy,
|
|
||||||
populatedDocs,
|
|
||||||
populatedDocsTotal,
|
|
||||||
relationTo,
|
|
||||||
selectedDocs,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.archiveBlock} id={`block-${id}`}>
|
|
||||||
{introContent && (
|
|
||||||
<Gutter className={classes.introContent}>
|
|
||||||
<RichText content={introContent} />
|
|
||||||
</Gutter>
|
|
||||||
)}
|
|
||||||
<CollectionArchive
|
|
||||||
categories={categories}
|
|
||||||
limit={limit}
|
|
||||||
populateBy={populateBy}
|
|
||||||
populatedDocs={populatedDocs}
|
|
||||||
populatedDocsTotal={populatedDocsTotal}
|
|
||||||
relationTo={relationTo}
|
|
||||||
selectedDocs={selectedDocs}
|
|
||||||
sort="-publishedDate"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
export type ArchiveBlockProps = Extract<
|
|
||||||
Exclude<Page['layout'], undefined>[0],
|
|
||||||
{ blockType: 'archive' }
|
|
||||||
>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { CMSLink } from '../../_components/Link/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import { VerticalPadding } from '../../_components/VerticalPadding/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'cta' }>
|
|
||||||
|
|
||||||
export const CallToActionBlock: React.FC<
|
|
||||||
Props & {
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
> = ({ invertBackground, links, richText }) => {
|
|
||||||
return (
|
|
||||||
<Gutter>
|
|
||||||
<VerticalPadding
|
|
||||||
className={[classes.callToAction, invertBackground && classes.invert]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
>
|
|
||||||
<div className={classes.wrap}>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<RichText className={classes.richText} content={richText} />
|
|
||||||
</div>
|
|
||||||
<div className={classes.linkGroup}>
|
|
||||||
{(links || []).map(({ link }, i) => {
|
|
||||||
return <CMSLink key={i} {...link} invert={invertBackground} />
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</VerticalPadding>
|
|
||||||
</Gutter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { CMSLink } from '../../_components/Link/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'content' }>
|
|
||||||
|
|
||||||
export const ContentBlock: React.FC<
|
|
||||||
Props & {
|
|
||||||
id?: string
|
|
||||||
}
|
|
||||||
> = (props) => {
|
|
||||||
const { columns } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Gutter className={classes.content}>
|
|
||||||
<div className={classes.grid}>
|
|
||||||
{columns && columns.length > 0 ? (
|
|
||||||
<Fragment>
|
|
||||||
{columns.map((col, index) => {
|
|
||||||
const { enableLink, link, richText, size } = col
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[classes.column, classes[`column--${size}`]].join(' ')} key={index}>
|
|
||||||
<RichText content={richText} />
|
|
||||||
{enableLink && <CMSLink className={classes.link} {...link} />}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Fragment>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import type { StaticImageData } from 'next/image.js'
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { Media } from '../../_components/Media/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'mediaBlock' }> & {
|
|
||||||
id?: string
|
|
||||||
staticImage?: StaticImageData
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MediaBlock: React.FC<Props> = (props) => {
|
|
||||||
const { media, position = 'default', staticImage } = props
|
|
||||||
|
|
||||||
let caption
|
|
||||||
if (media && typeof media === 'object') caption = media.caption
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.mediaBlock}>
|
|
||||||
{position === 'fullscreen' && (
|
|
||||||
<div className={classes.fullscreen}>
|
|
||||||
<Media resource={media} src={staticImage} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{position === 'default' && (
|
|
||||||
<Gutter>
|
|
||||||
<Media resource={media} src={staticImage} />
|
|
||||||
</Gutter>
|
|
||||||
)}
|
|
||||||
{caption && (
|
|
||||||
<Gutter className={classes.caption}>
|
|
||||||
<RichText content={caption} />
|
|
||||||
</Gutter>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Card } from '../../_components/Card/index.js'
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export type RelatedPostsProps = {
|
|
||||||
blockName: string
|
|
||||||
blockType: 'relatedPosts'
|
|
||||||
docs?: (Post | string)[] | null
|
|
||||||
introContent?: any
|
|
||||||
relationTo: 'posts'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RelatedPosts: React.FC<RelatedPostsProps> = (props) => {
|
|
||||||
const { docs, introContent, relationTo } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.relatedPosts}>
|
|
||||||
{introContent && (
|
|
||||||
<Gutter className={classes.introContent}>
|
|
||||||
<RichText content={introContent} />
|
|
||||||
</Gutter>
|
|
||||||
)}
|
|
||||||
<Gutter>
|
|
||||||
<div className={classes.grid}>
|
|
||||||
{docs?.map((doc, index) => {
|
|
||||||
if (typeof doc === 'string') return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={[
|
|
||||||
classes.column,
|
|
||||||
docs.length === 2 && classes['cols-half'],
|
|
||||||
docs.length >= 3 && classes['cols-thirds'],
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
key={index}
|
|
||||||
>
|
|
||||||
<Card doc={doc} relationTo={relationTo} showCategories />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export type RelationshipsBlockProps = {
|
|
||||||
blockName: string
|
|
||||||
blockType: 'relationships'
|
|
||||||
data: Page
|
|
||||||
}
|
|
||||||
|
|
||||||
export const RelationshipsBlock: React.FC<RelationshipsBlockProps> = (props) => {
|
|
||||||
const { data } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.relationshipsBlock}>
|
|
||||||
<Gutter>
|
|
||||||
<p>
|
|
||||||
This block is for testing purposes only. It renders every possible type of relationship.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>Rich Text — Slate:</b>
|
|
||||||
</p>
|
|
||||||
{data?.richTextSlate && <RichText content={data.richTextSlate} renderUploadFilenameOnly />}
|
|
||||||
<p>
|
|
||||||
<b>Rich Text — Lexical:</b>
|
|
||||||
</p>
|
|
||||||
{data?.richTextLexical && (
|
|
||||||
<RichText content={data.richTextLexical} renderUploadFilenameOnly serializer="lexical" />
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Upload:</b>
|
|
||||||
</p>
|
|
||||||
{data?.relationshipAsUpload ? (
|
|
||||||
<div>
|
|
||||||
{typeof data?.relationshipAsUpload === 'string'
|
|
||||||
? data?.relationshipAsUpload
|
|
||||||
: data?.relationshipAsUpload.filename}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Monomorphic Has One:</b>
|
|
||||||
</p>
|
|
||||||
{data?.relationshipMonoHasOne ? (
|
|
||||||
<div>
|
|
||||||
{typeof data?.relationshipMonoHasOne === 'string'
|
|
||||||
? data?.relationshipMonoHasOne
|
|
||||||
: data?.relationshipMonoHasOne.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Monomorphic Has Many:</b>
|
|
||||||
</p>
|
|
||||||
{data?.relationshipMonoHasMany ? (
|
|
||||||
<Fragment>
|
|
||||||
{data?.relationshipMonoHasMany.length
|
|
||||||
? data?.relationshipMonoHasMany?.map((item, index) =>
|
|
||||||
item ? (
|
|
||||||
<div key={index}>{typeof item === 'string' ? item : item.title}</div>
|
|
||||||
) : (
|
|
||||||
'null'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: 'None'}
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Polymorphic Has One:</b>
|
|
||||||
</p>
|
|
||||||
{data?.relationshipPolyHasOne ? (
|
|
||||||
<div>
|
|
||||||
{typeof data?.relationshipPolyHasOne.value === 'string'
|
|
||||||
? data?.relationshipPolyHasOne.value
|
|
||||||
: data?.relationshipPolyHasOne.value.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Polymorphic Has Many:</b>
|
|
||||||
</p>
|
|
||||||
{data?.relationshipPolyHasMany ? (
|
|
||||||
<Fragment>
|
|
||||||
{data?.relationshipPolyHasMany.length
|
|
||||||
? data?.relationshipPolyHasMany?.map((item, index) =>
|
|
||||||
item.value ? (
|
|
||||||
<div key={index}>
|
|
||||||
{typeof item.value === 'string' ? item.value : item.value.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
'null'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: 'None'}
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Array of Relationships:</b>
|
|
||||||
</p>
|
|
||||||
{data?.arrayOfRelationships?.map((item, index) => (
|
|
||||||
<div className={classes.array} key={index}>
|
|
||||||
<p>
|
|
||||||
<b>Rich Text:</b>
|
|
||||||
</p>
|
|
||||||
{item?.richTextInArray && <RichText content={item.richTextInArray} />}
|
|
||||||
<p>
|
|
||||||
<b>Upload:</b>
|
|
||||||
</p>
|
|
||||||
{item?.uploadInArray ? (
|
|
||||||
<div>
|
|
||||||
{typeof item?.uploadInArray === 'string'
|
|
||||||
? item?.uploadInArray
|
|
||||||
: item?.uploadInArray.filename}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Monomorphic Has One:</b>
|
|
||||||
</p>
|
|
||||||
{item?.relationshipInArrayMonoHasOne ? (
|
|
||||||
<div>
|
|
||||||
{typeof item?.relationshipInArrayMonoHasOne === 'string'
|
|
||||||
? item?.relationshipInArrayMonoHasOne
|
|
||||||
: item?.relationshipInArrayMonoHasOne.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Monomorphic Has Many:</b>
|
|
||||||
</p>
|
|
||||||
{item?.relationshipInArrayMonoHasMany ? (
|
|
||||||
<Fragment>
|
|
||||||
{item?.relationshipInArrayMonoHasMany.length
|
|
||||||
? item?.relationshipInArrayMonoHasMany?.map((rel, relIndex) =>
|
|
||||||
rel ? (
|
|
||||||
<div key={relIndex}>{typeof rel === 'string' ? rel : rel.title}</div>
|
|
||||||
) : (
|
|
||||||
'null'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: 'None'}
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Polymorphic Has One:</b>
|
|
||||||
</p>
|
|
||||||
{item?.relationshipInArrayPolyHasOne ? (
|
|
||||||
<div>
|
|
||||||
{typeof item?.relationshipInArrayPolyHasOne.value === 'string'
|
|
||||||
? item?.relationshipInArrayPolyHasOne.value
|
|
||||||
: item?.relationshipInArrayPolyHasOne.value.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
<p>
|
|
||||||
<b>Polymorphic Has Many:</b>
|
|
||||||
</p>
|
|
||||||
{item?.relationshipInArrayPolyHasMany ? (
|
|
||||||
<Fragment>
|
|
||||||
{item?.relationshipInArrayPolyHasMany.length
|
|
||||||
? item?.relationshipInArrayPolyHasMany?.map((rel, relIndex) =>
|
|
||||||
rel.value ? (
|
|
||||||
<div key={relIndex}>
|
|
||||||
{typeof rel.value === 'string' ? rel.value : rel.value.title}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
'null'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: 'None'}
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
|
||||||
<div>None</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Gutter>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children?: React.ReactNode
|
|
||||||
className?: string
|
|
||||||
id?: string
|
|
||||||
invert?: boolean | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export const BackgroundColor: React.FC<Props> = (props) => {
|
|
||||||
const { id, children, className, invert } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[invert && classes.invert, className].filter(Boolean).join(' ')} id={id}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
import type { RelationshipsBlockProps } from '../../_blocks/Relationships/index.js'
|
|
||||||
import type { VerticalPaddingOptions } from '../VerticalPadding/index.js'
|
|
||||||
|
|
||||||
import { ArchiveBlock } from '../../_blocks/ArchiveBlock/index.js'
|
|
||||||
import { CallToActionBlock } from '../../_blocks/CallToAction/index.js'
|
|
||||||
import { ContentBlock } from '../../_blocks/Content/index.js'
|
|
||||||
import { MediaBlock } from '../../_blocks/MediaBlock/index.js'
|
|
||||||
import { RelatedPosts, type RelatedPostsProps } from '../../_blocks/RelatedPosts/index.js'
|
|
||||||
import { RelationshipsBlock } from '../../_blocks/Relationships/index.js'
|
|
||||||
import { toKebabCase } from '../../_utilities/toKebabCase.js'
|
|
||||||
import { BackgroundColor } from '../BackgroundColor/index.js'
|
|
||||||
import { VerticalPadding } from '../VerticalPadding/index.js'
|
|
||||||
|
|
||||||
const blockComponents = {
|
|
||||||
archive: ArchiveBlock,
|
|
||||||
content: ContentBlock,
|
|
||||||
cta: CallToActionBlock,
|
|
||||||
mediaBlock: MediaBlock,
|
|
||||||
relatedPosts: RelatedPosts,
|
|
||||||
relationships: RelationshipsBlock,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Block = NonNullable<Page['layout']>[number]
|
|
||||||
|
|
||||||
export const Blocks: React.FC<{
|
|
||||||
blocks?: (Block | RelatedPostsProps | RelationshipsBlockProps)[] | null
|
|
||||||
disableTopPadding?: boolean
|
|
||||||
}> = (props) => {
|
|
||||||
const { blocks, disableTopPadding } = props
|
|
||||||
|
|
||||||
const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0
|
|
||||||
|
|
||||||
if (hasBlocks) {
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
{blocks.map((block, index) => {
|
|
||||||
const { blockName, blockType } = block
|
|
||||||
|
|
||||||
if (blockType && blockType in blockComponents) {
|
|
||||||
const Block = blockComponents[blockType]
|
|
||||||
|
|
||||||
// the cta block is containerized, so we don't consider it to be inverted at the block-level
|
|
||||||
const blockIsInverted =
|
|
||||||
'invertBackground' in block && blockType !== 'cta' ? block.invertBackground : false
|
|
||||||
const prevBlock = blocks[index - 1]
|
|
||||||
|
|
||||||
const prevBlockInverted =
|
|
||||||
prevBlock && 'invertBackground' in prevBlock && prevBlock?.invertBackground
|
|
||||||
|
|
||||||
const isPrevSame = Boolean(blockIsInverted) === Boolean(prevBlockInverted)
|
|
||||||
|
|
||||||
let paddingTop: VerticalPaddingOptions = 'large'
|
|
||||||
let paddingBottom: VerticalPaddingOptions = 'large'
|
|
||||||
|
|
||||||
if (prevBlock && isPrevSame) {
|
|
||||||
paddingTop = 'none'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index === blocks.length - 1) {
|
|
||||||
paddingBottom = 'large'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disableTopPadding && index === 0) {
|
|
||||||
paddingTop = 'none'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Block) {
|
|
||||||
return (
|
|
||||||
<BackgroundColor invert={blockIsInverted} key={index}>
|
|
||||||
<VerticalPadding bottom={paddingBottom} top={paddingTop}>
|
|
||||||
{/* @ts-expect-error */}
|
|
||||||
<Block id={toKebabCase(blockName)} {...block} />
|
|
||||||
</VerticalPadding>
|
|
||||||
</BackgroundColor>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
})}
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import type { ElementType } from 'react'
|
|
||||||
|
|
||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
appearance?: 'default' | 'none' | 'primary' | 'secondary'
|
|
||||||
className?: string
|
|
||||||
disabled?: boolean
|
|
||||||
el?: 'a' | 'button' | 'link'
|
|
||||||
href?: string
|
|
||||||
invert?: boolean
|
|
||||||
label?: string
|
|
||||||
newTab?: boolean
|
|
||||||
onClick?: () => void
|
|
||||||
type?: 'button' | 'submit'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Button: React.FC<Props> = ({
|
|
||||||
type = 'button',
|
|
||||||
appearance,
|
|
||||||
className: classNameFromProps,
|
|
||||||
disabled,
|
|
||||||
el: elFromProps = 'link',
|
|
||||||
href,
|
|
||||||
invert,
|
|
||||||
label,
|
|
||||||
newTab,
|
|
||||||
onClick,
|
|
||||||
}) => {
|
|
||||||
let el = elFromProps
|
|
||||||
|
|
||||||
const newTabProps = newTab ? { rel: 'noopener noreferrer', target: '_blank' } : {}
|
|
||||||
|
|
||||||
const className = [
|
|
||||||
classes.button,
|
|
||||||
classNameFromProps,
|
|
||||||
classes[`appearance--${appearance}`],
|
|
||||||
invert && classes[`${appearance}--invert`],
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')
|
|
||||||
|
|
||||||
const content = (
|
|
||||||
<div className={classes.content}>
|
|
||||||
<span className={classes.label}>{label}</span>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
if (onClick || type === 'submit') el = 'button'
|
|
||||||
|
|
||||||
if (el === 'link') {
|
|
||||||
return (
|
|
||||||
<Link className={className} href={href || ''} {...newTabProps} onClick={onClick}>
|
|
||||||
{content}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const Element: ElementType = el
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Element
|
|
||||||
className={className}
|
|
||||||
href={href}
|
|
||||||
type={type}
|
|
||||||
{...newTabProps}
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
{content}
|
|
||||||
</Element>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Media } from '../Media/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
export const Card: React.FC<{
|
|
||||||
alignItems?: 'center'
|
|
||||||
className?: string
|
|
||||||
doc?: Post
|
|
||||||
hideImagesOnMobile?: boolean
|
|
||||||
orientation?: 'horizontal' | 'vertical'
|
|
||||||
relationTo?: 'posts'
|
|
||||||
showCategories?: boolean
|
|
||||||
title?: string
|
|
||||||
}> = (props) => {
|
|
||||||
const {
|
|
||||||
className,
|
|
||||||
doc,
|
|
||||||
orientation = 'vertical',
|
|
||||||
relationTo,
|
|
||||||
showCategories,
|
|
||||||
title: titleFromProps,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
const { slug, categories, meta, title } = doc || {}
|
|
||||||
const { description, image: metaImage } = meta || {}
|
|
||||||
|
|
||||||
const hasCategories = categories && Array.isArray(categories) && categories.length > 0
|
|
||||||
const titleToUse = titleFromProps || title
|
|
||||||
const sanitizedDescription = description?.replace(/\s/g, ' ') // replace non-breaking space with white space
|
|
||||||
const href = `/live-preview/${relationTo}/${slug}`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={[classes.card, className, orientation && classes[orientation]]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
>
|
|
||||||
<Link className={classes.mediaWrapper} href={href}>
|
|
||||||
{!metaImage && <div className={classes.placeholder}>No image</div>}
|
|
||||||
{metaImage && typeof metaImage !== 'string' && (
|
|
||||||
<Media fill imgClassName={classes.image} resource={metaImage} />
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
<div className={classes.content}>
|
|
||||||
{showCategories && hasCategories && (
|
|
||||||
<div className={classes.leader}>
|
|
||||||
{showCategories && hasCategories && (
|
|
||||||
<div>
|
|
||||||
{categories?.map((category, index) => {
|
|
||||||
const titleFromCategory = typeof category === 'string' ? category : category.title
|
|
||||||
|
|
||||||
const categoryTitle = titleFromCategory || 'Untitled category'
|
|
||||||
|
|
||||||
const isLast = index === categories.length - 1
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment key={index}>
|
|
||||||
{categoryTitle}
|
|
||||||
{!isLast && <Fragment>, </Fragment>}
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{titleToUse && (
|
|
||||||
<h4 className={classes.title}>
|
|
||||||
<Link className={classes.titleLink} href={href}>
|
|
||||||
{titleToUse}
|
|
||||||
</Link>
|
|
||||||
</h4>
|
|
||||||
)}
|
|
||||||
{description && (
|
|
||||||
<div className={classes.body}>
|
|
||||||
{description && <p className={classes.description}>{sanitizedDescription}</p>}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
export const Chevron: React.FC<{
|
|
||||||
className?: string
|
|
||||||
rotate?: number
|
|
||||||
}> = ({ className, rotate }) => {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
className={className}
|
|
||||||
height="100%"
|
|
||||||
style={{
|
|
||||||
transform: typeof rotate === 'number' ? `rotate(${rotate || 0}deg)` : undefined,
|
|
||||||
}}
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="100%"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M23.245 4l-11.245 14.374-11.219-14.374-.781.619 12 15.381 12-15.391-.755-.609z"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
vectorEffect="non-scaling-stroke"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import qs from 'qs'
|
|
||||||
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
|
||||||
|
|
||||||
import type { Post } from '../../../../../test/live-preview/payload-types.js'
|
|
||||||
import type { ArchiveBlockProps } from '../../../_blocks/ArchiveBlock/types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
|
||||||
import { Card } from '../../Card/index.js'
|
|
||||||
import { Gutter } from '../../Gutter/index.js'
|
|
||||||
import { PageRange } from '../../PageRange/index.js'
|
|
||||||
import { Pagination } from '../../Pagination/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Result = {
|
|
||||||
docs: (Post | string)[]
|
|
||||||
hasNextPage: boolean
|
|
||||||
hasPrevPage: boolean
|
|
||||||
nextPage: number
|
|
||||||
page: number
|
|
||||||
prevPage: number
|
|
||||||
totalDocs: number
|
|
||||||
totalPages: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Props = Omit<ArchiveBlockProps, 'blockType'> & {
|
|
||||||
className?: string
|
|
||||||
onResultChange?: (result: Result) => void // eslint-disable-line no-unused-vars
|
|
||||||
showPageRange?: boolean
|
|
||||||
sort?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CollectionArchiveByCollection: React.FC<Props> = (props) => {
|
|
||||||
const {
|
|
||||||
categories: catsFromProps,
|
|
||||||
className,
|
|
||||||
limit = 10,
|
|
||||||
onResultChange,
|
|
||||||
populatedDocs,
|
|
||||||
populatedDocsTotal,
|
|
||||||
relationTo,
|
|
||||||
showPageRange,
|
|
||||||
sort = '-createdAt',
|
|
||||||
} = props
|
|
||||||
|
|
||||||
const [results, setResults] = useState<Result>({
|
|
||||||
docs: populatedDocs?.map((doc) => doc.value) || [],
|
|
||||||
hasNextPage: false,
|
|
||||||
hasPrevPage: false,
|
|
||||||
nextPage: 1,
|
|
||||||
page: 1,
|
|
||||||
prevPage: 1,
|
|
||||||
totalDocs: typeof populatedDocsTotal === 'number' ? populatedDocsTotal : 0,
|
|
||||||
totalPages: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
|
||||||
const [error, setError] = useState<string | undefined>(undefined)
|
|
||||||
const scrollRef = useRef<HTMLDivElement>(null)
|
|
||||||
const hasHydrated = useRef(false)
|
|
||||||
const [page, setPage] = useState(1)
|
|
||||||
|
|
||||||
const scrollToRef = useCallback(() => {
|
|
||||||
const { current } = scrollRef
|
|
||||||
if (current) {
|
|
||||||
// current.scrollIntoView({
|
|
||||||
// behavior: 'smooth',
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isLoading && typeof results.page !== 'undefined') {
|
|
||||||
// scrollToRef()
|
|
||||||
}
|
|
||||||
}, [isLoading, scrollToRef, results])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// hydrate the block with fresh content after first render
|
|
||||||
// don't show loader unless the request takes longer than x ms
|
|
||||||
// and don't show it during initial hydration
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
if (hasHydrated) {
|
|
||||||
setIsLoading(true)
|
|
||||||
}
|
|
||||||
}, 500)
|
|
||||||
|
|
||||||
const searchQuery = qs.stringify(
|
|
||||||
{
|
|
||||||
depth: 1,
|
|
||||||
limit,
|
|
||||||
page,
|
|
||||||
sort,
|
|
||||||
where: {
|
|
||||||
...(catsFromProps && catsFromProps?.length > 0
|
|
||||||
? {
|
|
||||||
categories: {
|
|
||||||
in:
|
|
||||||
typeof catsFromProps === 'string'
|
|
||||||
? [catsFromProps]
|
|
||||||
: catsFromProps
|
|
||||||
.map((cat) => (typeof cat === 'object' && cat !== null ? cat.id : cat))
|
|
||||||
.join(','),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: {}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{ encode: false },
|
|
||||||
)
|
|
||||||
|
|
||||||
const makeRequest = async () => {
|
|
||||||
try {
|
|
||||||
const req = await fetch(`${PAYLOAD_SERVER_URL}/api/${relationTo}?${searchQuery}`)
|
|
||||||
const json = await req.json()
|
|
||||||
clearTimeout(timer)
|
|
||||||
hasHydrated.current = true
|
|
||||||
|
|
||||||
const { docs } = json as { docs: Post[] }
|
|
||||||
|
|
||||||
if (docs && Array.isArray(docs)) {
|
|
||||||
setResults(json)
|
|
||||||
setIsLoading(false)
|
|
||||||
if (typeof onResultChange === 'function') {
|
|
||||||
onResultChange(json)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(err) // eslint-disable-line no-console
|
|
||||||
setIsLoading(false)
|
|
||||||
setError(`Unable to load "${relationTo} archive" data at this time.`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void makeRequest()
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (timer) clearTimeout(timer)
|
|
||||||
}
|
|
||||||
}, [page, catsFromProps, relationTo, onResultChange, sort, limit])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[classes.collectionArchive, className].filter(Boolean).join(' ')}>
|
|
||||||
<div className={classes.scrollRef} ref={scrollRef} />
|
|
||||||
{!isLoading && error && <Gutter>{error}</Gutter>}
|
|
||||||
<Fragment>
|
|
||||||
{showPageRange !== false && (
|
|
||||||
<Gutter>
|
|
||||||
<div className={classes.pageRange}>
|
|
||||||
<PageRange
|
|
||||||
collection={relationTo}
|
|
||||||
currentPage={results.page}
|
|
||||||
limit={limit}
|
|
||||||
totalDocs={results.totalDocs}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
)}
|
|
||||||
<Gutter>
|
|
||||||
<div className={classes.grid}>
|
|
||||||
{results.docs?.map((result, index) => {
|
|
||||||
if (typeof result === 'string') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.column} key={index}>
|
|
||||||
<Card doc={result} relationTo="posts" showCategories />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{results.totalPages > 1 && (
|
|
||||||
<Pagination
|
|
||||||
className={classes.pagination}
|
|
||||||
onClick={setPage}
|
|
||||||
page={results.page}
|
|
||||||
totalPages={results.totalPages}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Gutter>
|
|
||||||
</Fragment>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { ArchiveBlockProps } from '../../../_blocks/ArchiveBlock/types.js'
|
|
||||||
|
|
||||||
import { Card } from '../../Card/index.js'
|
|
||||||
import { Gutter } from '../../Gutter/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
className?: string
|
|
||||||
selectedDocs?: ArchiveBlockProps['selectedDocs']
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CollectionArchiveBySelection: React.FC<Props> = (props) => {
|
|
||||||
const { className, selectedDocs } = props
|
|
||||||
|
|
||||||
const result = selectedDocs?.map((doc) => doc.value)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[classes.collectionArchive, className].filter(Boolean).join(' ')}>
|
|
||||||
<Fragment>
|
|
||||||
<Gutter>
|
|
||||||
<div className={classes.grid}>
|
|
||||||
{result?.map((result, index) => {
|
|
||||||
if (typeof result === 'string') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.column} key={index}>
|
|
||||||
<Card doc={result} relationTo="posts" showCategories />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
</Fragment>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { ArchiveBlockProps } from '../../_blocks/ArchiveBlock/types.js'
|
|
||||||
|
|
||||||
import { CollectionArchiveByCollection } from './PopulateByCollection/index.js'
|
|
||||||
import { CollectionArchiveBySelection } from './PopulateBySelection/index.js'
|
|
||||||
|
|
||||||
export type Props = Omit<ArchiveBlockProps, 'blockType'> & {
|
|
||||||
className?: string
|
|
||||||
sort?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CollectionArchive: React.FC<Props> = (props) => {
|
|
||||||
const { className, populateBy, selectedDocs } = props
|
|
||||||
|
|
||||||
if (populateBy === 'selection') {
|
|
||||||
return <CollectionArchiveBySelection className={className} selectedDocs={selectedDocs} />
|
|
||||||
}
|
|
||||||
|
|
||||||
if (populateBy === 'collection') {
|
|
||||||
return <CollectionArchiveByCollection {...props} className={className} />
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { fetchFooter } from '../../_api/fetchFooter.js'
|
|
||||||
import { Gutter } from '../Gutter/index.js'
|
|
||||||
import { CMSLink } from '../Link/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
export async function Footer() {
|
|
||||||
const footer = await fetchFooter()
|
|
||||||
|
|
||||||
const navItems = footer?.navItems || []
|
|
||||||
|
|
||||||
return (
|
|
||||||
<footer className={classes.footer}>
|
|
||||||
<Gutter className={classes.wrap}>
|
|
||||||
<Link href="/">
|
|
||||||
<picture>
|
|
||||||
<img
|
|
||||||
alt="Payload Logo"
|
|
||||||
className={classes.logo}
|
|
||||||
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/admin/assets/images/payload-logo-light.svg"
|
|
||||||
/>
|
|
||||||
</picture>
|
|
||||||
</Link>
|
|
||||||
<nav className={classes.nav}>
|
|
||||||
{navItems.map(({ link }, i) => {
|
|
||||||
return <CMSLink key={i} {...link} />
|
|
||||||
})}
|
|
||||||
<Link href="/admin">Admin</Link>
|
|
||||||
<Link href="https://github.com/payloadcms/payload/tree/main/templates/ecommerce">
|
|
||||||
Source Code
|
|
||||||
</Link>
|
|
||||||
<Link href="https://github.com/payloadcms/payload">Payload</Link>
|
|
||||||
</nav>
|
|
||||||
</Gutter>
|
|
||||||
</footer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import type { Ref } from 'react'
|
|
||||||
|
|
||||||
import React, { forwardRef } from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children: React.ReactNode
|
|
||||||
className?: string
|
|
||||||
left?: boolean
|
|
||||||
ref?: Ref<HTMLDivElement>
|
|
||||||
right?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Gutter: React.FC<Props> = forwardRef<HTMLDivElement, Props>((props, ref) => {
|
|
||||||
const { children, className, left = true, right = true } = props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={[
|
|
||||||
classes.gutter,
|
|
||||||
left && classes.gutterLeft,
|
|
||||||
right && classes.gutterRight,
|
|
||||||
className,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
ref={ref}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
Gutter.displayName = 'Gutter'
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Header as HeaderType } from '../../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { CMSLink } from '../../Link/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const HeaderNav: React.FC<{ header: HeaderType }> = ({ header }) => {
|
|
||||||
const navItems = header?.navItems || []
|
|
||||||
|
|
||||||
return (
|
|
||||||
<nav className={classes.nav}>
|
|
||||||
{navItems.map(({ link }, i) => {
|
|
||||||
return <CMSLink key={i} {...link} />
|
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { fetchHeader } from '../../_api/fetchHeader.js'
|
|
||||||
import { Gutter } from '../Gutter/index.js'
|
|
||||||
import { HeaderNav } from './Nav/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
export async function Header() {
|
|
||||||
const header = await fetchHeader()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<header className={classes.header}>
|
|
||||||
<Gutter className={classes.wrap}>
|
|
||||||
<Link href="/live-preview">
|
|
||||||
<img
|
|
||||||
alt="Payload Logo"
|
|
||||||
className={classes.logo}
|
|
||||||
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/admin/assets/images/payload-logo-dark.svg"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<HeaderNav header={header} />
|
|
||||||
</Gutter>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { HighImpactHero } from '../../_heros/HighImpact/index.js'
|
|
||||||
import { LowImpactHero } from '../../_heros/LowImpact/index.js'
|
|
||||||
|
|
||||||
const heroes = {
|
|
||||||
highImpact: HighImpactHero,
|
|
||||||
lowImpact: LowImpactHero,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Hero: React.FC<Page['hero']> = (props) => {
|
|
||||||
const { type } = props || {}
|
|
||||||
|
|
||||||
if (!type || type === 'none') return null
|
|
||||||
|
|
||||||
const HeroToRender = heroes[type]
|
|
||||||
|
|
||||||
if (!HeroToRender) return null
|
|
||||||
|
|
||||||
return <HeroToRender {...props} />
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page, Post } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
import type { Props as ButtonProps } from '../Button/index.js'
|
|
||||||
|
|
||||||
import { Button } from '../Button/index.js'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
type CMSLinkType = {
|
|
||||||
appearance?: ButtonProps['appearance']
|
|
||||||
children?: React.ReactNode
|
|
||||||
className?: string
|
|
||||||
invert?: ButtonProps['invert']
|
|
||||||
label?: string
|
|
||||||
newTab?: boolean
|
|
||||||
reference?: {
|
|
||||||
relationTo: 'pages' | 'posts'
|
|
||||||
value: Page | Post | string
|
|
||||||
}
|
|
||||||
type?: 'custom' | 'reference'
|
|
||||||
url?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CMSLink: React.FC<CMSLinkType> = ({
|
|
||||||
type,
|
|
||||||
appearance,
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
invert,
|
|
||||||
label,
|
|
||||||
newTab,
|
|
||||||
reference,
|
|
||||||
url,
|
|
||||||
}) => {
|
|
||||||
const href =
|
|
||||||
type === 'reference' && typeof reference?.value === 'object' && reference.value.slug
|
|
||||||
? `/${reference.value.slug}`
|
|
||||||
: url
|
|
||||||
|
|
||||||
if (!href) return null
|
|
||||||
|
|
||||||
if (!appearance) {
|
|
||||||
const newTabProps = newTab ? { rel: 'noopener noreferrer', target: '_blank' } : {}
|
|
||||||
|
|
||||||
if (href || url) {
|
|
||||||
return (
|
|
||||||
<Link {...newTabProps} className={className} href={href || url || ''}>
|
|
||||||
{label && label}
|
|
||||||
{children && children}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
appearance={appearance}
|
|
||||||
className={className}
|
|
||||||
href={href}
|
|
||||||
invert={invert}
|
|
||||||
label={label}
|
|
||||||
newTab={newTab}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import type { StaticImageData } from 'next/image.js'
|
|
||||||
|
|
||||||
import NextImageWithDefault from 'next/image.js'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Props as MediaProps } from '../types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
|
||||||
import cssVariables from '../../../cssVariables.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const { breakpoints } = cssVariables
|
|
||||||
|
|
||||||
const NextImage = (NextImageWithDefault.default ||
|
|
||||||
NextImageWithDefault) as typeof NextImageWithDefault.default
|
|
||||||
|
|
||||||
export const Image: React.FC<MediaProps> = (props) => {
|
|
||||||
const {
|
|
||||||
alt: altFromProps,
|
|
||||||
fill,
|
|
||||||
imgClassName,
|
|
||||||
onClick,
|
|
||||||
onLoad: onLoadFromProps,
|
|
||||||
priority,
|
|
||||||
resource,
|
|
||||||
src: srcFromProps,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = React.useState(true)
|
|
||||||
|
|
||||||
let width: number | undefined
|
|
||||||
let height: number | undefined
|
|
||||||
let alt = altFromProps
|
|
||||||
let src: StaticImageData | string = srcFromProps || ''
|
|
||||||
|
|
||||||
if (!src && resource && typeof resource !== 'string') {
|
|
||||||
const {
|
|
||||||
alt: altFromResource,
|
|
||||||
filename: fullFilename,
|
|
||||||
height: fullHeight,
|
|
||||||
width: fullWidth,
|
|
||||||
} = resource
|
|
||||||
|
|
||||||
width = fullWidth || undefined
|
|
||||||
height = fullHeight || undefined
|
|
||||||
alt = altFromResource
|
|
||||||
|
|
||||||
const filename = fullFilename
|
|
||||||
|
|
||||||
src = `${PAYLOAD_SERVER_URL}/api/media/file/${filename}`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: this is used by the browser to determine which image to download at different screen sizes
|
|
||||||
const sizes = Object.entries(breakpoints)
|
|
||||||
.map(([, value]) => `(max-width: ${value}px) ${value}px`)
|
|
||||||
.join(', ')
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NextImage
|
|
||||||
alt={alt || ''}
|
|
||||||
className={[isLoading && classes.placeholder, classes.image, imgClassName]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
fill={fill}
|
|
||||||
height={!fill ? height : undefined}
|
|
||||||
onClick={onClick}
|
|
||||||
onLoad={() => {
|
|
||||||
setIsLoading(false)
|
|
||||||
if (typeof onLoadFromProps === 'function') {
|
|
||||||
onLoadFromProps()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
priority={priority}
|
|
||||||
sizes={sizes}
|
|
||||||
src={src}
|
|
||||||
width={!fill ? width : undefined}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import React, { useEffect, useRef } from 'react'
|
|
||||||
|
|
||||||
import type { Props as MediaProps } from '../types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const Video: React.FC<MediaProps> = (props) => {
|
|
||||||
const { onClick, resource, videoClassName } = props
|
|
||||||
|
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
|
||||||
// const [showFallback] = useState<boolean>()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const { current: video } = videoRef
|
|
||||||
if (video) {
|
|
||||||
video.addEventListener('suspend', () => {
|
|
||||||
// setShowFallback(true);
|
|
||||||
// console.warn('Video was suspended, rendering fallback image.')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
if (resource && typeof resource !== 'string') {
|
|
||||||
const { filename } = resource
|
|
||||||
|
|
||||||
return (
|
|
||||||
<video
|
|
||||||
autoPlay
|
|
||||||
className={[classes.video, videoClassName].filter(Boolean).join(' ')}
|
|
||||||
controls={false}
|
|
||||||
loop
|
|
||||||
muted
|
|
||||||
onClick={onClick}
|
|
||||||
playsInline
|
|
||||||
ref={videoRef}
|
|
||||||
>
|
|
||||||
<source src={`${PAYLOAD_SERVER_URL}/media/${filename}`} />
|
|
||||||
</video>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import type { ElementType } from 'react'
|
|
||||||
|
|
||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Props } from './types.js'
|
|
||||||
|
|
||||||
import { Image } from './Image/index.js'
|
|
||||||
import { Video } from './Video/index.js'
|
|
||||||
|
|
||||||
export const Media: React.FC<Props> = (props) => {
|
|
||||||
const { className, htmlElement = 'div', resource } = props
|
|
||||||
|
|
||||||
const isVideo = typeof resource !== 'string' && resource?.mimeType?.includes('video')
|
|
||||||
const Tag = (htmlElement as ElementType) || Fragment
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tag
|
|
||||||
{...(htmlElement !== null
|
|
||||||
? {
|
|
||||||
className,
|
|
||||||
}
|
|
||||||
: {})}
|
|
||||||
>
|
|
||||||
{isVideo ? (
|
|
||||||
<Video {...props} />
|
|
||||||
) : (
|
|
||||||
<Image {...props} /> // eslint-disable-line
|
|
||||||
)}
|
|
||||||
</Tag>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import type { StaticImageData } from 'next/image'
|
|
||||||
import type { ElementType, Ref } from 'react'
|
|
||||||
|
|
||||||
import type { Media as MediaType } from '../../../payload-types'
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
alt?: string
|
|
||||||
className?: string
|
|
||||||
fill?: boolean // for NextImage only
|
|
||||||
htmlElement?: ElementType | null
|
|
||||||
imgClassName?: string
|
|
||||||
onClick?: () => void
|
|
||||||
onLoad?: () => void
|
|
||||||
priority?: boolean // for NextImage only
|
|
||||||
ref?: Ref<HTMLImageElement | HTMLVideoElement | null>
|
|
||||||
resource?: MediaType | string // for Payload media
|
|
||||||
size?: string // for NextImage only
|
|
||||||
src?: StaticImageData // for static media
|
|
||||||
videoClassName?: string
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const defaultLabels = {
|
|
||||||
plural: 'Docs',
|
|
||||||
singular: 'Doc',
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultCollectionLabels = {
|
|
||||||
products: {
|
|
||||||
plural: 'Products',
|
|
||||||
singular: 'Product',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PageRange: React.FC<{
|
|
||||||
className?: string
|
|
||||||
collection?: string
|
|
||||||
collectionLabels?: {
|
|
||||||
plural?: string
|
|
||||||
singular?: string
|
|
||||||
}
|
|
||||||
currentPage?: number
|
|
||||||
limit?: number
|
|
||||||
totalDocs?: number
|
|
||||||
}> = (props) => {
|
|
||||||
const {
|
|
||||||
className,
|
|
||||||
collection,
|
|
||||||
collectionLabels: collectionLabelsFromProps,
|
|
||||||
currentPage,
|
|
||||||
limit,
|
|
||||||
totalDocs,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
const indexStart = (currentPage ? currentPage - 1 : 1) * (limit || 1) + 1
|
|
||||||
let indexEnd = (currentPage || 1) * (limit || 1)
|
|
||||||
if (totalDocs && indexEnd > totalDocs) indexEnd = totalDocs
|
|
||||||
|
|
||||||
const { plural, singular } =
|
|
||||||
collectionLabelsFromProps || defaultCollectionLabels[collection || ''] || defaultLabels || {}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[className, classes.pageRange].filter(Boolean).join(' ')}>
|
|
||||||
{(typeof totalDocs === 'undefined' || totalDocs === 0) && 'Search produced no results.'}
|
|
||||||
{typeof totalDocs !== 'undefined' &&
|
|
||||||
totalDocs > 0 &&
|
|
||||||
`Showing ${indexStart} - ${indexEnd} of ${totalDocs} ${totalDocs > 1 ? plural : singular}`}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { Chevron } from '../Chevron/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const Pagination: React.FC<{
|
|
||||||
className?: string
|
|
||||||
onClick: (page: number) => void
|
|
||||||
page: number
|
|
||||||
totalPages: number
|
|
||||||
}> = (props) => {
|
|
||||||
const { className, onClick, page, totalPages } = props
|
|
||||||
const hasNextPage = page < totalPages
|
|
||||||
const hasPrevPage = page > 1
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[classes.pagination, className].filter(Boolean).join(' ')}>
|
|
||||||
<button
|
|
||||||
className={classes.button}
|
|
||||||
disabled={!hasPrevPage}
|
|
||||||
onClick={() => {
|
|
||||||
onClick(page - 1)
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Chevron className={classes.icon} rotate={90} />
|
|
||||||
</button>
|
|
||||||
<div className={classes.pageRange}>
|
|
||||||
<span className={classes.pageRangeLabel}>
|
|
||||||
Page {page} of {totalPages}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className={classes.button}
|
|
||||||
disabled={!hasNextPage}
|
|
||||||
onClick={() => {
|
|
||||||
onClick(page + 1)
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<Chevron className={classes.icon} rotate={-90} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
import serializeLexical from './serializeLexical.js'
|
|
||||||
import serializeSlate from './serializeSlate.js'
|
|
||||||
|
|
||||||
const RichText: React.FC<{
|
|
||||||
className?: string
|
|
||||||
content: any
|
|
||||||
renderUploadFilenameOnly?: boolean
|
|
||||||
serializer?: 'lexical' | 'slate'
|
|
||||||
}> = ({ className, content, renderUploadFilenameOnly, serializer = 'slate' }) => {
|
|
||||||
if (!content) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={[classes.richText, className].filter(Boolean).join(' ')}>
|
|
||||||
{serializer === 'slate'
|
|
||||||
? serializeSlate(content, renderUploadFilenameOnly)
|
|
||||||
: serializeLexical(content, renderUploadFilenameOnly)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RichText
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export type VerticalPaddingOptions = 'large' | 'medium' | 'none'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
bottom?: VerticalPaddingOptions
|
|
||||||
children: React.ReactNode
|
|
||||||
className?: string
|
|
||||||
top?: VerticalPaddingOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
export const VerticalPadding: React.FC<Props> = ({
|
|
||||||
bottom = 'medium',
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
top = 'medium',
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={[className, classes[`top-${top}`], classes[`bottom-${bottom}`]]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' ')}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
@use './queries.scss' as *;
|
|
||||||
@use './colors.scss' as *;
|
|
||||||
@use './type.scss' as *;
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--base: 24px;
|
|
||||||
--font-body: system-ui;
|
|
||||||
--font-mono: 'Roboto Mono', monospace;
|
|
||||||
|
|
||||||
--gutter-h: 180px;
|
|
||||||
--block-padding: 120px;
|
|
||||||
|
|
||||||
--theme-text: var(--color-base-750);
|
|
||||||
|
|
||||||
@include large-break {
|
|
||||||
--gutter-h: 144px;
|
|
||||||
--block-padding: 96px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include mid-break {
|
|
||||||
--gutter-h: 24px;
|
|
||||||
--block-padding: 60px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
@extend %body;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
|
||||||
|
|
||||||
html,
|
|
||||||
body,
|
|
||||||
#app {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: var(--font-body);
|
|
||||||
margin: 0;
|
|
||||||
color: var(--theme-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
::selection {
|
|
||||||
background: var(--color-success-500);
|
|
||||||
color: var(--color-base-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
::-moz-selection {
|
|
||||||
background: var(--color-success-500);
|
|
||||||
color: var(--color-base-800);
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
@extend %h1;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
@extend %h2;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
@extend %h3;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
@extend %h4;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
@extend %h5;
|
|
||||||
}
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
@extend %h6;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: var(--base) 0;
|
|
||||||
|
|
||||||
@include mid-break {
|
|
||||||
margin: calc(var(--base) * 0.75) 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#page-title {
|
|
||||||
@extend %h6;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
|
||||||
ol {
|
|
||||||
padding-left: var(--base);
|
|
||||||
margin: 0 0 var(--base);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: currentColor;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
opacity: 0.8;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
opacity: 0.7;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { Media } from '../../_components/Media/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const HighImpactHero: React.FC<Page['hero']> = ({ media, richText }) => {
|
|
||||||
return (
|
|
||||||
<Gutter className={classes.hero}>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<RichText content={richText} />
|
|
||||||
</div>
|
|
||||||
<div className={classes.media}>
|
|
||||||
{typeof media === 'object' && media !== null && (
|
|
||||||
<Fragment>
|
|
||||||
<Media
|
|
||||||
// fill
|
|
||||||
imgClassName={classes.image}
|
|
||||||
priority
|
|
||||||
resource={media}
|
|
||||||
/>
|
|
||||||
{media?.caption && <RichText className={classes.caption} content={media.caption} />}
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import { VerticalPadding } from '../../_components/VerticalPadding/index.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
export const LowImpactHero: React.FC<Page['hero']> = ({ richText }) => {
|
|
||||||
return (
|
|
||||||
<Gutter className={classes.lowImpactHero}>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<VerticalPadding>
|
|
||||||
<RichText className={classes.richText} content={richText} />
|
|
||||||
</VerticalPadding>
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import LinkWithDefault from 'next/link.js'
|
|
||||||
import React, { Fragment } from 'react'
|
|
||||||
|
|
||||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
|
||||||
|
|
||||||
import { PAYLOAD_SERVER_URL } from '../../_api/serverURL.js'
|
|
||||||
import { Gutter } from '../../_components/Gutter/index.js'
|
|
||||||
import { Media } from '../../_components/Media/index.js'
|
|
||||||
import RichText from '../../_components/RichText/index.js'
|
|
||||||
import { formatDateTime } from '../../_utilities/formatDateTime.js'
|
|
||||||
import classes from './index.module.scss'
|
|
||||||
|
|
||||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
|
||||||
|
|
||||||
export const PostHero: React.FC<{
|
|
||||||
post: Post
|
|
||||||
}> = ({ post }) => {
|
|
||||||
const { id, createdAt, meta: { description, image: metaImage } = {} } = post
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<Gutter className={classes.postHero}>
|
|
||||||
<div className={classes.content}>
|
|
||||||
<RichText className={classes.richText} content={post?.hero?.richText} />
|
|
||||||
<p className={classes.meta}>
|
|
||||||
{createdAt && (
|
|
||||||
<Fragment>
|
|
||||||
{'Created on '}
|
|
||||||
{formatDateTime(createdAt)}
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<p className={classes.description}>
|
|
||||||
{`${description ? `${description} ` : ''}To edit this post, `}
|
|
||||||
<Link href={`${PAYLOAD_SERVER_URL}/admin/collections/posts/${id}`}>
|
|
||||||
navigate to the admin dashboard
|
|
||||||
</Link>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes.media}>
|
|
||||||
<div className={classes.mediaWrapper}>
|
|
||||||
{!metaImage && <div className={classes.placeholder}>No image</div>}
|
|
||||||
{metaImage && typeof metaImage !== 'string' && (
|
|
||||||
<Media fill imgClassName={classes.image} resource={metaImage} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{metaImage && typeof metaImage !== 'string' && metaImage?.caption && (
|
|
||||||
<RichText className={classes.caption} content={metaImage.caption} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Gutter>
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import type { Metadata } from 'next'
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { Footer } from './_components/Footer/index.js'
|
|
||||||
import { Header } from './_components/Header/index.js'
|
|
||||||
import './_css/app.scss'
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
description: 'Payload Live Preview',
|
|
||||||
title: 'Payload Live Preview',
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<html lang="en">
|
|
||||||
<body>
|
|
||||||
<Header />
|
|
||||||
{children}
|
|
||||||
<Footer />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { Gutter } from './_components/Gutter/index.js'
|
|
||||||
import { VerticalPadding } from './_components/VerticalPadding/index.js'
|
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return (
|
|
||||||
<main>
|
|
||||||
<VerticalPadding bottom="medium" top="none">
|
|
||||||
<Gutter>
|
|
||||||
<h1>404</h1>
|
|
||||||
<p>This page could not be found.</p>
|
|
||||||
</Gutter>
|
|
||||||
</VerticalPadding>
|
|
||||||
</main>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import PageTemplate from './(pages)/[slug]/page.js'
|
|
||||||
|
|
||||||
export default PageTemplate
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export const GET = () => {
|
|
||||||
return Response.json({
|
|
||||||
hello: 'elliot',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,7 @@ import { webpackBundler } from '@payloadcms/bundler-webpack'
|
|||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
// highlight-start
|
// highlight-start
|
||||||
admin: {
|
admin: {
|
||||||
bundler: webpackBundler(), // or viteBundler()
|
bundler: webpackBundler() // or viteBundler()
|
||||||
},
|
},
|
||||||
// highlight-end
|
// highlight-end
|
||||||
})
|
})
|
||||||
@@ -48,7 +48,7 @@ Since the bundled file is sent to the browser, it can't include any server-only
|
|||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
<strong>Using environment variables in the admin UI</strong>
|
<strong>Using environment variables in the admin UI</strong>
|
||||||
<br />
|
<br />
|
||||||
Bundles should not contain sensitive information. By default, Payload excludes env variables from
|
Bundles should not contain sensitive information. By default, Payload
|
||||||
the bundle. If you need to use env variables in your payload config, you need to prefix them with
|
excludes env variables from the bundle. If you need to use env variables in your payload config,
|
||||||
`PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
you need to prefix them with `PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|||||||
@@ -13,29 +13,29 @@ To swap in your own React component, first, consult the list of available compon
|
|||||||
<Banner type="success">
|
<Banner type="success">
|
||||||
<strong>Tip:</strong>
|
<strong>Tip:</strong>
|
||||||
<br />
|
<br />
|
||||||
Custom components will automatically be provided with all props that the default component
|
Custom components will automatically be provided with all props that the default component normally
|
||||||
normally accepts.
|
accepts.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
### Base Component Overrides
|
### Base Component Overrides
|
||||||
|
|
||||||
You can override a set of admin panel-wide components by providing a component to your base Payload config's `admin.components` property. The following options are available:
|
You can override a set of admin panel-wide components by providing a component to your base Payload config's `admin.components` property. The following options are available:
|
||||||
|
|
||||||
| Path | Description |
|
| Path | Description |
|
||||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
||||||
| **`BeforeNavLinks`** | Array of components to inject into the built-in Nav, _before_ the links themselves. |
|
| **`BeforeNavLinks`** | Array of components to inject into the built-in Nav, _before_ the links themselves. |
|
||||||
| **`AfterNavLinks`** | Array of components to inject into the built-in Nav, _after_ the links. |
|
| **`AfterNavLinks`** | Array of components to inject into the built-in Nav, _after_ the links. |
|
||||||
| **`BeforeDashboard`** | Array of components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
|
| **`BeforeDashboard`** | Array of components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
|
||||||
| **`AfterDashboard`** | Array of components to inject into the built-in Dashboard, _after_ the default dashboard contents. [Demo](https://github.com/payloadcms/payload/tree/main/test/admin/components/AfterDashboard/index.tsx) |
|
| **`AfterDashboard`** | Array of components to inject into the built-in Dashboard, _after_ the default dashboard contents. [Demo](https://github.com/payloadcms/payload/tree/main/test/admin/components/AfterDashboard/index.tsx) |
|
||||||
| **`BeforeLogin`** | Array of components to inject into the built-in Login, _before_ the default login form. |
|
| **`BeforeLogin`** | Array of components to inject into the built-in Login, _before_ the default login form. |
|
||||||
| **`AfterLogin`** | Array of components to inject into the built-in Login, _after_ the default login form. |
|
| **`AfterLogin`** | Array of components to inject into the built-in Login, _after_ the default login form. |
|
||||||
| **`logout.Button`** | A custom React component. |
|
| **`logout.Button`** | A custom React component. |
|
||||||
| **`graphics.Icon`** | Used as a graphic within the `Nav` component. Often represents a condensed version of a full logo. |
|
| **`graphics.Icon`** | Used as a graphic within the `Nav` component. Often represents a condensed version of a full logo. |
|
||||||
| **`graphics.Logo`** | The full logo to be used in contexts like the `Login` view. |
|
| **`graphics.Logo`** | The full logo to be used in contexts like the `Login` view. |
|
||||||
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
||||||
| **`actions`** | Array of custom components to be rendered in the Payload Admin UI header, providing additional interactivity and functionality. |
|
| **`actions`** | Array of custom components to be rendered in the Payload Admin UI header, providing additional interactivity and functionality. |
|
||||||
| **`views`** | Override or create new views within the Payload Admin UI. [More](#views) |
|
| **`views`** | Override or create new views within the Payload Admin UI. [More](#views) |
|
||||||
|
|
||||||
Here is a full example showing how to swap some of these components for your own.
|
Here is a full example showing how to swap some of these components for your own.
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ export default buildConfig({
|
|||||||
|
|
||||||
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views by default, all of which can be overridden:
|
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views by default, all of which can be overridden:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| --------------- | ----------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
|
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
|
||||||
| **`Dashboard`** | The main landing page of the Admin panel. |
|
| **`Dashboard`** | The main landing page of the Admin panel. |
|
||||||
|
|
||||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
|
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
|
||||||
|
|
||||||
@@ -135,10 +135,7 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
|
|||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
<strong>Note:</strong>
|
<strong>Note:</strong>
|
||||||
<br />
|
<br />
|
||||||
Routes are cascading. This means that unless explicitly given the `exact` property, they will
|
Routes are cascading. This means that unless explicitly given the `exact` property, they will match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all routes in your application. Alternatively, you could define your nested route _before_ your parent route.
|
||||||
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
|
|
||||||
routes in your application. Alternatively, you could define your nested route _before_ your parent
|
|
||||||
route.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
|
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
|
||||||
@@ -217,7 +214,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
PreviewButton: CustomPreviewButton,
|
PreviewButton: CustomPreviewButton,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -225,10 +222,10 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
|
|
||||||
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default, all of which can be overridden:
|
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default, all of which can be overridden:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ---------- | ------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
||||||
| **`List`** | The List view is used to show a list of documents for a given collection. |
|
| **`List`** | The List view is used to show a list of documents for a given collection. |
|
||||||
|
|
||||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
|
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
|
||||||
|
|
||||||
@@ -313,9 +310,9 @@ As with Collections, you can override components on a global-by-global basis via
|
|||||||
|
|
||||||
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default, all of which can be overridden:
|
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default, all of which can be overridden:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ---------- | ------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
|
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
|
||||||
|
|
||||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
|
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
|
||||||
|
|
||||||
@@ -382,13 +379,13 @@ You can also add _new_ tabs to the `Edit` view by adding another key to the `com
|
|||||||
|
|
||||||
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views by default, all of which can be overridden:
|
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views by default, all of which can be overridden:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Default`** | The Default view is the primary view in which your document is edited. |
|
| **`Default`** | The Default view is the primary view in which your document is edited. |
|
||||||
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
|
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
|
||||||
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
||||||
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
|
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
|
||||||
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
|
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
@@ -399,8 +396,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
views: {
|
views: {
|
||||||
Edit: {
|
Edit: { // You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
||||||
// You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
|
||||||
Default: MyCustomDefaultTab,
|
Default: MyCustomDefaultTab,
|
||||||
Versions: MyCustomVersionsTab,
|
Versions: MyCustomVersionsTab,
|
||||||
Version: MyCustomVersionTab,
|
Version: MyCustomVersionTab,
|
||||||
@@ -427,7 +423,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
Component: MyCustomTab,
|
Component: MyCustomTab,
|
||||||
path: '/my-custom-tab',
|
path: '/my-custom-tab',
|
||||||
// You an swap the entire tab component out for your own
|
// You an swap the entire tab component out for your own
|
||||||
Tab: MyCustomTab,
|
Tab: MyCustomTab
|
||||||
},
|
},
|
||||||
AnotherCustomView: {
|
AnotherCustomView: {
|
||||||
Component: AnotherCustomView,
|
Component: AnotherCustomView,
|
||||||
@@ -436,7 +432,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
Tab: {
|
Tab: {
|
||||||
label: 'Another Custom View',
|
label: 'Another Custom View',
|
||||||
href: '/another-custom-view',
|
href: '/another-custom-view',
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -543,6 +539,7 @@ const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
|
|||||||
const { value, setValue } = useField<string>({ path })
|
const { value, setValue } = useField<string>({ path })
|
||||||
// highlight-end
|
// highlight-end
|
||||||
|
|
||||||
|
|
||||||
return <input onChange={(e) => setValue(e.target.value)} value={value} />
|
return <input onChange={(e) => setValue(e.target.value)} value={value} />
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -556,11 +553,11 @@ const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
|
|||||||
|
|
||||||
These are the props that will be passed to your custom Label.
|
These are the props that will be passed to your custom Label.
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| -------------- | ---------------------------------------------------------------- |
|
| ---------------- | ---------------------------------------------------------------- |
|
||||||
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
||||||
| **`label`** | Label value provided in field, it can be used with i18n. |
|
| **`label`** | Label value provided in field, it can be used with i18n. |
|
||||||
| **`required`** | A boolean value that represents if the field is required or not. |
|
| **`required`** | A boolean value that represents if the field is required or not. |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@@ -582,12 +579,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
|||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
|
|
||||||
if (label) {
|
if (label) {
|
||||||
return (
|
return (<span>
|
||||||
<span>
|
{getTranslation(label, i18n)}
|
||||||
{getTranslation(label, i18n)}
|
{required && <span className="required">*</span>}
|
||||||
{required && <span className="required">*</span>}
|
</span>);
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -598,10 +593,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
These are the props that will be passed to your custom Error.
|
These are the props that will be passed to your custom Error.
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| --------------- | ------------------------------------------------------------- |
|
| ---------------- | ------------------------------------------------------------- |
|
||||||
| **`message`** | The error message. |
|
| **`message`** | The error message. |
|
||||||
| **`showError`** | A boolean value that represents if the error should be shown. |
|
| **`showError`** | A boolean value that represents if the error should be shown. |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@@ -617,8 +612,8 @@ const CustomError: React.FC<Props> = (props) => {
|
|||||||
const { message, showError } = props
|
const { message, showError } = props
|
||||||
|
|
||||||
if (showError) {
|
if (showError) {
|
||||||
return <p style={{ color: 'red' }}>{message}</p>
|
return <p style={{color: 'red'}}>{message}</p>
|
||||||
} else return null
|
} else return null;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -635,15 +630,7 @@ import { Field } from 'payload/types'
|
|||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
const ClearButton: React.FC = () => {
|
const ClearButton: React.FC = () => {
|
||||||
return (
|
return <button onClick={() => {/* ... */}}>X</button>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
/* ... */
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
X
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleField: Field = {
|
const titleField: Field = {
|
||||||
@@ -651,12 +638,12 @@ const titleField: Field = {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
afterInput: [ClearButton],
|
afterInput: [ClearButton]
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default titleField
|
export default titleField;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom providers
|
## Custom providers
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ By default the browser bundle will now include all the code from that file and a
|
|||||||
To fix this, we need to alias the `createStripeSubscription` file to a different file that can safely be included in the browser bundle.
|
To fix this, we need to alias the `createStripeSubscription` file to a different file that can safely be included in the browser bundle.
|
||||||
|
|
||||||
First, we will create a mock file to replace the server-only file when bundling:
|
First, we will create a mock file to replace the server-only file when bundling:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// mocks/modules.js
|
// mocks/modules.js
|
||||||
|
|
||||||
@@ -132,7 +131,7 @@ import { Subscriptions } from './collections/Subscriptions'
|
|||||||
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
|
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
|
||||||
const fullFilePath = path.resolve(
|
const fullFilePath = path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
'collections/Subscriptions/hooks/createStripeSubscription',
|
'collections/Subscriptions/hooks/createStripeSubscription'
|
||||||
)
|
)
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
@@ -174,23 +173,24 @@ export default buildConfig({
|
|||||||
admin: {
|
admin: {
|
||||||
bundler: viteBundler(),
|
bundler: viteBundler(),
|
||||||
vite: (incomingViteConfig) => {
|
vite: (incomingViteConfig) => {
|
||||||
const existingAliases = incomingViteConfig?.resolve?.alias || {}
|
const existingAliases = incomingViteConfig?.resolve?.alias || {};
|
||||||
let aliasArray: { find: string | RegExp; replacement: string }[] = []
|
let aliasArray: { find: string | RegExp; replacement: string; }[] = [];
|
||||||
|
|
||||||
// Pass the existing Vite aliases
|
// Pass the existing Vite aliases
|
||||||
if (Array.isArray(existingAliases)) {
|
if (Array.isArray(existingAliases)) {
|
||||||
aliasArray = existingAliases
|
aliasArray = existingAliases;
|
||||||
} else {
|
} else {
|
||||||
aliasArray = Object.values(existingAliases)
|
aliasArray = Object.values(existingAliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// highlight-start
|
// highlight-start
|
||||||
// Add your own aliases using the find and replacement keys
|
// Add your own aliases using the find and replacement keys
|
||||||
// remember, vite aliases are exact-match only
|
// remember, vite aliases are exact-match only
|
||||||
aliasArray.push({
|
aliasArray.push({
|
||||||
find: '../server-only-module',
|
find: '../server-only-module',
|
||||||
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js'),
|
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js')
|
||||||
})
|
});
|
||||||
// highlight-end
|
// highlight-end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -198,8 +198,8 @@ export default buildConfig({
|
|||||||
resolve: {
|
resolve: {
|
||||||
...(incomingViteConfig?.resolve || {}),
|
...(incomingViteConfig?.resolve || {}),
|
||||||
alias: aliasArray,
|
alias: aliasArray,
|
||||||
},
|
}
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -635,43 +635,12 @@ export const CustomArrayManager = () => {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
### useCollapsible
|
|
||||||
|
|
||||||
The `useCollapsible` hook allows you to control parent collapsibles:
|
|
||||||
|
|
||||||
| Property | Description |
|
|
||||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------ | --- |
|
|
||||||
| **`collapsed`** | State of the collapsible. `true` if open, `false` if collapsed |
|
|
||||||
| **`isVisible`** | If nested, determine if the nearest collapsible is visible. `true` if no parent is closed, `false` otherwise |
|
|
||||||
| **`toggle`** | Toggles the state of the nearest collapsible |
|
|
||||||
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
import { useCollapsible } from 'payload/components/utilities'
|
|
||||||
|
|
||||||
const CustomComponent: React.FC = () => {
|
|
||||||
const { collapsed, toggle } = useCollapsible()
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p className="field-type">I am {collapsed ? 'closed' : 'open'}</p>
|
|
||||||
<button onClick={toggle} type="button">
|
|
||||||
Toggle
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### useDocumentInfo
|
### useDocumentInfo
|
||||||
|
|
||||||
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`collection`** | If the doc is a collection, its collection config will be returned |
|
| **`collection`** | If the doc is a collection, its collection config will be returned |
|
||||||
| **`global`** | If the doc is a global, its global config will be returned |
|
| **`global`** | If the doc is a global, its global config will be returned |
|
||||||
| **`id`** | If the doc is a collection, its ID will be returned |
|
| **`id`** | If the doc is a collection, its ID will be returned |
|
||||||
@@ -804,17 +773,15 @@ const MyComponent: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>
|
<span>The current theme is {theme} and autoMode is {autoMode}</span>
|
||||||
The current theme is {theme} and autoMode is {autoMode}
|
<button
|
||||||
</span>
|
type="button"
|
||||||
<button
|
onClick={() => setTheme(prev => prev === "light" ? "dark" : "light")}
|
||||||
type="button"
|
|
||||||
onClick={() => setTheme((prev) => (prev === 'light' ? 'dark' : 'light'))}
|
|
||||||
>
|
>
|
||||||
Toggle theme
|
Toggle theme
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -835,7 +802,10 @@ const MyComponent: React.FC = () => {
|
|||||||
// highlight-end
|
// highlight-end
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button type="button" onClick={resetColumns}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={resetColumns}
|
||||||
|
>
|
||||||
Reset columns
|
Reset columns
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
@@ -846,10 +816,10 @@ const MyComponent: React.FC = () => {
|
|||||||
|
|
||||||
The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following:
|
The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
|
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
|
||||||
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
|
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -859,11 +829,14 @@ import { useDocumentEvents } from 'payload/components/hooks'
|
|||||||
const ListenForUpdates: React.FC = () => {
|
const ListenForUpdates: React.FC = () => {
|
||||||
const { mostRecentUpdate } = useDocumentEvents()
|
const { mostRecentUpdate } = useDocumentEvents()
|
||||||
|
|
||||||
return <span>{JSON.stringify(mostRecentUpdate)}</span>
|
return (
|
||||||
|
<span>
|
||||||
|
{JSON.stringify(mostRecentUpdate)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<Banner type="info">
|
<Banner type="info">
|
||||||
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future
|
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future it will track more document-related events as needed, such as document creation, deletion, etc.
|
||||||
it will track more document-related events as needed, such as document creation, deletion, etc.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ desc: NEEDS TO BE WRITTEN
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Banner type="info">
|
<Banner type="info">
|
||||||
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love
|
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
|
||||||
to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
Payload has a Vite bundler that you can install and bundle the Admin Panel with. This is an alternative to the [Webpack](/docs/admin/webpack) bundler and might give some performance boosts to your development workflow.
|
Payload has a Vite bundler that you can install and bundle the Admin Panel with. This is an alternative to the [Webpack](/docs/admin/webpack) bundler and might give some performance boosts to your development workflow.
|
||||||
@@ -28,7 +27,7 @@ export default buildConfig({
|
|||||||
collections: [],
|
collections: [],
|
||||||
admin: {
|
admin: {
|
||||||
bundler: viteBundler(),
|
bundler: viteBundler(),
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -37,8 +36,7 @@ Vite works fundamentally differently than Webpack. In development mode, it will
|
|||||||
It then uses Rollup to create production builds of your admin UI. With Vite, you should see a decent performance boost—especially after your first cold start. However, that first cold start might take a few more seconds.
|
It then uses Rollup to create production builds of your admin UI. With Vite, you should see a decent performance boost—especially after your first cold start. However, that first cold start might take a few more seconds.
|
||||||
|
|
||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
In most cases, Vite should work out of the box. But existing Payload plugins may need to make
|
In most cases, Vite should work out of the box. But existing Payload plugins may need to make compatibility changes to support Vite.
|
||||||
compatibility changes to support Vite.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
This is because Vite aliases work fundamentally differently than Webpack aliases, and Payload relies on aliasing server-only code out of the Payload config to ensure that the bundled admin JS works within your browser.
|
This is because Vite aliases work fundamentally differently than Webpack aliases, and Payload relies on aliasing server-only code out of the Payload config to ensure that the bundled admin JS works within your browser.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { webpackBundler } from '@payloadcms/bundler-webpack'
|
|||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
// highlight-start
|
// highlight-start
|
||||||
admin: {
|
admin: {
|
||||||
bundler: webpackBundler(),
|
bundler: webpackBundler()
|
||||||
},
|
},
|
||||||
// highlight-end
|
// highlight-end
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ To enable API keys on a collection, set the `useAPIKey` auth option to `true`. F
|
|||||||
<strong>Important:</strong>
|
<strong>Important:</strong>
|
||||||
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
|
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
|
||||||
<br />
|
<br />
|
||||||
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will
|
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will no longer be valid.
|
||||||
no longer be valid.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
#### Authenticating via API Key
|
#### Authenticating via API Key
|
||||||
|
|||||||
@@ -57,7 +57,12 @@ export const Admins: CollectionConfig = {
|
|||||||
name: 'role',
|
name: 'role',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
required: true,
|
required: true,
|
||||||
options: ['user', 'admin', 'editor', 'developer'],
|
options: [
|
||||||
|
'user',
|
||||||
|
'admin',
|
||||||
|
'editor',
|
||||||
|
'developer',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ It's often best practice to write your Collections in separate files and then im
|
|||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||||
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||||
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||||
@@ -68,7 +68,7 @@ You can customize the way that the Admin panel behaves on a collection-by-collec
|
|||||||
property on a collection's config.
|
property on a collection's config.
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
||||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. |
|
| `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](#admin-hooks) |
|
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
|
||||||
@@ -129,7 +129,7 @@ export const Posts: CollectionConfig = {
|
|||||||
Here are a few options that you can specify options for pagination on a collection-by-collection basis:
|
Here are a few options that you can specify options for pagination on a collection-by-collection basis:
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| -------------- | --------------------------------------------------------------------------------------------------- |
|
|----------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
||||||
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. |
|
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. |
|
||||||
|
|
||||||
@@ -167,6 +167,53 @@ those three fields plus the ID field.
|
|||||||
so your admin queries can remain performant.
|
so your admin queries can remain performant.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
|
### Admin Hooks
|
||||||
|
|
||||||
|
In addition to collection hooks themselves, Payload provides for admin UI-specific hooks that you can leverage.
|
||||||
|
|
||||||
|
**`beforeDuplicate`**
|
||||||
|
|
||||||
|
The `beforeDuplicate` hook is an async function that accepts an object containing the data to duplicate, as well as the
|
||||||
|
locale of the doc to duplicate. Within this hook, you can modify the data to be duplicated, which is useful in cases
|
||||||
|
where you have unique fields that need to be incremented or similar, as well as if you want to automatically modify a
|
||||||
|
document's `title`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { BeforeDuplicate, CollectionConfig } from 'payload/types'
|
||||||
|
// Your auto-generated Page type
|
||||||
|
import { Page } from '../payload-types.ts'
|
||||||
|
|
||||||
|
const beforeDuplicate: BeforeDuplicate<Page> = ({ data }) => {
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
title: `${data.title} Copy`,
|
||||||
|
uniqueField: data.uniqueField ? `${data.uniqueField}-copy` : '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Page: CollectionConfig = {
|
||||||
|
slug: 'pages',
|
||||||
|
admin: {
|
||||||
|
hooks: {
|
||||||
|
beforeDuplicate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
type: 'text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'uniqueField',
|
||||||
|
type: 'text',
|
||||||
|
unique: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### TypeScript
|
### TypeScript
|
||||||
|
|
||||||
You can import collection types as follows:
|
You can import collection types as follows:
|
||||||
|
|||||||
@@ -65,14 +65,14 @@ You can find a few [example Global configs](https://github.com/payloadcms/public
|
|||||||
|
|
||||||
You can customize the way that the Admin panel behaves on a Global-by-Global basis by defining the `admin` property on a Global's config.
|
You can customize the way that the Admin panel behaves on a Global-by-Global basis by defining the `admin` property on a Global's config.
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
||||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this global from navigation and admin routing. |
|
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this global from navigation and admin routing. |
|
||||||
| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) |
|
| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) |
|
||||||
| `preview` | Function to generate a preview URL within the Admin panel for this global that can point to your app. [More](#preview). |
|
| `preview` | Function to generate a preview URL within the Admin panel for this global that can point to your app. [More](#preview). |
|
||||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
|
| `livePreview`| Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
|
||||||
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. |
|
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. |
|
||||||
|
|
||||||
### Preview
|
### Preview
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ language and country codes (ISO 3166‑1) such as `en-US`, `en-UK`, `es-MX`, etc
|
|||||||
### Locale Properties:
|
### Locale Properties:
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|----------------------|--------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
|
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
|
||||||
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
|
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
|
||||||
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
|
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
|
||||||
@@ -207,11 +207,11 @@ The `fallbackLocale` arg will accept valid locales as well as `none` to disable
|
|||||||
|
|
||||||
```graphql
|
```graphql
|
||||||
query {
|
query {
|
||||||
Posts(locale: de, fallbackLocale: none) {
|
Posts(locale: de, fallbackLocale: none) {
|
||||||
docs {
|
docs {
|
||||||
title
|
title
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -19,33 +19,33 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `admin` \* | Base Payload admin configuration. Specify bundler\*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
|
| `admin` \* | Base Payload admin configuration. Specify bundler*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
|
||||||
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
|
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
|
||||||
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
|
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
|
||||||
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
||||||
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
||||||
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
||||||
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
||||||
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
||||||
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
||||||
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
||||||
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
||||||
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
||||||
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||||
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||||
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
||||||
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
||||||
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
||||||
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
||||||
| `debug` | Enable to expose more detailed error information. |
|
| `debug` | Enable to expose more detailed error information. |
|
||||||
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
||||||
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
||||||
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
||||||
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
||||||
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ Ensure you have an npm script called "payload" in your `package.json` file.
|
|||||||
```
|
```
|
||||||
|
|
||||||
<Banner>
|
<Banner>
|
||||||
Note that you need to run Payload migrations through the package manager that you are using,
|
Note that you need to run Payload migrations through the package manager that you are using, because Payload should not be globally installed on your system.
|
||||||
because Payload should not be globally installed on your system.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
### Migration file contents
|
### Migration file contents
|
||||||
@@ -42,15 +41,15 @@ Here is an example migration file:
|
|||||||
```ts
|
```ts
|
||||||
import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/your-db-adapter'
|
import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/your-db-adapter'
|
||||||
|
|
||||||
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
|
export async function up ({ payload, req }: MigrateUpArgs): Promise<void> {
|
||||||
// Perform changes to your database here.
|
// Perform changes to your database here.
|
||||||
// You have access to `payload` as an argument, and
|
// You have access to `payload` as an argument, and
|
||||||
// everything is done in TypeScript.
|
// everything is done in TypeScript.
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
|
export async function down ({ payload, req }: MigrateDownArgs): Promise<void> {
|
||||||
// Do whatever you need to revert changes if the `up` function fails
|
// Do whatever you need to revert changes if the `up` function fails
|
||||||
}
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Migrations Directory
|
### Migrations Directory
|
||||||
|
|||||||
@@ -31,12 +31,12 @@ export default buildConfig({
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
|
|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
|
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
|
||||||
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
|
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
|
||||||
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
|
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
|
||||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||||
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. | |
|
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. | |
|
||||||
|
|
||||||
### Access to Mongoose models
|
### Access to Mongoose models
|
||||||
|
|
||||||
|
|||||||
@@ -42,15 +42,15 @@ You should prefer a relational DB like Postgres if:
|
|||||||
|
|
||||||
#### Differences in Payload features
|
#### Differences in Payload features
|
||||||
|
|
||||||
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
|
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
|
||||||
|
|
||||||
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
|
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
|
||||||
|
|
||||||
It's up to you to choose which database you would like to use.
|
It's up to you to choose which database you would like to use.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
|
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
|
||||||
|
|
||||||
Here's an example:
|
Here's an example:
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ export default buildConfig({
|
|||||||
db: postgresAdapter({
|
db: postgresAdapter({
|
||||||
pool: {
|
pool: {
|
||||||
connectionString: process.env.DATABASE_URI,
|
connectionString: process.env.DATABASE_URI,
|
||||||
},
|
}
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
@@ -2,15 +2,14 @@
|
|||||||
title: Postgres
|
title: Postgres
|
||||||
label: Postgres
|
label: Postgres
|
||||||
order: 50
|
order: 50
|
||||||
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
|
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
|
||||||
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, express
|
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, express
|
||||||
---
|
---
|
||||||
|
|
||||||
To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It leverages Drizzle ORM and `node-postgres` to interact with a Postgres database that you provide.
|
To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It leverages Drizzle ORM and `node-postgres` to interact with a Postgres database that you provide.
|
||||||
|
|
||||||
<Banner>
|
<Banner>
|
||||||
The Postgres database adapter is currently in beta. If you would like to help us test this
|
The Postgres database adapter is currently in beta. If you would like to help us test this package, we'd love to hear if you find any bugs or issues!
|
||||||
package, we'd love to hear if you find any bugs or issues!
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
|
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
|
||||||
@@ -31,19 +30,18 @@ export default buildConfig({
|
|||||||
// `pool` is required.
|
// `pool` is required.
|
||||||
pool: {
|
pool: {
|
||||||
connectionString: process.env.DATABASE_URI,
|
connectionString: process.env.DATABASE_URI,
|
||||||
},
|
}
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
|
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
|
||||||
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
|
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
|
||||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||||
| `schemaName` | A string for the postgres schema to use, defaults to 'public'. |
|
|
||||||
|
|
||||||
### Access to Drizzle
|
### Access to Drizzle
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@ In addition to exposing Drizzle directly, all of the tables, Drizzle relations,
|
|||||||
|
|
||||||
Drizzle exposes two ways to work locally in development mode.
|
Drizzle exposes two ways to work locally in development mode.
|
||||||
|
|
||||||
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
|
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
|
||||||
|
|
||||||
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
|
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
|
||||||
|
|
||||||
@@ -79,13 +77,11 @@ Migrations are extremely powerful thanks to the seamless way that Payload and Dr
|
|||||||
|
|
||||||
1. You are building your Payload config locally, with a local database used for testing.
|
1. You are building your Payload config locally, with a local database used for testing.
|
||||||
1. You have left the default setting of `push` enabled, so every time you change your Payload config (add or remove fields, collections, etc.), Drizzle will automatically push changes to your local DB.
|
1. You have left the default setting of `push` enabled, so every time you change your Payload config (add or remove fields, collections, etc.), Drizzle will automatically push changes to your local DB.
|
||||||
1. Once you're done with your changes, or have completed a feature, you can run `npm run payload migrate:create`.
|
1. Once you're done with your changes, or have completed a feature, you can run `npm run payload migrate:create`.
|
||||||
1. Payload and Drizzle will look for any existing migrations, and automatically generate all SQL changes necessary to convert your schema from its prior state into the state of your current Payload config, and store the resulting DDL in a newly created migration.
|
1. Payload and Drizzle will look for any existing migrations, and automatically generate all SQL changes necessary to convert your schema from its prior state into the state of your current Payload config, and store the resulting DDL in a newly created migration.
|
||||||
1. Once you're ready to go to production, you will be able to run `npm run payload migrate` against your production database, which will apply any new migrations that have not yet run.
|
1. Once you're ready to go to production, you will be able to run `npm run payload migrate` against your production database, which will apply any new migrations that have not yet run.
|
||||||
1. Now your production database is in sync with your Payload config!
|
1. Now your production database is in sync with your Payload config!
|
||||||
|
|
||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
Warning: do not mix "push" and migrations with your local development database. If you use "push"
|
Warning: do not mix "push" and migrations with your local development database. If you use "push" locally, and then try to migrate, Payload will throw a warning, telling you that these two methods are not meant to be used interchangeably.
|
||||||
locally, and then try to migrate, Payload will throw a warning, telling you that these two methods
|
</Banner>
|
||||||
are not meant to be used interchangeably.
|
|
||||||
</Banner>
|
|
||||||
@@ -66,4 +66,4 @@ The following functions can be used for managing transactions:
|
|||||||
|
|
||||||
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
|
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
|
||||||
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
|
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
|
||||||
`payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
|
`payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
|
||||||
@@ -25,13 +25,13 @@ in the `email` property object of your payload init call. Payload will make use
|
|||||||
|
|
||||||
The following options are configurable in the `email` property object as part of the options object when calling payload.init().
|
The following options are configurable in the `email` property object as part of the options object when calling payload.init().
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`fromName`** \* | The name part of the From field that will be seen on the delivered email |
|
| **`fromName`** \* | The name part of the From field that will be seen on the delivered email |
|
||||||
| **`fromAddress`** \* | The email address part of the From field that will be used when delivering email |
|
| **`fromAddress`** \* | The email address part of the From field that will be used when delivering email |
|
||||||
| **`transport`** | The NodeMailer transport object for when you want to do it yourself, not needed when transportOptions is set |
|
| **`transport`** | The NodeMailer transport object for when you want to do it yourself, not needed when transportOptions is set |
|
||||||
| **`transportOptions`** | An object that configures the transporter that Payload will create. For all the available options see the [NodeMailer documentation](https://nodemailer.com) or see the examples below |
|
| **`transportOptions`** | An object that configures the transporter that Payload will create. For all the available options see the [NodeMailer documentation](https://nodemailer.com) or see the examples below |
|
||||||
| **`logMockCredentials`** | If set to true and no transport/transportOptions, ethereal credentials will be logged to console on startup |
|
| **`logMockCredentials`** | If set to true and no transport/transportOptions, ethereal credentials will be logged to console on startup |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ Blocks are defined as separate configs of their own.
|
|||||||
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
||||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||||
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
|
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
#### Auto-generated data per block
|
#### Auto-generated data per block
|
||||||
|
|
||||||
|
|||||||
@@ -17,21 +17,21 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -23,24 +23,24 @@ This field uses the `monaco-react` editor syntax highlighting.
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||||
| **`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. |
|
| **`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. |
|
| **`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. |
|
| **`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](/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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -22,21 +22,21 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||||
| **`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. |
|
| **`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) |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
@@ -44,20 +44,20 @@ _\* An asterisk denotes that a property is required._
|
|||||||
|
|
||||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the admin panel via the `date` property.
|
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the admin panel via the `date` property.
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------------------ | ------------------------------------------------------------------------------------------- |
|
||||||
| **`placeholder`** | Placeholder text for the field. |
|
| **`placeholder`** | Placeholder text for the field. |
|
||||||
| **`date`** | Pass options to customize date field appearance. |
|
| **`date`** | Pass options to customize date field appearance. |
|
||||||
| **`date.displayFormat`** | Format date to be shown in field **cell**. |
|
| **`date.displayFormat`** | Format date to be shown in field **cell**. |
|
||||||
| **`date.pickerAppearance`** \* | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. |
|
| **`date.pickerAppearance`** \* | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. |
|
||||||
| **`date.monthsToShow`** \* | Number of months to display max is 2. Defaults to 1. |
|
| **`date.monthsToShow`** \* | Number of months to display max is 2. Defaults to 1. |
|
||||||
| **`date.minDate`** \* | Min date value to allow. |
|
| **`date.minDate`** \* | Min date value to allow. |
|
||||||
| **`date.maxDate`** \* | Max date value to allow. |
|
| **`date.maxDate`** \* | Max date value to allow. |
|
||||||
| **`date.minTime`** \* | Min time value to allow. |
|
| **`date.minTime`** \* | Min time value to allow. |
|
||||||
| **`date.maxTime`** \* | Max date value to allow. |
|
| **`date.maxTime`** \* | Max date value to allow. |
|
||||||
| **`date.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
|
| **`date.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
|
||||||
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
|
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
|
||||||
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
|
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
|
||||||
|
|
||||||
_\* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). ._
|
_\* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). ._
|
||||||
|
|
||||||
|
|||||||
@@ -17,22 +17,22 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||||
| **`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. |
|
| **`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) |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -23,22 +23,22 @@ This field uses the `monaco-react` editor syntax highlighting.
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||||
| **`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. |
|
| **`index`** | Build a 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) |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
@@ -46,8 +46,8 @@ _\* An asterisk denotes that a property is required._
|
|||||||
|
|
||||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/typedoc/variables/editor.EditorOptions.html). |
|
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/typedoc/variables/editor.EditorOptions.html). |
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|||||||
@@ -20,27 +20,27 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`min`** | Minimum value accepted. Used in the default `validation` function. |
|
||||||
| **`max`** | Maximum value accepted. Used in the default `validation` function. |
|
| **`max`** | Maximum value accepted. Used in the default `validation` function. |
|
||||||
| **`hasMany`** | Makes this field an ordered array of numbers instead of just a single number. |
|
| **`hasMany`** | Makes this field an ordered array of numbers instead of just a single number. |
|
||||||
| **`minRows`** | Minimum number of numbers in the numbers array, if `hasMany` is set to true. |
|
| **`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. |
|
| **`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. |
|
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||||
| **`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. |
|
| **`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) |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ export const Page: CollectionConfig = {
|
|||||||
- [Date](/docs/fields/date) - date / time field that saves a timestamp
|
- [Date](/docs/fields/date) - date / time field that saves a timestamp
|
||||||
- [Email](/docs/fields/email) - validates the entry is a properly formatted email
|
- [Email](/docs/fields/email) - validates the entry is a properly formatted email
|
||||||
- [Group](/docs/fields/group) - nest fields within an object
|
- [Group](/docs/fields/group) - nest fields within an object
|
||||||
- [JSON](/docs/fields/json) - saves actual JSON in the database
|
|
||||||
- [Number](/docs/fields/number) - field that enforces that its value be a number
|
- [Number](/docs/fields/number) - field that enforces that its value be a number
|
||||||
- [Point](/docs/fields/point) - geometric coordinates for location data
|
- [Point](/docs/fields/point) - geometric coordinates for location data
|
||||||
- [Radio](/docs/fields/radio) - radio button group, allowing only one value to be selected
|
- [Radio](/docs/fields/radio) - radio button group, allowing only one value to be selected
|
||||||
@@ -83,15 +82,15 @@ There are two arguments available to custom validation functions.
|
|||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||||
| `data` | An object containing the full collection or global document currently being edited |
|
| `data` | An object of the full collection or global document. |
|
||||||
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
|
| `siblingData` | An object of the document data limited to fields within the same parent to the field. |
|
||||||
| `operation` | Will be `create` or `update` depending on the UI action or API call |
|
| `operation` | Will be "create" or "update" depending on the UI action or API call. |
|
||||||
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
|
| `id` | The value of the collection `id`, will be `undefined` on create request. |
|
||||||
| `t` | The function for translating text, [more](/docs/configuration/i18n) |
|
| `t` | The function for translating text, [more](/docs/configuration/i18n). |
|
||||||
| `user` | An object containing the currently authenticated user |
|
| `user` | The currently authenticated user object. |
|
||||||
| `payload` | If the `validate` function is being executed on the server, Payload will be exposed for easily running local operations. |
|
| `payload` | If the `validate` function is being executed on the server, Payload will be exposed for easily running local operations. |
|
||||||
|
|
||||||
### Example
|
Example:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { CollectionConfig } from 'payload/types'
|
import { CollectionConfig } from 'payload/types'
|
||||||
|
|||||||
@@ -27,22 +27,22 @@ The data structure in the database matches the GeoJSON structure to represent po
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||||
| **`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`. |
|
| **`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) |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,22 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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 an `label` string and a `value` string. |
|
| **`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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
|
|||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
<LightDarkImage
|
<LightDarkImage
|
||||||
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
|
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
|
||||||
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
|
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
|
||||||
alt="Shows a relationship field in the Payload admin panel"
|
alt="Shows a relationship field in the Payload admin panel"
|
||||||
caption="Admin panel screenshot of a Relationship field"
|
caption="Admin panel screenshot of a Relationship field"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
**Example uses:**
|
**Example uses:**
|
||||||
@@ -26,28 +26,28 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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](#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. |
|
| **`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`. |
|
| **`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`. |
|
| **`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](/docs/getting-started/concepts#depth) |
|
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](/docs/getting-started/concepts#depth) |
|
||||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
| **`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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`index`** | Build a 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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
@@ -131,13 +131,13 @@ The `filterOptions` property can either be a `Where` query, or a function return
|
|||||||
prevent all, or a `Where` query. When using a function, it will be
|
prevent all, or a `Where` query. When using a function, it will be
|
||||||
called with an argument object with the following properties:
|
called with an argument object with the following properties:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ------------- | ----------------------------------------------------------------------------------------------------- |
|
|---------------|--------------------------------------------------------------------------------------|
|
||||||
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property |
|
| `relationTo` | The `relationTo` to filter against (as defined on the field) |
|
||||||
| `data` | An object containing the full collection or global document currently being edited |
|
| `data` | An object of the full collection or global document currently being edited |
|
||||||
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
|
| `siblingData` | An object of the document data limited to fields within the same parent to the field |
|
||||||
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
|
| `id` | The value of the collection `id`, will be `undefined` on create request |
|
||||||
| `user` | An object containing the currently authenticated user |
|
| `user` | The currently authenticated user object |
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@@ -287,7 +287,10 @@ To save the to `hasMany` relationship field we need to send an array of IDs:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"owners": ["6031ac9e1289176380734024", "602c3c327b811235943ee12b"]
|
"owners": [
|
||||||
|
"6031ac9e1289176380734024",
|
||||||
|
"602c3c327b811235943ee12b"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -359,6 +362,5 @@ Since we are referencing multiple collections, the field you are querying on may
|
|||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
<strong>Note:</strong>
|
<strong>Note:</strong>
|
||||||
<br />
|
<br />
|
||||||
You <strong>cannot</strong> query on a field within a polymorphic relationship as you would with a
|
You <strong>cannot</strong> query on a field within a polymorphic relationship as you would with a non-polymorphic relationship.
|
||||||
non-polymorphic relationship.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ keywords: rich text, fields, config, configuration, documentation, Content Manag
|
|||||||
caption="Admin panel screenshot of a Rich Text field"
|
caption="Admin panel screenshot of a Rich Text field"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
Payload's rich text field is built on an "adapter pattern" which lets you specify which rich text editor you'd like to use.
|
Payload's rich text field is built on an "adapter pattern" which lets you specify which rich text editor you'd like to use.
|
||||||
|
|
||||||
Right now, Payload is officially supporting two rich text editors:
|
Right now, Payload is officially supporting two rich text editors:
|
||||||
|
|
||||||
@@ -26,13 +26,7 @@ Right now, Payload is officially supporting two rich text editors:
|
|||||||
2. [Lexical](/docs/rich-text/lexical) - beta, where things will be moving
|
2. [Lexical](/docs/rich-text/lexical) - beta, where things will be moving
|
||||||
|
|
||||||
<Banner type="success">
|
<Banner type="success">
|
||||||
<strong>
|
<strong>Consistent with Payload's goal of making you learn as little of Payload as possible, customizing and using the Rich Text Editor does not involve learning how to develop for a <em>Payload</em> rich text editor.</strong> Instead, you can invest your time and effort into learning the underlying open-source tools that will allow you to apply your learnings elsewhere as well.
|
||||||
Consistent with Payload's goal of making you learn as little of Payload as possible, customizing
|
|
||||||
and using the Rich Text Editor does not involve learning how to develop for a <em>Payload</em>{' '}
|
|
||||||
rich text editor.
|
|
||||||
</strong>{' '}
|
|
||||||
Instead, you can invest your time and effort into learning the underlying open-source tools that
|
|
||||||
will allow you to apply your learnings elsewhere as well.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
### Config
|
### Config
|
||||||
@@ -73,4 +67,4 @@ Override the default text direction of the Admin panel for this field. Set to `t
|
|||||||
|
|
||||||
### Editor-specific options
|
### Editor-specific options
|
||||||
|
|
||||||
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
|
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
|
||||||
@@ -20,24 +20,24 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`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. |
|
| **`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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ export const CustomSelectField: Field = {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -174,9 +174,9 @@ export const CustomSelectComponent: React.FC<CustomSelectProps> = ({ path, optio
|
|||||||
If you are looking to create a dynamic select field, the following tutorial will walk you through the process of creating a custom select field that fetches its options from an external API.
|
If you are looking to create a dynamic select field, the following tutorial will walk you through the process of creating a custom select field that fetches its options from an external API.
|
||||||
|
|
||||||
<VideoDrawer
|
<VideoDrawer
|
||||||
id="Efn9OxSjA6Y"
|
id='Efn9OxSjA6Y'
|
||||||
label="How to Create a Custom Select Field"
|
label='How to Create a Custom Select Field'
|
||||||
drawerTitle="How to Create a Custom Select Field: A Step-by-Step Guide"
|
drawerTitle='How to Create a Custom Select Field: A Step-by-Step Guide'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/components#field-component) docs.
|
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/components#field-component) docs.
|
||||||
|
|||||||
@@ -20,28 +20,27 @@ keywords: text, fields, config, configuration, documentation, Content Management
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`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. |
|
| **`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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
| **`hasMany`** | Makes this field an ordered array of text instead of just a single text. |
|
| **`hasMany`** | Makes this field an ordered array of text instead of just a single text. |
|
||||||
| **`minRows`** | Minimum number of texts in the array, if `hasMany` is set to true. |
|
| **`minRows`** | Minimum number of texts in the array, if `hasMany` is set to true. |
|
||||||
| **`maxRows`** | Maximum number of texts in the array, if `hasMany` is set to true. |
|
| **`maxRows`** | Maximum number of texts in the array, if `hasMany` is set to true. |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
### Admin config
|
### Admin config
|
||||||
|
|||||||
@@ -20,24 +20,24 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
|
|||||||
|
|
||||||
### Config
|
### Config
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/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. |
|
| **`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. |
|
| **`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. |
|
| **`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. |
|
| **`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](/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) |
|
||||||
| **`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. |
|
| **`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/config), include its data in the user JWT. |
|
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||||
| **`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. |
|
| **`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](/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. |
|
| **`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. |
|
| **`required`** | Require this field to have a value. |
|
||||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||||
|
|
||||||
_\* An asterisk denotes that a property is required._
|
_\* An asterisk denotes that a property is required._
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user