Compare commits

...

116 Commits

Author SHA1 Message Date
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
128 changed files with 2307 additions and 480 deletions

View File

@@ -213,8 +213,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,3 +1,86 @@
## [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

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

@@ -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

@@ -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",

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,7 +183,10 @@ export async function parseParams({
IS
NULL`,
)
} else {
break
}
constraints.push(
operatorMap[queryOperator](rawColumn || table[columnName], queryValue),
)
@@ -185,7 +197,6 @@ export async function parseParams({
}
}
}
}
if (constraints.length > 0) {
if (result) {
result = and(result, ...constraints)

View File

@@ -42,7 +42,8 @@ export const sanitizeQueryValue = ({
if (val.toLowerCase() === 'false') formattedValue = false
}
if (['all', 'in', 'not_in'].includes(operator) && typeof formattedValue === 'string') {
if (['all', 'in', 'not_in'].includes(operator)) {
if (typeof formattedValue === 'string') {
formattedValue = createArrayFromCommaDelineated(formattedValue)
if (field.type === 'number') {
@@ -50,6 +51,11 @@ export const sanitizeQueryValue = ({
}
}
if (!Array.isArray(formattedValue) || formattedValue.length === 0) {
return null
}
}
if (field.type === 'number' && typeof formattedValue === 'string') {
formattedValue = Number(val)
}

View File

@@ -1,6 +1,6 @@
{
"name": "payload",
"version": "2.0.6",
"version": "2.0.7",
"description": "Node, React and MongoDB Headless CMS and Application Framework",
"license": "MIT",
"main": "./dist/index.js",
@@ -187,7 +187,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;
// 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;
}
&__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;
&::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

@@ -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

@@ -297,7 +297,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

@@ -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

@@ -46,7 +46,7 @@
@include mid-break {
--gutter-h: #{base(2)};
--app-header-height: calc(var(--base) * 2);
--doc-controls-height: calc(var(--base) * 1.5);
--doc-controls-height: calc(var(--base) * 2.5);
// set to xs-breakpoint to achieve a seamless transition to full screen
--nav-width: var(--breakpoint-xs-width);
}

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

@@ -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": "معاينة",

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ış",

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",

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",

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": "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",

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",

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",

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",

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": "လက်ရှိ {{docStatus}} ဖိုင်",
"draft": "မူကြမ်း",
"draftSavedSuccessfully": "မူကြမ်းကို အောင်မြင်စွာ သိမ်းဆည်းပြီးပါပြီ။",
"lastSavedAgo": "နောက်ဆုံး ပြင်ဆင်ခဲ့သည်။ {{distance, relativetime(minutes)}}",
"lastSavedAgo": "နောက်ဆုံး သိမ်းချက် {{distance}} ကြာပြီး",
"noFurtherVersionsFound": "နောက်ထပ်ဗားရှင်းများ မတွေ့ပါ။",
"noRowsFound": "{{label}} အားမတွေ့ပါ။",
"preview": "နမူနာပြရန်",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Nåværende {{docStatus}} dokument",
"draft": "Utkast",
"draftSavedSuccessfully": "Utkast lagret.",
"lastSavedAgo": "Sist lagret {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Sist lagret {{distance}} siden",
"noFurtherVersionsFound": "Ingen flere versjoner funnet",
"noRowsFound": "Ingen {{label}} funnet",
"preview": "Forhåndsvisning",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Huidig {{docStatus}} document",
"draft": "Concept",
"draftSavedSuccessfully": "Concept succesvol bewaard.",
"lastSavedAgo": "Laatst bewaard {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Laatst opgeslagen {{distance}} geleden",
"noFurtherVersionsFound": "Geen verdere versies gevonden",
"noRowsFound": "Geen {{label}} gevonden",
"preview": "Voorbeeld",

View File

@@ -334,7 +334,7 @@
"currentDocumentStatus": "Bieżący status {{docStatus}} dokumentu",
"draft": "Szkic",
"draftSavedSuccessfully": "Wersja robocza została pomyślnie zapisana.",
"lastSavedAgo": "Ostatnio zapisano {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Ostatnio zapisane {{distance}} temu",
"noFurtherVersionsFound": "Nie znaleziono dalszych wersji",
"noRowsFound": "Nie znaleziono {{label}}",
"preview": "Podgląd",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Documento {{docStatus}} atual",
"draft": "Rascunho",
"draftSavedSuccessfully": "Rascunho salvo com sucesso.",
"lastSavedAgo": "Salvo pela última vez {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Última gravação há {{distance}}",
"noFurtherVersionsFound": "Nenhuma outra versão encontrada",
"noRowsFound": "Nenhum(a) {{label}} encontrado(a)",
"preview": "Pré-visualização",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Documentul {{docStatus}} curent",
"draft": "Proiect",
"draftSavedSuccessfully": "Proiect salvat cu succes.",
"lastSavedAgo": "Ultima salvare {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Ultima salvare acum {{distance}}",
"noFurtherVersionsFound": "Nu s-au găsit alte versiuni",
"noRowsFound": "Nu s-a găsit niciun {{label}}",
"preview": "Previzualizare",

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": "Nuvarande {{docStatus}} dokument",
"draft": "Utkast",
"draftSavedSuccessfully": "Utkastet sparades framgångsrikt.",
"lastSavedAgo": "Sparades senast {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Senast sparad för {{distance}} sedan",
"noFurtherVersionsFound": "Inga fler versioner hittades",
"noRowsFound": "Inga {{label}} hittades",
"preview": "Förhandsvisa",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "เอกสารปัจจุบัน",
"draft": "ฉบับร่าง",
"draftSavedSuccessfully": "บันทึกร่างสำเร็จ",
"lastSavedAgo": "บันทึกล่าสุดเมื่อ {{distance, relativetime(minutes)}}",
"lastSavedAgo": "บันทึกครั้งล่าสุด {{distance}} ที่ผ่านมา",
"noFurtherVersionsFound": "ไม่พบเวอร์ชันอื่น ๆ",
"noRowsFound": "ไม่พบ {{label}}",
"preview": "ตัวอย่าง",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "Şu an {{docStatus}} döküman",
"draft": "Taslak",
"draftSavedSuccessfully": "Taslak başarıyla kaydedildi.",
"lastSavedAgo": "Son kaydedilme: {{distance, relativetime(minutes)}}",
"lastSavedAgo": "Son kaydedildi {{distance}} önce",
"noFurtherVersionsFound": "Başka sürüm bulunamadı.",
"noRowsFound": "{{label}} bulunamadı",
"preview": "Önizleme",

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": "Trạng thái tài liệu hiện tại: {{docStatus}}",
"draft": "Bản nháp",
"draftSavedSuccessfully": "Bản nháp đã được lưu thành công.",
"lastSavedAgo": "Bản lưu mới nhất: {{distance, relativetime(minutes)}} trước",
"lastSavedAgo": "Lần lưu cuối cùng {{distance}} trước đây",
"noFurtherVersionsFound": "Không tìm thấy phiên bản cũ hơn",
"noRowsFound": "Không tìm thấy: {{label}}",
"preview": "Bản xem trước",

View File

@@ -333,7 +333,7 @@
"currentDocumentStatus": "当前{{docStatus}}文件",
"draft": "草稿",
"draftSavedSuccessfully": "草稿成功保存。",
"lastSavedAgo": "最后一次保存{{distance, relativetime(minutes)}}",
"lastSavedAgo": "次保存{{distance}}之前",
"noFurtherVersionsFound": "没有发现其他版本",
"noRowsFound": "没有发现{{label}}",
"preview": "预览",

View File

@@ -217,11 +217,11 @@ export default async function resizeAndTransformImageSizes({
const maxOffsetX = Math.max(info.width - width, 0)
const maxOffsetY = Math.max(info.height - height, 0)
const focalPointX = Math.floor(info.width * focalPoint.x - width / 2)
const focalPointY = Math.floor(info.height * focalPoint.y - height / 2)
const focalPointX = Math.floor((info.width / 100) * focalPoint.x)
const focalPointY = Math.floor((info.height / 100) * focalPoint.y)
const offsetX = Math.min(Math.max(focalPointX, 0), maxOffsetX)
const offsetY = Math.min(Math.max(focalPointY, 0), maxOffsetY)
const offsetX = Math.min(Math.max(focalPointX - width / 2, 0), maxOffsetX)
const offsetY = Math.min(Math.max(focalPointY - height / 2, 0), maxOffsetY)
resized = resized.extract({
height,

View File

@@ -0,0 +1,37 @@
/** @type {import('prettier').Config} */
module.exports = {
extends: ['@payloadcms'],
overrides: [
{
extends: ['plugin:@typescript-eslint/disable-type-checked'],
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
},
{
files: ['package.json', 'tsconfig.json'],
rules: {
'perfectionist/sort-array-includes': 'off',
'perfectionist/sort-astro-attributes': 'off',
'perfectionist/sort-classes': 'off',
'perfectionist/sort-enums': 'off',
'perfectionist/sort-exports': 'off',
'perfectionist/sort-imports': 'off',
'perfectionist/sort-interfaces': 'off',
'perfectionist/sort-jsx-props': 'off',
'perfectionist/sort-keys': 'off',
'perfectionist/sort-maps': 'off',
'perfectionist/sort-named-exports': 'off',
'perfectionist/sort-named-imports': 'off',
'perfectionist/sort-object-types': 'off',
'perfectionist/sort-objects': 'off',
'perfectionist/sort-svelte-attributes': 'off',
'perfectionist/sort-union-types': 'off',
'perfectionist/sort-vue-attributes': 'off',
},
},
],
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
},
root: true,
}

View File

@@ -0,0 +1,3 @@
module.exports = {
extends: ['@payloadcms'],
}

View File

@@ -0,0 +1,6 @@
node_modules
.env
dist
build
.DS_Store
package-lock.json

View File

@@ -0,0 +1,10 @@
.tmp
**/.git
**/.hg
**/.pnp.*
**/.svn
**/.yarn/**
**/build
**/dist/**
**/node_modules
**/temp

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

@@ -0,0 +1,248 @@
# Payload Nested Docs Plugin
[![NPM](https://img.shields.io/npm/v/@payloadcms/plugin-nested-docs)](https://www.npmjs.com/package/@payloadcms/plugin-nested-docs)
A plugin for [Payload CMS](https://github.com/payloadcms/payload) to easily allow for documents to be nested inside one another.
Core features:
- Allows for [parent/child](#parent) relationships between documents
- Automatically populates [breadcrumbs](#breadcrumbs) data
## Installation
```bash
yarn add @payloadcms/plugin-nested-docs
# OR
npm i @payloadcms/plugin-nested-docs
```
## Basic Usage
In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
```js
import { buildConfig } from "payload/config";
import nestedDocs from "@payloadcms/plugin-nested-docs";
const config = buildConfig({
collections: [
{
slug: "pages",
fields: [
{
name: "title",
type: "text",
},
{
name: "slug",
type: "text",
},
],
},
],
plugins: [
nestedDocs({
collections: ["pages"],
generateLabel: (_, doc) => doc.title,
generateURL: (docs) =>
docs.reduce((url, doc) => `${url}/${doc.slug}`, ""),
}),
],
});
export default config;
```
### Fields
#### Parent
The `parent` relationship field is automatically added to every document which allows editors to choose another document from the same collection to act as the direct parent.
#### Breadcrumbs
The `breadcrumbs` field is an array which dynamically populates all parent relationships of a document up to the top level. It does not store any data in the database, and instead, acts as a `virtual` field which is dynamically populated each time the document is loaded.
The `breadcrumbs` array stores the following fields:
- `label`
The label of the breadcrumb. This field is automatically set to either the `collection.admin.useAsTitle` (if defined) or is set to the `ID` of the document. You can also dynamically define the `label` by passing a function to the options property of [`generateLabel`](#generateLabel).
- `url`
The URL of the breadcrumb. By default, this field is undefined. You can manually define this field by passing a property called function to the plugin options property of [`generateURL`](#generateURL).
### Options
#### `collections`
An array of collections slugs to enable nested docs.
#### `generateLabel`
Each `breadcrumb` has a required `label` field. By default, its value will be set to the collection's `admin.useAsTitle` or fallback the the `ID` of the document.
You can also pass a function to dynamically set the `label` of your breadcrumb.
```js
{
plugins: [
...
nestedDocs({
...
generateLabel: (_, doc) => doc.title // NOTE: 'title' is a hypothetical field
})
]
```
The function takes two arguments and returns a string:
1. `breadcrumbs` - an array of the breadcrumbs up to that point
2. `currentDoc` - the current document being edited
#### `generateURL`
A function that allows you to dynamically generate each breadcrumb `url`. Each `breadcrumb` has an optional `url` field which is undefined by default. For example, you might want to format a full URL to contain all of the breadcrumbs up to that point, like `/about-us/company/our-team`.
```js
plugins: [
...
nestedDocs({
...
generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''), // NOTE: 'slug' is a hypothetical field
})
]
```
This function takes two arguments and returns a string:
1. `breadcrumbs` - an array of the breadcrumbs up to that point
1. `currentDoc` - the current document being edited
#### `parentFieldSlug`
When defined, the `parent` field will not be provided for you automatically, and instead, expects you to add your own `parent` field to each collection manually. This gives you complete control over where you put the field in your admin dashboard, etc. Set this property to the `name` of your custom field.
#### `breadcrumbsFieldSlug`
When defined, the `breadcrumbs` field will not be provided for you, and instead, expects your to add your own `breadcrumbs` field to each collection manually. Set this property to the `name` of your custom field.
> Note - if you opt out of automatically being provided a `parent` or `breadcrumbs` field, you need to make sure that both fields are placed at the top-level of your document. They cannot exist within any nested data structures like a `group`, `array`, or `blocks`.
## Overrides
You can also extend the built-in `parent` and `breadcrumbs` fields per collection by using the `createParentField` and `createBreadcrumbField` methods. They will merge your customizations overtop the plugin's base field configurations.
```js
import { CollectionConfig } from "payload/types";
import createParentField from "@payloadcms/plugin-nested-docs/fields/parent";
import createBreadcrumbsField from "@payloadcms/plugin-nested-docs/fields/breadcrumbs";
const examplePageConfig: CollectionConfig = {
slug: "pages",
fields: [
createParentField(
// First argument is equal to the slug of the collection
// that the field references
"pages",
// Second argument is equal to field overrides that you specify,
// which will be merged into the base parent field config
{
admin: {
position: "sidebar",
},
// Note: if you override the `filterOptions` of the `parent` field,
// be sure to continue to prevent the document from referencing itself as the parent like this:
// filterOptions: ({ id }) => ({ id: {not_equals: id }})`
}
),
createBreadcrumbsField(
// First argument is equal to the slug of the collection
// that the field references
"pages",
// Argument equal to field overrides that you specify,
// which will be merged into the base `breadcrumbs` field config
{
label: "Page Breadcrumbs",
}
),
],
};
```
## Localization
This plugin supports localization by default. If the `localization` property is set in your Payload config, the `breadcrumbs` field is automatically localized. For more details on how localization works in Payload, see the [Localization](https://payloadcms.com/docs/localization/overview) docs.
## TypeScript
All types can be directly imported:
```js
import {
PluginConfig,
GenerateURL,
GenerateLabel,
} from "@payloadcms/plugin-nested-docs/types";
```
## Development
To actively develop or debug this plugin you can either work directly within the demo directory of this repo, or link your own project.
1. #### Internal Demo
This repo includes a fully working, self-seeding instance of Payload that installs the plugin directly from the source code. This is the easiest way to get started. To spin up this demo, follow these steps:
1. First clone the repo
1. Then, `cd YOUR_PLUGIN_REPO && yarn && cd demo && yarn && yarn dev`
1. Now open `http://localhost:3000/admin` in your browser
1. Enter username `dev@payloadcms.com` and password `test`
That's it! Changes made in `./src` will be reflected in your demo. Keep in mind that the demo database is automatically seeded on every startup, any changes you make to the data get destroyed each time you reboot the app.
1. #### Linked Project
You can alternatively link your own project to the source code:
1. First clone the repo
1. Then, `cd YOUR_PLUGIN_REPO && yarn && cd demo && cp env.example .env && yarn && yarn dev`
1. Now `cd` back into your own project and run, `yarn link @payloadcms/plugin-nested-docs`
1. If this plugin using React in any way, continue to the next step. Otherwise skip to step 7.
1. From your own project, `cd node_modules/react && yarn link && cd ../react-dom && yarn link && cd ../../`
1. Then, `cd YOUR_PLUGIN_REPO && yarn link react react-dom`
All set! You can now boot up your own project as normal, and your local copy of the plugin source code will be used. Keep in mind that changes to the source code require a rebuild, `yarn build`.
You might also need to alias these modules in your Webpack config. To do this, open your project's Payload config and add the following:
```js
import { buildConfig } from "payload/config";
export default buildConfig({
admin: {
webpack: (config) => ({
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
react: path.join(__dirname, "../node_modules/react"),
"react-dom": path.join(__dirname, "../node_modules/react-dom"),
payload: path.join(__dirname, "../node_modules/payload"),
"@payloadcms/plugin-nested-docs": path.join(
__dirname,
"../../payload/plugin-nested-docs/src"
),
},
},
}),
},
});
```
## Screenshots

View File

@@ -0,0 +1,2 @@
export * from './dist/fields/breadcrumbs';
export * from './dist/fields/parent';

View File

@@ -0,0 +1,7 @@
const breadcrumbs = require('./dist/fields/breadcrumbs');
const parent = require('./dist/fields/parent');
module.exports = {
breadcrumbs,
parent
};

View File

@@ -0,0 +1,42 @@
{
"name": "@payloadcms/plugin-nested-docs",
"version": "1.0.8",
"description": "The official Nested Docs plugin for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",
"homepage": "https://payloadcms.com",
"author": "Payload CMS, Inc.",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "pnpm copyfiles && pnpm build:swc && pnpm build:types",
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
"build:types": "tsc --emitDeclarationOnly --outDir dist",
"clean": "rimraf {dist,*.tsbuildinfo}",
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json}\" dist/",
"prepublishOnly": "pnpm clean && pnpm build"
},
"devDependencies": {
"@payloadcms/eslint-config": "workspace:*",
"payload": "workspace:*"
},
"exports": {
".": {
"default": "./src/index.ts",
"types": "./src/index.ts"
}
},
"publishConfig": {
"exports": null,
"main": "./dist/index.js",
"registry": "https://registry.npmjs.org/",
"types": "./dist/index.d.ts"
},
"files": [
"dist",
"fields.js",
"fields.d.ts",
"types.js",
"types.d.ts"
]
}

View File

@@ -0,0 +1,49 @@
import type { ArrayField, Field } from 'payload/types'
const createBreadcrumbsField = (
relationTo: string,
overrides: Partial<ArrayField> = {},
): Field => ({
name: 'breadcrumbs',
type: 'array',
localized: true,
fields: [
{
name: 'doc',
type: 'relationship',
relationTo,
maxDepth: 0,
admin: {
disabled: true,
},
},
{
type: 'row',
fields: [
{
name: 'url',
label: 'URL',
type: 'text',
admin: {
width: '50%',
},
},
{
name: 'label',
type: 'text',
admin: {
width: '50%',
},
},
],
},
...(overrides?.fields || []),
],
admin: {
readOnly: true,
...(overrides?.admin || {}),
},
...(overrides || {}),
})
export default createBreadcrumbsField

View File

@@ -0,0 +1,32 @@
import { RelationshipField } from 'payload/types'
const createParentField = (
relationTo: string,
overrides?: Partial<
RelationshipField & {
hasMany: false
}
>,
): RelationshipField => ({
name: 'parent',
relationTo,
type: 'relationship',
maxDepth: 1,
filterOptions: ({ id }) => {
if (id) {
return {
id: { not_equals: id },
'breadcrumbs.doc': { not_in: [id] },
}
}
return null
},
admin: {
position: 'sidebar',
...(overrides?.admin || {}),
},
...(overrides || {}),
})
export default createParentField

View File

@@ -0,0 +1,56 @@
import type { CollectionAfterChangeHook, CollectionConfig } from 'payload/types'
import type { PluginConfig } from '../types'
import populateBreadcrumbs from '../utilities/populateBreadcrumbs'
const resaveChildren =
(pluginConfig: PluginConfig, collection: CollectionConfig): CollectionAfterChangeHook =>
({ req: { payload, locale }, req, doc }) => {
const resaveChildrenAsync = async (): Promise<void> => {
const children = await payload.find({
req,
collection: collection.slug,
where: {
parent: {
equals: doc.id,
},
},
depth: 0,
locale,
})
try {
children.docs.forEach((child: any) => {
const updateAsDraft =
typeof collection.versions === 'object' &&
collection.versions.drafts &&
child._status !== 'published'
payload.update({
req,
id: child.id,
collection: collection.slug,
draft: updateAsDraft,
data: {
...child,
breadcrumbs: populateBreadcrumbs(req, pluginConfig, collection, child),
},
depth: 0,
locale,
})
})
} catch (err: unknown) {
payload.logger.error(
`Nested Docs plugin has had an error while re-saving a child document.`,
)
payload.logger.error(err)
}
}
// Non-blocking
resaveChildrenAsync()
return undefined
}
export default resaveChildren

View File

@@ -0,0 +1,59 @@
import type { CollectionAfterChangeHook, CollectionConfig } from 'payload/types'
import type { Breadcrumb } from '../types'
interface DocWithBreadcrumbs {
breadcrumbs: Breadcrumb[]
}
// This hook automatically re-saves a document after it is created
// so that we can build its breadcrumbs with the newly created document's ID.
const resaveSelfAfterCreate =
(collection: CollectionConfig): CollectionAfterChangeHook =>
async ({ req, doc, operation }) => {
const { payload, locale } = req
const { breadcrumbs = [] } = doc as DocWithBreadcrumbs
if (operation === 'create') {
const originalDocWithDepth0 = await payload.findByID({
req,
collection: collection.slug,
depth: 0,
id: doc.id,
})
const updateAsDraft =
typeof collection.versions === 'object' &&
collection.versions.drafts &&
doc._status !== 'published'
try {
await payload.update({
req,
collection: collection.slug,
id: doc.id,
locale,
depth: 0,
draft: updateAsDraft,
data: {
...originalDocWithDepth0,
breadcrumbs:
breadcrumbs?.map((crumb, i) => ({
...crumb,
doc: breadcrumbs.length === i + 1 ? doc.id : crumb.doc,
})) || [],
},
})
} catch (err: unknown) {
payload.logger.error(
`Nested Docs plugin has had an error while adding breadcrumbs during document creation.`,
)
payload.logger.error(err)
}
}
return undefined
}
export default resaveSelfAfterCreate

View File

@@ -0,0 +1,49 @@
import type { Plugin } from 'payload/config'
import createBreadcrumbsField from './fields/breadcrumbs'
import createParentField from './fields/parent'
import resaveChildren from './hooks/resaveChildren'
import resaveSelfAfterCreate from './hooks/resaveSelfAfterCreate'
import type { PluginConfig } from './types'
import populateBreadcrumbs from './utilities/populateBreadcrumbs'
const nestedDocs =
(pluginConfig: PluginConfig): Plugin =>
(config) => ({
...config,
collections: (config.collections || []).map((collection) => {
if (pluginConfig.collections.indexOf(collection.slug) > -1) {
const fields = [...(collection?.fields || [])]
if (!pluginConfig.parentFieldSlug) {
fields.push(createParentField(collection.slug))
}
if (!pluginConfig.breadcrumbsFieldSlug) {
fields.push(createBreadcrumbsField(collection.slug))
}
return {
...collection,
hooks: {
...(collection.hooks || {}),
beforeChange: [
async ({ req, data, originalDoc }) =>
populateBreadcrumbs(req, pluginConfig, collection, data, originalDoc),
...(collection?.hooks?.beforeChange || []),
],
afterChange: [
resaveChildren(pluginConfig, collection),
resaveSelfAfterCreate(collection),
...(collection?.hooks?.afterChange || []),
],
},
fields,
}
}
return collection
}),
})
export default nestedDocs

View File

@@ -0,0 +1,23 @@
export interface Breadcrumb {
url?: string
label: string
doc: string
}
export type GenerateURL = (
docs: Array<Record<string, unknown>>,
currentDoc: Record<string, unknown>,
) => string
export type GenerateLabel = (
docs: Array<Record<string, unknown>>,
currentDoc: Record<string, unknown>,
) => string
export interface PluginConfig {
collections: string[]
generateURL?: GenerateURL
generateLabel?: GenerateLabel
parentFieldSlug?: string
breadcrumbsFieldSlug?: string
}

View File

@@ -0,0 +1,33 @@
import type { CollectionConfig } from 'payload/types'
import type { Breadcrumb, PluginConfig } from '../types'
const formatBreadcrumb = (
pluginConfig: PluginConfig,
collection: CollectionConfig,
docs: Array<Record<string, unknown>>,
): Breadcrumb => {
let url: string | undefined = undefined
let label: string
const lastDoc = docs[docs.length - 1]
if (typeof pluginConfig?.generateURL === 'function') {
url = pluginConfig.generateURL(docs, lastDoc)
}
if (typeof pluginConfig?.generateLabel === 'function') {
label = pluginConfig.generateLabel(docs, lastDoc)
} else {
const useAsTitle = collection?.admin?.useAsTitle || 'id'
label = lastDoc[useAsTitle] as string
}
return {
label,
url,
doc: lastDoc.id as string,
}
}
export default formatBreadcrumb

View File

@@ -0,0 +1,47 @@
import type { CollectionConfig } from 'payload/types'
import type { PluginConfig } from '../types'
const getParents = async (
req: any,
pluginConfig: PluginConfig,
collection: CollectionConfig,
doc: Record<string, unknown>,
docs: Array<Record<string, unknown>> = [],
): Promise<Array<Record<string, unknown>>> => {
const parent = doc[pluginConfig?.parentFieldSlug || 'parent']
let retrievedParent
if (parent) {
// If not auto-populated, and we have an ID
if (typeof parent === 'string' || typeof parent === 'number') {
retrievedParent = await req.payload.findByID({
req,
id: parent,
collection: collection.slug,
depth: 0,
disableErrors: true,
})
}
// If auto-populated
if (typeof parent === 'object') {
retrievedParent = parent
}
if (retrievedParent) {
if (retrievedParent.parent) {
return getParents(req, pluginConfig, collection, retrievedParent, [
retrievedParent,
...docs,
])
}
return [retrievedParent, ...docs]
}
}
return docs
}
export default getParents

View File

@@ -0,0 +1,43 @@
import type { CollectionConfig } from 'payload/types'
import type { PluginConfig } from '../types'
import formatBreadcrumb from './formatBreadcrumb'
import getParents from './getParents'
const populateBreadcrumbs = async (
req: any,
pluginConfig: PluginConfig,
collection: CollectionConfig,
data: any,
originalDoc?: any,
): Promise<any> => {
const newData = data
const breadcrumbDocs = [
...(await getParents(req, pluginConfig, collection, {
...originalDoc,
...data,
})),
]
const currentDocBreadcrumb = {
...originalDoc,
...data,
}
if (originalDoc?.id) {
currentDocBreadcrumb.id = originalDoc?.id
}
breadcrumbDocs.push(currentDocBreadcrumb)
const breadcrumbs = breadcrumbDocs.map((_, i) =>
formatBreadcrumb(pluginConfig, collection, breadcrumbDocs.slice(0, i + 1)),
) // eslint-disable-line function-paren-newline
return {
...newData,
[pluginConfig?.breadcrumbsFieldSlug || 'breadcrumbs']: breadcrumbs,
}
}
export default populateBreadcrumbs

View File

@@ -0,0 +1,25 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"composite": true, // Make sure typescript knows that this module depends on their references
"noEmit": false /* Do not emit outputs. */,
"emitDeclarationOnly": true,
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
"jsx": "react"
},
"exclude": [
"dist",
"build",
"tests",
"test",
"node_modules",
".eslintrc.js",
"src/**/*.spec.js",
"src/**/*.spec.jsx",
"src/**/*.spec.ts",
"src/**/*.spec.tsx"
],
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
"references": [{ "path": "../payload" }] // db-mongodb depends on payload
}

View File

@@ -0,0 +1 @@
export * from './dist/types';

View File

@@ -0,0 +1 @@
module.exports = require('./dist/types');

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-lexical",
"version": "0.1.11",
"version": "0.1.12",
"description": "The officially supported Lexical richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -18,9 +18,10 @@ export const LinkDrawer: React.FC<Props> = ({
initialState,
}) => {
const { t } = useTranslation('fields')
return (
<Drawer className={baseClass} slug={drawerSlug} title={t('editLink') ?? ''}>
<Form initialState={initialState} onSubmit={handleModalSubmit}>
<Form fields={fieldSchema} initialState={initialState} onSubmit={handleModalSubmit}>
<RenderFields
fieldSchema={fieldSchema}
fieldTypes={fieldTypes}

View File

@@ -23,7 +23,9 @@ export function transformExtraFields(
// Wrap fields which are not part of the base schema in a group named 'fields' - otherwise they will be rendered but not saved
const extraFields = []
fields.forEach((field) => {
for (let i = fields.length - 1; i >= 0; i--) {
const field = fields[i]
if ('name' in field) {
if (
!baseFields.find((baseField) => !('name' in baseField) || baseField.name === field.name)
@@ -35,7 +37,7 @@ export function transformExtraFields(
}
}
}
})
}
if (Array.isArray(customFieldSchema) || fields.length > 0) {
// find field with name 'fields' and add the extra fields to it

View File

@@ -2,7 +2,6 @@
.rich-text-lexical {
display: flex;
isolation: isolate;
.errorBoundary {
pre {

View File

@@ -6,6 +6,7 @@
tab-size: 1;
outline: 0;
padding-top: 8px;
isolation: isolate;
&:focus-visible {
outline: none !important;

View File

@@ -1,6 +1,6 @@
{
"name": "@payloadcms/richtext-slate",
"version": "1.0.5",
"version": "1.0.6",
"description": "The officially supported Slate richtext adapter for Payload",
"repository": "https://github.com/payloadcms/payload",
"license": "MIT",

View File

@@ -22,7 +22,7 @@ export const LinkDrawer: React.FC<Props> = ({
return (
<Drawer className={baseClass} slug={drawerSlug} title={t('editLink')}>
<Form initialState={initialState} onSubmit={handleModalSubmit}>
<Form fields={fieldSchema} initialState={initialState} onSubmit={handleModalSubmit}>
<RenderFields
fieldSchema={fieldSchema}
fieldTypes={fieldTypes}

View File

@@ -64,7 +64,9 @@ export function transformExtraFields(
// Wrap fields which are not part of the base schema in a group named 'fields' - otherwise they will be rendered but not saved
const extraFields = []
fields.forEach((field) => {
for (let i = fields.length - 1; i >= 0; i--) {
const field = fields[i]
if ('name' in field) {
if (
!baseFields.find((baseField) => !('name' in baseField) || baseField.name === field.name)
@@ -76,7 +78,7 @@ export function transformExtraFields(
}
}
}
})
}
if (Array.isArray(customFieldSchema) || fields.length > 0) {
fields.push({

25
pnpm-lock.yaml generated
View File

@@ -60,6 +60,9 @@ importers:
'@types/react':
specifier: 18.2.15
version: 18.2.15
'@types/semver':
specifier: ^7.5.3
version: 7.5.3
'@types/shelljs':
specifier: 0.8.12
version: 0.8.12
@@ -96,6 +99,9 @@ importers:
glob:
specifier: 8.1.0
version: 8.1.0
graphql-request:
specifier: 6.1.0
version: 6.1.0(graphql@16.8.1)
husky:
specifier: ^8.0.3
version: 8.0.3
@@ -138,6 +144,9 @@ importers:
rimraf:
specifier: 3.0.2
version: 3.0.2
semver:
specifier: ^7.5.4
version: 7.5.4
shelljs:
specifier: 0.8.5
version: 0.8.5
@@ -940,9 +949,6 @@ importers:
get-port:
specifier: 5.1.1
version: 5.1.1
graphql-request:
specifier: 6.1.0
version: 6.1.0(graphql@16.8.1)
mini-css-extract-plugin:
specifier: 1.6.2
version: 1.6.2(webpack@5.88.2)
@@ -1035,6 +1041,15 @@ importers:
specifier: ^5.78.0
version: 5.88.2(@swc/core@1.3.78)(webpack-cli@4.10.0)
packages/plugin-nested-docs:
devDependencies:
'@payloadcms/eslint-config':
specifier: workspace:*
version: link:../eslint-config-payload
payload:
specifier: workspace:*
version: link:../payload
packages/richtext-lexical:
dependencies:
'@faceless-ui/modal':
@@ -5786,6 +5801,10 @@ packages:
resolution: {integrity: sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==}
dev: false
/@types/semver@7.5.3:
resolution: {integrity: sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==}
dev: true
/@types/send@0.17.1:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies:

View File

@@ -0,0 +1,79 @@
import path from 'path'
import fse from 'fs-extra'
import chalk from 'chalk'
import chalkTemplate from 'chalk-template'
import simpleGit from 'simple-git'
const git = simpleGit()
const packagesDir = path.resolve(__dirname, '../../packages')
export type PackageDetails = {
name: string
newCommits: number
shortName: string
packagePath: string
publishedVersion: string
publishDate: string
version: string
}
export const getPackageDetails = async (): Promise<PackageDetails[]> => {
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
const packageDetails = await Promise.all(
packageDirs.map(async (dirName) => {
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
const isPublic = packageJson.private !== true
if (!isPublic) return null
// Get published version from npm
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
res.json(),
)
const publishedVersion = json?.['dist-tags']?.latest
const publishDate = json?.time?.[publishedVersion]
const prevGitTag = `${dirName}/${packageJson.version}`
const prevGitTagHash = await git.revparse(prevGitTag)
const newCommits = await git.log({
from: prevGitTagHash,
file: `packages/${dirName}`,
})
return {
name: packageJson.name as string,
newCommits: newCommits.total,
shortName: dirName,
packagePath: `packages/${dirName}`,
publishedVersion,
publishDate,
version: packageJson.version,
}
}),
)
return packageDetails.filter((p): p is Exclude<typeof p, null> => p !== null)
}
export const showPackageDetails = (details: PackageDetails[]) => {
console.log(chalkTemplate`
{bold Packages:}
${details
.map((p) => {
const name = p?.newCommits ? chalk.bold.green(p?.shortName.padEnd(28)) : p?.shortName.padEnd(28)
const publishData = `${p?.publishedVersion} at ${p?.publishDate
.split(':')
.slice(0, 2)
.join(':')
.replace('T', ' ')}`
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
return ` ${name}${publishData} ${newCommits}`
})
.join('\n')}
`)
}

View File

@@ -1,74 +1,10 @@
import path from 'path'
import fse from 'fs-extra'
import chalk from 'chalk'
import chalkTemplate from 'chalk-template'
import simpleGit from 'simple-git'
const git = simpleGit()
const packagesDir = path.resolve(__dirname, '../packages')
import { getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
async function main() {
// List all public packages excluding eslint-config-payload
const packageDirs = fse.readdirSync(packagesDir).filter((d) => d !== 'eslint-config-payload')
const packageDetails = await Promise.all(
packageDirs.map(async (dirName) => {
const packageJson = await fse.readJson(`${packagesDir}/${dirName}/package.json`)
const isPublic = packageJson.private !== true
if (!isPublic) return null
// Get published version from npm
const json = await fetch(`https://registry.npmjs.org/${packageJson.name}`).then((res) =>
res.json(),
)
const publishedVersion = json?.['dist-tags']?.latest
const publishDate = json?.time?.[publishedVersion]
const prevGitTag = `${dirName}/${packageJson.version}`
const prevGitTagHash = await git.revparse(prevGitTag)
const newCommits = await git.log({
from: prevGitTagHash,
file: `packages/${dirName}`,
})
return {
name: packageJson.name,
newCommits: newCommits.total,
packageDir: dirName,
packagePath: `packages/${dirName}`,
publishedVersion,
publishDate,
version: packageJson.version,
}
}),
)
console.log(chalkTemplate`
{bold Packages:}
${packageDetails
.map((p) => {
const name = p?.newCommits
? chalk.bold.green(p?.packageDir.padEnd(28))
: p?.packageDir.padEnd(28)
const publishData = `${p?.publishedVersion} at ${p?.publishDate
.split(':')
.slice(0, 2)
.join(':')
.replace('T', ' ')}`
const newCommits = `${p?.newCommits ? `${chalk.bold.green(p?.newCommits)} new commits` : ''}`
return ` ${name}${publishData} ${newCommits}`
})
.join('\n')}
`)
const packageDetails = await getPackageDetails()
showPackageDetails(packageDetails)
}
// console.log(packageNames)
main().catch((error) => {
console.error(error)
process.exit(1)

View File

@@ -4,32 +4,54 @@ import chalk from 'chalk'
import prompts from 'prompts'
import minimist from 'minimist'
import chalkTemplate from 'chalk-template'
import { PackageDetails, getPackageDetails, showPackageDetails } from './lib/getPackageDetails'
import semver from 'semver'
const execOpts: ExecSyncOptions = { stdio: 'inherit' }
const args = minimist(process.argv.slice(2))
async function main() {
const { _: packageNames, tag = 'latest', bump = 'patch' } = args
const { tag = 'latest', bump = 'patch' } = args
if (packageNames.length === 0) {
if (!semver.RELEASE_TYPES.includes(bump)) {
abort(`Invalid bump type: ${bump}.\n\nMust be one of: ${semver.RELEASE_TYPES.join(', ')}`)
}
const packageDetails = await getPackageDetails()
showPackageDetails(packageDetails)
const { packagesToRelease } = (await prompts({
type: 'multiselect',
name: 'packagesToRelease',
message: 'Select packages to release',
instructions: 'Space to select. Enter to submit.',
choices: packageDetails.map((p) => {
const title = p?.newCommits ? chalk.bold.green(p?.shortName) : p?.shortName
return {
title,
value: p.shortName,
}
}),
})) as { packagesToRelease: string[] }
if (!packagesToRelease) {
abort()
}
if (packagesToRelease.length === 0) {
abort('Please specify a package to publish')
}
if (packageNames.find((p) => p === 'payload' && packageNames.length > 1)) {
abort('Cannot publish payload with other packages')
if (packagesToRelease.find((p) => p === 'payload' && packagesToRelease.length > 1)) {
abort('Cannot publish payload with other packages. Release Payload first.')
}
// Get current version of each package from package.json
const packageDetails = await Promise.all(
packageNames.map(async (packageName) => {
const packageDir = `packages/${packageName}`
if (!(await fse.pathExists(packageDir))) {
abort(`Package path ${packageDir} does not exist`)
}
const packageObj = await fse.readJson(`${packageDir}/package.json`)
return { name: packageName, version: packageObj.version, dir: packageDir }
}),
const packageMap = packageDetails.reduce(
(acc, p) => {
acc[p.shortName] = p
return acc
},
{} as Record<string, PackageDetails>,
)
console.log(chalkTemplate`
@@ -38,10 +60,15 @@ async function main() {
{bold.yellow Bump: ${bump}}
{bold.yellow Tag: ${tag}}
${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
${packagesToRelease
.map((p) => {
const { shortName, version } = packageMap[p]
return ` ${shortName.padEnd(24)} ${version} -> ${semver.inc(version, bump)}`
})
.join('\n')}
`)
const confirmPublish = await confirm(`Publish ${packageNames.length} package(s)?`)
const confirmPublish = await confirm(`Publish ${packagesToRelease.length} package(s)?`)
if (!confirmPublish) {
abort()
@@ -49,26 +76,26 @@ ${packageDetails.map((p) => ` ${p.name} - current: ${p.version}`).join('\n')}
const results: { name: string; success: boolean }[] = []
for (const pkg of packageDetails) {
const { dir, name } = pkg
for (const pkg of packagesToRelease) {
const { packagePath, shortName } = packageMap[pkg]
try {
console.log(chalk.bold(`\n\nPublishing ${name}...\n\n`))
console.log(chalk.bold(`\n\nPublishing ${shortName}...\n\n`))
execSync(`npm --no-git-tag-version --prefix ${dir} version ${bump}`, execOpts)
execSync(`git add ${dir}/package.json`, execOpts)
execSync(`npm --no-git-tag-version --prefix ${packagePath} version ${bump}`, execOpts)
execSync(`git add ${packagePath}/package.json`, execOpts)
const packageObj = await fse.readJson(`${dir}/package.json`)
const packageObj = await fse.readJson(`${packagePath}/package.json`)
const newVersion = packageObj.version
const tagName = `${name}/${newVersion}`
const tagName = `${shortName}/${newVersion}`
execSync(`git commit -m "chore(release): ${tagName}"`, execOpts)
execSync(`git tag -a ${tagName} -m "${tagName}"`, execOpts)
execSync(`pnpm publish -C ${dir} --no-git-checks`, execOpts)
results.push({ name, success: true })
execSync(`pnpm publish -C ${packagePath} --no-git-checks`, execOpts)
results.push({ name: shortName, success: true })
} catch (error) {
console.error(chalk.bold.red(`ERROR: ${error.message}`))
results.push({ name, success: false })
results.push({ name: shortName, success: false })
}
}

14
templates/ecommerce/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"command": "yarn dev",
"name": "Debug Ecommerce",
"request": "launch",
"type": "node-terminal",
},
]
}

View File

@@ -24,7 +24,7 @@
"@payloadcms/bundler-webpack": "^1.0.0",
"@payloadcms/db-mongodb": "^1.0.0",
"@payloadcms/plugin-cloud": "^2.0.0",
"@payloadcms/plugin-nested-docs": "^1.0.4",
"@payloadcms/plugin-nested-docs": "^1.0.8",
"@payloadcms/plugin-redirects": "^1.0.0",
"@payloadcms/plugin-seo": "^1.0.10",
"@payloadcms/plugin-stripe": "^0.0.14",
@@ -35,10 +35,10 @@
"dotenv": "^8.2.0",
"escape-html": "^1.0.3",
"express": "^4.17.1",
"qs": "6.11.2",
"next": "^13.4.8",
"payload": "^2.0.0",
"payload": "^2.0.7",
"payload-admin-bar": "^1.0.6",
"qs": "6.11.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.45.1",
@@ -48,9 +48,9 @@
"devDependencies": {
"@next/eslint-plugin-next": "^13.1.6",
"@payloadcms/eslint-config": "^0.0.1",
"@swc/core": "1.3.76",
"@types/escape-html": "^1.0.2",
"@types/express": "^4.17.9",
"@swc/core": "1.3.76",
"@types/node": "18.11.3",
"@types/qs": "^6.9.8",
"@types/react": "18.0.21",

View File

@@ -51,10 +51,7 @@ export const cartPage: Partial<Page> = {
link: {
type: 'reference',
url: '',
reference: {
relationTo: 'pages',
value: '',
},
reference: null,
label: '',
},
richText: [

View File

@@ -141,10 +141,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -196,10 +193,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -251,10 +245,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -281,10 +272,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -310,10 +298,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -339,10 +324,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -368,10 +350,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -410,10 +389,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},
@@ -439,10 +415,7 @@ export const home: Partial<Page> = {
],
enableLink: false,
link: {
reference: {
value: '',
relationTo: 'pages',
},
reference: null,
url: '',
label: '',
},

View File

@@ -72,6 +72,16 @@ export const seed = async (payload: Payload): Promise<void> => {
}),
])
let image1ID = image1Doc.id
let image2ID = image2Doc.id
let image3ID = image3Doc.id
if (payload.db.defaultIDType === 'text') {
image1ID = `"${image1ID}"`
image2ID = `"${image2ID}"`
image3ID = `"${image3ID}"`
}
payload.logger.info(`— Seeding categories...`)
const [apparelCategory, ebooksCategory, coursesCategory] = await Promise.all([
@@ -103,8 +113,8 @@ export const seed = async (payload: Payload): Promise<void> => {
collection: 'products',
data: JSON.parse(
JSON.stringify({ ...product1, categories: [apparelCategory.id] }).replace(
/{{PRODUCT_IMAGE}}/g,
image1Doc.id,
/"\{\{PRODUCT_IMAGE\}\}"/g,
image1ID,
),
),
})
@@ -113,8 +123,8 @@ export const seed = async (payload: Payload): Promise<void> => {
collection: 'products',
data: JSON.parse(
JSON.stringify({ ...product2, categories: [ebooksCategory.id] }).replace(
/{{PRODUCT_IMAGE}}/g,
image2Doc.id,
/"\{\{PRODUCT_IMAGE\}\}"/g,
image2ID,
),
),
})
@@ -123,8 +133,8 @@ export const seed = async (payload: Payload): Promise<void> => {
collection: 'products',
data: JSON.parse(
JSON.stringify({ ...product3, categories: [coursesCategory.id] }).replace(
/{{PRODUCT_IMAGE}}/g,
image3Doc.id,
/"\{\{PRODUCT_IMAGE\}\}"/g,
image3ID,
),
),
})
@@ -157,20 +167,24 @@ export const seed = async (payload: Payload): Promise<void> => {
payload.logger.info(`— Seeding products page...`)
const { id: productsPageID } = await payload.create({
let { id: productsPageID } = await payload.create({
collection: 'pages',
data: productsPage,
})
if (payload.db.defaultIDType === 'text') {
productsPageID = `"${productsPageID}"`
}
payload.logger.info(`— Seeding home page...`)
await payload.create({
collection: 'pages',
data: JSON.parse(
JSON.stringify(home)
.replace(/{{PRODUCT1_IMAGE}}/g, image1Doc.id)
.replace(/{{PRODUCT2_IMAGE}}/g, image2Doc.id)
.replace(/{{PRODUCTS_PAGE_ID}}/g, productsPageID),
.replace(/"\{\{PRODUCT1_IMAGE\}\}"/g, image1ID)
.replace(/"\{\{PRODUCT2_IMAGE\}\}"/g, image2ID)
.replace(/"\{\{PRODUCTS_PAGE_ID\}\}"/g, productsPageID),
),
})
@@ -178,7 +192,9 @@ export const seed = async (payload: Payload): Promise<void> => {
await payload.create({
collection: 'pages',
data: JSON.parse(JSON.stringify(cartPage).replace(/{{PRODUCTS_PAGE_ID}}/g, productsPageID)),
data: JSON.parse(
JSON.stringify(cartPage).replace(/"\{\{PRODUCTS_PAGE_ID\}\}"/g, productsPageID),
),
})
payload.logger.info(`— Seeding settings...`)

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