Compare commits

...

147 Commits

Author SHA1 Message Date
Elliot DeNolf
e847061c74 chore(release): payload/2.0.10 [skip ci] 2023-10-17 16:45:10 -04:00
TomDo1234
48de89794b feat: filesRequired is optional for uploads (#3668)
* filesRequired is optional for uploads

* More accurate name

* Updated docs

* ensure that by default you throw on missing file
2023-10-17 15:21:16 -04:00
Elliot DeNolf
ef4b5d8bfd chore: add payload as peer dep to all adapters (#3716) 2023-10-17 15:20:09 -04:00
Elliot DeNolf
5711d42eca chore: update pnpm-lock.yaml 2023-10-17 15:03:58 -04:00
Elliot DeNolf
a446a788a9 chore(release): payload/2.0.9 2023-10-17 15:00:55 -04:00
Elliot DeNolf
df57196d19 chore(live-preview-react): adjust live-preview semver dep 2023-10-17 15:00:55 -04:00
Alessio Gravili
86c563e4e5 Merge remote-tracking branch 'origin/main' 2023-10-17 20:57:17 +02:00
Alessio Gravili
734b8c08ed chore(richtext-lexical): add additional safety checks for incorrect data passed into the editor 2023-10-17 20:56:22 +02:00
geminigeek
68c5a57515 [fix] Register first user verify update missing transaction id / req (#3665)
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2023-10-17 14:50:56 -04:00
Elliot DeNolf
d9f0b7bd30 chore(release): live-preview-react/0.1.4 2023-10-17 13:23:10 -04:00
Elliot DeNolf
5ecfe3da28 chore(release): richtext-lexical/0.1.13 2023-10-17 13:18:30 -04:00
Elliot DeNolf
3e3163e875 chore(release): live-preview/0.1.4 2023-10-17 13:17:33 -04:00
Elliot DeNolf
cfe1698dfd chore: update changelog 2023-10-17 13:15:36 -04:00
Elliot DeNolf
5722634660 chore(release): v2.0.8 2023-10-17 13:06:25 -04:00
Jacob Fletcher
cdbfc9132a chore: optimizes live preview (#3713) 2023-10-17 12:42:31 -04:00
Jacob Fletcher
dd0ac066ce feat(live-preview): caches field schema (#3711) 2023-10-17 12:11:55 -04:00
PatrikKozak
8b8ceabbdd fix(templates): user access control (#3712) 2023-10-17 12:07:37 -04:00
Alessio Gravili
8da18d3496 Merge pull request #3707 from payloadcms/fix/3683
fix(richtext-lexical): Blocks Field: Sub-forms being re-rendered unnecessarily
2023-10-17 17:33:05 +02:00
Elliot DeNolf
6cd4df3dc4 chore(script): properly version and publish non-latest packages 2023-10-17 11:30:09 -04:00
Elliot DeNolf
e74dc8633b ci: add retries to e2e tests (#3708)
* ci: add retries to e2e tests

* ci: add timeout_minutes for retry
2023-10-17 11:26:34 -04:00
Alessio Gravili
2f945919a3 chore: disable props for useIntersect hook 2023-10-17 17:24:50 +02:00
Alessio Gravili
52dc9177d7 chore: enable forceRender for richtext-lexical's Blocks feature form, and all their sub-forms 2023-10-17 16:44:34 +02:00
Alessio Gravili
cec757d098 chore: make sure intersectionObserver does not cause re-renders if forceRender is enabled 2023-10-17 16:34:44 +02:00
Jacob Fletcher
80e57150a0 chore: refines live preview shadow and bg (#3706) 2023-10-17 10:11:21 -04:00
Elliot DeNolf
2969da7402 chore(release): create-payload-app/1.0.0 2023-10-16 23:32:32 -04:00
Elliot DeNolf
35da1db99f chore(create-payload-app): use swc, cleanup scripts 2023-10-16 23:17:45 -04:00
Elliot DeNolf
a578226d34 ci: rework release-it script 2023-10-16 22:47:27 -04:00
James
8c75f32620 chore: website seed script compatibility with postgres + mongo 2023-10-16 18:39:28 -04:00
James
c3ab8b9115 Merge branch 'main' of github.com:payloadcms/payload 2023-10-16 18:34:18 -04:00
James
993568a195 fix: bug with seeding ecommerce 2023-10-16 18:34:10 -04:00
Jacob Fletcher
c3cec64220 chore: refines main nav (#3703) 2023-10-16 17:36:05 -04:00
Elliot DeNolf
084e9f0ff8 chore(release): db-postgres/0.1.9 2023-10-16 16:32:03 -04:00
James Mikrut
9f0ef9b7da chore: template compatibility with postgres (#3701)
* fix: blocks within groups in postgres

* chore: template compatibility
2023-10-16 16:26:21 -04:00
James Mikrut
c384f490c8 Merge pull request #3700 from payloadcms/fix/postgres-blocks-within-groups
fix: blocks within groups in postgres
2023-10-16 16:25:46 -04:00
James
45a62ba949 fix: blocks within groups in postgres 2023-10-16 16:12:21 -04:00
Elliot DeNolf
1eae5f9c99 test(create-payload-app): test create project for all templates 2023-10-16 15:12:59 -04:00
James
dfa861557d chore: website template postgres compatibility 2023-10-16 14:47:18 -04:00
James
228fd58020 chore: ecommerce template postgres compatibility 2023-10-16 14:40:37 -04:00
Take Weiland
150799e10e fix: some local operations missing req.transactionID (#3651)
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2023-10-16 14:17:58 -04:00
Elliot DeNolf
823436a883 chore(release): richtext-slate/1.0.6 2023-10-16 14:16:20 -04:00
Elliot DeNolf
cbb0ba1a2c chore(release): richtext-lexical/0.1.12 2023-10-16 14:15:55 -04:00
Alessio Gravili
cb39354a9d fix(richtext-*): link drawer form receiving incorrect field schema (#3696) 2023-10-16 19:43:23 +02:00
Jacob Fletcher
1625ff244e fix: renders mobile document controls (#3695) 2023-10-16 13:37:40 -04:00
Alessio Gravili
24918fe1d2 fix(richtext-lexical): #3682 isolated editor container causing z-index issues 2023-10-16 18:56:25 +02:00
Alessio Gravili
b8a58666e7 fix(richtext-*): extra fields not being iterated correctly (#3693) 2023-10-16 18:47:52 +02:00
Elliot DeNolf
2e6a2c8355 ci: add plugin-nested-docs build 2023-10-16 12:16:14 -04:00
Elliot DeNolf
1fdff92525 chore(script): use semver to validate and show next version 2023-10-16 12:10:30 -04:00
Elliot DeNolf
7da5f6e92a chore(release): plugin-nested-docs/1.0.8 2023-10-16 12:07:17 -04:00
James Mikrut
67c7572e5f Merge pull request #3689 from payloadcms/chore/nested-docs
Chore/nested docs
2023-10-16 11:44:11 -04:00
craigrdaniels
e311e8fff9 fix: autosave time shown minutes only (#3492) 2023-10-16 11:32:31 -04:00
James
086e50b9b3 chore: renames nested-docs test suite 2023-10-16 11:30:45 -04:00
James
66ab6c587d chore: moves nested docs to monorepo 2023-10-16 11:28:40 -04:00
Elliot DeNolf
786fb926c2 chore: update changelog 2023-10-16 11:16:56 -04:00
James
7d954b11a3 Merge branch 'feat/allow-filteroptions-null' of github.com:payloadcms/payload into chore/nested-docs 2023-10-16 11:09:23 -04:00
Jarrod Flesch
3c5044368d fix: corrects add block index (#3681) 2023-10-16 10:58:54 -04:00
Jacob Fletcher
f129d6c607 Merge pull request #3687 from payloadcms/dependabot/npm_and_yarn/examples/testing/babel/traverse-7.23.2
chore(deps): bump @babel/traverse from 7.22.17 to 7.23.2 in /examples/testing
2023-10-16 10:57:29 -04:00
dependabot[bot]
de2d985405 chore(deps): bump @babel/traverse in /examples/testing
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.17 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 14:44:39 +00:00
Jacob Fletcher
060f3c73fa Merge pull request #3674 from payloadcms/chore/plugin-nested-docs
chore: imports nested docs plugin
2023-10-16 10:43:52 -04:00
Jacob Fletcher
62ae7be113 chore(plugin-nested-docs): migrates demo to payload 2.x 2023-10-16 10:40:23 -04:00
Jacob Fletcher
771df061b4 chore(plugin-nested-docs): migrates to monorepo setup 2023-10-16 10:29:04 -04:00
Alessio Gravili
09e64c3be8 chore: _community test: add missing "extends" to tsconfig.json 2023-10-16 16:28:17 +02:00
PatrikKozak
1a006fef19 chore(templates/website): uses correct logo color in dark mode (#3667) 2023-10-16 10:14:09 -04:00
James
c4cac99875 feat: allows filterOptions to return null 2023-10-16 10:01:19 -04:00
Jessica Chowdhury
d616772740 fix: misc upload crop/focal point updates (#3580) 2023-10-16 08:42:35 -04:00
Elliot DeNolf
4b9e87bb4d chore(release): db-postgres/0.1.8 2023-10-15 21:04:46 -04:00
Elliot DeNolf
ff5e174497 chore(script): multiselect publishing prompt 2023-10-15 20:53:16 -04:00
Elliot DeNolf
34017e1758 chore(release): payload/2.0.7 2023-10-15 20:49:18 -04:00
James Mikrut
23d95526ab Merge pull request #3666 from payloadcms/fix/empty-in-array
fix: empty inArray no longer crashes postgres
2023-10-15 18:05:15 -04:00
James
59b87fdb21 chore: typo 2023-10-15 17:55:30 -04:00
James
f2ac1f7d48 chore: merge main 2023-10-15 17:31:24 -04:00
James
8d4f39af5e Merge branch 'main' of github.com:payloadcms/payload into fix/empty-in-array 2023-10-15 17:29:51 -04:00
James
c4ac341d75 fix: empty inArray no longer crashes postgres 2023-10-15 17:28:13 -04:00
Jacob Fletcher
3eefe8cb21 Merge remote-tracking branch 'plugin-nested-docs/main' into chore/plugin-nested-docs 2023-10-15 02:28:29 -04:00
Elliot DeNolf
8938f2b7e9 chore(release): plugin-nested-docs/1.0.7 2023-10-13 10:52:51 -04:00
Elliot DeNolf
ed8a9ffa09 chore(deps): add payload 2.0 to peer deps 2023-10-13 10:51:14 -04:00
Jacob Fletcher
b5b487ab90 1.0.6 2023-07-10 16:49:14 -04:00
Jacob Fletcher
940bfe4f18 fix: threads locale through resaveChildren (#24) 2023-07-10 16:45:21 -04:00
Jacob Fletcher
41dcdd4e01 chore: adds localization section to docs (#25) 2023-07-10 16:43:28 -04:00
Jacob Fletcher
3dbb70a9e6 1.0.5 2023-06-19 17:02:48 -04:00
Jacob Fletcher
adef360275 Merge pull request #21 from payloadcms/fix/parent-types
fix: createParentField types
2023-06-19 17:01:02 -04:00
Jacob Fletcher
abebd7f440 Merge pull request #11 from payloadcms/chore/export-fields
chore: exports fields top-level
2023-06-19 16:56:50 -04:00
Jacob Fletcher
e9ed969ad9 fix: createParentField types 2023-06-19 16:56:34 -04:00
Jacob Fletcher
6b1a7f0843 Merge pull request #16 from payloadcms/chore/eslint
chore: eslint and prettier
2023-05-18 14:43:26 -04:00
Jacob Fletcher
e76cd58425 chore: bumps demo to payload v1.8.2 2023-05-18 13:57:32 -04:00
Jacob Fletcher
888f937e3c chore: eslint and prettier 2023-05-18 13:57:32 -04:00
Jacob Fletcher
d61ced9cbd chore: exports fields top-level 2023-02-01 17:57:16 -05:00
Jacob Fletcher
ada165a21e Merge pull request #10 from payloadcms/chore/export-types
chore: exports types
2023-02-01 17:42:12 -05:00
Jacob Fletcher
8d4fd14ff2 chore: exports types 2023-02-01 17:36:31 -05:00
Jacob Fletcher
0363c85dbd chore: renames Options to PluginConfig 2022-11-17 17:13:27 -05:00
Jacob Fletcher
fa660cd4ef chore: ignores package-lock 2022-11-16 14:06:03 -05:00
Jacob Fletcher
4f6eb1e307 chore: adds .env.example to demo 2022-11-16 12:50:53 -05:00
Jacob Fletcher
50860bc8c1 1.0.4 2022-11-16 12:27:39 -05:00
Jacob Fletcher
52f7890989 docs: adds development documentation 2022-11-16 12:22:57 -05:00
Jacob Fletcher
6200a119f9 fix: prevents child-parents 2022-11-16 11:31:15 -05:00
Jacob Fletcher
46eb61d18a chore: payload peerDep 2022-11-16 10:45:14 -05:00
Jacob Fletcher
2766489476 chore: bumps payload deps 2022-11-15 17:44:59 -05:00
Jacob Fletcher
0c1102a138 chore: seeds grandchild page 2022-11-15 17:10:53 -05:00
Jacob Fletcher
e765b96a4e Merge pull request #8 from payloadcms/fix/localization
fix: conditionally localizes breadcrumbs
2022-11-15 16:33:39 -05:00
Jacob Fletcher
01c42d9630 fix: conditionally localizes breadcrumbs 2022-11-15 16:19:18 -05:00
Jacob Fletcher
f421a2715d chore: seeds demo 2022-11-15 16:01:27 -05:00
Jacob Fletcher
edd7a8086c Merge pull request #7 from bencun/feat/disable-self-as-parent
Disable referencing self as a parent by default to prevent crashes
2022-11-15 13:24:09 -05:00
Jacob Fletcher
010db46e08 docs: updates README 2022-11-15 13:18:11 -05:00
Jacob Fletcher
fc8a6e107e chore: ignores .DS_Store 2022-11-15 12:58:09 -05:00
Aleksandar Bencun
2cb79f1752 Improved the docs a bit. 2022-10-26 23:22:53 +02:00
Aleksandar Bencun
5f740a60cc Prevent selecting self as a parent unless this behavior is overridden explicitly. 2022-10-26 23:15:04 +02:00
Jacob Fletcher
27313995cc Merge pull request #5 from mikemoooo/patch-1
feat: localized breadcrumbs
2022-08-15 10:03:02 -04:00
Mike
93afe1d000 Support localised breadcrumbs 2022-08-15 15:51:28 +02:00
James
e7ffa2638a 1.0.3 2022-07-11 15:19:02 -07:00
James
666765f3fb fix: further ensures resaving children works with drafts 2022-07-11 15:18:52 -07:00
James
fc14622555 1.0.2 2022-07-11 15:14:14 -07:00
James
0d83d83d3c feat: ensures drafts work 2022-07-11 15:14:09 -07:00
Jacob Fletcher
aab2f5f7d2 chore: updates README 2022-07-05 15:11:25 -04:00
Jacob Fletcher
fbdc74ea71 chore: adds homepage and repository to package.json 2022-07-05 14:54:39 -04:00
Jacob Fletcher
141e40ffb9 Merge branch 'main' of github.com:payloadcms/payload-plugin-nested-pages 2022-07-05 14:46:41 -04:00
Jacob Fletcher
bd2c1c6bf2 1.0.1 2022-07-05 14:46:27 -04:00
Jacob Fletcher
ba90fdbdfd feat: updates payload 2022-07-05 14:45:48 -04:00
James Mikrut
9991fdb8c8 Update README.md 2022-06-13 09:15:14 -04:00
Jacob Fletcher
15c9ce56c2 chore: updates package name 2022-05-27 10:25:15 -04:00
Jacob Fletcher
eecdd0e118 Merge branch 'main' of github.com:payloadcms/payload-plugin-nested-pages 2022-05-04 11:13:21 -04:00
Jacob Fletcher
f749732a0a 0.0.3 2022-05-04 11:13:07 -04:00
Jacob Fletcher
78e2b518cf chore: updates react peerDep 2022-05-04 11:12:09 -04:00
James
91362587f0 chore: renames plugin 2022-05-04 10:48:36 -04:00
Jacob Fletcher
a4c4fc7060 Merge pull request #1 from payloadcms/fix/disable-errors-breadcrumbs
fix: disables errors while populating breadcrumbs
2022-04-18 08:43:31 -04:00
James
db09f4839f fix: disables errors while populating breadcrumbs 2022-04-15 15:28:18 -04:00
Jacob Fletcher
c71e079fae 0.0.2 2022-04-10 12:23:09 -04:00
Jacob Fletcher
b90785fa8c chore: bumps payload to v0.15.6 2022-04-10 12:22:54 -04:00
Jacob Fletcher
6e340f008f feat: initial working draft 2022-03-07 16:19:40 -05:00
Jacob Fletcher
e08e681eda chore: initializes standalone repository 2022-02-22 15:22:13 -05:00
James
238db1750c fix: potential bug in breadcrumbs plugin 2022-01-31 16:18:46 -05:00
James
0962cd6fcb fix: allows breadcrumbs to populate without being passed full copy of page data 2022-01-07 18:34:40 -05:00
James
6b436d38e1 fix: bug with breadcrumbs 2021-10-18 11:42:29 -04:00
James
ae93006446 chore: revises logs 2021-10-07 19:59:17 -04:00
James
fc722573bf chore: logging 2021-10-07 19:18:49 -04:00
James
b72ba7fe86 feat: resaves page after create to properly generate breadcrumb 2021-09-14 11:47:17 -04:00
James
3dd777343b fix: ensures id is passed through to populateBreadcrumbs 2021-09-14 11:42:17 -04:00
James
f1f7592eb2 fix: big rip 2021-09-08 20:30:21 -04:00
James
3816589e8b fix: restricts depth to 0 in search sync ops 2021-09-08 20:15:11 -04:00
James
ba70b8065e feat: improves breadcrumbs performance 2021-09-08 19:01:05 -04:00
James
9b88a47a47 feat: attempts to optimize breadcrumbs 2021-09-01 18:14:18 -04:00
James
9a747bc1eb feat: adds alerts 2021-09-01 13:42:28 -04:00
James
f82723ef33 fix: reverts plugin back to beforeRead 2021-08-31 12:49:19 -04:00
James
897f7be0f7 feat: adds author and improves breadcrumbs 2021-08-31 12:43:09 -04:00
James
80f6c7ebe1 fix: cleans breadcrumb types 2021-08-31 12:33:53 -04:00
James
9da4151642 fix: breadcrumbs plugin beforeChange 2021-08-31 12:31:38 -04:00
James
b89cbe5715 fix: breadcrumbs, fullTitle, subsite 2021-08-30 17:08:56 -04:00
James
725a1d35ef feat: revises breadcrumbs and subsites to rely on depth properly 2021-08-02 22:01:58 -04:00
James
2fbfb5d305 feat: builds breadcrumbs plugin 2021-08-02 21:08:01 -04:00
193 changed files with 3014 additions and 1025 deletions

View File

@@ -132,7 +132,12 @@ jobs:
key: ${{ github.sha }}-${{ github.run_number }}
- name: E2E Tests
run: pnpm test:e2e --part ${{ matrix.part }} --bail
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@v3
if: always()
@@ -213,8 +218,9 @@ jobs:
fail-fast: false
matrix:
pkg:
- plugin-cloud
- create-payload-app
- plugin-cloud
- plugin-nested-docs
steps:
- name: Use Node.js 18

View File

@@ -1,22 +0,0 @@
{
"verbose": true,
"git": {
"commitMessage": "chore(release): v${version}",
"requireCleanWorkingDir": true
},
"github": {
"release": true
},
"npm": {
"skipChecks": true
},
"hooks": {
"before:init": ["pnpm i", "pnpm clean", "pnpm test"]
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": "CHANGELOG.md"
}
}
}

16
.release-it.pre.js Normal file
View 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'],
},
}

View File

@@ -1,25 +0,0 @@
{
"verbose": true,
"git": {
"requireCleanWorkingDir": false,
"commit": false,
"push": false,
"tag": false
},
"github": {
"release": true
},
"npm": {
"skipChecks": true,
"tag": "canary"
},
"hooks": {
"before:init": ["pnpm i", "pnpm clean", "pnpm test"]
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": "CHANGELOG.md"
}
}
}

View File

@@ -1,3 +1,111 @@
## [2.0.8](https://github.com/payloadcms/payload/compare/v2.0.7...v2.0.8) (2023-10-17)
### Features
* allows filterOptions to return null ([c4cac99](https://github.com/payloadcms/payload/commit/c4cac998752730e7084598c92c77789da8c82e0d))
* **live-preview:** caches field schema ([#3711](https://github.com/payloadcms/payload/issues/3711)) ([dd0ac06](https://github.com/payloadcms/payload/commit/dd0ac066ce2ed88b85025309303610a95b6089e1))
### Bug Fixes
* autosave time shown minutes only ([#3492](https://github.com/payloadcms/payload/issues/3492)) ([e311e8f](https://github.com/payloadcms/payload/commit/e311e8fff9cd4264d7a71903f63c4fa825a3564d))
* blocks within groups in postgres ([45a62ba](https://github.com/payloadcms/payload/commit/45a62ba949aca33b25e0808773a5c2f1cf4adf82))
* bug with seeding ecommerce ([993568a](https://github.com/payloadcms/payload/commit/993568a1959ea10f960e35e4ed7a8e06af672a72))
* corrects add block index ([#3681](https://github.com/payloadcms/payload/issues/3681)) ([3c50443](https://github.com/payloadcms/payload/commit/3c5044368d5b30c76a2ff20c25b9234ef89dc205))
* misc upload crop/focal point updates ([#3580](https://github.com/payloadcms/payload/issues/3580)) ([d616772](https://github.com/payloadcms/payload/commit/d6167727401a01282345e63636560e029ae8e0f3))
* renders mobile document controls ([#3695](https://github.com/payloadcms/payload/issues/3695)) ([1625ff2](https://github.com/payloadcms/payload/commit/1625ff244e6e81e6edc0357037c3abc1a3bf8ba7))
* some local operations missing req.transactionID ([#3651](https://github.com/payloadcms/payload/issues/3651)) ([150799e](https://github.com/payloadcms/payload/commit/150799e10e580281d1af49388eb142ee9639a002))
* **richtext-*:** extra fields not being iterated correctly ([#3693](https://github.com/payloadcms/payload/issues/3693)) ([b8a5866](https://github.com/payloadcms/payload/commit/b8a58666e70f604af1e1cf349bcb4f9add0147e7))
* **richtext-*:** link drawer form receiving incorrect field schema ([#3696](https://github.com/payloadcms/payload/issues/3696)) ([cb39354](https://github.com/payloadcms/payload/commit/cb39354a9de3d20960110e453f62c4aa166d8448))
* **richtext-lexical:** [#3682](https://github.com/payloadcms/payload/issues/3682) isolated editor container causing z-index issues ([24918fe](https://github.com/payloadcms/payload/commit/24918fe1d2ca251e211632765d370c214cef2a38))
* **templates:** user access control ([#3712](https://github.com/payloadcms/payload/issues/3712)) ([8b8ceab](https://github.com/payloadcms/payload/commit/8b8ceabbdd6354761e7d744cacb1192cac3a2427))
## [2.0.6](https://github.com/payloadcms/payload/compare/v2.0.5...v2.0.6) (2023-10-14)
### Bug Fixes
* document sidebar vertical overflow ([#3639](https://github.com/payloadcms/payload/issues/3639)) ([fcd4c8d](https://github.com/payloadcms/payload/commit/fcd4c8d83040f00d10142ca12ba92616618b966e))
* login form clearing out and field spacing ([#3633](https://github.com/payloadcms/payload/issues/3633)) ([4bd01df](https://github.com/payloadcms/payload/commit/4bd01df411e4ad2ccacdcd6de0fb21a8145c3964))
* sidebar field permissions ([#3629](https://github.com/payloadcms/payload/issues/3629)) ([c956a85](https://github.com/payloadcms/payload/commit/c956a85252bc7de1686925cc783694383c0ac9be))
* preview button conditions ([#3613](https://github.com/payloadcms/payload/issues/3613)) ([beed83b](https://github.com/payloadcms/payload/commit/beed83b231b19090902dd502ff5eab054a67a1a6))
* allows drafts to be duplicated ([1a99d66](https://github.com/payloadcms/payload/commit/1a99d66cd0675cf2cb2c4317a121721f35682ff3))
## [2.0.5](https://github.com/payloadcms/payload/compare/v2.0.4...v2.0.5) (2023-10-12)
### Bug Fixes
* properly renders custom buttons for globals ([#3616](https://github.com/payloadcms/payload/issues/3616)) ([05cc287](https://github.com/payloadcms/payload/commit/05cc2873b4a19e2bd46be778f3610643d3e15d09))
* minor type issue in richText validate function ([06a51b3](https://github.com/payloadcms/payload/commit/06a51b3c9b9045b23051807aa03b222b542b46f5))
* live preview device size ([#3606](https://github.com/payloadcms/payload/issues/3606)) ([8bbac60](https://github.com/payloadcms/payload/commit/8bbac60e60a6dbe4dc0c7b05edbca7f6f2d1c569))
* properly handles nested routes for live preview ([#3586](https://github.com/payloadcms/payload/issues/3586)) ([6486468](https://github.com/payloadcms/payload/commit/64864686c418f9822bf61c45ece078a39e81b4cb))
* various stepnav related issues ([#3599](https://github.com/payloadcms/payload/issues/3599)) ([aaf8839](https://github.com/payloadcms/payload/commit/aaf883909c588bae1145ddddc5291a98740c2c03))
* database adapter types ([cc56da1](https://github.com/payloadcms/payload/commit/cc56da11d635d11ebbee67e6d0919c7275ede36e))
* postgres select fields within groups ([#3570](https://github.com/payloadcms/payload/issues/3570)) ([06e2fa9](https://github.com/payloadcms/payload/commit/06e2fa9d111c18fad3422953082266db9329fc91))
* [#3511](https://github.com/payloadcms/payload/issues/3511), documents don't delete their versions ([#3520](https://github.com/payloadcms/payload/issues/3520)) ([e3c7765](https://github.com/payloadcms/payload/commit/e3c776523a64da03a4756ee5ae8a84175090979f))
### Documentation
- updates building your own live preview hook ([#3604](https://github.com/payloadcms/payload/issues/3604)) ([15c7f0dbf](https://github.com/payloadcms/payload/commit/15c7f0dbf3ebf5c6a2bb011970dda515a15acb56))
- update config overview ([cfd923140](https://github.com/payloadcms/payload/commit/1a006fef19a215d7ef74c71a210fd511727f95bd))
## [2.0.4](https://github.com/payloadcms/payload/compare/v2.0.3...v2.0.4) (2023-10-12)
### Bug Fixes
- API tab breadcrumbs and results indentation ([#3564](https://github.com/payloadcms/payload/issues/3564)) ([e0afeec](https://github.com/payloadcms/payload/commit/e0afeeca974d0a0cac7aca8e40f9436449c902b5))
- sticky sidebar ([#3563](https://github.com/payloadcms/payload/issues/3563)) ([76e306d](https://github.com/payloadcms/payload/commit/76e306ddd8aae45f03fd4715415d6a44501a9400))
- sidebar width when fields have long descriptions ([#3562](https://github.com/payloadcms/payload/issues/3562)) ([cfc78ed](https://github.com/payloadcms/payload/commit/cfc78ed4f58647769f651da5a952fed20cfb217f))
- row field margins ([#3558](https://github.com/payloadcms/payload/issues/3558)) ([6d9353b](https://github.com/payloadcms/payload/commit/6d9353b53f4197bae2b15ca95298a87d784c7e76))
- removes nested array field configs from array value ([#3549](https://github.com/payloadcms/payload/issues/3549)) ([af892ec](https://github.com/payloadcms/payload/commit/af892ecb0e67777a97206bb5fccf489387ce68fc))
- [#3521](https://github.com/payloadcms/payload/issues/3521) ([eb97acd](https://github.com/payloadcms/payload/commit/eb97acd408f128438c2122ab6a6e2930f5b4a1ca))
- [#3540](https://github.com/payloadcms/payload/issues/3540) ([2567ac5](https://github.com/payloadcms/payload/commit/2567ac58bac851d0a15ee40db0f5f4737b199a75))
- row field width ([#3550](https://github.com/payloadcms/payload/issues/3550)) ([9ff014b](https://github.com/payloadcms/payload/commit/9ff014bbfe08d7b114c11824294f0d59f5f6c2c3))
- [#3541](https://github.com/payloadcms/payload/issues/3541) ([e6f0d35](https://github.com/payloadcms/payload/commit/e6f0d3598549a921e36f470adfcbacbaebaea53f))
- renders global label as page title ([#3532](https://github.com/payloadcms/payload/issues/3532)) ([ace3e57](https://github.com/payloadcms/payload/commit/ace3e577f6b1cbeb12860dc936c578c2a1f68570))
- increases document controls popup list button hitbox ([#3529](https://github.com/payloadcms/payload/issues/3529)) ([f009593](https://github.com/payloadcms/payload/commit/f0095937bafdd85c53c99bcc1d29d3361aa07238))
### Documentation
- removes MONGODB_URI ([8bfae6b93](https://github.com/payloadcms/payload/commit/8bfae6b932d6c9bd0c628a203ebf8d24121d66f8))
- adds build your own plugin page ([#3184](https://github.com/payloadcms/payload/pull/3184)) ([15f650afd](https://github.com/payloadcms/payload/commit/15f650afdef717d62c162846fec77aa0f326bb43))
## [2.0.3](https://github.com/payloadcms/payload/compare/v2.0.2...v2.0.3) (2023-10-09)
### Bug Fixes
- webpack export default was not found [#3494](https://github.com/payloadcms/payload/issues/3494) ([be049ce](https://github.com/payloadcms/payload/commit/be049cea0029cf497822e337777b8a86b7d38bed))
- postgres generated type id [#3504](https://github.com/payloadcms/payload/issues/3504) ([c90d1fa](https://github.com/payloadcms/payload/commit/c90d1faa7fedd5d902949089fd457c56eed4643d))
- hasMany relationships unable to be cleared [#3513](https://github.com/payloadcms/payload/issues/3513) ([5d9384f](https://github.com/payloadcms/payload/commit/5d9384f53052c96403d8c07ae9d05edf3676c4ef))
### Documentation
- move payload script mention to top of migrations ([26967fb92](https://github.com/payloadcms/payload/commit/26967fb92))
- payload script in package.json ([2f86c196e](https://github.com/payloadcms/payload/commit/2f86c196e))
- updates required node version ([70e068b18](https://github.com/payloadcms/payload/commit/70e068b18))
- improves custom views (#3499) ([6c17222a6](https://github.com/payloadcms/payload/commit/6c17222a6))
## [2.0.2](https://github.com/payloadcms/payload/compare/v2.0.1...v2.0.2) (2023-10-09)
### Bug Fixes
- beforeOperation hooks now correctly only run once ([e5d6a75](https://github.com/payloadcms/payload/commit/e5d6a75449acce2e53820a65386f1af78ff1317b))
## [2.0.1](https://github.com/payloadcms/payload/compare/v2.0.0...v2.0.1) (2023-10-09)
### Bug Fixes
- fix: richtext adapter types (#3497) ([7679e3f0a](https://github.com/payloadcms/payload/commit/7679e3f0aa351832ca933a3978d5931c47375e8b))
### Documentation
- remove --save flag for install command ([f7c35df6d](https://github.com/payloadcms/payload/commit/f7c35df6de6817ef33837f60951cd2812431fec7))
- updates live preview docs ([ca97f692c](https://github.com/payloadcms/payload/commit/ca97f692c3d470e658e417daf29213b2b2b49e11))
- fixes label for rich text overview ([7df1256bf](https://github.com/payloadcms/payload/commit/7df1256bf61daa911089d308cf7c0532d524c9c6))
## [2.0.0](https://github.com/payloadcms/payload/releases/tag/v2.0.0) (2023-10-09)
### Features
@@ -123,7 +231,7 @@ To avoid any issues, you can pass the `req.transactionID` through to your Local
### ⚠️ Locales now have more functionality, and in some places, you might need to update custom code
Payload's locales have become more powerful and now allow you to customize more aspects per locale such as a human-friendly label and if the locale is RTL or not.
Payload's locales have become more powerful and now allow you to customize more aspects per locale such as a human-friendly label and if the locale is RTL or not.
This means that certain functions now return a different shape, such as `useLocale`. This hook used to return a string of the locale code you are currently editing, but it now returns an object with type of `Locale`.
@@ -218,7 +326,7 @@ To pass connection options for MongoDB, you now need to pass them to `db: mongoo
### ⚠️ Some types have changed locations
If you are importing types from Payload, some of their locations may have changed. An example would be Slate-specific types being no longer exported from Payload itself—they are now exported from the `@payloadcms/richtext-slate` package.
If you are importing types from Payload, some of their locations may have changed. An example would be Slate-specific types being no longer exported from Payload itself—they are now exported from the `@payloadcms/richtext-slate` package.
### Recap

View File

@@ -40,20 +40,21 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
#### Collection Upload Options
| Option | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`staticURL`** \* | The URL path to use to access your uploads. Relative path like `/media` will be served by payload. Full path like `https://example.com/media` needs to be served by another web server. |
| **`staticDir`** \* | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. |
| **`adminThumbnail`** | Set the way that the Admin panel will display thumbnails for this Collection. [More](#admin-thumbnails) |
| **`crop`** | Set to `false` to disable the cropping tool in the Admin panel. Crop is enabled by default. [More](#crop-and-focal-point-selector) |
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the Admin panel. The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Express request handlers to execute before the built-in Payload static middleware executes. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
| **`staticOptions`** | Set options for `express.static` to use while serving your static files. [More](http://expressjs.com/en/resources/middleware/serve-static.html) format) |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
| Option | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`staticURL`** \* | The URL path to use to access your uploads. Relative path like `/media` will be served by payload. Full path like `https://example.com/media` needs to be served by another web server. |
| **`staticDir`** \* | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. |
| **`adminThumbnail`** | Set the way that the Admin panel will display thumbnails for this Collection. [More](#admin-thumbnails) |
| **`crop`** | Set to `false` to disable the cropping tool in the Admin panel. Crop is enabled by default. [More](#crop-and-focal-point-selector) |
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the Admin panel. The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Express request handlers to execute before the built-in Payload static middleware executes. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
| **`staticOptions`** | Set options for `express.static` to use while serving your static files. [More](http://expressjs.com/en/resources/middleware/serve-static.html) format) |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
_An asterisk denotes that a property above is required._

View File

@@ -496,6 +496,16 @@
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/generator@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420"
integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==
dependencies:
"@babel/types" "^7.23.0"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
"@babel/helper-compilation-targets@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52"
@@ -507,18 +517,23 @@
lru-cache "^5.1.1"
semver "^6.3.1"
"@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
"@babel/helper-environment-visitor@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98"
integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==
"@babel/helper-function-name@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be"
integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==
"@babel/helper-function-name@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
dependencies:
"@babel/template" "^7.22.5"
"@babel/types" "^7.22.5"
"@babel/template" "^7.22.15"
"@babel/types" "^7.23.0"
"@babel/helper-hoist-variables@^7.22.5":
version "7.22.5"
@@ -574,6 +589,11 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz#601fa28e4cc06786c18912dca138cec73b882044"
integrity sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
"@babel/helper-validator-option@^7.22.15":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040"
@@ -602,6 +622,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95"
integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==
"@babel/parser@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719"
integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -707,7 +732,7 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.3.3":
"@babel/template@^7.22.15", "@babel/template@^7.3.3":
version "7.22.15"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38"
integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==
@@ -717,18 +742,18 @@
"@babel/types" "^7.22.15"
"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17":
version "7.22.17"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44"
integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==
version "7.23.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8"
integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==
dependencies:
"@babel/code-frame" "^7.22.13"
"@babel/generator" "^7.22.15"
"@babel/helper-environment-visitor" "^7.22.5"
"@babel/helper-function-name" "^7.22.5"
"@babel/generator" "^7.23.0"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
"@babel/parser" "^7.22.16"
"@babel/types" "^7.22.17"
"@babel/parser" "^7.23.0"
"@babel/types" "^7.23.0"
debug "^4.1.0"
globals "^11.1.0"
@@ -741,6 +766,15 @@
"@babel/helper-validator-identifier" "^7.22.15"
to-fast-properties "^2.0.0"
"@babel/types@^7.23.0":
version "7.23.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
"@bcherny/json-schema-ref-parser@9.0.9":
version "9.0.9"
resolved "https://registry.yarnpkg.com/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#09899d405bc708c0acac0066ae8db5b94d465ca4"

View File

@@ -47,6 +47,7 @@
"@types/prompts": "^2.4.5",
"@types/qs": "6.9.7",
"@types/react": "18.2.15",
"@types/semver": "^7.5.3",
"@types/shelljs": "0.8.12",
"@types/testing-library__jest-dom": "5.14.8",
"chalk": "^5.3.0",
@@ -59,6 +60,7 @@
"fs-extra": "10.1.0",
"get-port": "5.1.1",
"glob": "8.1.0",
"graphql-request": "6.1.0",
"husky": "^8.0.3",
"isomorphic-fetch": "3.0.0",
"jest": "29.6.4",
@@ -73,6 +75,7 @@
"prompts": "2.4.2",
"qs": "6.11.2",
"rimraf": "3.0.2",
"semver": "^7.5.4",
"shelljs": "0.8.5",
"simple-git": "^3.20.0",
"slash": "3.0.0",

View File

@@ -36,6 +36,7 @@
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0",
"react-dom": "18.2.0"
},
"publishConfig": {

View File

@@ -58,6 +58,9 @@
"@types/webpack-hot-middleware": "2.25.6",
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0"
},
"publishConfig": {
"main": "./dist/index.js",
"registry": "https://registry.npmjs.org/",

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": "inline",
"jsc": {
"target": "esnext",
"parser": {
"syntax": "typescript",
"tsx": true,
"dts": true
}
},
"module": {
"type": "commonjs"
}
}

View File

@@ -1,18 +1,14 @@
{
"name": "create-payload-app",
"version": "0.5.2",
"version": "1.0.0",
"license": "MIT",
"bin": {
"create-payload-app": "bin/cli.js"
},
"scripts": {
"build": "tsc && pnpm copyfiles",
"copyfiles": "copyfiles -u 1 \"src/templates/**\" \"src/lib/common-files/**\" dist",
"build": "pnpm build:swc",
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
"clean": "rimraf dist",
"typecheck": "tsc --noEmit",
"lint": "eslint \"src/**/*.ts\"",
"lint:fix": "eslint \"src/**/*.ts\" --fix",
"lint-staged": "lint-staged --quiet",
"test": "jest",
"prepublishOnly": "pnpm test && pnpm clean && pnpm build"
},

View File

@@ -4,6 +4,7 @@ import type { BundlerType, CliArgs, DbType, ProjectTemplate } from '../types'
import { createProject } from './create-project'
import { bundlerPackages, dbPackages, editorPackages } from './packages'
import exp from 'constants'
import { getValidTemplates } from './templates'
const projectDir = path.resolve(__dirname, './tmp')
describe('createProject', () => {
@@ -78,17 +79,20 @@ describe('createProject', () => {
})
describe('db adapters and bundlers', () => {
const templates = getValidTemplates()
it.each([
['mongodb', 'webpack'],
['postgres', 'webpack'],
])('update config and deps: %s, %s', async (db, bundler) => {
['blank', 'mongodb', 'webpack'],
['blank', 'postgres', 'webpack'],
['website', 'mongodb', 'webpack'],
['website', 'postgres', 'webpack'],
['ecommerce', 'mongodb', 'webpack'],
['ecommerce', 'postgres', 'webpack'],
])('update config and deps: %s, %s, %s', async (templateName, db, bundler) => {
const projectName = 'starter-project'
const template: ProjectTemplate = {
name: 'blank',
type: 'starter',
url: 'https://github.com/payloadcms/payload/templates/blank',
description: 'Blank Template',
}
const template = templates.find((t) => t.name === templateName)
await createProject({
cliArgs: args,
projectName,
@@ -124,7 +128,12 @@ describe('createProject', () => {
editorReplacement.version,
)
const payloadConfigPath = path.resolve(projectDir, 'src/payload.config.ts')
let payloadConfigPath = path.resolve(projectDir, 'src/payload.config.ts')
// Website and ecommerce templates have payload.config.ts in src/payload
if (!fse.existsSync(payloadConfigPath)) {
payloadConfigPath = path.resolve(projectDir, 'src/payload/payload.config.ts')
}
const content = fse.readFileSync(payloadConfigPath, 'utf-8')
// Check payload.config.ts

View File

@@ -19,6 +19,5 @@
"src/**/*.spec.ts",
"src/**/*.spec.tsx"
],
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
"references": [{ "path": "../payload" }]
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"]
}

View File

@@ -35,6 +35,9 @@
"mongodb-memory-server": "8.13.0",
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0"
},
"publishConfig": {
"main": "./dist/index.js",
"registry": "https://registry.npmjs.org/",

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/db-postgres",
"version": "0.1.7",
"version": "0.1.9",
"description": "The officially supported Postgres database adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",
@@ -34,6 +34,9 @@
"@types/to-snake-case": "1.0.0",
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0"
},
"publishConfig": {
"main": "./dist/index.js",
"registry": "https://registry.npmjs.org/",

View File

@@ -33,7 +33,7 @@ export const findMany = async function find({
const db = adapter.sessions[req.transactionID]?.db || adapter.drizzle
const table = adapter.tables[tableName]
let limit = limitArg
let limit = limitArg ?? 10
let totalDocs: number
let totalPages: number
let hasPrevPage: boolean
@@ -119,7 +119,11 @@ export const findMany = async function find({
findManyArgs.where = inArray(adapter.tables[tableName].id, Object.keys(orderedIDMap))
} else {
findManyArgs.limit = limitArg === 0 ? undefined : limitArg
findManyArgs.offset = skip || (page - 1) * limitArg
const offset = skip || (page - 1) * limitArg
if (!Number.isNaN(offset)) findManyArgs.offset = offset
if (where) {
findManyArgs.where = where
}

View File

@@ -139,7 +139,7 @@ export const traverseFields = ({
currentTableName,
depth,
fields: block.fields,
path,
path: '',
topLevelArgs,
topLevelTableName,
})

View File

@@ -148,13 +148,19 @@ export async function parseParams({
break
}
const { operator: queryOperator, value: queryValue } = sanitizeQueryValue({
const sanitizedQueryValue = sanitizeQueryValue({
field,
operator,
relationOrPath,
val,
})
if (sanitizedQueryValue === null) {
break
}
const { operator: queryOperator, value: queryValue } = sanitizedQueryValue
if (queryOperator === 'not_equals' && queryValue !== null) {
constraints.push(
or(
@@ -163,7 +169,10 @@ export async function parseParams({
ne<any>(rawColumn || table[columnName], queryValue),
),
)
} else if (
break
}
if (
(field.type === 'relationship' || field.type === 'upload') &&
Array.isArray(queryValue) &&
operator === 'not_in'
@@ -174,11 +183,13 @@ export async function parseParams({
IS
NULL`,
)
} else {
constraints.push(
operatorMap[queryOperator](rawColumn || table[columnName], queryValue),
)
break
}
constraints.push(
operatorMap[queryOperator](rawColumn || table[columnName], queryValue),
)
}
}
}

View File

@@ -42,11 +42,17 @@ export const sanitizeQueryValue = ({
if (val.toLowerCase() === 'false') formattedValue = false
}
if (['all', 'in', 'not_in'].includes(operator) && typeof formattedValue === 'string') {
formattedValue = createArrayFromCommaDelineated(formattedValue)
if (['all', 'in', 'not_in'].includes(operator)) {
if (typeof formattedValue === 'string') {
formattedValue = createArrayFromCommaDelineated(formattedValue)
if (field.type === 'number') {
formattedValue = formattedValue.map((arrayVal) => parseFloat(arrayVal))
if (field.type === 'number') {
formattedValue = formattedValue.map((arrayVal) => parseFloat(arrayVal))
}
}
if (!Array.isArray(formattedValue) || formattedValue.length === 0) {
return null
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview-react",
"version": "0.1.3",
"version": "0.1.4",
"description": "The official live preview React SDK for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",
@@ -17,7 +17,7 @@
"prepublishOnly": "pnpm clean && pnpm build"
},
"dependencies": {
"@payloadcms/live-preview": "workspace:*"
"@payloadcms/live-preview": "workspace:^0.x"
},
"devDependencies": {
"@payloadcms/eslint-config": "workspace:*",
@@ -25,6 +25,7 @@
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"exports": {

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/live-preview",
"version": "0.1.3",
"version": "0.1.4",
"description": "The official live preview JavaScript SDK for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",
@@ -20,6 +20,9 @@
"@payloadcms/eslint-config": "workspace:*",
"payload": "workspace:*"
},
"peerDependencies": {
"payload": "^2.0.0"
},
"exports": {
".": {
"default": "./src/index.ts",

View File

@@ -1,5 +1,11 @@
import { mergeData } from '.'
// For performance reasons, `fieldSchemaJSON` will only be sent once on the initial message
// We need to cache this value so that it can be used across subsequent messages
// To do this, save `fieldSchemaJSON` when it arrives as a global variable
// Send this cached value to `mergeData`, instead of `eventData.fieldSchemaJSON` directly
let payloadLivePreviewFieldSchema = undefined // TODO: type this from `fieldSchemaToJSON` return type
export const handleMessage = async <T>(args: {
depth: number
event: MessageEvent
@@ -11,9 +17,13 @@ export const handleMessage = async <T>(args: {
const eventData = JSON.parse(event?.data)
if (eventData.type === 'payload-live-preview') {
if (!payloadLivePreviewFieldSchema && eventData.fieldSchemaJSON) {
payloadLivePreviewFieldSchema = eventData.fieldSchemaJSON
}
const mergedData = await mergeData<T>({
depth,
fieldSchema: eventData.fieldSchemaJSON,
fieldSchema: payloadLivePreviewFieldSchema,
incomingData: eventData.data,
initialData,
serverURL,

View File

@@ -2,11 +2,14 @@ export const ready = (args: { serverURL: string }): void => {
const { serverURL } = args
if (typeof window !== 'undefined') {
// This subscription may have been from either an iframe `src` or `window.open()`
// i.e. `window?.opener` || `window?.parent`
window?.opener?.postMessage(
// This subscription may have been from either an iframe or a popup
// We need to report 'ready' to the parent window, whichever it may be
// i.e. `window?.opener` for popups, `window?.parent` for iframes
const windowToPostTo: Window = window?.opener || window?.parent
windowToPostTo?.postMessage(
JSON.stringify({
popupReady: true,
ready: true,
type: 'payload-live-preview',
}),
serverURL,

View File

@@ -9,7 +9,7 @@ export const subscribe = <T>(args: {
const { callback, depth, initialData, serverURL } = args
const onMessage = async (event: MessageEvent) => {
const mergedData = await handleMessage({ depth, event, initialData, serverURL })
const mergedData = await handleMessage<T>({ depth, event, initialData, serverURL })
callback(mergedData)
}

View File

@@ -0,0 +1,51 @@
module.exports = {
verbose: true,
git: {
commitMessage: 'chore(release): v${version}',
requireCleanWorkingDir: false,
tagMatch: 'v*', // payload is tagged normally, other packages are tagged with a prefix
},
github: {
release: true,
},
npm: {
skipChecks: true,
},
hooks: {
'before:init': ['pnpm install', 'pnpm clean', 'pnpm build'], // Assume tests have already been run
},
plugins: {
'@release-it/conventional-changelog': {
infile: '../../CHANGELOG.md',
preset: {
name: 'conventionalcommits',
types: [
{ type: 'feat', section: 'Features' },
{ type: 'feature', section: 'Features' },
{ type: 'fix', section: 'Bug Fixes' },
{ type: 'docs', section: 'Documentation' },
],
},
writerOpts: {
commitGroupsSort: (a, b) => {
const groupOrder = ['Features', 'Bug Fixes', 'Documentation']
return groupOrder.indexOf(a.title) - groupOrder.indexOf(b.title)
},
// Scoped commits at the end, alphabetical sort
commitsSort: (a, b) => {
if (a.scope || b.scope) {
if (!a.scope) return -1
if (!b.scope) return 1
return a.scope === b.scope
? a.subject.localeCompare(b.subject)
: a.scope.localeCompare(b.scope)
}
// Alphabetical sort
return a.subject.localeCompare(b.subject)
},
},
},
},
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "2.0.6",
"version": "2.0.10",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./dist/index.js",
@@ -40,8 +40,7 @@
"lint": "eslint \"src/**/*.ts\"",
"prepublishOnly": "pnpm clean && pnpm build",
"pretest": "pnpm build",
"release:beta": "release-it pre --preReleaseId=beta --npm.tag=beta --config .release-it.pre.json",
"release:canary": "release-it pre --preReleaseId=canary --npm.tag=canary --config .release-it.pre.json",
"release:beta": "release-it pre --preReleaseId=beta --npm.tag=beta --config .release-it.pre.js",
"release:major": "release-it major",
"release:minor": "release-it minor",
"release:patch": "release-it patch",
@@ -187,7 +186,6 @@
"file-loader": "6.2.0",
"form-data": "3.0.1",
"get-port": "5.1.1",
"graphql-request": "6.1.0",
"mini-css-extract-plugin": "1.6.2",
"node-fetch": "2.6.12",
"nodemon": "3.0.1",

View File

@@ -6,13 +6,13 @@ import { toast } from 'react-toastify'
import type { Props } from './types'
import useDebounce from '../../../hooks/useDebounce'
import { formatTimeToNow } from '../../../utilities/formatDate'
import { useAllFormFields, useFormModified } from '../../forms/Form/context'
import reduceFieldsToValues from '../../forms/Form/reduceFieldsToValues'
import { useConfig } from '../../utilities/Config'
import { useDocumentInfo } from '../../utilities/DocumentInfo'
import { useLocale } from '../../utilities/Locale'
import './index.scss'
const baseClass = 'autosave'
const Autosave: React.FC<Props> = ({ id, collection, global, publishedDocUpdatedAt }) => {
@@ -163,7 +163,7 @@ const Autosave: React.FC<Props> = ({ id, collection, global, publishedDocUpdated
{!saving && lastSaved && (
<React.Fragment>
{t('lastSavedAgo', {
distance: Math.round((Number(new Date(lastSaved)) - Number(new Date())) / 1000 / 60),
distance: formatTimeToNow(lastSaved, i18n.language),
})}
</React.Fragment>
)}

View File

@@ -28,10 +28,10 @@
gap: var(--base);
padding-bottom: 1px;
z-index: 1;
height: var(--doc-controls-height);
}
&__content {
height: var(--doc-controls-height);
display: flex;
align-items: center;
flex-grow: 1;
@@ -140,21 +140,21 @@
// On mobile, only stick the controls to the top
// The timestamps and meta can scroll past
// The same container needs to the sticky, though
// So we use a static height with a negative top
top: calc(var(--doc-controls-height) * -1);
// So we use a static height with a negative top equal to the meta height plus top padding
top: calc(var(--base) * -2);
padding-right: 0;
padding-left: 0;
&__wrapper {
flex-direction: column;
gap: 0;
height: unset;
}
&__content {
width: 100%;
align-items: flex-start;
padding-top: calc(var(--base) / 2);
overflow: auto;
height: calc(var(--base) * 2);
// this container has a fixed height
// this means the scrollbar (when present) overlaps the content
@@ -167,26 +167,52 @@
width: auto;
gap: calc(var(--base) / 2);
margin-left: var(--gutter-h);
margin-right: var(--gutter-h);
&::after {
content: '';
display: block;
position: sticky;
right: 0;
width: calc(var(--base) * 2);
height: var(--base);
background: linear-gradient(to right, transparent, var(--theme-bg));
flex-shrink: 0;
z-index: 1111;
pointer-events: none;
}
}
&__controls-wrapper {
width: 100%;
transform: translate3d(0, 0, 0);
padding: calc(var(--base) / 2) 0;
overflow: auto;
padding-right: var(--gutter-h);
justify-content: space-between;
height: var(--doc-controls-height);
border-top: 1px solid var(--theme-elevation-100);
}
&__controls {
margin-left: var(--gutter-h);
margin-right: var(--gutter-h);
}
padding-left: var(--gutter-h);
overflow: auto;
&__popup {
// TODO: the container needs to overflow on mobile
// But the popup interferes with this because it requires overflow in order to be visible
// So we likely need to outright show the controls nested within the popup on mobile
display: none;
// do not show scrollbar because the parent container has a static height
// this container has a gradient overlay as visual indication of `overflow: scroll`
&::-webkit-scrollbar {
display: none;
}
&::after {
content: '';
display: block;
position: sticky;
right: 0;
width: calc(var(--base) * 2);
height: calc(var(--base) * 1.5);
background: linear-gradient(to right, transparent, var(--theme-bg));
flex-shrink: 0;
z-index: 1111;
pointer-events: none;
}
}
}
}

View File

@@ -2,7 +2,8 @@ import React, { Fragment } from 'react'
import { useTranslation } from 'react-i18next'
import type { CollectionPermission, GlobalPermission } from '../../../../auth'
import type { SanitizedCollectionConfig, SanitizedGlobalConfig } from '../../../../exports/types'
import type { SanitizedCollectionConfig } from '../../../../collections/config/types'
import type { SanitizedGlobalConfig } from '../../../../globals/config/types'
import { formatDate } from '../../../utilities/formatDate'
import { useConfig } from '../../utilities/Config'

View File

@@ -1,4 +1,5 @@
import { useModal } from '@faceless-ui/modal'
import queryString from 'qs'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { toast } from 'react-toastify'
@@ -16,6 +17,7 @@ import X from '../../icons/X'
import { useAuth } from '../../utilities/Auth'
import { useConfig } from '../../utilities/Config'
import { DocumentInfoProvider, useDocumentInfo } from '../../utilities/DocumentInfo'
import { useFormQueryParams } from '../../utilities/FormQueryParams'
import { useLocale } from '../../utilities/Locale'
import RenderCustomComponent from '../../utilities/RenderCustomComponent'
import DefaultEdit from '../../views/collections/Edit/Default'
@@ -42,6 +44,8 @@ const Content: React.FC<DocumentDrawerProps> = ({
const [isOpen, setIsOpen] = useState(false)
const [collectionConfig] = useRelatedCollections(collectionSlug)
const config = useConfig()
const { formQueryParams } = useFormQueryParams()
const formattedQueryParams = queryString.stringify(formQueryParams)
const { admin: { components: { views: { Edit } = {} } = {} } = {} } = collectionConfig
@@ -117,8 +121,8 @@ const Content: React.FC<DocumentDrawerProps> = ({
const apiURL = id ? `${serverURL}${api}/${collectionSlug}/${id}?locale=${locale}` : null
const action = `${serverURL}${api}/${collectionSlug}${
id ? `/${id}` : ''
}?locale=${locale}&fallback-locale=null`
isEditing ? `/${id}` : ''
}?${formattedQueryParams}`
const hasSavePermission =
(isEditing && docPermissions?.update?.permission) ||

View File

@@ -17,6 +17,24 @@
padding: 0;
overflow: auto;
// this container has a gradient overlay as visual indication of `overflow: scroll`
&::-webkit-scrollbar {
display: none;
}
&::after {
content: '';
display: block;
position: sticky;
right: 0;
width: calc(var(--base) * 2);
height: calc(var(--base) * 2);
background: linear-gradient(to right, transparent, var(--theme-bg));
flex-shrink: 0;
z-index: 1111;
pointer-events: none;
}
&__tabs {
padding: 0;
margin-left: var(--gutter-h);

View File

@@ -35,11 +35,6 @@ $header-height: base(5);
text-wrap: nowrap;
}
&__cancel,
&__save {
width: 50%;
}
&__toolWrap {
display: flex;
justify-content: flex-end;

View File

@@ -50,14 +50,13 @@ export const EditUpload: React.FC<{
y: uploadEdits?.focalPoint?.y || 50,
})
const [checkBounds, setCheckBounds] = useState<boolean>(false)
const [originalHeight, setOriginalHeight] = useState<number>(0)
const [originalWidth, setOriginalWidth] = useState<number>(0)
const focalWrapRef = useRef<HTMLDivElement | undefined>()
const imageRef = useRef<HTMLImageElement | undefined>()
const cropRef = useRef<HTMLDivElement | undefined>()
const originalHeight = imageRef.current ? imageRef.current.naturalHeight : 0
const originalWidth = imageRef.current ? imageRef.current.naturalWidth : 0
const fineTuneCrop = ({ dimension, value }: { dimension: 'height' | 'width'; value: string }) => {
const intValue = parseInt(value)
if (dimension === 'width' && intValue >= originalWidth) return null
@@ -152,7 +151,15 @@ export const EditUpload: React.FC<{
return <div className={`${baseClass}__crop-window`} ref={cropRef} />
}}
>
<img alt={t('upload:setCropArea')} ref={imageRef} src={fileSrcToUse} />
<img
alt={t('upload:setCropArea')}
onLoad={(e) => {
setOriginalHeight(e.currentTarget.naturalHeight)
setOriginalWidth(e.currentTarget.naturalWidth)
}}
ref={imageRef}
src={fileSrcToUse}
/>
</ReactCrop>
) : (
<img alt={t('upload:setFocalPoint')} ref={imageRef} src={fileSrcToUse} />

View File

@@ -6,16 +6,22 @@
cursor: pointer;
background-color: transparent;
outline: none;
position: absolute;
position: relative;
--hamburger-padding: 5px;
--hamburger-padding: 8px;
--hamburger-size: 9px;
--hamburger-line-gap: 3px;
padding: var(--hamburger-padding);
border: 1px solid var(--theme-elevation-350);
border: 1px solid var(--theme-elevation-150);
color: var(--theme-text);
border-radius: 3px;
&:hover {
border: 1px solid var(--theme-elevation-500);
background-color: var(--theme-elevation-100);
}
&:focus {
outline: none;
}

View File

@@ -92,6 +92,12 @@
right: base(2);
}
&--nav-open {
.app-header__localizer {
display: none;
}
}
&__mobile-nav-toggler {
display: flex;
align-items: center;

View File

@@ -8,6 +8,7 @@ import { Hamburger } from '../Hamburger'
import Localizer from '../Localizer'
import { LocalizerLabel } from '../Localizer/LocalizerLabel'
import { NavToggler } from '../Nav/NavToggler'
import { useNav } from '../Nav/context'
import StepNav from '../StepNav'
import './index.scss'
@@ -21,8 +22,10 @@ export const AppHeader: React.FC = (props) => {
routes: { admin: adminRoute },
} = useConfig()
const { navOpen } = useNav()
return (
<header className={[baseClass].filter(Boolean).join(' ')}>
<header className={[baseClass, navOpen && `${baseClass}--nav-open`].filter(Boolean).join(' ')}>
<div className={`${baseClass}__bg`} />
<div className={`${baseClass}__content`}>
<div className={`${baseClass}__wrapper`}>

View File

@@ -6,11 +6,5 @@
padding: 0;
margin: 0;
border: 0;
height: var(--app-header-height);
width: var(--gutter-h);
cursor: pointer;
@include small-break {
width: calc(var(--gutter-h) * 2);
}
}

View File

@@ -19,11 +19,21 @@ export const NavContext = React.createContext<NavContextType>({
export const useNav = () => React.useContext(NavContext)
const getNavPreference = async (getPreference): Promise<boolean> => {
const navPrefs = await getPreference('nav')
const preferredState = navPrefs?.open
if (typeof preferredState === 'boolean') {
return preferredState
} else {
return true
}
}
export const NavProvider: React.FC<{
children: React.ReactNode
}> = ({ children }) => {
const {
breakpoints: { l: largeBreak },
breakpoints: { l: largeBreak, m: midBreak, s: smallBreak },
} = useWindowInfo()
const { getPreference } = usePreferences()
@@ -40,16 +50,11 @@ export const NavProvider: React.FC<{
useEffect(() => {
if (largeBreak === false) {
const setNavFromPreferences = async () => {
const navPrefs = await getPreference('nav')
const preferredState = navPrefs?.open
if (typeof preferredState === 'boolean') {
setNavOpen(preferredState)
} else {
setNavOpen(true)
}
const preferredState = await getNavPreference(getPreference)
setNavOpen(preferredState)
}
setNavFromPreferences()
setNavFromPreferences() // eslint-disable-line @typescript-eslint/no-floating-promises
}
}, [largeBreak, getPreference, setNavOpen])
@@ -58,7 +63,7 @@ export const NavProvider: React.FC<{
useEffect(() => {
let unlisten: () => void
if (largeBreak) {
if (midBreak) {
unlisten = history.listen(() => {
setNavOpen(false)
})
@@ -67,27 +72,28 @@ export const NavProvider: React.FC<{
}
return () => unlisten && unlisten()
}, [history, setNavOpen, largeBreak])
// on smaller screens where the nav is a modal
// close the nav when the user resizes down to a smaller screen
useEffect(() => {
if (largeBreak) {
setNavOpen(false)
}
}, [largeBreak])
}, [history, setNavOpen, midBreak])
// on open and close, lock the body scroll
// do not do this on desktop, the sidebar is not a modal
useEffect(() => {
if (navRef.current) {
if (navOpen && largeBreak) {
if (navOpen && midBreak) {
disableBodyScroll(navRef.current)
} else {
enableBodyScroll(navRef.current)
}
}
}, [navOpen, largeBreak])
}, [navOpen, midBreak])
// on smaller screens where the nav is a modal
// close the nav when the user resizes down to mobile
// the sidebar is a modal on mobile
useEffect(() => {
if (largeBreak === false || midBreak === false || smallBreak === false) {
setNavOpen(false)
}
}, [largeBreak, midBreak, smallBreak])
// when the component unmounts, clear all body scroll locks
useEffect(() => {

View File

@@ -41,7 +41,7 @@
height: 100%;
display: flex;
flex-direction: column;
padding: var(--app-header-height) base(1.5) base(2) base(1.25);
padding: var(--app-header-height) base(1) base(2) base(1);
overflow-y: auto;
// remove the scrollbar here to prevent layout shift as nav groups are toggled
@@ -128,12 +128,7 @@
@include mid-break {
&__scroll {
padding: var(--app-header-height) base(0.75) base(2) base(0.75);
}
nav a {
font-size: base(0.875);
line-height: base(1.5);
padding: var(--app-header-height) base(0.5) base(2);
}
}
@@ -141,9 +136,12 @@
&__scroll {
padding: var(--app-header-height) var(--gutter-h) base(2);
}
}
@include extra-small-break {
nav a {
font-size: base(0.875);
line-height: base(1.5);
}
&--nav-open {
transition: none;
}

View File

@@ -14,7 +14,7 @@
}
&__preview {
max-height: calc(100% - base(4));
max-height: calc(100% - base(6));
padding: base(1.5) base(1.5) base(1.5) var(--gutter-h);
object-fit: contain;
}

View File

@@ -28,8 +28,8 @@ const PreviewSizes: React.FC<{
doc?: Data & {
sizes?: FileSizes
}
updatedAt?: string
}> = ({ collection, doc, updatedAt }) => {
imageCacheTag?: string
}> = ({ collection, doc, imageCacheTag }) => {
const {
upload: { imageSizes, staticURL },
} = collection
@@ -39,20 +39,15 @@ const PreviewSizes: React.FC<{
const [selectedSize, setSelectedSize] = useState<null | string>(
orderedSizes?.[imageSizes[0]?.name]?.filename ? imageSizes[0]?.name : null,
)
const [appendUrl, setAppendUrl] = useState<boolean>(false)
const generateImageUrl = (filename) => {
const query = appendUrl ? `?${Date.now()}` : ''
return `${staticURL}/${filename}${query}`
return `${staticURL}/${filename}${imageCacheTag ? `?${imageCacheTag}` : ''}`
}
useEffect(() => {
setOrderedSizes(sortSizes(sizes, imageSizes))
}, [sizes, imageSizes, updatedAt])
}, [sizes, imageSizes, imageCacheTag])
useEffect(() => {
setAppendUrl(true)
}, [updatedAt])
const mainPreviewSrc = generateImageUrl(`${orderedSizes[selectedSize]?.filename}`)
return (
<div className={baseClass}>
@@ -61,17 +56,15 @@ const PreviewSizes: React.FC<{
<div className={`${baseClass}__sizeName`}>{selectedSize}</div>
<Meta {...(selectedSize && orderedSizes[selectedSize])} staticURL={staticURL} />
</div>
<img
alt={doc.filename}
className={`${baseClass}__preview`}
src={generateImageUrl(`${orderedSizes[selectedSize]?.filename}`)}
/>
<img alt={doc.filename} className={`${baseClass}__preview`} src={mainPreviewSrc} />
</div>
<div className={`${baseClass}__listWrap`}>
<div className={`${baseClass}__list`}>
{Object.entries(orderedSizes).map(([key, val]) => {
const selected = selectedSize === key
if (val?.filename) {
const previewSrc = generateImageUrl(val.filename)
if (previewSrc) {
return (
<div
className={[`${baseClass}__sizeOption`, selected && `${baseClass}--selected`]
@@ -88,7 +81,7 @@ const PreviewSizes: React.FC<{
tabIndex={0}
>
<div className={`${baseClass}__image`}>
<img alt={val.filename} src={generateImageUrl(val.filename)} />
<img alt={val.filename} src={previewSrc} />
</div>
<div className={`${baseClass}__sizeMeta`}>
<div className={`${baseClass}__sizeName`}>{key}</div>

View File

@@ -25,12 +25,9 @@ const Thumbnail: React.FC<Props> = (props) => {
const classes = [baseClass, `${baseClass}--size-${size || 'medium'}`, className].join(' ')
useEffect(() => {
if (doc && collection && thumbnailSRC) {
if (thumbnailSRC) {
setSrc(`${thumbnailSRC}${imageCacheTag ? `?${imageCacheTag}` : ''}`)
}
if (fileSrc) {
setSrc(fileSrc)
}
}, [doc, collection, thumbnailSRC, fileSrc, imageCacheTag])
return (

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import type { Props } from './types'
@@ -37,7 +37,7 @@ const RenderFields: React.FC<Props> = (props) => {
const { i18n, t } = useTranslation('general')
const [hasRendered, setHasRendered] = useState(Boolean(forceRender))
const [intersectionRef, entry] = useIntersect(intersectionObserverOptions)
const [intersectionRef, entry] = useIntersect(intersectionObserverOptions, forceRender)
const isIntersecting = Boolean(entry?.isIntersecting)
const isAboveViewport = entry?.boundingClientRect?.top < 0
@@ -105,6 +105,7 @@ const RenderFields: React.FC<Props> = (props) => {
readOnly,
},
fieldTypes,
forceRender,
indexPath:
'indexPath' in props ? `${props?.indexPath}.${fieldIndex}` : `${fieldIndex}`,
path: field.path || (isFieldAffectingData && 'name' in field ? field.name : ''),

View File

@@ -24,6 +24,7 @@ type ArrayRowProps = UseDraggableSortableReturn &
CustomRowLabel?: RowLabelType
addRow: (rowIndex: number) => void
duplicateRow: (rowIndex: number) => void
forceRender?: boolean
hasMaxRows?: boolean
moveRow: (fromIndex: number, toIndex: number) => void
readOnly?: boolean
@@ -40,6 +41,7 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
duplicateRow,
fieldTypes,
fields,
forceRender = false,
hasMaxRows,
indexPath,
labels,
@@ -126,10 +128,11 @@ export const ArrayRow: React.FC<ArrayRowProps> = ({
path: createNestedFieldPath(path, field),
}))}
fieldTypes={fieldTypes}
forceRender={forceRender}
indexPath={indexPath}
margins="small"
permissions={permissions?.fields}
readOnly={readOnly}
margins="small"
/>
</Collapsible>
</div>

View File

@@ -32,6 +32,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
admin: { className, components, condition, description, readOnly },
fieldTypes,
fields,
forceRender = false,
indexPath,
localized,
maxRows,
@@ -234,6 +235,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
duplicateRow={duplicateRow}
fieldTypes={fieldTypes}
fields={fields}
forceRender={forceRender}
hasMaxRows={hasMaxRows}
indexPath={indexPath}
labels={labels}

View File

@@ -4,6 +4,7 @@ import type { ArrayField } from '../../../../../fields/config/types'
export type Props = Omit<ArrayField, 'type'> & {
fieldTypes: FieldTypes
forceRender?: boolean
indexPath: string
label: false | string
path?: string

View File

@@ -24,6 +24,7 @@ type BlockFieldProps = UseDraggableSortableReturn &
addRow: (rowIndex: number, blockType: string) => void
blockToRender: Block
duplicateRow: (rowIndex: number) => void
forceRender?: boolean
hasMaxRows?: boolean
moveRow: (fromIndex: number, toIndex: number) => void
readOnly: boolean
@@ -40,6 +41,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
blocks,
duplicateRow,
fieldTypes,
forceRender,
hasMaxRows,
indexPath,
labels,
@@ -130,6 +132,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
path: createNestedFieldPath(path, field),
}))}
fieldTypes={fieldTypes}
forceRender={forceRender}
indexPath={indexPath}
margins="small"
permissions={permissions?.blocks?.[row.blockType]?.fields}

View File

@@ -37,6 +37,7 @@ const BlocksField: React.FC<Props> = (props) => {
admin: { className, condition, description, readOnly },
blocks,
fieldTypes,
forceRender = false,
indexPath,
label,
labels: labelsFromProps,
@@ -238,6 +239,7 @@ const BlocksField: React.FC<Props> = (props) => {
blocks={blocks}
duplicateRow={duplicateRow}
fieldTypes={fieldTypes}
forceRender={forceRender}
hasMaxRows={hasMaxRows}
indexPath={indexPath}
labels={labels}
@@ -297,7 +299,7 @@ const BlocksField: React.FC<Props> = (props) => {
</DrawerToggler>
<BlocksDrawer
addRow={addRow}
addRowIndex={value || 0}
addRowIndex={rows?.length || 0}
blocks={blocks}
drawerSlug={drawerSlug}
labels={labels}

View File

@@ -4,6 +4,7 @@ import type { BlockField } from '../../../../../fields/config/types'
export type Props = Omit<BlockField, 'type'> & {
fieldTypes: FieldTypes
forceRender?: boolean
indexPath: string
path?: string
permissions: FieldPermissions

View File

@@ -14,9 +14,9 @@ import { WatchChildErrors } from '../../WatchChildErrors'
import withCondition from '../../withCondition'
import { useRow } from '../Row/provider'
import { useTabs } from '../Tabs/provider'
import { fieldBaseClass } from '../shared'
import './index.scss'
import { GroupProvider, useGroup } from './provider'
import { fieldBaseClass } from '../shared'
const baseClass = 'group-field'
@@ -26,6 +26,7 @@ const Group: React.FC<Props> = (props) => {
admin: { className, description, hideGutter = false, readOnly, style, width },
fieldTypes,
fields,
forceRender = false,
indexPath,
label,
path: pathFromProps,
@@ -88,6 +89,7 @@ const Group: React.FC<Props> = (props) => {
path: createNestedFieldPath(path, subField),
}))}
fieldTypes={fieldTypes}
forceRender={forceRender}
indexPath={indexPath}
margins="small"
permissions={permissions?.fields}

View File

@@ -4,6 +4,7 @@ import type { GroupField } from '../../../../../fields/config/types'
export type Props = Omit<GroupField, 'type'> & {
fieldTypes: FieldTypes
forceRender?: boolean
indexPath: string
path?: string
permissions: FieldPermissions

View File

@@ -14,6 +14,7 @@ const Row: React.FC<Props> = (props) => {
admin: { className, readOnly },
fieldTypes,
fields,
forceRender = false,
indexPath,
path,
permissions,
@@ -28,6 +29,7 @@ const Row: React.FC<Props> = (props) => {
path: createNestedFieldPath(path, field),
}))}
fieldTypes={fieldTypes}
forceRender={forceRender}
indexPath={indexPath}
permissions={permissions}
readOnly={readOnly}

View File

@@ -4,6 +4,7 @@ import type { RowField } from '../../../../../fields/config/types'
export type Props = Omit<RowField, 'type'> & {
fieldTypes: FieldTypes
forceRender?: boolean
indexPath: string
path?: string
permissions: FieldPermissions

View File

@@ -18,9 +18,9 @@ import { createNestedFieldPath } from '../../Form/createNestedFieldPath'
import RenderFields from '../../RenderFields'
import { WatchChildErrors } from '../../WatchChildErrors'
import withCondition from '../../withCondition'
import { fieldBaseClass } from '../shared'
import './index.scss'
import { TabsProvider } from './provider'
import { fieldBaseClass } from '../shared'
const baseClass = 'tabs-field'
@@ -72,6 +72,7 @@ const TabsField: React.FC<Props> = (props) => {
const {
admin: { className, readOnly },
fieldTypes,
forceRender = false,
indexPath,
path,
permissions,
@@ -188,7 +189,7 @@ const TabsField: React.FC<Props> = (props) => {
}
})}
fieldTypes={fieldTypes}
forceRender
forceRender={forceRender}
indexPath={indexPath}
key={String(activeTabConfig.label)}
margins="small"

View File

@@ -4,6 +4,7 @@ import type { TabsField } from '../../../../../fields/config/types'
export type Props = Omit<TabsField, 'type'> & {
fieldTypes: FieldTypes
forceRender?: boolean
indexPath: string
path?: string
permissions: FieldPermissions

View File

@@ -1,17 +1,23 @@
.graphic-account {
vector-effect: non-scaling-stroke;
overflow: visible;
&__bg {
fill: var(--theme-elevation-100);
fill: var(--theme-elevation-50);
stroke: var(--theme-elevation-200);
stroke-width: 1px;
}
&__head,
&__body {
fill: var(--theme-elevation-300);
fill: var(--theme-elevation-200);
}
&--active {
.graphic-account {
&__bg {
fill: var(--theme-elevation-500);
stroke: var(--theme-text);
}
&__head,
@@ -25,6 +31,7 @@
.graphic-account {
&__bg {
fill: var(--theme-elevation-200);
stroke: var(--theme-elevation-600);
}
&__head,
@@ -41,6 +48,12 @@
.graphic-account {
&__bg {
fill: var(--theme-elevation-300);
stroke: var(--theme-elevation-600);
}
&__head,
&__body {
fill: var(--theme-elevation-600);
}
}
}

View File

@@ -21,7 +21,7 @@
}
}
&__nav-toggler {
&__nav-toggler-wrapper {
position: fixed;
z-index: var(--z-modal);
top: 0;
@@ -40,113 +40,32 @@
position: relative;
}
&__nav-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
background: var(--theme-overlay);
padding: 0;
border: 0;
z-index: var(--z-modal);
cursor: pointer;
pointer-events: none;
display: none;
}
// on large break, push the document off the screen
// show an overlay to prevent clicking on the document
@include large-break {
width: calc(100% + var(--nav-width));
transform: translate3d(0, 0, 0);
&__wrap {
transform: translate3d(calc(var(--nav-width) * -1), 0, 0);
}
&__nav-overlay {
display: block;
}
&--nav-open {
transform: translate3d(0, 0, 0);
.template-default {
&__wrap {
pointer-events: none;
transform: translate3d(0, 0, 0);
transition: transform var(--nav-trans-time) linear;
}
&__nav-overlay {
opacity: 1;
pointer-events: auto;
}
}
}
&__nav-toggler {
.hamburger {
left: calc(var(--base) * 1.25);
}
}
}
@include mid-break {
&__nav-toggler {
&__nav-toggler-wrapper {
.hamburger {
left: calc(var(--base) * 0.75);
left: unset;
}
}
}
@include small-break {
&__nav-toggler {
.hamburger {
left: calc(var(--base) * 0.5);
}
&.nav-toggler--is-open .hamburger {
display: flex;
display: inline;
}
}
}
@include small-break {
&__nav-toggler {
width: unset;
justify-content: unset;
.hamburger {
opacity: none;
}
}
&__nav-toggler.nav-toggler--is-open .hamburger {
display: flex;
display: inline;
}
}
@include extra-small-break {
&--nav-open {
transition: none;
}
&__nav-toggler.nav-toggler--is-open .hamburger {
display: none;
&__nav-toggler-wrapper {
width: unset;
justify-content: unset;
.hamburger {
display: none;
}
}
.template-default {
&__wrap {
transition: none;
}
&__nav-overlay {
transition: none;
}
}
}
}

View File

@@ -44,17 +44,13 @@ const Default: React.FC<Props> = ({ children, className }) => {
<div className={`${baseClass}__wrap`}>
<AppHeader />
{children}
<button
aria-label={t('close')}
className={`${baseClass}__nav-overlay`}
onClick={() => setNavOpen(!navOpen)}
type="button"
/>
</div>
</div>
<NavToggler className={`${baseClass}__nav-toggler`} id="nav-toggler">
<Hamburger closeIcon="collapse" isActive={navOpen} />
</NavToggler>
<div className={`${baseClass}__nav-toggler-wrapper`} id="nav-toggler">
<NavToggler className={`${baseClass}__nav-toggler`}>
<Hamburger closeIcon="collapse" isActive={navOpen} />
</NavToggler>
</div>
</Fragment>
)
}

View File

@@ -3,13 +3,10 @@
.global-default-edit {
width: 100%;
display: flex;
--doc-sidebar-width: 325px;
&--has-sidebar {
.global-default-edit {
&__main {
width: 66.66%;
}
&__edit {
[dir='ltr'] & {
top: 0;
@@ -40,6 +37,7 @@
display: flex;
flex-direction: column;
min-height: 100%;
flex-grow: 1;
}
&__edit {
@@ -48,11 +46,16 @@
flex-grow: 1;
}
&__auth {
margin-bottom: var(--base);
}
&__sidebar-wrap {
position: sticky;
top: var(--doc-controls-height);
width: 33.33%;
height: calc(100vh - var(--doc-controls-height));
min-width: var(--doc-sidebar-width);
}
&__sidebar {
@@ -71,24 +74,16 @@
display: flex;
flex-direction: column;
gap: var(--base);
padding: calc(var(--base) * 1.5) var(--gutter-h) var(--spacing-view-bottom)
calc(var(--base) * 2);
padding-top: calc(var(--base) * 1.5);
padding-left: calc(var(--base) * 2);
padding-right: var(--gutter-h);
padding-bottom: var(--spacing-view-bottom);
}
&__label {
color: var(--theme-elevation-400);
}
@include large-break {
&--no-sidebar {
.global-default-edit {
&__main {
width: 100%;
}
}
}
}
@include mid-break {
display: block;
@@ -130,6 +125,7 @@
height: initial;
border-left: 0;
margin-top: calc(var(--base) / 2);
width: var(--doc-sidebar-width);
}
&__form {
@@ -158,6 +154,11 @@
}
@include small-break {
&__sidebar-wrap {
min-width: initial;
width: 100%;
}
&__edit {
padding-top: calc(var(--base) / 2);
}

View File

@@ -3,21 +3,31 @@ import type { Dispatch } from 'react'
import { createContext, useContext } from 'react'
import type { LivePreviewConfig } from '../../../../../exports/config'
import type { fieldSchemaToJSON } from '../../../../../utilities/fieldSchemaToJSON'
import type { usePopupWindow } from '../usePopupWindow'
import type { SizeReducerAction } from './sizeReducer'
export interface LivePreviewContextType {
appIsReady: boolean
breakpoint: LivePreviewConfig['breakpoints'][number]['name']
breakpoints: LivePreviewConfig['breakpoints']
fieldSchemaJSON?: ReturnType<typeof fieldSchemaToJSON>
iframeHasLoaded: boolean
iframeRef: React.RefObject<HTMLIFrameElement>
isPopupOpen: boolean
measuredDeviceSize: {
height: number
width: number
}
openPopupWindow: ReturnType<typeof usePopupWindow>['openPopupWindow']
popupRef?: React.MutableRefObject<Window | null>
previewWindowType: 'iframe' | 'popup'
setAppIsReady: (appIsReady: boolean) => void
setBreakpoint: (breakpoint: LivePreviewConfig['breakpoints'][number]['name']) => void
setHeight: (height: number) => void
setIframeHasLoaded: (loaded: boolean) => void
setMeasuredDeviceSize: (size: { height: number; width: number }) => void
setPreviewWindowType: (previewWindowType: 'iframe' | 'popup') => void
setSize: Dispatch<SizeReducerAction>
setToolbarPosition: (position: { x: number; y: number }) => void
setWidth: (width: number) => void
@@ -30,22 +40,31 @@ export interface LivePreviewContextType {
x: number
y: number
}
url: string | undefined
zoom: number
}
export const LivePreviewContext = createContext<LivePreviewContextType>({
appIsReady: false,
breakpoint: undefined,
breakpoints: undefined,
fieldSchemaJSON: undefined,
iframeHasLoaded: false,
iframeRef: undefined,
isPopupOpen: false,
measuredDeviceSize: {
height: 0,
width: 0,
},
openPopupWindow: () => {},
popupRef: undefined,
previewWindowType: 'iframe',
setAppIsReady: () => {},
setBreakpoint: () => {},
setHeight: () => {},
setIframeHasLoaded: () => {},
setMeasuredDeviceSize: () => {},
setPreviewWindowType: () => {},
setSize: () => {},
setToolbarPosition: () => {},
setWidth: () => {},
@@ -58,6 +77,7 @@ export const LivePreviewContext = createContext<LivePreviewContextType>({
x: 0,
y: 0,
},
url: undefined,
zoom: 1,
})

View File

@@ -1,39 +1,48 @@
import { DndContext } from '@dnd-kit/core'
import React, { useCallback, useEffect } from 'react'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import type { LivePreviewConfig } from '../../../../../exports/config'
import type { Field } from '../../../../../fields/config/types'
import type { EditViewProps } from '../../types'
import type { usePopupWindow } from '../usePopupWindow'
import { fieldSchemaToJSON } from '../../../../../utilities/fieldSchemaToJSON'
import { customCollisionDetection } from './collisionDetection'
import { LivePreviewContext } from './context'
import { sizeReducer } from './sizeReducer'
export type ToolbarProviderProps = EditViewProps & {
export type LivePreviewProviderProps = EditViewProps & {
appIsReady?: boolean
breakpoints?: LivePreviewConfig['breakpoints']
children: React.ReactNode
deviceSize?: {
height: number
width: number
}
popupState: ReturnType<typeof usePopupWindow>
isPopupOpen?: boolean
openPopupWindow?: ReturnType<typeof usePopupWindow>['openPopupWindow']
popupRef?: React.MutableRefObject<Window>
url?: string
}
export const LivePreviewProvider: React.FC<ToolbarProviderProps> = (props) => {
const { breakpoints, children } = props
export const LivePreviewProvider: React.FC<LivePreviewProviderProps> = (props) => {
const { breakpoints, children, isPopupOpen, openPopupWindow, popupRef, url } = props
const [previewWindowType, setPreviewWindowType] = useState<'iframe' | 'popup'>('iframe')
const [appIsReady, setAppIsReady] = useState(false)
const iframeRef = React.useRef<HTMLIFrameElement>(null)
const [iframeHasLoaded, setIframeHasLoaded] = React.useState(false)
const [iframeHasLoaded, setIframeHasLoaded] = useState(false)
const [zoom, setZoom] = React.useState(1)
const [zoom, setZoom] = useState(1)
const [position, setPosition] = React.useState({ x: 0, y: 0 })
const [position, setPosition] = useState({ x: 0, y: 0 })
const [size, setSize] = React.useReducer(sizeReducer, { height: 0, width: 0 })
const [measuredDeviceSize, setMeasuredDeviceSize] = React.useState({
const [measuredDeviceSize, setMeasuredDeviceSize] = useState({
height: 0,
width: 0,
})
@@ -41,6 +50,22 @@ export const LivePreviewProvider: React.FC<ToolbarProviderProps> = (props) => {
const [breakpoint, setBreakpoint] =
React.useState<LivePreviewConfig['breakpoints'][0]['name']>('responsive')
const [fieldSchemaJSON] = useState(() => {
let fields: Field[]
if ('collection' in props) {
const { collection } = props
fields = collection.fields
}
if ('global' in props) {
const { global } = props
fields = global.fields
}
return fieldSchemaToJSON(fields)
})
// The toolbar needs to freely drag and drop around the page
const handleDragEnd = (ev) => {
// only update position if the toolbar is completely within the preview area
@@ -94,24 +119,70 @@ export const LivePreviewProvider: React.FC<ToolbarProviderProps> = (props) => {
}
}, [breakpoint, breakpoints])
// Receive the `ready` message from the popup window
// This indicates that the app is ready to receive `window.postMessage` events
// This is also the only cross-origin way of detecting when a popup window has loaded
// Unlike iframe elements which have an `onLoad` handler, there is no way to access `window.open` on popups
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
const data = JSON.parse(event.data)
if (url.startsWith(event.origin) && data.type === 'payload-live-preview' && data.ready) {
setAppIsReady(true)
}
}
window.addEventListener('message', handleMessage)
return () => {
window.removeEventListener('message', handleMessage)
}
}, [url])
const handleWindowChange = useCallback(
(type: 'iframe' | 'popup') => {
setAppIsReady(false)
setPreviewWindowType(type)
if (type === 'popup') openPopupWindow()
},
[openPopupWindow],
)
// when the user closes the popup window, switch back to the iframe
// the `usePopupWindow` reports the `isPopupOpen` state for us to use here
useEffect(() => {
if (!isPopupOpen) {
handleWindowChange('iframe')
}
}, [isPopupOpen, handleWindowChange])
return (
<LivePreviewContext.Provider
value={{
appIsReady,
breakpoint,
breakpoints,
fieldSchemaJSON,
iframeHasLoaded,
iframeRef,
isPopupOpen,
measuredDeviceSize,
openPopupWindow,
popupRef,
previewWindowType,
setAppIsReady,
setBreakpoint,
setHeight,
setIframeHasLoaded,
setMeasuredDeviceSize,
setPreviewWindowType: handleWindowChange,
setSize,
setToolbarPosition: setPosition,
setWidth,
setZoom,
size,
toolbarPosition: position,
url,
zoom,
}}
>

View File

@@ -1,6 +1,7 @@
@import '../../../../scss/styles.scss';
.live-preview-iframe {
background-color: white;
border: 0;
width: 100%;
height: 100%;

View File

@@ -1,6 +1,7 @@
@import '../../../../scss/styles.scss';
.live-preview-window {
background-color: var(--theme-bg);
width: 60%;
flex-shrink: 0;
flex-grow: 0;

View File

@@ -1,14 +1,9 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect } from 'react'
import type { LivePreviewConfig } from '../../../../../exports/config'
import type { Field } from '../../../../../fields/config/types'
import type { EditViewProps } from '../../types'
import type { usePopupWindow } from '../usePopupWindow'
import { fieldSchemaToJSON } from '../../../../../utilities/fieldSchemaToJSON'
import { useAllFormFields } from '../../../forms/Form/context'
import reduceFieldsToValues from '../../../forms/Form/reduceFieldsToValues'
import { LivePreviewProvider } from '../Context'
import { useLivePreviewContext } from '../Context/context'
import { DeviceContainer } from '../Device'
import { IFrame } from '../IFrame'
@@ -17,93 +12,81 @@ import './index.scss'
const baseClass = 'live-preview-window'
const Preview: React.FC<
EditViewProps & {
popupState: ReturnType<typeof usePopupWindow>
url?: string
}
> = (props) => {
export const LivePreview: React.FC<EditViewProps> = (props) => {
const {
popupState: { isPopupOpen, popupHasLoaded, popupRef },
appIsReady,
iframeHasLoaded,
iframeRef,
popupRef,
previewWindowType,
setIframeHasLoaded,
url,
} = props
} = useLivePreviewContext()
const { iframeHasLoaded, iframeRef, setIframeHasLoaded } = useLivePreviewContext()
const { breakpoint, fieldSchemaJSON } = useLivePreviewContext()
const { breakpoint } = useLivePreviewContext()
const prevWindowType =
React.useRef<ReturnType<typeof useLivePreviewContext>['previewWindowType']>()
const [fields] = useAllFormFields()
const [fieldSchemaJSON] = useState(() => {
let fields: Field[]
if ('collection' in props) {
const { collection } = props
fields = collection.fields
}
if ('global' in props) {
const { global } = props
fields = global.fields
}
return fieldSchemaToJSON(fields)
})
// The preview could either be an iframe embedded on the page
// Or it could be a separate popup window
// We need to transmit data to both accordingly
useEffect(() => {
if (fields && window && 'postMessage' in window) {
// For performance, do no reduce fields to values until after the iframe or popup has loaded
if (fields && window && 'postMessage' in window && appIsReady) {
const values = reduceFieldsToValues(fields, true)
// TODO: only send `fieldSchemaToJSON` one time
// To reduce on large `postMessage` payloads, only send `fieldSchemaToJSON` one time
// To do this, the underlying JS function maintains a cache of this value
// So we need to send it through each time the window type changes
// But only once per window type change, not on every render, because this is a potentially large obj
const shouldSendSchema =
!prevWindowType.current || prevWindowType.current !== previewWindowType
prevWindowType.current = previewWindowType
const message = JSON.stringify({
data: values,
fieldSchemaJSON,
fieldSchemaJSON: shouldSendSchema ? fieldSchemaJSON : undefined,
type: 'payload-live-preview',
})
// external window
if (isPopupOpen) {
setIframeHasLoaded(false)
if (popupRef.current) {
popupRef.current.postMessage(message, url)
}
// Post message to external popup window
if (previewWindowType === 'popup' && popupRef.current) {
popupRef.current.postMessage(message, url)
}
// embedded iframe
if (!isPopupOpen) {
if (iframeHasLoaded && iframeRef.current) {
iframeRef.current.contentWindow?.postMessage(message, url)
}
// Post message to embedded iframe
if (previewWindowType === 'iframe' && iframeRef.current) {
iframeRef.current.contentWindow?.postMessage(message, url)
}
}
}, [
fields,
url,
iframeHasLoaded,
isPopupOpen,
previewWindowType,
popupRef,
popupHasLoaded,
appIsReady,
iframeRef,
setIframeHasLoaded,
fieldSchemaJSON,
])
if (!isPopupOpen) {
if (previewWindowType === 'iframe') {
return (
<div
className={[
baseClass,
isPopupOpen && `${baseClass}--popup-open`,
breakpoint && breakpoint !== 'responsive' && `${baseClass}--has-breakpoint`,
]
.filter(Boolean)
.join(' ')}
>
<div className={`${baseClass}__wrapper`}>
<LivePreviewToolbar {...props} iframeRef={iframeRef} url={url} />
<LivePreviewToolbar {...props} />
<div className={`${baseClass}__main`}>
<DeviceContainer>
<IFrame ref={iframeRef} setIframeHasLoaded={setIframeHasLoaded} url={url} />
@@ -114,29 +97,3 @@ const Preview: React.FC<
)
}
}
export const LivePreview: React.FC<
EditViewProps & {
livePreviewConfig?: LivePreviewConfig
popupState: ReturnType<typeof usePopupWindow>
url?: string
}
> = (props) => {
const { livePreviewConfig, url } = props
const breakpoints: LivePreviewConfig['breakpoints'] = [
...(livePreviewConfig?.breakpoints || []),
{
name: 'responsive',
height: '100%',
label: 'Responsive',
width: '100%',
},
]
return (
<LivePreviewProvider {...props} breakpoints={breakpoints} url={url}>
<Preview {...props} />
</LivePreviewProvider>
)
}

View File

@@ -1,6 +1,6 @@
import React from 'react'
import type { LivePreviewToolbarProps } from '..'
import type { EditViewProps } from '../../../types'
import { X } from '../../../..'
import { ExternalLinkIcon } from '../../../../graphics/ExternalLink'
@@ -10,13 +10,9 @@ import './index.scss'
const baseClass = 'live-preview-toolbar-controls'
export const ToolbarControls: React.FC<LivePreviewToolbarProps> = (props) => {
const { breakpoint, breakpoints, setBreakpoint, setZoom, zoom } = useLivePreviewContext()
const {
popupState: { openPopupWindow },
url,
} = props
export const ToolbarControls: React.FC<EditViewProps> = () => {
const { breakpoint, breakpoints, setBreakpoint, setPreviewWindowType, setZoom, url, zoom } =
useLivePreviewContext()
return (
<div className={baseClass}>
@@ -57,7 +53,15 @@ export const ToolbarControls: React.FC<LivePreviewToolbarProps> = (props) => {
<option value={150}>150%</option>
<option value={200}>200%</option>
</select>
<a className={`${baseClass}__external`} href={url} onClick={openPopupWindow} type="button">
<a
className={`${baseClass}__external`}
href={url}
onClick={(e) => {
e.preventDefault()
setPreviewWindowType('popup')
}}
type="button"
>
<ExternalLinkIcon />
</a>
</div>

View File

@@ -1,7 +1,7 @@
import { useDraggable } from '@dnd-kit/core'
import React from 'react'
import type { ToolbarProviderProps } from '../Context'
import type { EditViewProps } from '../../types'
import DragHandle from '../../../icons/Drag'
import { useLivePreviewContext } from '../Context/context'
@@ -10,11 +10,7 @@ import './index.scss'
const baseClass = 'live-preview-toolbar'
export type LivePreviewToolbarProps = Omit<ToolbarProviderProps, 'children'> & {
iframeRef: React.RefObject<HTMLIFrameElement>
}
const DraggableToolbar: React.FC<LivePreviewToolbarProps> = (props) => {
const DraggableToolbar: React.FC<EditViewProps> = (props) => {
const { toolbarPosition } = useLivePreviewContext()
const { attributes, listeners, setNodeRef, transform } = useDraggable({
@@ -50,7 +46,7 @@ const DraggableToolbar: React.FC<LivePreviewToolbarProps> = (props) => {
)
}
const StaticToolbar: React.FC<LivePreviewToolbarProps> = (props) => {
const StaticToolbar: React.FC<EditViewProps> = (props) => {
return (
<div className={[baseClass, `${baseClass}--static`].join(' ')}>
<ToolbarControls {...props} />
@@ -59,7 +55,7 @@ const StaticToolbar: React.FC<LivePreviewToolbarProps> = (props) => {
}
export const LivePreviewToolbar: React.FC<
LivePreviewToolbarProps & {
EditViewProps & {
draggable?: boolean
}
> = (props) => {

View File

@@ -3,6 +3,7 @@
.live-preview {
width: 100%;
display: flex;
--gradient: linear-gradient(to left, rgba(0, 0, 0, 0.04) 0%, transparent 100%);
[dir='rtl'] & {
flex-direction: row-reverse;
@@ -34,7 +35,7 @@
right: 0;
width: calc(var(--base) * 2);
height: 100%;
background: linear-gradient(to left, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0) 100%);
background: var(--gradient);
pointer-events: none;
z-index: -1;
}
@@ -58,6 +59,10 @@
&__main {
min-height: initial;
width: 100%;
&::after {
display: none;
}
}
&__form {
@@ -77,3 +82,9 @@
}
}
}
html[data-theme='dark'] {
.live-preview {
--gradient: linear-gradient(to left, rgba(0, 0, 0, 0.4) 0%, rgba(0, 0, 0, 0) 100%);
}
}

View File

@@ -17,47 +17,17 @@ import { useDocumentInfo } from '../../utilities/DocumentInfo'
import { useLocale } from '../../utilities/Locale'
import Meta from '../../utilities/Meta'
import { SetStepNav } from '../collections/Edit/SetStepNav'
import { LivePreviewProvider } from './Context'
import { useLivePreviewContext } from './Context/context'
import { LivePreview } from './Preview'
import './index.scss'
import { usePopupWindow } from './usePopupWindow'
const baseClass = 'live-preview'
export const LivePreviewView: React.FC<EditViewProps> = (props) => {
const PreviewView: React.FC<EditViewProps> = (props) => {
const { i18n, t } = useTranslation('general')
const config = useConfig()
const documentInfo = useDocumentInfo()
const locale = useLocale()
let livePreviewConfig: LivePreviewConfig = config?.admin?.livePreview
if ('collection' in props) {
livePreviewConfig = {
...(livePreviewConfig || {}),
...(props?.collection.admin.livePreview || {}),
}
}
if ('global' in props) {
livePreviewConfig = {
...(livePreviewConfig || {}),
...(props?.global.admin.livePreview || {}),
}
}
const url =
typeof livePreviewConfig?.url === 'function'
? livePreviewConfig?.url({
data: props?.data,
documentInfo,
locale,
})
: livePreviewConfig?.url
const popupState = usePopupWindow({
eventType: 'payload-live-preview',
url,
})
const { previewWindowType } = useLivePreviewContext()
const { apiURL, data, permissions } = props
@@ -113,14 +83,14 @@ export const LivePreviewView: React.FC<EditViewProps> = (props) => {
permissions={permissions}
/>
<div
className={[baseClass, popupState?.isPopupOpen && `${baseClass}--detached`]
className={[baseClass, previewWindowType === 'popup' && `${baseClass}--detached`]
.filter(Boolean)
.join(' ')}
>
<div
className={[
`${baseClass}__main`,
popupState?.isPopupOpen && `${baseClass}__main--popup-open`,
previewWindowType === 'popup' && `${baseClass}__main--popup-open`,
]
.filter(Boolean)
.join(' ')}
@@ -148,13 +118,67 @@ export const LivePreviewView: React.FC<EditViewProps> = (props) => {
)}
</Gutter>
</div>
<LivePreview
{...props}
livePreviewConfig={livePreviewConfig}
popupState={popupState}
url={url}
/>
<LivePreview {...props} />
</div>
</Fragment>
)
}
export const LivePreviewView: React.FC<EditViewProps> = (props) => {
const config = useConfig()
const documentInfo = useDocumentInfo()
const locale = useLocale()
let livePreviewConfig: LivePreviewConfig = config?.admin?.livePreview
if ('collection' in props) {
livePreviewConfig = {
...(livePreviewConfig || {}),
...(props?.collection.admin.livePreview || {}),
}
}
if ('global' in props) {
livePreviewConfig = {
...(livePreviewConfig || {}),
...(props?.global.admin.livePreview || {}),
}
}
const url =
typeof livePreviewConfig?.url === 'function'
? livePreviewConfig?.url({
data: props?.data,
documentInfo,
locale,
})
: livePreviewConfig?.url
const breakpoints: LivePreviewConfig['breakpoints'] = [
...(livePreviewConfig?.breakpoints || []),
{
name: 'responsive',
height: '100%',
label: 'Responsive',
width: '100%',
},
]
const { isPopupOpen, openPopupWindow, popupRef } = usePopupWindow({
eventType: 'payload-live-preview',
url,
})
return (
<LivePreviewProvider
{...props}
breakpoints={breakpoints}
isPopupOpen={isPopupOpen}
openPopupWindow={openPopupWindow}
popupRef={popupRef}
url={url}
>
<PreviewView {...props} />
</LivePreviewProvider>
)
}

View File

@@ -19,17 +19,14 @@ export const usePopupWindow = (props: {
url: string
}): {
isPopupOpen: boolean
openPopupWindow: (e: React.MouseEvent<HTMLAnchorElement>) => void
popupHasLoaded: boolean
openPopupWindow: () => void
popupRef?: React.MutableRefObject<Window | null>
} => {
const { eventType, onMessage, url } = props
const isReceivingMessage = useRef(false)
const [isOpen, setIsOpen] = useState(false)
const [popupHasLoaded, setPopupHasLoaded] = useState(false)
const { serverURL } = useConfig()
const popupRef = useRef<Window | null>(null)
const hasAttachedMessageListener = useRef(false)
// Optionally broadcast messages back out to the parent component
useEffect(() => {
@@ -65,8 +62,10 @@ export const usePopupWindow = (props: {
// Customize the size, position, and style of the popup window
const openPopupWindow = useCallback(
(e) => {
e.preventDefault()
(e?: MouseEvent) => {
if (e) {
e.preventDefault()
}
const features = {
height: 700,
@@ -106,27 +105,6 @@ export const usePopupWindow = (props: {
[url],
)
// the only cross-origin way of detecting when a popup window has loaded
// we catch a message event that the site rendered within the popup window fires
// there is no way in js to add an event listener to a popup window across domains
useEffect(() => {
if (hasAttachedMessageListener.current) return
hasAttachedMessageListener.current = true
window.addEventListener('message', (event) => {
const data = JSON.parse(event.data)
if (
url.startsWith(event.origin) &&
data.type === eventType &&
data.popupReady &&
!popupHasLoaded
) {
setPopupHasLoaded(true)
}
})
}, [url, eventType, popupHasLoaded])
// this is the most stable and widely supported way to check if a popup window is no longer open
// we poll its ref every x ms and use the popup window's `closed` property
useEffect(() => {
@@ -137,7 +115,6 @@ export const usePopupWindow = (props: {
if (popupRef.current.closed) {
clearInterval(timer)
setIsOpen(false)
setPopupHasLoaded(false)
}
}, 1000)
} else {
@@ -154,7 +131,6 @@ export const usePopupWindow = (props: {
return {
isPopupOpen: isOpen,
openPopupWindow,
popupHasLoaded,
popupRef,
}
}

View File

@@ -3,13 +3,10 @@
.collection-default-edit {
width: 100%;
display: flex;
--doc-sidebar-width: 500px;
&--has-sidebar {
.collection-default-edit {
&__main {
width: 66.66%;
}
&__edit {
[dir='ltr'] & {
top: 0;
@@ -40,6 +37,7 @@
display: flex;
flex-direction: column;
min-height: 100%;
flex-grow: 1;
}
&__edit {
@@ -55,8 +53,9 @@
&__sidebar-wrap {
position: sticky;
top: var(--doc-controls-height);
width: 33.33%;
height: calc(100vh - var(--doc-controls-height));
width: var(--doc-sidebar-width);
flex-shrink: 0;
}
&__sidebar {
@@ -85,6 +84,10 @@
color: var(--theme-elevation-400);
}
@include large-break {
--doc-sidebar-width: 350px;
}
@include mid-break {
display: block;
@@ -154,6 +157,10 @@
}
@include small-break {
&__sidebar-wrap {
min-width: initial;
}
&__edit {
padding-top: calc(var(--base) / 2);
}

View File

@@ -32,7 +32,6 @@ export const DefaultCollectionEdit: React.FC<CollectionEditViewProps> = (props)
internalState,
isEditing,
permissions,
updatedAt,
} = props
const { auth, fields, upload } = collection
@@ -97,9 +96,7 @@ export const DefaultCollectionEdit: React.FC<CollectionEditViewProps> = (props)
verify={auth.verify}
/>
)}
{upload && (
<Upload collection={collection} internalState={internalState} updatedAt={updatedAt} />
)}
{upload && <Upload collection={collection} internalState={internalState} />}
<RenderFields
className={`${baseClass}__fields`}
fieldSchema={fields}

View File

@@ -201,7 +201,7 @@ export const Upload: React.FC<Props> = (props) => {
slug={sizePreviewSlug}
title={t('upload:sizesFor', { label: doc?.filename })}
>
<PreviewSizes collection={collection} doc={doc} updatedAt={updatedAt} />
<PreviewSizes collection={collection} doc={doc} />
</Drawer>
)}
</div>

View File

@@ -3,7 +3,10 @@ import { useEffect, useRef, useState } from 'react'
type Intersect = [setNode: React.Dispatch<Element>, entry: IntersectionObserverEntry]
const useIntersect = ({ root = null, rootMargin = '0px', threshold = 0 } = {}): Intersect => {
const useIntersect = (
{ root = null, rootMargin = '0px', threshold = 0 } = {},
disable?: boolean,
): Intersect => {
const [entry, updateEntry] = useState<IntersectionObserverEntry>()
const [node, setNode] = useState(null)
@@ -16,13 +19,16 @@ const useIntersect = ({ root = null, rootMargin = '0px', threshold = 0 } = {}):
)
useEffect(() => {
if (disable) {
return
}
const { current: currentObserver } = observer
currentObserver.disconnect()
if (node) currentObserver.observe(node)
return () => currentObserver.disconnect()
}, [node])
}, [node, disable])
return [setNode, entry]
}

View File

@@ -40,23 +40,18 @@
--spacing-view-bottom: var(--gutter-h);
--app-header-height: calc(var(--base) * 3);
--doc-controls-height: calc(var(--base) * 3);
--nav-width: 300px;
--nav-width: 275px;
--nav-trans-time: 150ms;
@include mid-break {
--gutter-h: #{base(2)};
--app-header-height: calc(var(--base) * 2);
--doc-controls-height: calc(var(--base) * 1.5);
// set to xs-breakpoint to achieve a seamless transition to full screen
--nav-width: var(--breakpoint-xs-width);
--doc-controls-height: calc(var(--base) * 2.5);
}
@include small-break {
--gutter-h: #{base(0.5)};
--spacing-view-bottom: calc(var(--base) * 2);
}
@include extra-small-break {
--nav-width: 100vw;
}
}

View File

@@ -1,4 +1,4 @@
import { format } from 'date-fns'
import { format, formatDistanceToNow } from 'date-fns'
import * as Locale from 'date-fns/locale'
import { getSupportedDateLocale } from './getSupportedDateLocale'
@@ -12,3 +12,12 @@ export const formatDate = (
const currentLocale = Locale[getSupportedDateLocale(locale)]
return format(theDate, pattern, { locale: currentLocale })
}
export const formatTimeToNow = (
date: Date | number | string | undefined,
locale?: string,
): string => {
const theDate = new Date(date)
const currentLocale = Locale[getSupportedDateLocale(locale)]
return formatDistanceToNow(theDate, { locale: currentLocale })
}

View File

@@ -3,10 +3,13 @@ import type { PayloadRequest } from '../../../express/types'
import type { Payload } from '../../../payload'
import { APIError } from '../../../errors'
import { setRequestContext } from '../../../express/setRequestContext'
import { i18nInit } from '../../../translations/init'
import verifyEmail from '../verifyEmail'
export type Options<T extends keyof GeneratedTypes['collections']> = {
collection: T
req?: PayloadRequest
token: string
}
@@ -14,11 +17,8 @@ async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>(
payload: Payload,
options: Options<T>,
): Promise<boolean> {
const { collection: collectionSlug, token } = options
const req = {
payload,
} as PayloadRequest
const { collection: collectionSlug, req = {} as PayloadRequest, token } = options
setRequestContext(options.req)
const collection = payload.collections[collectionSlug]
@@ -28,6 +28,10 @@ async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>(
)
}
req.payload = payload
req.payloadAPI = req.payloadAPI || 'local'
req.i18n = i18nInit(payload.config.i18n)
return verifyEmail({
collection,
req,

View File

@@ -69,6 +69,7 @@ async function registerFirstUser<TSlug extends keyof GeneratedTypes['collections
data: {
_verified: true,
},
req,
})
}
@@ -79,6 +80,7 @@ async function registerFirstUser<TSlug extends keyof GeneratedTypes['collections
const { token } = await payload.login({
...args,
collection: slug,
req,
})
const resultToReturn = {

View File

@@ -163,6 +163,7 @@ const collectionSchema = joi.object().keys({
crop: joi.bool(),
disableLocalStorage: joi.bool(),
focalPoint: joi.bool(),
filesRequiredOnCreate: joi.bool(),
formatOptions: joi.object().keys({
format: joi.string(),
options: joi.object(),

View File

@@ -128,7 +128,8 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
data,
overwriteExistingFiles,
req,
throwOnMissingFile: !shouldSaveDraft,
throwOnMissingFile:
!shouldSaveDraft && collection.config.upload.filesRequiredOnCreate !== false,
})
data = newFileData

View File

@@ -24,6 +24,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
locale?: string
overrideAccess?: boolean
page?: number
req?: PayloadRequest
showHiddenFields?: boolean
sort?: string
user?: Document
@@ -43,6 +44,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
locale = null,
overrideAccess = true,
page,
req: incomingReq,
showHiddenFields,
sort,
user,
@@ -67,6 +69,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
locale: locale ?? defaultLocale,
payload,
payloadAPI: 'local',
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req, context)

View File

@@ -21,6 +21,7 @@ export type Options<T extends keyof GeneratedTypes['collections']> = {
id: string
locale?: string
overrideAccess?: boolean
req?: PayloadRequest
showHiddenFields?: boolean
user?: Document
}
@@ -37,6 +38,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
fallbackLocale = null,
locale = payload.config.localization ? payload.config.localization?.defaultLocale : null,
overrideAccess = true,
req: incomingReq,
showHiddenFields,
user,
} = options
@@ -59,6 +61,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
payload,
payloadAPI: 'local',
t: i18n.t,
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req, context)

View File

@@ -67,6 +67,7 @@ export type FilterOptionsProps<T = any> = {
export type FilterOptions<T = any> =
| ((options: FilterOptionsProps<T>) => Promise<Where> | Where)
| Where
| null
type Admin = {
className?: string

View File

@@ -258,14 +258,18 @@ const validateFilterOptions: Validate = async (
})
if (valueIDs.length > 0) {
const findWhere = {
and: [{ id: { in: valueIDs } }],
}
if (optionFilter) findWhere.and.push(optionFilter)
const result = await payload.find({
collection,
depth: 0,
limit: 0,
pagination: false,
where: {
and: [{ id: { in: valueIDs } }, optionFilter],
},
where: findWhere,
})
options[collection] = result.docs.map((doc) => doc.id)

View File

@@ -17,6 +17,7 @@ export type Options<T extends keyof GeneratedTypes['globals']> = {
id: string
locale?: string
overrideAccess?: boolean
req?: PayloadRequest
showHiddenFields?: boolean
slug: T
user?: Document
@@ -36,6 +37,7 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
showHiddenFields,
slug: globalSlug,
user,
req: incomingReq,
} = options
const globalConfig = payload.globals.config.find((config) => config.slug === globalSlug)
@@ -52,6 +54,7 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
payload,
payloadAPI: 'local',
t: i18n.t,
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req)

View File

@@ -18,6 +18,7 @@ export type Options<T extends keyof GeneratedTypes['globals']> = {
locale?: string
overrideAccess?: boolean
page?: number
req?: PayloadRequest
showHiddenFields?: boolean
slug: T
sort?: string
@@ -36,6 +37,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
locale = payload.config.localization ? payload.config.localization?.defaultLocale : null,
overrideAccess = true,
page,
req: incomingReq,
showHiddenFields,
slug: globalSlug,
sort,
@@ -57,6 +59,7 @@ export default async function findVersionsLocal<T extends keyof GeneratedTypes['
payload,
payloadAPI: 'local',
t: i18n.t,
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req)

View File

@@ -15,6 +15,7 @@ export type Options<T extends keyof GeneratedTypes['globals']> = {
id: string
locale?: string
overrideAccess?: boolean
req?: PayloadRequest
showHiddenFields?: boolean
slug: string
user?: Document
@@ -30,6 +31,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
fallbackLocale = null,
locale = payload.config.localization ? payload.config.localization?.defaultLocale : null,
overrideAccess = true,
req: incomingReq,
showHiddenFields,
slug: globalSlug,
user,
@@ -49,6 +51,7 @@ export default async function restoreVersionLocal<T extends keyof GeneratedTypes
payload,
payloadAPI: 'local',
t: i18n.t,
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req)

View File

@@ -18,6 +18,7 @@ export type Options<TSlug extends keyof GeneratedTypes['globals']> = {
fallbackLocale?: string
locale?: string
overrideAccess?: boolean
req?: PayloadRequest
showHiddenFields?: boolean
slug: TSlug
user?: Document
@@ -34,6 +35,7 @@ export default async function updateLocal<TSlug extends keyof GeneratedTypes['gl
fallbackLocale = null,
locale = payload.config.localization ? payload.config.localization?.defaultLocale : null,
overrideAccess = true,
req: incomingReq,
showHiddenFields,
slug: globalSlug,
user,
@@ -53,6 +55,7 @@ export default async function updateLocal<TSlug extends keyof GeneratedTypes['gl
payload,
payloadAPI: 'local',
t: i18n.t,
transactionID: incomingReq?.transactionID,
user,
} as PayloadRequest
setRequestContext(req)

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "المستند {{docStatus}} الحالي",
"draft": "مسودّة",
"draftSavedSuccessfully": "تمّ حفظ المسودّة بنجاح.",
"lastSavedAgo": "آخر حفظ في {{distance, relativetime(minutes)}}",
"lastSavedAgo": "تم الحفظ آخر مرة قبل {{distance}}",
"noFurtherVersionsFound": "لم يتمّ العثور على نسخات أخرى",
"noRowsFound": "لم يتمّ العثور على {{label}}",
"preview": "معاينة",
@@ -368,4 +368,4 @@
"viewingVersions": "يتمّ استعراض النُّسَخ ل {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "يتمّ استعراض النُّسَخ للاعداد العامّ {{entityLabel}}"
}
}
}

View File

@@ -334,7 +334,7 @@
"currentDocumentStatus": "Cari {{docStatus}} sənədi",
"draft": "Qaralama",
"draftSavedSuccessfully": "Qaralama uğurla yadda saxlandı.",
"lastSavedAgo": "Son yadda saxlama: {{distance, relativetime(minutes)}} əvvəl",
"lastSavedAgo": "{{distance}} əvvəl son yadda saxlanıldı",
"noFurtherVersionsFound": "Başqa versiyalar tapılmadı",
"noRowsFound": "Heç bir {{label}} tapılmadı",
"preview": "Öncədən baxış",
@@ -369,4 +369,4 @@
"viewingVersions": "{{entityLabel}} {{documentTitle}} üçün versiyaları göstərir",
"viewingVersionsGlobal": "Qlobal {{entityLabel}} üçün versiyaları göstərir"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Сегашен статус на документа: {{docStatus}}",
"draft": "Чернова",
"draftSavedSuccessfully": "Чернова запазена успешно.",
"lastSavedAgo": "Последно запазен {{distance, relativetime(minutes)}}",
"lastSavedAgo": "последно запазено преди {{distance}}",
"noFurtherVersionsFound": "Не са открити повече версии",
"noRowsFound": "Не е открит {{label}}",
"preview": "Предварителен преглед",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Současný {{docStatus}} dokument",
"draft": "Koncept",
"draftSavedSuccessfully": "Koncept úspěšně uložen.",
"lastSavedAgo": "Naposledy uloženo {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Naposledy uloženo před {{distance}}",
"noFurtherVersionsFound": "Nenalezeny další verze",
"noRowsFound": "Nenalezen {{label}}",
"preview": "Náhled",
@@ -368,4 +368,4 @@
"viewingVersions": "Zobrazuji verze pro {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "Zobrazuji verze pro globální {{entityLabel}}"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Aktueller Dokumentenstatus: {{docStatus}}",
"draft": "Entwurf",
"draftSavedSuccessfully": "Entwurf erfolgreich gespeichert.",
"lastSavedAgo": "Zuletzt gespeichert {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Zuletzt vor {{distance}} gespeichert",
"noFurtherVersionsFound": "Keine weiteren Versionen vorhanden",
"noRowsFound": "Kein {{label}} gefunden",
"preview": "Vorschau",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Current {{docStatus}} document",
"draft": "Draft",
"draftSavedSuccessfully": "Draft saved successfully.",
"lastSavedAgo": "Last saved {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Last saved {{distance}} ago",
"noFurtherVersionsFound": "No further versions found",
"noRowsFound": "No {{label}} found",
"preview": "Preview",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Documento {{docStatus}} actual",
"draft": "Borrador",
"draftSavedSuccessfully": "Borrador guardado con éxito.",
"lastSavedAgo": "Último guardado {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Guardado por última vez hace {{distance}}",
"noFurtherVersionsFound": "No se encontraron más versiones",
"noRowsFound": "No encontramos {{label}}",
"preview": "Previsualizar",
@@ -368,4 +368,4 @@
"viewingVersions": "Viendo versiones para {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "Viendo versiones para el global {{entityLabel}}"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "جاری {{docStatus}} سند",
"draft": "پیش‌نویس",
"draftSavedSuccessfully": "پیش‌نویس با موفقیت ذخیره شد.",
"lastSavedAgo": "آخرین ذخیره‌سازی {{distance, relativetime(minutes)}}",
"lastSavedAgo": "آخرین بار {{distance}} پیش ذخیره شد",
"noFurtherVersionsFound": "نگارش دیگری یافت نشد",
"noRowsFound": "هیچ {{label}} یافت نشد",
"preview": "پیش‌نمایش",
@@ -368,4 +368,4 @@
"viewingVersions": "مشاهده نگارش‌ها برای {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "مشاهده نگارش‌های کلی {{entityLabel}}"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Document {{docStatus}} actuel",
"draft": "Brouillon",
"draftSavedSuccessfully": "Brouillon enregistré avec succès.",
"lastSavedAgo": "Enregistré il y a de cela {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Dernière sauvegarde il y a {{distance}}",
"noFurtherVersionsFound": "Aucune autre version trouvée",
"noRowsFound": "Aucun(e) {{label}} trouvé(e)",
"preview": "Aperçu",
@@ -368,4 +368,4 @@
"viewingVersions": "Affichage des versions de ou du {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "Affichage des versions globales de ou du {{entityLabel}}"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Trenutni {{docStatus}} dokumenta",
"draft": "Nacrt",
"draftSavedSuccessfully": "Nacrt uspješno spremljen.",
"lastSavedAgo": "Zadnje spremljeno prije {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Zadnji put spremljeno prije {{distance}",
"noFurtherVersionsFound": "Nisu pronađene daljnje verzije",
"noRowsFound": "{{label}} nije pronađeno",
"preview": "Pregled",
@@ -368,4 +368,4 @@
"viewingVersions": "Pregled verzija za {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "Pregled verzije za globalni {{entityLabel}}"
}
}
}

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Jelenlegi {{docStatus}} dokumentum",
"draft": "Piszkozat",
"draftSavedSuccessfully": "A piszkozat sikeresen mentve.",
"lastSavedAgo": "Utoljára mentve {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Utoljára mentve {{distance}} órája",
"noFurtherVersionsFound": "További verziók nem találhatók",
"noRowsFound": "Nem található {{label}}",
"preview": "Előnézet",
@@ -368,4 +368,4 @@
"viewingVersions": "A {{entityLabel}} {{documentTitle}} verzióinak megtekintése",
"viewingVersionsGlobal": "A globális {{entityLabel}} verzióinak megtekintése"
}
}
}

View File

@@ -334,7 +334,7 @@
"currentDocumentStatus": "Documento {{docStatus}} corrente",
"draft": "Bozza",
"draftSavedSuccessfully": "Bozza salvata con successo.",
"lastSavedAgo": "Ultimo salvataggio {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Ultimo salvataggio {{distance}} fa",
"noFurtherVersionsFound": "Non sono state trovate ulteriori versioni",
"noRowsFound": "Nessun {{label}} trovato",
"preview": "Anteprima",
@@ -369,4 +369,4 @@
"viewingVersions": "Visualizzazione delle versioni per {{entityLabel}} {{documentTitle}}",
"viewingVersionsGlobal": "`Visualizzazione delle versioni per {{entityLabel}}"
}
}
}

Some files were not shown because too many files have changed in this diff Show More