diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 41309bc3b6..cea3058c29 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -1,7 +1,8 @@ name: Acceptance Tests -on: [push] +on: [push, pull_request] jobs: core: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest name: Core Basic timeout-minutes: 45 @@ -56,6 +57,7 @@ jobs: path: cypress/videos coreblocks: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest name: Core Blocks timeout-minutes: 35 @@ -110,6 +112,7 @@ jobs: path: cypress/videos corevoltoslate: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest name: Core Volto Slate timeout-minutes: 45 @@ -164,6 +167,7 @@ jobs: path: cypress/videos core5: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest name: Core Basic - Plone 5 strategy: @@ -217,6 +221,7 @@ jobs: path: cypress/videos coresandbox: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest name: Coresandbox timeout-minutes: 35 @@ -270,6 +275,7 @@ jobs: path: cypress/videos guillotina: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Guillotina runs-on: ubuntu-latest timeout-minutes: 35 @@ -325,6 +331,7 @@ jobs: path: cypress/videos multilingual: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Multilingual runs-on: ubuntu-latest timeout-minutes: 35 @@ -379,6 +386,7 @@ jobs: path: cypress/videos workingcopy: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Working Copy runs-on: ubuntu-latest timeout-minutes: 35 @@ -458,6 +466,7 @@ jobs: path: cypress/videos generator: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Project Generator runs-on: ubuntu-latest timeout-minutes: 35 @@ -553,6 +562,7 @@ jobs: working-directory: ${{env.generator-directory}} seamless: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Seamless Mode runs-on: ubuntu-latest timeout-minutes: 35 diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index 66ad61e73b..9b4db344de 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -1,7 +1,8 @@ name: Code Analysis Check -on: [push] +on: [push, pull_request] jobs: prettier: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Prettier runs-on: ubuntu-latest strategy: @@ -24,6 +25,7 @@ jobs: run: yarn run prettier eslint: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: ESlint runs-on: ubuntu-latest strategy: @@ -46,6 +48,7 @@ jobs: run: yarn run lint i18n: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: i18n runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bf6a564301..d9aacb121b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -37,3 +37,13 @@ jobs: - name: Build HTML documentation run: make docs-html + + - uses: errata-ai/vale-action@reviewdog + with: + # debug: true + files: all + env: + # Required, set by GitHub actions automatically: + # https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 36880bd257..3bad45b9aa 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -1,7 +1,8 @@ name: Unit Tests -on: [push] +on: [push, pull_request] jobs: unit: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name name: Core Unit Tests runs-on: ubuntu-latest strategy: @@ -15,7 +16,8 @@ jobs: - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + # remove workaround for 18.x once https://github.com/nodejs/node/issues/47563 is fixed + node-version: ${{ matrix.node-version == '18.x' && '18.15.0' || matrix.node-version }} cache: yarn # node install diff --git a/.gitignore b/.gitignore index 971b10aee2..ebcc210125 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ selenium-screenshot-*.png /selenium/ cypress/videos/ cypress/screenshots +/styles/Microsoft # Local environment setup .env diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000000..da6af903f2 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,10 @@ +StylesPath = styles + +MinAlertLevel = suggestion + +Vocab = Base,Plone + +Packages = Microsoft + +[*.md] +BasedOnStyles = Vale, Microsoft diff --git a/CHANGELOG.md b/CHANGELOG.md index 02e9f73734..8295c62725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,106 @@ +## 17.0.0-alpha.5 (2023-04-14) + +### Bugfix + +- Generate a split sitemap @reebalazs [#4638](https://github.com/plone/volto/issues/4638) +- Fix Move to top of folder ordering in folder content view @iFlameing [#4690](https://github.com/plone/volto/issues/4690) +- Revert "Add current page parameter to the route in the listing and search block pagination (#4159)" @sneridagh [#4695](https://github.com/plone/volto/issues/4695) +- Fix search block in edit mode re-queries multiple blocks with an empty search text @reebalazs [#4697](https://github.com/plone/volto/issues/4697) + +### Documentation + +- Update links for 2022 Training archive. @stevepiercy [#4635](https://github.com/plone/volto/issues/4635) + + +## 17.0.0-alpha.4 (2023-04-12) + +### Feature + +- DefaultView (view of fields for content types with blocks disabled): Show field name as tip on hover of label. @ksuess [#4598](https://github.com/plone/volto/issues/4598) +- Support RelationList field with named StaticCatalogVocabulary and SelectWidget. @ksuess [#4614](https://github.com/plone/volto/issues/4614) +- Support for declaring a theme in `volto.config.js` or in `package.json` + Add two entry points to allow extension of a theme from other add-ons. @sneridagh [#4625](https://github.com/plone/volto/issues/4625) +- Set sameSite in I18N_LANGUAGE cookie @sneridagh [#4627](https://github.com/plone/volto/issues/4627) +- Added querystring search get option. @robgietema [#4658](https://github.com/plone/volto/issues/4658) + +### Bugfix + +- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) +- Fix regexp that checks valid URLs and improve tests [cekk] [#4601](https://github.com/plone/volto/issues/4601) +- Fixed wrong localization on password reset page @iRohitSingh [#4656](https://github.com/plone/volto/issues/4656) +- fix sitemap.xml.gz not is not compressed @dobri1408 [#4663](https://github.com/plone/volto/issues/4663) + +### Internal + +- Trigger CI workflows to run from external pull requests. @davisagli [#4629](https://github.com/plone/volto/issues/4629) +- Update to p.restapi 8.36.0 and Plone 6.0.3 @sneridagh [#4682](https://github.com/plone/volto/issues/4682) + +### Documentation + +- Added `JavaScript` and `NodeJS` as accepted spellings, and deviations of them as rejected spellings. @utkkkarshhh [#3092](https://github.com/plone/volto/issues/3092) +- Fix documentation build, add pins @sneridagh [#4626](https://github.com/plone/volto/issues/4626) +- Update Volto contributing to align with and refer to the new Plone core code contributing requirements. @stevepiercy [#4634](https://github.com/plone/volto/issues/4634) +- Improve creating views documentation page. @rboixaderg [#4636](https://github.com/plone/volto/issues/4636) +- Razzle upgrade notice in upgrade guide @sneridagh [#4641](https://github.com/plone/volto/issues/4641) +- Rename "Developer Guidelines" to "Contributing". @stevepiercy [#4666](https://github.com/plone/volto/issues/4666) +- Fix broken link to `ReactJS.org`. @stevepiercy [#4667](https://github.com/plone/volto/issues/4667) + + +## 17.0.0-alpha.3 (2023-03-22) + +### Feature + +- Add Vale to CI for spell and style checks. @MAX-786 [#4423](https://github.com/plone/volto/issues/4423) + +### Bugfix + +- Fix Search is case sensitive in Block chooser @iRohitSingh [#4526](https://github.com/plone/volto/issues/4526) +- InternalURl helper method should incorporate externalRoutes settings into consideration. @iFlameing [#4559](https://github.com/plone/volto/issues/4559) +- Update message add-on control panel: remove 'buildout', update reference. @ksuess [#4574](https://github.com/plone/volto/issues/4574) + +### Documentation + +- Deleted duplicate import and fixed training URLs. @yahya-cloud [#4523](https://github.com/plone/volto/issues/4523) +- Fix grammar in PR #4542. @stevepiercy [#4555](https://github.com/plone/volto/issues/4555) +- Fix broken links at `ReactJS.org`. @stevepiercy [#4569](https://github.com/plone/volto/issues/4569) +- Fix video warnings and link errors. @stevepiercy [#4578](https://github.com/plone/volto/issues/4578) + + +## 17.0.0-alpha.2 (2023-03-15) + +### Breaking + +- Add custom CSS animation to hamburger menu. Removed `hamburgers` dependency. @danalvrz [#4433](https://github.com/plone/volto/issues/4433) +- Improve i18n script ordering of addons, so that addons can override translations from their dependencies. @davisagli [#4495](https://github.com/plone/volto/issues/4495) + +### Feature + +- Add option to hide empty listing blocks @ksuess [#4393](https://github.com/plone/volto/issues/4393) + +### Bugfix + +- Update build dependencies (razzle and react-dev-utils) @davisagli [#3997](https://github.com/plone/volto/issues/3997) +- Added block prop to BlockDataForm in the Edit component of ToC. If block is not passed, OnChangeBlock will be called with undefined block id. @tedw87 [#4110](https://github.com/plone/volto/issues/4110) +- Fix focus steal in Form @tedw87 [#4230](https://github.com/plone/volto/issues/4230) +- Fixed paste issue in Table Block and added cypress test for pasting text in Table Block. [#4301](https://github.com/plone/volto/issues/4301) +- Fixed i18n script to avoid overwriting translations with an empty msgstr @danalvrz [#4316](https://github.com/plone/volto/issues/4316) +- bugfix: conditionally render all delete items in confirm widget [#4336](https://github.com/plone/volto/issues/4336) +- Make the Site Setup control panel responsive for small screen devices. @lord2anil [#4484](https://github.com/plone/volto/issues/4484) +- The menu for the contents page was unresponsive on mobile devices. Fixed this by changing the menu overflow to scroll. @sudhanshu1309 [#4492](https://github.com/plone/volto/issues/4492) +- Make Drag and Drop list work with container-type inline-size. @robgietema [#4497](https://github.com/plone/volto/issues/4497) +- (fix): Paste button disappearing while coping from nested blocks @dobri1408 [#4505](https://github.com/plone/volto/issues/4505) +- Patch updates for some dependencies. @davisagli [#4520](https://github.com/plone/volto/issues/4520) +- Fix flaky Cypress test introduced in #4521 @sneridagh [#4522](https://github.com/plone/volto/issues/4522) + +### Documentation + +- Fix training urls @ksuess [#4502](https://github.com/plone/volto/issues/4502) +- Add upgrade guide for 4504 @sneridagh [#4542](https://github.com/plone/volto/issues/4542) + + ## 17.0.0-alpha.1 (2023-03-09) ### Feature @@ -60,6 +160,146 @@ - Use a universal static path for both documentation and volto repos. @stevepiercy [#4376](https://github.com/plone/volto/issues/4376) +## 16.20.4 (2023-04-20) + +### Bugfix + +- Fix fetching API paths with urlencoded characters in the querystring. @davisagli [#4718](https://github.com/plone/volto/issues/4718) + +### Internal + +- Security upgrade for momentjs [#4716](https://github.com/plone/volto/issues/4716) + + +## 16.20.3 (2023-04-18) + +### Bugfix + +- Revert inadvertently included files from another PR in #4710 @sneridagh [#4713](https://github.com/plone/volto/issues/4713) + + +## 16.20.2 (2023-04-18) + +### Bugfix + +- Fix robot.txt - the sitemap link should respect x-forwarded headers @reebalazs [#4638](https://github.com/plone/volto/issues/4638) +- Fix Move to top of folder ordering in folder content view by searching also @iFlameing [#4690](https://github.com/plone/volto/issues/4690) +- Fix faulty D&D elements in ObjectBrowserList widget @sneridagh [#4703](https://github.com/plone/volto/issues/4703) + + +## 16.20.1 (2023-04-14) + +### Bugfix + +- Generate a split sitemap @reebalazs [#4638](https://github.com/plone/volto/issues/4638) +- Fix Move to top of folder ordering in folder content view @iFlameing [#4690](https://github.com/plone/volto/issues/4690) +- Revert "Add current page parameter to the route in the listing and search block pagination (#4159)" @sneridagh [#4695](https://github.com/plone/volto/issues/4695) +- Fix search block in edit mode re-queries multiple blocks with an empty search text @reebalazs [#4697](https://github.com/plone/volto/issues/4697) + + +## 16.20.0 (2023-04-12) + +### Feature + +- Support RelationList field with named StaticCatalogVocabulary and SelectWidget. @ksuess [#4614](https://github.com/plone/volto/issues/4614) +- Support for declaring a theme in `volto.config.js` or in `package.json` + Add two entry points to allow extension of a theme from other add-ons. @sneridagh [#4625](https://github.com/plone/volto/issues/4625) +- Added querystring search get option. @robgietema [#4658](https://github.com/plone/volto/issues/4658) + +### Bugfix + +- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) +- Fixed wrong localization on password reset page @iRohitSingh [#4656](https://github.com/plone/volto/issues/4656) +- fix sitemap.xml.gz not is not compressed @dobri1408 [#4663](https://github.com/plone/volto/issues/4663) + +### Internal + +- Update to p.restapi 8.36.0 and Plone 6.0.3 @sneridagh [#4682](https://github.com/plone/volto/issues/4682) + +### Documentation + +- Update Volto contributing to align with and refer to the new Plone core code contributing requirements. @stevepiercy [#4634](https://github.com/plone/volto/issues/4634) +- Improve creating views documentation page. @rboixaderg [#4636](https://github.com/plone/volto/issues/4636) +- Rename "Developer Guidelines" to "Contributing". @stevepiercy [#4666](https://github.com/plone/volto/issues/4666) +- Fix broken link to `ReactJS.org`. @stevepiercy [#4667](https://github.com/plone/volto/issues/4667) + + +## 16.19.0 (2023-04-04) + +### Feature + +- DefaultView (view of fields for content types with blocks disabled): Show field name as tip on hover of label. @ksuess [#4598](https://github.com/plone/volto/issues/4598) +- Set sameSite in I18N_LANGUAGE cookie @sneridagh [#4627](https://github.com/plone/volto/issues/4627) + +### Bugfix + +- Fix regexp that checks valid URLs and improve tests [cekk] [#4601](https://github.com/plone/volto/issues/4601) + +### Documentation + +- Added `JavaScript` and `NodeJS` as accepted spellings, and deviations of them as rejected spellings. @utkkkarshhh [#3092](https://github.com/plone/volto/issues/3092) +- Fix documentation build, add pins @sneridagh [#4626](https://github.com/plone/volto/issues/4626) + + +## 16.18.0 (2023-03-22) + +### Feature + +- Add Vale to CI for spell and style checks. @MAX-786 [#4423](https://github.com/plone/volto/issues/4423) + +### Bugfix + +- Patch updates for some dependencies. @davisagli [#4520](https://github.com/plone/volto/issues/4520) +- InternalURl helper method should incorporate externalRoutes settings into consideration. @iFlameing [#4559](https://github.com/plone/volto/issues/4559) +- Update message add-on control panel: remove 'buildout', update reference. @ksuess [#4574](https://github.com/plone/volto/issues/4574) + +### Documentation + +- Fix broken links at `ReactJS.org`. @stevepiercy [#4569](https://github.com/plone/volto/issues/4569) +- Fix video warnings and link errors. @stevepiercy [#4578](https://github.com/plone/volto/issues/4578) + + +## 16.17.1 (2023-03-16) + + ### Bugfix + + - Fix Search is case sensitive in Block chooser @iRohitSingh [#4526](https://github.com/plone/volto/issues/4526) + + ### Documentation + + - Deleted duplicate import and fixed training URLs. @yahya-cloud [#4523](https://github.com/plone/volto/issues/4523) + + +## 16.17.0 (2023-03-15) + +### Feature + +- Add option to hide empty listing blocks @ksuess [#4393](https://github.com/plone/volto/issues/4393) + +### Bugfix + +- Added block prop to BlockDataForm in the Edit component of ToC. If block is not passed, OnChangeBlock will be called with undefined block id. @tedw87 [#4110](https://github.com/plone/volto/issues/4110) +- Fix focus steal in Form @tedw87 [#4230](https://github.com/plone/volto/issues/4230) +- Fixed paste issue in Table Block and added cypress test for pasting text in Table Block. [#4301](https://github.com/plone/volto/issues/4301) +- Fixed i18n script to avoid overwriting translations with an empty msgstr @danalvrz [#4316](https://github.com/plone/volto/issues/4316) +- bugfix: conditionally render all delete items in confirm widget [#4336](https://github.com/plone/volto/issues/4336) +- Make the Site Setup control panel responsive for small screen devices. @lord2anil [#4484](https://github.com/plone/volto/issues/4484) +- The menu for the contents page was unresponsive on mobile devices. Fixed this by changing the menu overflow to scroll. @sudhanshu1309 [#4492](https://github.com/plone/volto/issues/4492) +- (fix): Paste button disappearing while coping from nested blocks @dobri1408 [#4505](https://github.com/plone/volto/issues/4505) +- Fix flaky Cypress test introduced in #4521 @sneridagh [#4522](https://github.com/plone/volto/issues/4522) + +### Documentation + +- Fix training urls @ksuess [#4502](https://github.com/plone/volto/issues/4502) + + +## 16.16.0 (2023-03-09) + +### Feature + +- Add directive to cache stable resources in browser or intermediate server for 365 days by default directly in the SSR Express server, static resource that could change after a new deployment for 1 minute. @mamico [#2216](https://github.com/plone/volto/issues/2216) + + ## 16.15.0 (2023-03-08) ### Feature @@ -82,7 +322,7 @@ ### Documentation -- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/issues/4461) +- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/pull/4461) ## 16.14.0 (2023-03-03) @@ -412,7 +652,7 @@ - Enable the use of yarn 3 in the build by default @sneridagh - The `ContentsBreadcrumbs` component now renders the whole language name of the language root folder (if any) instead of just the `id` (before: `de`, now: `Deutsch`) @sneridagh -See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -909,7 +1149,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa - Moved all sentry-related code from Volto to the `@plone-collective/volto-sentry` package. @tiberiuichim - The listing block icon has been improved to avoid confusion with the normal text list. @sneridagh -See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1020,7 +1260,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa - Sentry integration is now lazy-loaded. The `sentryOptions` key from the `settings` registry becomes a callable that passes resolved sentry libraries. @tiberiuichim - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1084,7 +1324,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa - Upgrade to Razzle 4 @davisagli - Jest downgraded from 27 to 26 @davisagli -See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Internal @@ -1124,7 +1364,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ### Breaking - `react-window` no longer a Volto dependency @sneridagh - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Bugfix @@ -1163,7 +1403,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ### Breaking - Move Layout constants to `config.views.layoutViewsNamesMapping`. Complete the list. i18n the list. Improve Display component. @sneridagh - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1209,7 +1449,7 @@ Undo html_static_path configuration in `plone/documentation`, and restore image ### Breaking - Main workflow change menu changed from Pastanaga UI simplification to classic Plone implementation. @sneridagh - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1305,7 +1545,7 @@ Undo html_static_path configuration in `plone/documentation`, and restore image - change password-reset url to be consistent with Plone configuration @erral - Simplify over the existing Component Registry API. The `component` key has been flattened for simplification and now it's mapped directly to the `component` argument of `registerComponent`. @sneridagh -See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1883,14 +2123,14 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp ### Breaking - Upgrade `react-cookie` to the latest version. @sneridagh @robgietema - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - Language Switcher no longer takes care of the change of the language on the Redux Store. This responsibility has been unified in the API Redux middleware @sneridagh - Markup change in `LinkView` component. - Rename `core-sandbox` to `coresandbox` for sake of consistency @sneridagh - Extend the original intent and rename `RAZZLE_TESTING_ADDONS` to `ADDONS`. @sneridagh - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - Lazyload Draft.js library. See the upgrade guide on how that impacts you, in case you have extended the rich text editor configuration @tiberiuichim @kreafox - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - Deprecating `lang` cookie in favor of Plone official one `I18N_LANGUAGE` @sneridagh ### Feature @@ -2374,7 +2614,7 @@ See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information - Use Plone logo @ericof - Update favicon and related tags with best practices @sneridagh - Enable to be able to use the internal proxy in production as well @sneridagh -- Add runtime configuration for `@babel/plugin-transform-react-jsx` set to `automatic`. This enables the new JSX runtime: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html So no longer `import React from 'react'` is needed anymore. @sneridagh +- Add runtime configuration for `@babel/plugin-transform-react-jsx` set to `automatic`. This enables the new JSX runtime: https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html So no longer `import React from 'react'` is needed anymore. @sneridagh - Add `autocomplete` Widget component - It holds off the vocabulary endpoint pull until you search (more than 2 chars). Useful when dealing with huge vocabularies @sneridagh @reebalazs - Add new listing block option "fullobjects" per variation @ksuess - `FormFieldWrapper` accepts now strings and elements for description @nzambello @@ -2504,7 +2744,7 @@ See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information ### Feature -- Add runtime configuration for `@babel/plugin-transform-react-jsx` set to `automatic`. This enables the new JSX runtime: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html So no longer `import React from 'react'` is needed anymore. +- Add runtime configuration for `@babel/plugin-transform-react-jsx` set to `automatic`. This enables the new JSX runtime: https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html So no longer `import React from 'react'` is needed anymore. - Update favicon and related tags with best practices @sneridagh ### Bugfix @@ -4836,7 +5076,7 @@ https://6.docs.plone.org/volto/upgrade-guide/index.html - Added item type as a tooltip in contents @nzambello - Added Italian translations and translated array, token and select widget. @giuliaghisini - Added uploading image preview in FileWidget @iFlameing -- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.dev-docs.plone.org/volto/recipes/express.html) @tiberiuichim +- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.docs.plone.org/volto/recipes/express.html) @tiberiuichim ### Bugfix diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 330fc2cddb..21c3b21d4c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,3 @@ # Contributing to Volto -See [Contributing to Volto](https://6.dev-docs.plone.org/volto/developer-guidelines/contributing.html). +See [Contributing to Volto](https://6.docs.plone.org/volto/developer-guidelines/contributing.html). diff --git a/Makefile b/Makefile index 6ef4a70b87..16e1c6f4ab 100644 --- a/Makefile +++ b/Makefile @@ -13,15 +13,15 @@ MAKEFLAGS+=--no-builtin-rules # Project settings INSTANCE_PORT=8080 -DOCKER_IMAGE=plone/server-dev:6.0.2 -DOCKER_IMAGE_ACCEPTANCE=plone/server-acceptance:6.0.2 -KGS= +DOCKER_IMAGE=plone/server-dev:6.0.3 +DOCKER_IMAGE_ACCEPTANCE=plone/server-acceptance:6.0.3 +KGS=plone.restapi==8.36.0 NODEBIN = ./node_modules/.bin SCRIPTSPACKAGE = ./packages/scripts # Plone 5 legacy DOCKER_IMAGE5=plone/plone-backend:5.2.10 -KGS5=plone.restapi==8.35.0 plone.volto==4.0.7 plone.rest==3.0.0 +KGS5=plone.restapi==8.36.0 plone.volto==4.0.7 plone.rest==3.0.0 TESTING_ADDONS=plone.app.robotframework==2.0.0 plone.app.testing==7.0.0 # Sphinx variables diff --git a/README.md b/README.md index 8cdca13cbe..7c32093b7f 100644 --- a/README.md +++ b/README.md @@ -182,23 +182,20 @@ Please create a new [issue](https://github.com/plone/volto/issues/new) or [pull ## Documentation -You can find the latest (in-progress) documentation in [https://6.dev-docs.plone.org/](https://6.dev-docs.plone.org/volto/index.html) +You can find the latest (in-progress) documentation in [https://6.docs.plone.org/](https://6.docs.plone.org/volto/index.html) ## Training -On the [Plone Trainings Website](https://training.plone.org) you'll find -Volto-dedicated open training materials, plus React and other -JavaScript-centered trainings. +On the [Plone Training website](https://training.plone.org), you'll find Volto-dedicated training materials, plus other JavaScript-centered trainings. - [Mastering Plone 6 Development](https://training.plone.org/mastering-plone/) The comprehensive training on Plone 6 with best practice tips for developers and integrators. -- [Volto](https://training.plone.org/5/volto/index.html) - A detailed training on how to create your own website using Volto frontend. - [Volto Hands-On](https://training.plone.org/voltohandson/index.html) - [Volto Add-ons Development](https://training.plone.org/voltoaddons/index.html) -- [Plone Deployment](https://training.plone.org/5/plone-deployment/index.html) -- [React](https://training.plone.org/react/index.html) -- [JavaScript For Plone Developers](https://training.plone.org/5/javascript/index.html) +- [Effective Volto](https://training.plone.org/effective-volto/index.html) +- [Plone Deployment](https://training.plone.org/plone-deployment/index.html) +- [Volto](https://2022.training.plone.org/volto/index.html) (archived) +- [JavaScript For Plone Developers](https://2022.training.plone.org/javascript/index.html) (archived) ## Talks @@ -245,7 +242,7 @@ We do not guarantee that deprecated browsers (e.g., Internet Explorer 11) are su ## Upgrades -You can find the upgrade guide here: https://6.dev-docs.plone.org/volto/upgrade-guide/index.html +You can find the upgrade guide here: https://6.docs.plone.org/volto/upgrade-guide/index.html ## Volto Development @@ -320,11 +317,11 @@ yarn test Here you can find a guide on how acceptance testing is done in Volto: -https://6.dev-docs.plone.org/volto/developer-guidelines/acceptance-tests.html +https://6.docs.plone.org/volto/developer-guidelines/acceptance-tests.html ## Translations -If you would like contribute to translate Volto into several languages, please, read the [Internationalization (i18n) guide](https://6.dev-docs.plone.org/volto/recipes/i18n.html). +If you would like contribute to translate Volto into several languages, please, read the [Internationalization (i18n) guide](https://6.docs.plone.org/volto/recipes/i18n.html). ## Contributors diff --git a/addon-registry.js b/addon-registry.js index 666c0bcd04..b502977ee8 100644 --- a/addon-registry.js +++ b/addon-registry.js @@ -130,6 +130,11 @@ class AddonConfigurationRegistry { this.packages = {}; this.customizations = new Map(); + // Theme from a package.json key, from volto.config.js or from an ENV VAR + // Programatically via volto.config.js wins or the ENV VAR if present + this.theme = + packageJson.theme || this.voltoConfigJS.theme || process.env.THEME; + this.initDevelopmentPackages(); this.initPublishedPackages(); this.initAddonsFromEnvVar(); @@ -354,6 +359,35 @@ class AddonConfigurationRegistry { .filter((e) => e); } + getCustomThemeAddons() { + const customThemeAddonsInfo = { + variables: [], + main: [], + }; + + this.getAddonDependencies().forEach((addon) => { + const normalizedAddonName = addon.split(':')[0]; + // We have two possible insertion points, variables and main + + const customThemeVariables = `${this.packages[normalizedAddonName].modulePath}/theme/_variables.scss`; + const customThemeMain = `${this.packages[normalizedAddonName].modulePath}/theme/_main.scss`; + if ( + fs.existsSync(customThemeVariables) && + normalizedAddonName !== this.theme + ) { + customThemeAddonsInfo.variables.push(normalizedAddonName); + } + if ( + fs.existsSync(customThemeMain) && + normalizedAddonName !== this.theme + ) { + customThemeAddonsInfo.main.push(normalizedAddonName); + } + }); + + return customThemeAddonsInfo; + } + /** * Returns a mapping name:diskpath to be uses in webpack's resolve aliases */ diff --git a/api/buildout.cfg b/api/buildout.cfg index feb689d278..1579cd7ac4 100644 --- a/api/buildout.cfg +++ b/api/buildout.cfg @@ -1,7 +1,7 @@ [buildout] index = https://pypi.org/simple/ extends = - http://dist.plone.org/release/6.0.2/versions.cfg + http://dist.plone.org/release/6.0.3/versions.cfg version-constraints.cfg versions.cfg parts = instance plonesite site-packages test robot-server diff --git a/api/versions.cfg b/api/versions.cfg index d404ee2ec3..abdae1715b 100644 --- a/api/versions.cfg +++ b/api/versions.cfg @@ -5,7 +5,7 @@ async-generator = 1.10 collective.folderishtypes = 3.0.0 collective.recipe.plonesite = 1.12.0 h11 = 0.12.0 -plone.restapi = 8.35.1 +plone.restapi = 8.36.0 plone.volto = 4.0.7 prompt-toolkit = 2.0.10 pyOpenSSL = 21.0.0 diff --git a/create-theme-addons-loader.js b/create-theme-addons-loader.js new file mode 100644 index 0000000000..41da132b44 --- /dev/null +++ b/create-theme-addons-loader.js @@ -0,0 +1,79 @@ +const path = require('path'); +const fs = require('fs'); +const tmp = require('tmp'); +const cryptoRandomString = require('crypto-random-string'); + +const titleCase = (w) => w.slice(0, 1).toUpperCase() + w.slice(1, w.length); + +/* + * Transforms a package name to javascript variable name + */ +function nameFromPackage(name) { + name = + name.replace(/[@~./\\:\s]/gi, '') || + cryptoRandomString({ length: 10, characters: 'abcdefghijk' }); + return name + .split('-') + .map((w, i) => (i > 0 ? titleCase(w) : w)) + .join(''); +} + +/* + * Creates a static file with code necessary to load the addons configuration + * + */ +function getAddonsLoaderCode(name, customThemeAddons = []) { + let buf = `/* +This file is autogenerated. Don't change it directly. +Add a ./theme/_${name}.scss in your add-on to load your theme customizations in the current theme. +*/ + +`; + customThemeAddons.forEach((addon) => { + const customization = `${addon}/theme/${name}`; + const line = `@import '${customization}';\n`; + buf += line; + }); + + return buf; +} + +module.exports = ({ main, variables }) => { + // const addonsThemeLoaderVariablesPath = path.join( + // process.cwd(), + // 'src', + // '_variables.scss', + // ); + // const addonsThemeLoaderMainPath = path.join( + // process.cwd(), + // 'src', + // '_main.scss', + // ); + + // const addonsThemeLoaderVariablesPath = path.join( + // process.cwd(), + // 'src', + // '_variables.scss', + // ); + // const addonsThemeLoaderMainPath = path.join( + // process.cwd(), + // 'src', + // '_main.scss', + // ); + + const addonsThemeLoaderVariablesPath = tmp.tmpNameSync({ postfix: '.scss' }); + const addonsThemeLoaderMainPath = tmp.tmpNameSync({ postfix: '.scss' }); + fs.writeFileSync( + addonsThemeLoaderVariablesPath, + new Buffer.from(getAddonsLoaderCode('variables', variables)), + ); + fs.writeFileSync( + addonsThemeLoaderMainPath, + new Buffer.from(getAddonsLoaderCode('main', main)), + ); + + return [addonsThemeLoaderVariablesPath, addonsThemeLoaderMainPath]; +}; + +module.exports.getAddonsLoaderCode = getAddonsLoaderCode; +module.exports.nameFromPackage = nameFromPackage; diff --git a/cypress/support/commands.js b/cypress/support/commands.js index f950f973ac..cd2e6f23d4 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -11,6 +11,11 @@ const PLONE_API_URL = const SLATE_SELECTOR = '.content-area .slate-editor [contenteditable=true]'; const SLATE_TITLE_SELECTOR = '.block.inner.title [contenteditable="true"]'; +const TABLE_SLATE_SELECTOR = + '.celled.fixed.table tbody tr:nth-child(1) td:first-child() [contenteditable="true"]'; +const TABLE_HEAD_SLATE_SELECTOR = + '.celled.fixed.table thead tr th:first-child() [contenteditable="true"]'; + const ploneAuthObj = { user: ploneAuth[0], pass: ploneAuth[1], @@ -824,3 +829,23 @@ Cypress.Commands.add('settings', (key, value) => { return cy.window().its('settings'); }); Cypress.Commands.add('getIfExists', getIfExists); + +Cypress.Commands.add('getTableSlate', (header = false) => { + let slate; + + cy.addNewBlock('table'); + cy.wait(2000); + + const selector = header ? TABLE_HEAD_SLATE_SELECTOR : TABLE_SLATE_SELECTOR; + + cy.getIfExists( + selector, + () => { + slate = cy.get(selector).last(); + }, + () => { + slate = cy.get(selector, { timeout: 10000 }).last(); + }, + ); + return slate; +}); diff --git a/cypress/tests/core/basic/folder-contents.js b/cypress/tests/core/basic/folder-contents.js index 1aa45e1dac..3be1299b51 100644 --- a/cypress/tests/core/basic/folder-contents.js +++ b/cypress/tests/core/basic/folder-contents.js @@ -128,4 +128,89 @@ describe('Folder Contents Tests', () => { cy.waitForResourceToLoad('@breadcrumbs'); cy.get('thead tr').contains('Creator'); }); + it('Move items to top of folder and bottom of folder', () => { + // creating a Document + cy.createContent({ + contentType: 'Document', + contentId: 'child', + contentTitle: 'My Child', + path: 'my-folder', + }); + + // doing copy paste for dummy data + cy.get('svg[class="icon unchecked"]').click(); + cy.get('svg[class="icon copy"]').click(); + var genArr = Array.from({ length: 56 }, (v, k) => k + 1); + cy.wrap(genArr).each((index) => { + cy.get('svg[class="icon paste"]').click({ force: true }); + }); + cy.wait(2000); // just for clearing of toast + + // after adding 56 page I need to add a final page to move around. + // when I add a page + cy.get('#toolbar-add').click(); + cy.get('#toolbar-add-document').click(); + cy.getSlateTitle() + .focus() + .click() + .type('last and first page') + .contains('last and first page'); + + // then a new page has been created + cy.get('#toolbar-save').click(); + cy.url().should( + 'eq', + Cypress.config().baseUrl + '/my-folder/last-and-first-page', + ); + cy.visit('my-folder/contents'); + cy.get('.contents-pagination .menu').findByText('2').click(); + + cy.get( + 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', + ).click(); + cy.findByText('Move to top of folder').click(); + cy.url().should('eq', Cypress.config().baseUrl + '/my-folder/contents'); + cy.wait(1000); // waiting for settling of odering or search return + + // Checking if move to top of folder works or not. + cy.get('table tbody tr:first-child a span').findByText( + 'last and first page', + ); + cy.get( + 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', + ).click(); + cy.findByText('Move to bottom of folder').click(); + + // Checking whether moving to bottom of folder works or not. + cy.get('.contents-pagination .menu').findByText('2').click(); + cy.get('table tbody tr:last-child a span').findByText( + 'last and first page', + ); + + // Now doing for filtering by searhing content and moving them + cy.visit('my-folder/contents'); + cy.url().should('eq', Cypress.config().baseUrl + '/my-folder/contents'); + cy.get('.ui.small.transparent.input input').type('last'); + cy.get( + 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', + ).click(); + // cy.intercept('GET', '/plone/++api++/my-folder/@search').as('getSearch'); // I don't know proper way to wait + cy.findByText('Move to top of folder').click(); + cy.get('.search.item button').click(); + + // Checking if move to top of folder works or not. + cy.get('table tbody tr:first-child a span').findByText( + 'last and first page', + ); + cy.get( + 'tr[aria-label="/my-folder/last-and-first-page"] svg[class="icon dropdown-popup-trigger"]', + ).click(); + cy.findByText('Move to bottom of folder').click(); + cy.get('.contents-pagination .menu').findByText('2').click(); + + // Checking whether moving to bottom of folder works or not. + cy.get('table tbody tr:last-child a span').findByText( + 'last and first page', + ); + }); }); diff --git a/cypress/tests/core/volto-slate/28-table-block-slate-paste.js b/cypress/tests/core/volto-slate/28-table-block-slate-paste.js new file mode 100644 index 0000000000..50b3b64627 --- /dev/null +++ b/cypress/tests/core/volto-slate/28-table-block-slate-paste.js @@ -0,0 +1,55 @@ +import { slateBeforeEach } from '../../../support/volto-slate'; + +describe('Block Tests: pasting content in table block', () => { + beforeEach(slateBeforeEach); + + it('should paste text', function () { + cy.intercept('PATCH', '/**/my-page').as('save'); + + // Paste + cy.getTableSlate(true) + .focus() + .click() + .pasteClipboard('Some Text from Clipboard'); + + cy.getTableSlate() + .focus() + .click() + .pasteClipboard('Some Text from Clipboard'); + + // Save + cy.toolbarSave(); + cy.wait('@save'); + + // View + cy.get('.celled.fixed.table thead tr th:first').contains( + 'Some Text from Clipboard', + ); + cy.get( + '.celled.fixed.table tbody tr:nth-child(1) td:first-child()', + ).contains('Some Text from Clipboard'); + }); + + it('should paste external text containing html', function () { + // Paste + cy.getTableSlate(true) + .focus() + .click() + .pasteClipboard( + '

For simplicity, emissions arising (CRF 3B) were presented for all livestock type h CH4 and N2O), e CO2e value.single CO2e figure.

', + ); + + cy.getTableSlate() + .focus() + .click() + .pasteClipboard( + '

For simplicity, emissions arising (CRF 3B) were presented for all livestock type h CH4 and N2O), e CO2e value.single CO2e figure.

', + ); + + // Save + cy.toolbarSave(); + + // View + cy.get('[id="page-document"] p').should('have.length', 2); + }); +}); diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css index aa980421c2..d792d49f36 100644 --- a/docs/source/_static/custom.css +++ b/docs/source/_static/custom.css @@ -240,3 +240,7 @@ span.guilabel, span.menuselection { font-style: italic; white-space: nowrap; } + +video { + width: 100%; +} diff --git a/docs/source/addons/index.md b/docs/source/addons/index.md index cf456c215b..b692529aa5 100644 --- a/docs/source/addons/index.md +++ b/docs/source/addons/index.md @@ -14,6 +14,7 @@ myst: i18n best-practices +theme ``` There are several advanced scenarios where we might want to have more control diff --git a/docs/source/addons/theme.md b/docs/source/addons/theme.md new file mode 100644 index 0000000000..c3ec9ae413 --- /dev/null +++ b/docs/source/addons/theme.md @@ -0,0 +1,230 @@ +--- +myst: + html_meta: + "description": "Create a theme add-on" + "property=og:description": "Create a theme add-on" + "property=og:title": "Create a theme add-on" + "keywords": "Volto, Plone, Semantic UI, CSS, Volto theme" +--- + +# Create a Volto theme add-on + +We can create a Volto Add-on that acts as a Volto theme Add-on, so we can detach it from the project files. +The advantage is that you convert the project Volto theme in a pluggable one, so you can deploy the same theme in different projects. +You can even have themes depending on conditions that you could inject on build time. +This is the purpose of `volto.config.js`, the ability of declaring `add-ons` and the active `theme` programatically. See {ref}`volto-config-js` for more information. +For convenience, it can also be set via a `THEME` environment variable. + +1. Add a `theme` key in your `volto.config.js` file in the root of your project: + +```js +module.exports = { + addons: [], + theme: 'volto-my-theme' +}; +``` + +or add a key in your `package.json` project: + +```json +"theme": "volto-my-theme" +``` + +or via a `THEME` variable: + +```shell +THEME='volto-my-theme' yarn start +``` + +2. Create a directory `src/theme` in your add-on, then add this file `theme.config`, replacing `` with your add-on name: + +```less +/******************************* + Theme Selection +*******************************/ + +/* To override a theme for an individual element specify theme name below */ + +/* Global */ +@site : 'pastanaga'; +@reset : 'pastanaga'; + +/* Elements */ +@button : 'pastanaga'; +@container : 'pastanaga'; +@divider : 'pastanaga'; +@flag : 'pastanaga'; +@header : 'pastanaga'; +@icon : 'pastanaga'; +@image : 'pastanaga'; +@input : 'pastanaga'; +@label : 'pastanaga'; +@list : 'pastanaga'; +@loader : 'pastanaga'; +@placeholder : 'pastanaga'; +@rail : 'pastanaga'; +@reveal : 'pastanaga'; +@segment : 'pastanaga'; +@step : 'pastanaga'; + +/* Collections */ +@breadcrumb : 'pastanaga'; +@form : 'pastanaga'; +@grid : 'pastanaga'; +@menu : 'pastanaga'; +@message : 'pastanaga'; +@table : 'pastanaga'; + +/* Modules */ +@accordion : 'pastanaga'; +@checkbox : 'pastanaga'; +@dimmer : 'pastanaga'; +@dropdown : 'pastanaga'; +@embed : 'pastanaga'; +@modal : 'pastanaga'; +@nag : 'pastanaga'; +@popup : 'pastanaga'; +@progress : 'pastanaga'; +@rating : 'pastanaga'; +@search : 'pastanaga'; +@shape : 'pastanaga'; +@sidebar : 'pastanaga'; +@sticky : 'pastanaga'; +@tab : 'pastanaga'; +@transition : 'pastanaga'; + +/* Views */ +@ad : 'pastanaga'; +@card : 'pastanaga'; +@comment : 'pastanaga'; +@feed : 'pastanaga'; +@item : 'pastanaga'; +@statistic : 'pastanaga'; + +/* Extras */ +@main : 'pastanaga'; +@custom : 'pastanaga'; + +/******************************* + Folders +*******************************/ + +/* Path to theme packages */ +@themesFolder : '~volto-themes'; + +/* Path to site override folder */ +@siteFolder : "/theme"; + +/******************************* + Import Theme +*******************************/ + +@import (multiple) "~semantic-ui-less/theme.less"; +@fontPath : "~volto-themes/@{theme}/assets/fonts"; + +.loadAddonOverrides() { + @import (optional) "@{siteFolder}/@{addon}/@{addontype}s/@{addonelement}.overrides"; +} + +/* End Config */ +``` + +3. Declare the theme as an add-on by adding its name to the value for the `addons` key in either `volto.config.js` or `package.json` of your project. +4. After starting Volto, the theme should be active. + Now you can add overrides to the default theme in `src/theme`, same as you would in a project. +5. Now you can safely delete your project's `theme` folder, since the one in the add-on will take precedence and a project can only have one active theme at a time. + +## Using your own theming escape hatch + +Volto theming uses SemanticUI theming capabilities to define and extend a theme for your site. +However, while maintaining and playing well with the Semantic UI Volto base, using a traditional CSS approach can be done using the LESS preprocessor-based `extras` escape hatch. + +At the same time, one can either discard or complement the extras escape hatch and add your own, by customizing the `theme.js` module in Volto. + +```js +import 'semantic-ui-less/semantic.less'; +import '@plone/volto/../theme/themes/pastanaga/extras/extras.less'; + +// You can add more entry points for theming +import '@kitconcept/volto-light-theme/theme/main.scss'; +``` + +Customizing it is a special use case in Volto: add a `./@root/theme.js` file structure in your `customizations` folder in your add-on or project. + +You may want to do this to create a complete new theming experience adapted to your way of doing things that do not match the current Volto theming experience. +For example, if you want to use another preprocessor in the theme, like SCSS. +Maybe because your client forces you to have another entirely base of pre-made components based on another library other than Semantic UI: +See {ref}`volto-custom-theming-strategy` for an example of a custom theme escape hatch. + +While building your own escape hatch for theming, you can use the preprocessor of your choice (in the example, SCSS) while maintaining the "base" Volto theme, but customizing it using the resultant CSS. + +You can see an example of such a theme in: https://github.com/kitconcept/volto-light-theme + +## Modify a custom theme from another add-on + +Sometimes you have a custom theme that you want to reuse through all your projects, but with some differences, maintaining the base. +Usually, the only option would be to use an add-on that adds more CSS to the base theme, using imports that will load after the theme. +However, there is a problem with this approach. +You cannot use existing theme variables, including breakpoints, on these new styles. +Similarly, it gets somewhat detached from the normal flow of the loaded theme. +The same applies for add-ons, as they are detached from the current theme. +One could use a SemanticUI approach for making this work, but it's SemanticUI bound. + +```{warning} +This is only possible when using your own escape hatch, and works only with SCSS-based themes, and not with SemanticUI themes, since it enables a couple of entry points that only support SCSS files. +For an example of how it could be used, see: https://github.com/kitconcept/volto-light-theme +``` + +If your custom escape hatch defines a custom theme using SCSS, you can take advantage of this feature. +Although not limited to this, it would be possible to extend this feature to add more entry points, using another preprocessor or theming approach. + +This feature enables two entry points: variables and main. +From your add-on code, you can extend an existing theme by creating a file corresponding to each entry point: + +* `./src/theme/_variables.scss` +* `./src/theme/_main.scss` + +### Variables (`addonsThemeCustomizationsVariables`) + +Use this entry point file to modify the original variables of the current loaded theme by adding the entry point before the theme variable definitions. +In the theme, it should be imported as shown below: + +```scss hl_lines="2" +@import 'addonsThemeCustomizationsVariables'; +@import 'variables'; +@import 'typography'; +@import 'utils'; +@import 'layout'; +``` + +```{warning} +Following SCSS best practices, your theme variables should be "overridable" using the `!default` flag. +This assigns a value to a variable _only_ if that variable isn't defined or its value is [`null`](https://sass-lang.com/documentation/values/null). +Otherwise, the existing value will be used. +For more information, see https://sass-lang.com/documentation/variables#default-values +``` + +Volto will not only load your add-on entry point files, but it will also detect all the add-ons that have these entry point files and import them grouped under a single file. +It will also automatically add an `addonsThemeCustomizationsVariables` alias that can be referenced from the theme as shown above. + +### Main (`addonsThemeCustomizationsMain`) + +This entry point is intended to add your own style definitions, complementing those in the theme. +You should add it after all the CSS of your theme: + +```scss hl_lines="6" +@import 'blocks/search'; +@import 'blocks/listing'; + +@import 'temp'; + +@import 'addonsThemeCustomizationsMain'; + +/* No CSS beyond this point */ +``` + +Volto will also detect all the add-ons that have these entry point files, and import them grouped under a single file, and will automatically add an `addonsThemeCustomizationsMain` alias that can be referenced from the theme as shown above. + +```{note} +It will only work in combination with the theme declaration in `volto.config.js` or in `package.json`. +``` diff --git a/docs/source/blocks/settings.md b/docs/source/blocks/settings.md index e9d81009c5..e92e736042 100644 --- a/docs/source/blocks/settings.md +++ b/docs/source/blocks/settings.md @@ -26,7 +26,6 @@ import CardTeaserView from '@package/components/Blocks/CardTeaserView'; import DefaultColumnRenderer from '@package/components/Blocks/DefaultColumnRenderer'; import NumberColumnRenderer from '@package/components/Blocks/NumberColumnRenderer'; import ColoredColumnRenderer from '@package/components/Blocks/ColoredColumnRenderer'; -import CardTeaserView from '@package/components/Blocks/CardTeaserView'; import CustomSchemaEnhancer from '@package/components/Blocks/CustomSchemaEnhancer'; diff --git a/docs/source/blocks/ssr.md b/docs/source/blocks/ssr.md index 933dccb1c6..a1f231c53c 100644 --- a/docs/source/blocks/ssr.md +++ b/docs/source/blocks/ssr.md @@ -21,10 +21,10 @@ configuration, pointing to a function that returns a list of promises. For example: ```js -export default ({ dispatch, data, path }) => { +export default ({ dispatch, id, data, path }) => { return [ dispatch( - getQueryStringResults(path, { ...data, fullobjects: 1 }, data.block), + getQueryStringResults(path, { ...data, fullobjects: 1 }, id), ), ]; }; diff --git a/docs/source/cheatsheet.md b/docs/source/cheatsheet.md index dc7eb80d88..f7b8601d7d 100644 --- a/docs/source/cheatsheet.md +++ b/docs/source/cheatsheet.md @@ -14,7 +14,7 @@ myst: # Cheatsheet ```{seealso} -{doc}`plone:contributing/myst-reference` +{doc}`plone:contributing/documentation/myst-reference` ``` diff --git a/docs/source/conf.py b/docs/source/conf.py index 1421636d3f..679833e9a9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -119,7 +119,7 @@ "spelling_wordlist.txt", "**/CHANGES.rst", "**/LICENSE.rst", - "developer-guidelines/branch-policy.md", + "contributing/branch-policy.md", ] html_extra_path = [ diff --git a/docs/source/configuration/volto-config-js.md b/docs/source/configuration/volto-config-js.md index 56bbcf417d..9320c3c6d5 100644 --- a/docs/source/configuration/volto-config-js.md +++ b/docs/source/configuration/volto-config-js.md @@ -1,8 +1,25 @@ -# Dynamic Volto Addons Configuration +--- +myst: + html_meta: + "description": "Dynamic Volto Addons Configuration programmatically via volto.config.js" + "property=og:description": "Dynamic Volto Addons Configuration programmatically via volto.config.js" + "property=og:title": "Dynamic Volto Addons Configuration" + "keywords": "Volto, Plone, frontend, React, config" +--- -There are some cases where defining the Volto addons your project is going to use is not enough, and you need more control over it. For example, when you have several builds under the umbrella of the same project that share the core of the code, but each build have special requirements, like other CSS, customizations, {term}`shadowing` or the features of other addons available. +(volto-config-js)= -There is a scapehatch `volto.config.js`. This module exports an object and can have arbitrary code depending on your needs: +# Programatically define the active add-ons and theme + +Volto allows you to define the active `add-ons` and `theme` via a file in the root of your project called `volto.config.js`. + +## Dynamic Volto Addons Configuration + +There are some cases where defining the Volto addons your project is going to use via `package.json` `addons` key is not enough, and you need more control over it. +For example, when you have several builds under the umbrella of the same project that share the core of the code, but each build have special requirements, like other CSS, customizations, {term}`shadowing` or the features of other addons available. + +This is an example of a `volto.config.js` file. +This module exports an object and can have arbitrary code depending on your needs: ```js let addons = []; @@ -10,12 +27,38 @@ if (process.env.MY_SPECIAL_CUSTOM_BUILD) { addons = ['volto-custom-addon']; } +if (process.env.MY_SPECIAL_SECOND_CUSTOM_BUILD) { + addons = ['volto-custom-addon', 'volto-custom-addon-additional']; +} + module.exports = { - addons: addons, + addons, }; - ``` -In the case above, we delegate to the presence of an environment variable (MY_SPECIAL_CUSTOM_BUILD) the use of the list of addons specified. +In the case above, we delegate to the presence of an environment variable (`MY_SPECIAL_CUSTOM_BUILD`) the use of the list of addons specified. This list, sums up to the one defined in `package.json` (it does not override it), and the addons added are placed at the end of the addons list, so the config in there is applied after the ones in the `package.json`. + +## Dynamic Volto active theme configuration + +The same applies for the active theme: + +```js +let addons = []; +let theme; +if (process.env.MY_SPECIAL_CUSTOM_BUILD) { + addons = ['volto-custom-addon']; + theme = 'volto-my-theme'; +} + +if (process.env.MY_SPECIAL_SECOND_CUSTOM_BUILD) { + addons = ['volto-custom-addon-alternative', 'volto-custom-addon-additional']; + theme = 'volto-my-alternate-theme'; +} + +module.exports = { + addons, + theme +}; +``` diff --git a/docs/source/developer-guidelines/Quanta.pdf b/docs/source/contributing/Quanta.pdf similarity index 100% rename from docs/source/developer-guidelines/Quanta.pdf rename to docs/source/contributing/Quanta.pdf diff --git a/docs/source/developer-guidelines/acceptance-tests.md b/docs/source/contributing/acceptance-tests.md similarity index 100% rename from docs/source/developer-guidelines/acceptance-tests.md rename to docs/source/contributing/acceptance-tests.md diff --git a/docs/source/developer-guidelines/accessibility-guidelines.md b/docs/source/contributing/accessibility-guidelines.md similarity index 100% rename from docs/source/developer-guidelines/accessibility-guidelines.md rename to docs/source/contributing/accessibility-guidelines.md diff --git a/docs/source/developer-guidelines/branch-policy.md b/docs/source/contributing/branch-policy.md similarity index 100% rename from docs/source/developer-guidelines/branch-policy.md rename to docs/source/contributing/branch-policy.md diff --git a/docs/source/developer-guidelines/design-principles.md b/docs/source/contributing/design-principles.md similarity index 100% rename from docs/source/developer-guidelines/design-principles.md rename to docs/source/contributing/design-principles.md diff --git a/docs/source/developer-guidelines/icons.md b/docs/source/contributing/icons.md similarity index 100% rename from docs/source/developer-guidelines/icons.md rename to docs/source/contributing/icons.md diff --git a/docs/source/contributing/index.md b/docs/source/contributing/index.md new file mode 100644 index 0000000000..adc5e4d2aa --- /dev/null +++ b/docs/source/contributing/index.md @@ -0,0 +1,129 @@ +--- +myst: + html_meta: + "description": "How to contribute to Volto, the frontend for Plone." + "property=og:description": "How to contribute to Volto, the frontend for Plone." + "property=og:title": "How to contribute to Volto, the frontend for Plone." + "keywords": "Plone, Volto, contributing, developer, guidelines" +--- + +(contributing-to-volto-label)= + +# Contributing to Volto + +First read {doc}`plone:contributing/index`. +Volto follows those guidelines with a few specific variations, as described in this chapter. + + +(contributing-reporting-an-issue-or-making-a-feature-request-label)= + +## Reporting an issue or making a feature request + +If you know the issue or feature request is for Volto, first search for an existing item in the [Volto issue tracker](https://github.com/plone/volto/issues). + +If an issue does not already exist for your item, then you can [create a new issue or feature request in Volto](https://github.com/plone/volto/issues/new/choose). +When in doubt, create one in the [CMFPlone issue tracker](https://github.com/plone/Products.CMFPlone/issues). + +In your report, please specify a few things: + +- What are the steps to reproduce the problem? +- What do you expect when you follow those steps? +- What do you observe? +- Which Plone version are you using? +- Include relevant screenshots, error messages, and stack traces. + + +(contributing-volto-sign-and-return-the-plone-contributor-agreement-label)= + +## Sign and return the Plone Contributor Agreement + +The Volto Team reviews pull requests only from people with a GitHub account who have signed and returned the {ref}`Plone Contributor Agreement `, and subsequently been assigned to a Plone Team in GitHub. + + +(contributing-branch-policy-label)= + +## Branch policy + +```{include} ./branch-policy.md +``` + + +(contributing-translations-label)= + +## Translations + +All text that can be shown in a browser must be translatable. +Please mark all such strings as translatable as defined in the [i18n guide](../recipes/i18n.md). + + +(contributing-change-log-entry-label)= + +## Change log entry + +Volto requires that you include a change log entry or news item with your contribution. +Your attribution must be in the format of `@github_username`. + +```{seealso} +For details see {ref}`contributing-change-log-label`. +``` + + +(contributing-documenting-your-changes-label)= + +## Documenting your changes + +If the feature includes a breaking change, you must include instructions for how to upgrade in the [upgrade guide](../upgrade-guide/index.md). + + +(contributing-code-quality-label)= + +## Code quality + +All pull requests must pass tests, documentation builds, and other code quality checks. +These checks are enforced automatically on every pull request, so you might as well save time and frustration by doing these checks locally first. + +Specifically: + +- {doc}`./linting` +- {doc}`./testing` +- {doc}`./acceptance-tests` + + +(contributing-developer-guidelines-label)= + +## Developer guidelines + +Development and configuration of Volto is managed through your {ref}`choice of Plone installation method `. +You may choose to install Plone via {ref}`containers ` or from its {ref}`packages `. + +```{todo} +When referring to installation and configuration of Plone's backend, this part of the Volto documentation may have obsolete content. +The most current information for installing and configuring Plone is in {ref}`install-index-label`. +Please report any issues in the [Volto issue tracker](https://github.com/plone/volto/issues/). +``` + +```{toctree} +:maxdepth: 1 + +design-principles +style-guide +language-features +linting +react +redux +routing +icons +testing +acceptance-tests +accessibility-guidelines +typescript +volto-core-addons +``` + + +(contributing-final-advice-label)= + +## Final advice + +If you become hesitant after reading the foregoing, don't worry. +You can always create a pull request, mark it as "Draft", and improve these points later while requesting help from the community. diff --git a/docs/source/developer-guidelines/language-features.md b/docs/source/contributing/language-features.md similarity index 100% rename from docs/source/developer-guidelines/language-features.md rename to docs/source/contributing/language-features.md diff --git a/docs/source/developer-guidelines/linting.md b/docs/source/contributing/linting.md similarity index 100% rename from docs/source/developer-guidelines/linting.md rename to docs/source/contributing/linting.md diff --git a/docs/source/developer-guidelines/react.md b/docs/source/contributing/react.md similarity index 100% rename from docs/source/developer-guidelines/react.md rename to docs/source/contributing/react.md diff --git a/docs/source/developer-guidelines/redux.md b/docs/source/contributing/redux.md similarity index 100% rename from docs/source/developer-guidelines/redux.md rename to docs/source/contributing/redux.md diff --git a/docs/source/developer-guidelines/routing.md b/docs/source/contributing/routing.md similarity index 100% rename from docs/source/developer-guidelines/routing.md rename to docs/source/contributing/routing.md diff --git a/docs/source/developer-guidelines/style-guide.md b/docs/source/contributing/style-guide.md similarity index 97% rename from docs/source/developer-guidelines/style-guide.md rename to docs/source/contributing/style-guide.md index 7e2100b9af..112ed410aa 100644 --- a/docs/source/developer-guidelines/style-guide.md +++ b/docs/source/contributing/style-guide.md @@ -27,7 +27,7 @@ Volto adopted some time ago [Storybook](https://storybook.js.org), a tool that i Not all Volto's visual components are covered yet in Storybook, but it has already a good foundation. -You can find the current Storybook build in: https://6.dev-docs.plone.org/storybook +You can find the current Storybook build in: https://6.docs.plone.org/storybook ## Quanta, the design system for Plone 6 diff --git a/docs/source/developer-guidelines/testing.md b/docs/source/contributing/testing.md similarity index 100% rename from docs/source/developer-guidelines/testing.md rename to docs/source/contributing/testing.md diff --git a/docs/source/developer-guidelines/typescript.md b/docs/source/contributing/typescript.md similarity index 100% rename from docs/source/developer-guidelines/typescript.md rename to docs/source/contributing/typescript.md diff --git a/docs/source/developer-guidelines/volto-core-addons.md b/docs/source/contributing/volto-core-addons.md similarity index 100% rename from docs/source/developer-guidelines/volto-core-addons.md rename to docs/source/contributing/volto-core-addons.md diff --git a/docs/source/developer-guidelines/contributing.md b/docs/source/developer-guidelines/contributing.md deleted file mode 100644 index 42568ce6e6..0000000000 --- a/docs/source/developer-guidelines/contributing.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -myst: - html_meta: - "description": "A guide on how to contribute to Volto, the frontend for Plone." - "property=og:description": "A guide on how to contribute to Volto, the frontend for Plone." - "property=og:title": "Contributing to Volto" - "keywords": "Volto, Plone, frontend, React, guidelines" ---- - -# Contributing to Volto - -You may have an issue to report, make a feature request, report a security vulnerability, or you want to create a pull request. -You have come to the right place to learn how to do so. - - -## Reporting an issue or making a feature request - -If you know the issue or feature request is for Volto, first search for an existing item in the [Volto issue tracker](https://github.com/plone/volto/issues). - -If an issue does not already exist for your item, then you can [create a new issue or feature request in Volto](https://github.com/plone/volto/issues/new/choose). -When in doubt, create one in the [CMFPlone issue tracker](https://github.com/plone/Products.CMFPlone/issues). - -In your report, please specify a few things: - -- What are the steps to reproduce the problem? -- What do you expect when you follow those steps? -- What do you observe? -- Which Plone version are you using? -- Include relevant screenshots, error messages, and stack traces. - -## Branch policy - -```{include} ./branch-policy.md -``` - -## Create a pull request - -You must sign the [Plone Contributor Agreement](https://plone.org/foundation/contributors-agreement) to contribute code and documentation to any Plone project. -This means that we can NOT accept pull requests from you until you do this. - -All pull requests must include a `towncrier` news item. -This is a file that is placed in the root of the repository directory at `/news`. -Its format must be `###.type`, where `###` is the referenced GitHub issue or pull request number, `.` is the literal extension delimiter, and `type` is one of the following strings. - -- `breaking` for breaking changes -- `bugfix` for bug fixes -- `documentation` for documentation -- `feature` for new features -- `internal` for internal changes - -If the feature includes a breaking change, you must include instructions for how to upgrade in the [upgrade guide](../upgrade-guide/index.md). - -All text that can be shown in a browser must be translatable. Please mark all such -strings as translatable as defined in the [i18n guide](../recipes/i18n.md). - - -## Code Quality - -All pull requests must pass tests, documentation builds, and other code quality checks. -Contributors are strongly encouraged to run these checks locally before creating a pull request. -These checks are enforced automatically on every pull request, so you might as well save time and frustration by doing these checks locally first. - -Specifically: - -- {doc}`./linting` -- {doc}`./testing` -- {doc}`./acceptance-tests` - - -If after reading this you become hesitant, don't worry. -You can always create a pull request, mark it as "Draft", and improve the above points later, requesting help from the community. - -Welcome to the Plone community, and thank you for contributing! diff --git a/docs/source/developer-guidelines/index.md b/docs/source/developer-guidelines/index.md deleted file mode 100644 index a96f92b02b..0000000000 --- a/docs/source/developer-guidelines/index.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -myst: - html_meta: - "description": "Developer Guidelines" - "property=og:description": "Developer Guidelines" - "property=og:title": "Developer Guidelines" - "keywords": "Developer, Guidelines" ---- - -# Developer guidelines - -Development and configuration of Volto is managed through your {ref}`choice of Plone installation method `. -You may choose to install Plone via {ref}`containers ` or from its {ref}`packages `. - -```{todo} -When referring to installation and configuration of Plone's backend, this part of the Volto documentation may have obsolete content. -The most current information for installing and configuring Plone is in {ref}`install-index-label`. -Please report any issues in the [Volto issue tracker](https://github.com/plone/volto/issues/). -``` - -```{toctree} -:maxdepth: 1 - -contributing -design-principles -style-guide -language-features -linting -react -redux -routing -icons -testing -acceptance-tests -accessibility-guidelines -typescript -volto-core-addons -``` diff --git a/docs/source/getting-started/install.md b/docs/source/getting-started/install.md index 1e8dfc2460..cb405dac88 100644 --- a/docs/source/getting-started/install.md +++ b/docs/source/getting-started/install.md @@ -23,7 +23,7 @@ This chapter contains some legacy information that may be useful to Plone 5.2 de Volto can be installed in any operating system assuming that the following pre-requisites are met: -- [Node.js LTS (18.x)](https://nodejs.org/en/) +- [Node.js LTS (18.x)](https://nodejs.org/en) - [Python](https://www.python.org/) - See below for specific versions. - [Docker](https://www.docker.com/get-started) (if using the Plone docker images) @@ -188,7 +188,8 @@ docker run -it --rm --name=plone \ ``` ```{tip} -This setup is meant only for demonstration and quick testing purposes (since it destroys the container on exit (--rm)). In case you need production ready deployment, check the latest [Plone Deployment Training](https://training.plone.org/5/plone-deployment/index.html). +This setup is meant only for demonstration and quick testing purposes, since it destroys the container on exit (`--rm`). +In case you need production-ready deployment, check the latest [Plone Deployment Training](https://training.plone.org/plone-deployment/index.html). ``` ```{note} @@ -218,15 +219,28 @@ You may choose to install the canary version, which is the latest alpha release, 1. Open a terminal and execute: - ```bash + ```shell npm install -g yo @plone/generator-volto + # install latest stable release yo @plone/volto + # or install latest alpha release + yo @plone/volto --canary ``` -See the [Creating a project](../recipes/creating-project) page for more -advanced options that can be passed to the generator. + See {doc}`../recipes/creating-project` for more advanced options that can be passed to the generator. + +2. Answer the questions when prompted, and provide the name of the new app (folder) to be created. + For the sake of this documentation, provide `myvoltoproject` as the project name. + + ````{note} + You can run the generator with parameters to tailor your requirements. + + ```shell + yo @plone/volto --help + ``` -2. Answer the questions when prompted, and provide the name of the new app (folder) to be created. For the sake of this documentation, provide `myvoltoproject` as the project name. + or take a look at the [README](https://github.com/plone/volto/blob/master/packages/generator-volto/README.md) for more information. + ```` 3. Change directory to the newly created folder `myvoltoapp` (or the one you've chosen): ```bash diff --git a/docs/source/getting-started/others.md b/docs/source/getting-started/others.md index 3b5fcf48ea..a0b0ed82c2 100644 --- a/docs/source/getting-started/others.md +++ b/docs/source/getting-started/others.md @@ -11,19 +11,16 @@ myst: ## Plone Trainings -On the [Plone Trainings Website](https://training.plone.org) you'll find -Volto-dedicated open training materials plus React and other -Javascript-centered trainings. +On the [Plone Training website](https://training.plone.org), you'll find Volto-dedicated training materials, plus other JavaScript-centered trainings. - [Mastering Plone 6 Development](https://training.plone.org/mastering-plone/) The comprehensive training on Plone 6 with best practice tips for developers and integrators. -- [Volto](https://training.plone.org/5/volto/index.html) - A detailed training on how to create your own website using Volto frontend. - [Volto Hands-On](https://training.plone.org/voltohandson/index.html) - [Volto Add-ons Development](https://training.plone.org/voltoaddons/index.html) -- [Plone Deployment](https://training.plone.org/5/plone-deployment/index.html) -- [React](https://training.plone.org/react/index.html) -- [JavaScript For Plone Developers](https://training.plone.org/5/javascript/index.html) +- [Effective Volto](https://training.plone.org/effective-volto/index.html) +- [Plone Deployment](https://training.plone.org/plone-deployment/index.html) +- [Volto](https://2022.training.plone.org/volto/index.html) (archived) +- [JavaScript For Plone Developers](https://2022.training.plone.org/javascript/index.html) (archived) ## How does it work under the hood @@ -33,8 +30,7 @@ You can watch the talk during the World Plone Day 2021: ## Presentations at Plone Conferences (PloneConf) and other events -In recent years the react based Volto frontend for Plone has been presented in more and more talks at -our yearly Conferences: +In recent years the React based Volto frontend for Plone has been presented in more and more talks at our yearly Conferences. ### PloneConf 2022 diff --git a/docs/source/getting-started/roadmap.md b/docs/source/getting-started/roadmap.md index 933ef0515f..3af14a07b0 100644 --- a/docs/source/getting-started/roadmap.md +++ b/docs/source/getting-started/roadmap.md @@ -28,7 +28,7 @@ As is the case with similar modern Javascript-based applications, you should kno - Modern Javascript development. Volto uses next-generation Javascript. Follow the [ES6 guide](https://flaviocopes.com/es6/) to get up to speed. - React knowledge - [basic level is - fine](https://reactjs.org/tutorial/tutorial.html) for the beginning, you'll progress + fine](https://react.dev/learn/tutorial-tic-tac-toe) for the beginning, you'll progress along the way. React itself is a simple and well documented framework. - A basic understanding of Javascript [CommonJS](https://flaviocopes.com/commonjs/), diff --git a/docs/source/index.md b/docs/source/index.md index 222455dae2..ee7723015f 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -47,7 +47,7 @@ addons/index backend/index deploying/index upgrade-guide/index -developer-guidelines/index user-manual/index +contributing/index release-notes/index ``` diff --git a/docs/source/recipes/creating-project.md b/docs/source/recipes/creating-project.md index c577cedd35..03e0bd47b0 100644 --- a/docs/source/recipes/creating-project.md +++ b/docs/source/recipes/creating-project.md @@ -15,7 +15,7 @@ In addition to bootstrapping stand-alone Volto projects, it can also bootstrap V 1. Open a terminal and execute: - ```bash + ```shell npm install -g yo @plone/generator-volto # Install the latest and stable release of Volto with the following command yo @plone/volto @@ -29,7 +29,8 @@ In addition to bootstrapping stand-alone Volto projects, it can also bootstrap V yo @plone/volto --addon=volto-form-block ``` -2. Answer the questions when prompted, and provide the name of the new app (folder) to be created. For the sake of this documentation, provide `myvoltoproject` as the project name then. +2. Answer the questions when prompted, and provide the name of the new app (folder) to be created. + For the sake of this documentation, provide `myvoltoproject` as the project name then. ````{note} You can run the generator with parameters to tailor your requirements. diff --git a/docs/source/recipes/creating-views.md b/docs/source/recipes/creating-views.md index a087fa1201..39e51b9e8a 100644 --- a/docs/source/recipes/creating-views.md +++ b/docs/source/recipes/creating-views.md @@ -142,13 +142,18 @@ called `layoutViews` which registers all the layout views. We will add the `full ```js import { FullView } from './components'; -export const views = { - ...defaultViews, - layoutViews: { - ...defaultViews.layoutViews, - full_view: FullView, - }, -}; +export default function applyConfig(config) { + const defaultViews = config.views + // Add here your project's configuration here by modifying `config` accordingly + config.views = { + ...defaultViews, + layoutViews: { + ...defaultViewslayoutViews, + full_view: FullView, + }, + }; + return config; +} ``` ## Registering a new view called Album View @@ -290,45 +295,33 @@ And in `config.js`: * Add your config changes here. * @module config * @example - * export const settings = { - * ...defaultSettings, - * port: 4300, - * listBlockTypes: { - * ...defaultSettings.listBlockTypes, - * 'my-list-item', - * } + * export default function applyConfig(config) { + * config.settings = { + * ...config.settings, + * port: 4300, + * listBlockTypes: { + * ...config.settings.listBlockTypes, + * 'my-list-item', + * } * } */ -import { - settings as defaultSettings, - views as defaultViews, - widgets as defaultWidgets, - blocks as defaultBlocks, -} from '@plone/volto/config'; - +// All your imports required for the config here BEFORE this line +import '@plone/volto/config'; import { AlbumView, FullView } from './components'; -export const settings = { - ...defaultSettings, -}; - -export const views = { - ...defaultViews, - layoutViews: { - ...defaultViews.layoutViews, - album_view: AlbumView, - full_view: FullView, - }, -}; - -export const widgets = { - ...defaultWidgets, -}; - -export const blocks = { - ...defaultBlocks, -}; +export default function applyConfig(config) { + const defaultViews = config.views + // Add here your project's configuration here by modifying `config` accordingly + config.views = { + ...defaultViews, + layoutViews: { + ...defaultViews.layoutViews, + album_view: AlbumView, + full_view: FullView, + }, + }; + return config; +} -export default SummaryView; ``` diff --git a/docs/source/recipes/express.md b/docs/source/recipes/express.md index 9c15e107f8..0195efb933 100644 --- a/docs/source/recipes/express.md +++ b/docs/source/recipes/express.md @@ -45,6 +45,75 @@ if (__SERVER__) { Now the [test-middleware](http://localhost:3000/test-middleware) page can be visited and it will return the simple string and not the usual Volto pages. +## Static middleware + +The `staticMiddleware` is for serving static files such as style sheets and client-side JavaScript files from the `BUILD_DIR/PUBLIC` or `PUBLIC_DIR` directory. +It uses the `express.static()` function to serve static files, and the `setHeaders()` function to add response headers to the files that it serves. + +```js +import { settings as defaultSettings } from '@plone/volto/config'; +import express from 'express'; + +const settings = { ...defaultSettings }; +if (__SERVER__) { + const customStaticMiddleware = express.static('test/static/files'); + + function setCustomHeaders(req, res, next) { + res.setHeader('Cache-Control', 'public, max-age=3600'); + next(); + } + + customStaticMiddleware.setHeaders = setCustomHeaders; + customStaticMiddleware.id = 'custom-static-middleware'; + + settings.expressMiddleware = [ + ...defaultSettings.expressMiddleware, + customStaticMiddleware, + ]; +} +``` + +### Function `setHeaders(path)` + +The `setHeaders()` function is used to update the response headers for a file. +It takes the path of the file being served as an argument, and adds the response headers to that file. +It uses the `config` object specified in `config.settings.serverConfig.staticFiles` to determine which response headers should be added to the file. + +### Configuration + +The `config.settings.staticFiles` is an array of objects with three properties: + +`id` +: a string identifier for the static file rule + +`match` +: a regular expression that evaluates the path of the requested resource + +`headers` +: an object containing the headers added if the match is successful + +The following example shows how to add the response header `Cache-Control: public, max-age=3600` to a file named {file}`styles.css` located in the `BUILD_DIR/PUBLIC` directory: + +```js +import { + settings as defaultSettings, +} from '@plone/volto/config'; + +const settings = { ...defaultSettings }; +settings.staticFiles = [ + ...defaultSettings.staticFiles, { + id: 'styles_css', + match: /^\/styles\.css$/, + headers: { + 'Cache-Control': 'public, max-age=3600', + }, + } +] +``` + +The rules are checked in sequential order, and the search stops at the first match. +The default rules add headers that set the browser cache to 365 days for resources under the `/static` path and 60 seconds for all other paths. + Notice the use of the ``__SERVER__`` condition. Because the code in a Volto project's ``config.js`` gets executed by both the server and the client (browser), the server-side libraries need to "excluded" with conditions. @@ -54,4 +123,4 @@ See [ExpressJS](https://expressjs.com/) website for more documentation. ```{note} Addon authors should add the ``id`` property to the middleware so that it can be identified and manipulated in Volto projects configuration. -``` +``` \ No newline at end of file diff --git a/docs/source/recipes/widget.md b/docs/source/recipes/widget.md index ebb232d0d5..6b2e81d185 100644 --- a/docs/source/recipes/widget.md +++ b/docs/source/recipes/widget.md @@ -146,14 +146,112 @@ const applyConfig = (config) => { Based on this setup, Volto will render this field with the `TokenWidget`. -```{seealso} -See [storybook](https://6.dev-docs.plone.org/storybook) with available widgets. +(widget-relation-field-label)= + +## Relation fields + +A relation field is either a single relation field to hold at most one content object, `RelationChoice`, or a multi relation field, `RelationList`, that can hold more than one content object. + +Relation fields can be edited and rendered with the `Select` widget. +The restriction on content types, workflow states, and so on can be done with a `StaticCatalogVocabulary`. + +There are other vocabulary types and other widgets, including the `ObjectBrowser` widget. + +(widget-relation-field-single-label)= + +### Single relation field + +Relation field (`RelationChoice`) with a named `StaticCatalogVocabulary` and `Select` widget: + +```python +relationchoice_field_named_staticcatalogvocabulary = RelationChoice( + title="RelationChoice – named StaticCatalogVocabulary – Select widget", + description="field/relation: relationchoice_field_named_staticcatalogvocabulary", + vocabulary="relationchoice_field_named_staticcatalogvocabulary", + required=False, +) +directives.widget( + "relationchoice_field_named_staticcatalogvocabulary", + frontendOptions={ + "widget": "select", + }, +) ``` +It is recommended to define the vocabulary as a named `StaticCatalogVocabulary` with the field/relation name as its name. +This allows the {guilabel}`relations` control panel to respect the defined restrictions to potential relation targets. + +{file}`vocabularies.py` +```python +from plone.app.vocabularies.catalog import StaticCatalogVocabulary +from zope.interface import provider +from zope.schema.interfaces import IVocabularyFactory + +@provider(IVocabularyFactory) +def ExamplesVocabularyFactory(context=None): + return StaticCatalogVocabulary( + { + "portal_type": ["example"], + "review_state": "published", + "sort_on": "sortable_title", + } + ) +``` + +{file}`configure.zcml` +```xml + +``` + +The `Select` widget is currently the default for `RelationChoice` fields with vocabulary. +Therefore the directive can be omitted. + +```python +relationchoice_field_named_staticcatalogvocabulary = RelationChoice( + title="RelationChoice – named StaticCatalogVocabulary – Select widget", + description="field/relation: relationchoice_field_named_staticcatalogvocabulary", + vocabulary="relationchoice_field_named_staticcatalogvocabulary", + required=False, +) +``` + +(widget-relation-field-multi-label)= + +### Multi relation field + +Multi relation field (`RelationList`) with a named `StaticCatalogVocabulary`and `Select` widget: + +```python +relationlist_field_named_staticcatalogvocabulary = RelationList( + title="RelationList – named StaticCatalogVocabulary – Select widget", + description="field/relation: relationlist_field_named_staticcatalogvocabulary", + value_type=RelationChoice( + vocabulary="relationlist_field_named_staticcatalogvocabulary", + ), + required=False, +) +directives.widget( + "relationlist_field_named_staticcatalogvocabulary", + frontendOptions={ + "widget": "select", + }, +) +``` + + ## Widget `isDisabled` Props We can disable the input of a widget by passing props `isDisabled: true`. + +## Available widgets + +See [Storybook](https://6.docs.plone.org/storybook) with available widgets. + + ## Write a new widget ```{note} diff --git a/docs/source/theming/using-third-party-themes.md b/docs/source/theming/using-third-party-themes.md index ea8a8f0279..bc545302ca 100644 --- a/docs/source/theming/using-third-party-themes.md +++ b/docs/source/theming/using-third-party-themes.md @@ -7,6 +7,8 @@ myst: "keywords": "Volto, Plone, frontend, React, Semantic UI, semantic-ui, third, party, libraries, themes" --- +(volto-custom-theming-strategy)= + # Using third party libraries and themes other than `semantic-ui` You can use Volto with third party libraries or themes written in SASS and avoid applying `semantic-ui` on public facing views. diff --git a/docs/source/upgrade-guide/index.md b/docs/source/upgrade-guide/index.md index 30cb937c14..f33ea1d1d8 100644 --- a/docs/source/upgrade-guide/index.md +++ b/docs/source/upgrade-guide/index.md @@ -47,6 +47,11 @@ Volto 17 now uses Webpack 5. If you customized `razzle.config.js` for your project to change Webpack configuration or use Webpack plugins, you might need to make adjustments. +### Razzle upgraded to version `4.2.18` + +Razzle has been upgraded to version `4.2.18`. +It is recommended that you update your project's dependency on Razzle to this version in order to avoid duplication. + ### `BlockChooser` component now uses `popperjs` internally Technically not a breaking, the API nor the component contract has changed, but it's worth noting this change in here. @@ -59,6 +64,17 @@ This is better from the UI point of view, since any other element can take prece If you have customized the `BlockChooser` in any way could be that this now could interact with your customizations. +### Removed `hamburgers` library + +The `hamburgers` library was removed from core Volto, replaced by a much more lightweight approach. +If your theme or add-ons relied on it, add it again as a dependency in them, or adopt the CSS part that you are using in them. + +### Fixed i18n script by taking into account the real add-on order + +By fixing this, we may break how the locales were applied, since the order will now be correct. +Please check the translations of your project and add-ons, and verify that the translations are still correct. +This could be especially true if you did translation overrides, two add-ons were using different translations for the same `msgid`, or there were conflicting `msgid`s in different add-ons. + (volto-upgrade-guide-16.x.x)= ## Upgrading to Volto 16.x.x @@ -552,7 +568,7 @@ If you are extending an existing one, you should add it as a normal `schemaEnhan ``` ```{seealso} -See https://6.dev-docs.plone.org/volto/blocks/block-style-wrapper.html for more documentation. +See https://6.docs.plone.org/volto/blocks/block-style-wrapper.html for more documentation. ``` ### Sentry integration moved from Volto core to add-on diff --git a/docs/source/user-manual/copy-paste-blocks.md b/docs/source/user-manual/copy-paste-blocks.md index 1f922e2f75..c62544700e 100644 --- a/docs/source/user-manual/copy-paste-blocks.md +++ b/docs/source/user-manual/copy-paste-blocks.md @@ -27,7 +27,6 @@ This feature can be used by selecting a start block and an end block while holdi This will select all the blocks between the start and end blocks, allowing you to copy, cut, or delete multiple blocks at once. ```{video} /_static/user-manual/blocks/block-copy-cut.mp4 - :width: 100% ``` @@ -42,5 +41,4 @@ You can click the paste option Paste icon\n" "Language-Team: Plone i18n \n" "MIME-Version: 1.0\n" @@ -86,7 +86,7 @@ msgid "Add (object list)" msgstr "" #: components/manage/Controlpanels/AddonsControlpanel -# defaultMessage: To make new add-ons show up here, add them to your buildout configuration, run buildout, and restart the server process. For detailed instructions see +# defaultMessage: To make new add-ons show up here, add them to your configuration, build, and restart the server process. For detailed instructions see msgid "Add Addons" msgstr "" @@ -2091,7 +2091,7 @@ msgid "My email is" msgstr "" #: components/theme/PasswordReset/PasswordReset -# defaultMessage: My username is +# defaultMessage: My user name is msgid "My username is" msgstr "" @@ -3469,6 +3469,11 @@ msgstr "" msgid "Total comments" msgstr "" +#: components/manage/Contents/Contents +# defaultMessage: Total items to be deleted: +msgid "Total items to be deleted:" +msgstr "" + #: components/manage/Controlpanels/DatabaseInformation # defaultMessage: Total number of objects in each cache msgid "Total number of objects in each cache" @@ -4181,7 +4186,7 @@ msgid "label_my_email_is" msgstr "" #: components/theme/PasswordReset/RequestPasswordReset -# defaultMessage: My username is +# defaultMessage: My user name is msgid "label_my_username_is" msgstr "" diff --git a/locales/zh_CN/LC_MESSAGES/volto.po b/locales/zh_CN/LC_MESSAGES/volto.po index 5e39fce9ae..3d436e9e67 100644 --- a/locales/zh_CN/LC_MESSAGES/volto.po +++ b/locales/zh_CN/LC_MESSAGES/volto.po @@ -90,7 +90,7 @@ msgid "Add (object list)" msgstr "添加(对象列表)" #: components/manage/Controlpanels/AddonsControlpanel -# defaultMessage: To make new add-ons show up here, add them to your buildout configuration, run buildout, and restart the server process. For detailed instructions see +# defaultMessage: To make new add-ons show up here, add them to your configuration, build, and restart the server process. For detailed instructions see msgid "Add Addons" msgstr "添加附件" @@ -2095,7 +2095,7 @@ msgid "My email is" msgstr "我的邮箱是" #: components/theme/PasswordReset/PasswordReset -# defaultMessage: My username is +# defaultMessage: My user name is msgid "My username is" msgstr "我的用户名是" @@ -3473,6 +3473,11 @@ msgstr "活动和非活动对象的总数" msgid "Total comments" msgstr "全部评论" +#: components/manage/Contents/Contents +# defaultMessage: Total items to be deleted: +msgid "Total items to be deleted:" +msgstr "" + #: components/manage/Controlpanels/DatabaseInformation # defaultMessage: Total number of objects in each cache msgid "Total number of objects in each cache" @@ -4185,7 +4190,7 @@ msgid "label_my_email_is" msgstr "我的邮箱是" #: components/theme/PasswordReset/RequestPasswordReset -# defaultMessage: My username is +# defaultMessage: My user name is msgid "label_my_username_is" msgstr "我的用户名是" diff --git a/news/3990.bugfix b/news/3990.bugfix new file mode 100644 index 0000000000..fed2312d0f --- /dev/null +++ b/news/3990.bugfix @@ -0,0 +1 @@ +Apply suggestion from browser for password field @lord2anil \ No newline at end of file diff --git a/news/4234.bugfix b/news/4234.bugfix new file mode 100644 index 0000000000..26eb1934a1 --- /dev/null +++ b/news/4234.bugfix @@ -0,0 +1 @@ +Fix duplicating listing block by removing block uid from blocks data. @ksuess \ No newline at end of file diff --git a/news/4502.documentation b/news/4502.documentation deleted file mode 100644 index cc20ee1c42..0000000000 --- a/news/4502.documentation +++ /dev/null @@ -1 +0,0 @@ -Fix training urls @ksuess \ No newline at end of file diff --git a/news/4518.documentation b/news/4518.documentation new file mode 100644 index 0000000000..cb7f8b7a28 --- /dev/null +++ b/news/4518.documentation @@ -0,0 +1 @@ +Added documentation regarding the static middleware. @BhardwajAditya-github \ No newline at end of file diff --git a/news/4558.bugfix b/news/4558.bugfix new file mode 100644 index 0000000000..59b2af9e28 --- /dev/null +++ b/news/4558.bugfix @@ -0,0 +1 @@ +(fix):Object.normaliseMail: Cannot read properties of null @dobri1408 diff --git a/news/4567.internal b/news/4567.internal new file mode 100644 index 0000000000..05b356b1c6 --- /dev/null +++ b/news/4567.internal @@ -0,0 +1,2 @@ +Change conditional checking to optional chaining for a theme icon @nilootpal + diff --git a/news/4582.bugfix b/news/4582.bugfix new file mode 100644 index 0000000000..2a2383ed8f --- /dev/null +++ b/news/4582.bugfix @@ -0,0 +1 @@ +Update add-on control panel tranlsations: install -> activate. @ksuess diff --git a/news/4638.bugfix b/news/4638.bugfix new file mode 100644 index 0000000000..972338ec30 --- /dev/null +++ b/news/4638.bugfix @@ -0,0 +1 @@ +Fix robot.txt - the sitemap link should respect x-forwarded headers @reebalazs diff --git a/news/4690.bugfix b/news/4690.bugfix new file mode 100644 index 0000000000..4729717efa --- /dev/null +++ b/news/4690.bugfix @@ -0,0 +1 @@ +Fix Move to top of folder ordering in folder content view by searching also @iFlameing diff --git a/news/4703.bugfix b/news/4703.bugfix new file mode 100644 index 0000000000..d0b7241188 --- /dev/null +++ b/news/4703.bugfix @@ -0,0 +1 @@ +Fix faulty D&D elements in ObjectBrowserList widget @sneridagh diff --git a/news/4715.internal b/news/4715.internal new file mode 100644 index 0000000000..65b82d7d56 --- /dev/null +++ b/news/4715.internal @@ -0,0 +1 @@ +Security upgrade for momentjs diff --git a/news/4718.bugfix b/news/4718.bugfix new file mode 100644 index 0000000000..f31527f057 --- /dev/null +++ b/news/4718.bugfix @@ -0,0 +1 @@ +Fix fetching API paths with urlencoded characters in the querystring. @davisagli diff --git a/news/4726.documentation b/news/4726.documentation new file mode 100644 index 0000000000..b37c62ee68 --- /dev/null +++ b/news/4726.documentation @@ -0,0 +1 @@ +Use new URL `6.docs.plone.org`. @stevepiercy diff --git a/news/4728.documentation b/news/4728.documentation new file mode 100644 index 0000000000..c06faf93be --- /dev/null +++ b/news/4728.documentation @@ -0,0 +1 @@ +Synch stuff from `16.x.x` branch that should have been in `master` as well. @stevepiercy diff --git a/news/4742.documentation b/news/4742.documentation new file mode 100644 index 0000000000..a99a3b78c4 --- /dev/null +++ b/news/4742.documentation @@ -0,0 +1 @@ +Fix link in Volto, remove from linkcheck ignore in Documentation. @stevepiercy diff --git a/package-why.json b/package-why.json index dd2df66e1e..50362651f1 100644 --- a/package-why.json +++ b/package-why.json @@ -24,7 +24,6 @@ "i18n:ci": "Description for `npm run i18n:ci` command", "stylelint:patches": "Description for `npm run stylelint:patches` command", "patches": "Description for `npm run patches` command", - "deduplicate": "Description for `npm run deduplicate` command", "dry-release": "Description for `npm run dry-release` command", "release": "Description for `npm run release` command", "release-major-alpha": "Description for `npm run release-major-alpha` command", diff --git a/package.json b/package.json index 1029401f03..154e3efd0a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ } ], "license": "MIT", - "version": "17.0.0-alpha.1", + "version": "17.0.0-alpha.5", "repository": { "type": "git", "url": "git@github.com:plone/volto.git" @@ -290,7 +290,6 @@ "express": "4.17.3", "filesize": "6", "glob": "7.1.6", - "hamburgers": "1.1.3", "history": "4.10.1", "hoist-non-react-statics": "3.3.2", "html-webpack-plugin": "5.5.0", @@ -302,7 +301,6 @@ "is-hotkey": "0.2.0", "is-url": "1.2.4", "jest-file": "1.0.0", - "jsonwebtoken": "8.3.0", "jwt-decode": "2.2.0", "less": "3.11.1", "less-loader": "11.1.0", @@ -313,7 +311,7 @@ "lodash-move": "1.1.1", "lodash-webpack-plugin": "0.11.6", "mini-css-extract-plugin": "2.7.2", - "moment": "2.24.0", + "moment": "2.29.4", "object-assign": "4.1.1", "pofile": "1.0.10", "postcss": "8.4.13", @@ -330,9 +328,9 @@ "promise-file-reader": "1.0.2", "prop-types": "15.7.2", "query-string": "7.1.0", - "razzle": "4.2.17", - "razzle-dev-utils": "4.2.17", - "razzle-plugin-bundle-analyzer": "4.2.17", + "razzle": "4.2.18", + "razzle-dev-utils": "4.2.18", + "razzle-plugin-bundle-analyzer": "4.2.18", "razzle-plugin-scss": "4.2.18", "rc-time-picker": "3.7.3", "react": "17.0.2", @@ -400,7 +398,7 @@ "universal-cookie-express": "4.0.3", "use-deep-compare-effect": "1.8.1", "uuid": "^8.3.2", - "webpack": "5.75.0", + "webpack": "5.76.1", "webpack-dev-server": "4.11.1", "webpack-node-externals": "3.0.0", "xmlrpc": "1.3.2", @@ -419,6 +417,7 @@ "identity-obj-proxy": "3.0.0", "jest": "26.6.3", "jest-environment-jsdom": "^26", + "jsonwebtoken": "9.0.0", "react-error-overlay": "6.0.9", "react-is": "^16.13.1", "release-it": "^15.1.3", @@ -432,6 +431,7 @@ "resolutions": { "clean-css": "5.3.1", "http-proxy": "^1.18.1", + "react-dev-utils": "^12", "react-error-overlay": "6.0.9", "ua-parser-js": "0.7.28" }, diff --git a/packages/generator-volto/CHANGELOG.md b/packages/generator-volto/CHANGELOG.md index e3b7cc11cd..4696e00b0b 100644 --- a/packages/generator-volto/CHANGELOG.md +++ b/packages/generator-volto/CHANGELOG.md @@ -3,11 +3,25 @@ +## 7.0.0-alpha.4 (2023-04-13) + +### Bugfix + +- Force the resolution of the `react-error-overlay` package to `6.0.9` @sneridagh [#4687](https://github.com/plone/volto/issues/4687) + + +## 7.0.0-alpha.3 (2023-04-03) + +### Bugfix + +- Update to latest Razzle - needed since #3997. This fixes the duplicated Razzles issue @sneridagh [#4640](https://github.com/plone/volto/issues/4640) + + ## 7.0.0-alpha.2 (2023-03-05) ### Feature diff --git a/packages/generator-volto/generators/app/templates/README.md b/packages/generator-volto/generators/app/templates/README.md index 1410a4d24e..9547b698b2 100644 --- a/packages/generator-volto/generators/app/templates/README.md +++ b/packages/generator-volto/generators/app/templates/README.md @@ -1,6 +1,6 @@ ## Documentation -A training on how to create your own website using Volto is available as part of the Plone training at [https://training.plone.org/5/volto/index.html](https://training.plone.org/5/volto/index.html). +[Volto Hands-On](https://training.plone.org/voltohandson/index.html) is a training on how to create your own website. ## Quick Start diff --git a/packages/generator-volto/generators/app/templates/locales/de/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/de/LC_MESSAGES/volto.po index c820db7482..49d2e20662 100644 --- a/packages/generator-volto/generators/app/templates/locales/de/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/de/LC_MESSAGES/volto.po @@ -1,13 +1,4 @@ -# Translation of plone.pot to German -# Jan Ulrich Hasecke , 2003-2010. -# Simon Eisenmann , 2003. -# Hanno Schlichting , 2003-2008. -# Dominik Bittl , 2005. -# Christian Ullrich , 2005. -# Thomas Lotze , 2005-2008. -# Sven Deichmann , 2008-2010. -# Harald Friessnegger , 2011. -# Andreas Jung , 2012 +# Translation of volto.pot to German msgid "" msgstr "" "Project-Id-Version: Plone\n" diff --git a/packages/generator-volto/generators/app/templates/locales/es/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/es/LC_MESSAGES/volto.po index a89bace6f0..784b64fb17 100644 --- a/packages/generator-volto/generators/app/templates/locales/es/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/es/LC_MESSAGES/volto.po @@ -1,6 +1,3 @@ -# Gettext Message File for Plone -# Translators: -# Leonardo J. Caballero G. , 2019. msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -20,3 +17,5 @@ msgstr "" "Preferred-Encodings: utf-8\n" "Domain: volto\n" "X-Is-Fallback-For: es-ar es-bo es-cl es-co es-cr es-do es-ec es-es es-sv es-gt es-hn es-mx es-ni es-pa es-py es-pe es-pr es-us es-uy es-ve\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/eu/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/eu/LC_MESSAGES/volto.po index 066e3e8de9..984adca72e 100644 --- a/packages/generator-volto/generators/app/templates/locales/eu/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/eu/LC_MESSAGES/volto.po @@ -1,4 +1,4 @@ -# Translation of plone.pot to EU +# Translation of volto.pot to EU msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -15,3 +15,5 @@ msgstr "" "Language-Code: eu\n" "Language-Name: eu\n" "Preferred-Encodings: utf-8 latin1\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/fr/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/fr/LC_MESSAGES/volto.po index afed0b8a27..f6050e4530 100644 --- a/packages/generator-volto/generators/app/templates/locales/fr/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/fr/LC_MESSAGES/volto.po @@ -1,13 +1,4 @@ -# Translation of plone.pot to French -# French Translation Team , 2003-2006. -# Sebastien Douche , 2005-2007. -# Encolpe Degoute , 2006, 2007, 2008. -# Gilles Lenfant , 2008. -# Encolpe Degoute , 2008. -# Vincent Fretin , 2009. -# Kevin Deldycke , 2009. -# JeanMichel FRANCOIS , 2010. -# Denis Bitouzé , 2019. +# Translation of volto.pot to French msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -25,3 +16,5 @@ msgstr "" "Language-Name: French\n" "Preferred-Encodings: utf-8 latin1\n" "X-Is-Fallback-For: fr-be fr-ca fr-lu fr-mc fr-ch fr-fr\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/it/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/it/LC_MESSAGES/volto.po index fbc3cc0274..12b9a47628 100644 --- a/packages/generator-volto/generators/app/templates/locales/it/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/it/LC_MESSAGES/volto.po @@ -10,3 +10,5 @@ msgstr "" "Content-Type: \n" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/ja/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/ja/LC_MESSAGES/volto.po index 3b04a25584..a543785fbf 100644 --- a/packages/generator-volto/generators/app/templates/locales/ja/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/ja/LC_MESSAGES/volto.po @@ -1,5 +1,3 @@ -# Manabu TERADA 2019 -# Peacock 2019 msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -17,3 +15,5 @@ msgstr "" "Language-Name: Japanese\n" "Preferred-Encodings: utf-8\n" "X-Is-Fallback-For: ja-jp\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/nl/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/nl/LC_MESSAGES/volto.po index 1a240e59ff..a9816b4cea 100644 --- a/packages/generator-volto/generators/app/templates/locales/nl/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/nl/LC_MESSAGES/volto.po @@ -1,18 +1,3 @@ -# Translators: -# Fred van Dijk , 2016 -# Coen van der Kamp , 2015 -# Danny Bloemendaal , 2007 -# Diederik Veeze , 2015 -# Duco Dokter , 2007 -# Esther Ladage , 2005 -# Jean-Paul Ladage , 2017 -# Kees Hink , 2010 -# Maarten Kling , 2013 -# Mark van Lent , 2007 -# Mirella van Teulingen , 2005 -# Reinout van Rees , 2008 -# Roel Bruggink , 2009 -# Wietze Helmantel , 2007 msgid "" msgstr "" "Project-Id-Version: PlonenPOT-Creation-Date: 2017-04-27T19:30:59.079Z\n" diff --git a/packages/generator-volto/generators/app/templates/locales/pt/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/pt/LC_MESSAGES/volto.po index 84ccaf6942..3713b40e7d 100644 --- a/packages/generator-volto/generators/app/templates/locales/pt/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/pt/LC_MESSAGES/volto.po @@ -1,6 +1,3 @@ -# Translators: -# Emanuel de Jesus , 2019 -# msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -18,3 +15,5 @@ msgstr "" "Language-Code: pt\n" "Language-Name: Portuguese\n" "Preferred-Encodings: utf-8\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/pt_BR/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/pt_BR/LC_MESSAGES/volto.po index 2895094452..d788679fdc 100644 --- a/packages/generator-volto/generators/app/templates/locales/pt_BR/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/pt_BR/LC_MESSAGES/volto.po @@ -1,5 +1,3 @@ -# Translators: -# Léu Almeida , 2019 msgid "" msgstr "" "Project-Id-Version: Plone\n" @@ -16,3 +14,5 @@ msgstr "" "Language-Code: pt-br\n" "Language-Name: Português do Brasil\n" "Preferred-Encodings: utf-8\n" + + diff --git a/packages/generator-volto/generators/app/templates/locales/ro/LC_MESSAGES/volto.po b/packages/generator-volto/generators/app/templates/locales/ro/LC_MESSAGES/volto.po index 8ad5875b09..42c60f4d17 100644 --- a/packages/generator-volto/generators/app/templates/locales/ro/LC_MESSAGES/volto.po +++ b/packages/generator-volto/generators/app/templates/locales/ro/LC_MESSAGES/volto.po @@ -1,5 +1,3 @@ -# Translation of plone.pot to Romanian -# Alin Voinea , 2020. msgid "" msgstr "" "Project-Id-Version: Plone\n" diff --git a/packages/generator-volto/generators/app/templates/locales/volto.pot b/packages/generator-volto/generators/app/templates/locales/volto.pot index 8ff7bce29b..430c431165 100644 --- a/packages/generator-volto/generators/app/templates/locales/volto.pot +++ b/packages/generator-volto/generators/app/templates/locales/volto.pot @@ -12,3 +12,5 @@ msgstr "" "Language-Name: English\n" "Preferred-Encodings: utf-8\n" "Domain: volto\n" + + diff --git a/packages/generator-volto/generators/app/templates/package.json.tpl b/packages/generator-volto/generators/app/templates/package.json.tpl index eeea34b12f..648853b627 100644 --- a/packages/generator-volto/generators/app/templates/package.json.tpl +++ b/packages/generator-volto/generators/app/templates/package.json.tpl @@ -148,11 +148,14 @@ "@storybook/addon-essentials": "^6.3.0", "@storybook/addon-links": "^6.3.0", "@storybook/react": "^6.3.0", - "razzle": "4.2.17", + "razzle": "4.2.18", "stylelint": "14.0.1", "stylelint-config-idiomatic-order": "8.1.0", "stylelint-config-prettier": "8.0.1", "stylelint-prettier": "1.1.2" }, + "resolutions": { + "react-error-overlay": "6.0.9" + }, "packageManager": "yarn@3.2.3" } diff --git a/packages/generator-volto/news/4737.bugfix b/packages/generator-volto/news/4737.bugfix new file mode 100644 index 0000000000..e229208dff --- /dev/null +++ b/packages/generator-volto/news/4737.bugfix @@ -0,0 +1 @@ +Fix whitespace in empty locales created by the generator. @davisagli diff --git a/packages/generator-volto/package.json b/packages/generator-volto/package.json index 49f9944101..b35a36f5e8 100644 --- a/packages/generator-volto/package.json +++ b/packages/generator-volto/package.json @@ -10,7 +10,7 @@ } ], "license": "MIT", - "version": "7.0.0-alpha.2", + "version": "7.0.0-alpha.4", "repository": { "type": "git", "url": "git+https://github.com/plone/generator-volto.git" @@ -108,7 +108,6 @@ "fs-extra": "3.0.0", "gitly": "2.0.3", "mkdirp-then": "1.2.0", - "ms": "1.0.0", "mz": "2.6.0", "ora": "1.2.0", "promise": "7.1.1", diff --git a/packages/generator-volto/yarn.lock b/packages/generator-volto/yarn.lock index 9e0129dc37..c53534dc9f 100644 --- a/packages/generator-volto/yarn.lock +++ b/packages/generator-volto/yarn.lock @@ -682,7 +682,6 @@ __metadata: jest: ^24.8.0 lint-staged: ^9.4.3 mkdirp-then: 1.2.0 - ms: 1.0.0 mz: 2.6.0 ora: 1.2.0 prettier: 2.0.5 @@ -4150,9 +4149,9 @@ __metadata: linkType: hard "http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0": - version: 4.1.0 - resolution: "http-cache-semantics@npm:4.1.0" - checksum: 974de94a81c5474be07f269f9fd8383e92ebb5a448208223bfb39e172a9dbc26feff250192ecc23b9593b3f92098e010406b0f24bd4d588d631f80214648ed42 + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 languageName: node linkType: hard @@ -5635,13 +5634,11 @@ __metadata: linkType: hard "json5@npm:^2.1.2": - version: 2.1.3 - resolution: "json5@npm:2.1.3" - dependencies: - minimist: ^1.2.5 + version: 2.2.3 + resolution: "json5@npm:2.2.3" bin: json5: lib/cli.js - checksum: b2de57a66520eca0fbb6c5ef59249b8308efb93fe89a8c75f5a6846e4f5f7d99a5a6f2e4db4d7a1c7047802dd816ed602a052d147a415d0e6b7f834885b62bc3 + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 languageName: node linkType: hard @@ -6274,16 +6271,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.4": - version: 3.0.4 - resolution: "minimatch@npm:3.0.4" - dependencies: - brace-expansion: ^1.1.7 - checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078 - languageName: node - linkType: hard - -"minimatch@npm:^3.1.2": +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -6434,13 +6422,6 @@ __metadata: languageName: node linkType: hard -"ms@npm:1.0.0": - version: 1.0.0 - resolution: "ms@npm:1.0.0" - checksum: d8df74551552ffce335dcb07b77fae25573b6e83789cd58e04c6bd5652095390d55e5be54ec8e143b6dbb785b61615f6a314d5d8e1a141fdf53cf3596d8972b5 - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 560a57ee9b..6722cb2121 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -3,11 +3,22 @@ +## 3.0.0 (2023-04-07) + +### Breaking + +- Remove dependency on `simple-git`. It is used by `mrs-developer` but not directly. @davisagli [#4546](https://github.com/plone/volto/issues/4546) + +### Bugfix + +- Fixed i18n script to avoid overwriting translations with an empty msgstr @danalvrz [#4316](https://github.com/plone/volto/issues/4316) + + ## 2.3.0 (2023-01-13) ### Feature @@ -80,7 +91,7 @@ - Removed `Razzle` as dependency, leave only the `babel-preset-razzle` one which is enough. - See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ## 1.6.0 (2022-08-05) diff --git a/packages/scripts/README.md b/packages/scripts/README.md index c4b9ec0d59..3c85d2d2c1 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -6,7 +6,7 @@ This package is a library of scripts that are useful to automate certain tasks w It scans and detects i18n messages from the code and adds them to the i18n machinery. -See https://6.dev-docs.plone.org/volto/recipes/i18n.html for more information. +See https://6.docs.plone.org/volto/recipes/i18n.html for more information. This script is installed in the `node_modules/.bin` directory and can be called via `yarn i18n` or directly in the `scripts` `package.json` part. diff --git a/packages/scripts/i18n.cjs b/packages/scripts/i18n.cjs index 9136e6ef0e..b1023c4538 100755 --- a/packages/scripts/i18n.cjs +++ b/packages/scripts/i18n.cjs @@ -5,7 +5,7 @@ * @module scripts/i18n */ -const { find, keys, map, concat, reduce, zipObject } = require('lodash'); +const { find, keys, map, concat, reduce } = require('lodash'); const glob = require('glob').sync; const fs = require('fs'); const Pofile = require('pofile'); @@ -142,20 +142,52 @@ msgstr "" * @return {undefined} */ function poToJson({ registry, addonMode }) { + const mergeMessages = (result, items, language) => { + items.forEach((item) => { + if (item.msgid in result) { + if (item.msgstr[0] !== '') { + result[item.msgid] = item.msgstr[0]; + } + } else { + result[item.msgid] = + language === 'en' + ? item.msgstr[0] || + (item.comments[0] + ? item.comments[0].replace('defaultMessage: ', '') + : '') + : item.msgstr[0]; + } + }); + + return result; + }; + map(glob('locales/**/*.po'), (filename) => { let { items } = Pofile.parse(fs.readFileSync(filename, 'utf8')); + const projectLocalesItems = Pofile.parse(fs.readFileSync(filename, 'utf8')) + .items; const lang = filename.match(/locales\/(.*)\/LC_MESSAGES\//)[1]; + const result = {}; + + // Merge volto core locales + const lib = `node_modules/@plone/volto/${filename}`; + if (fs.existsSync(lib)) { + const libItems = Pofile.parse(fs.readFileSync(lib, 'utf8')).items; + items = [...libItems, ...items]; + mergeMessages(result, items, lang); + } if (!addonMode) { // Merge addons locales if (packageJson.addons) { - registry.addonNames.forEach((addon) => { + registry.getAddonDependencies().forEach((addon) => { const addonlocale = `${registry.packages[addon].modulePath}/../${filename}`; if (fs.existsSync(addonlocale)) { const addonItems = Pofile.parse( fs.readFileSync(addonlocale, 'utf8'), ).items; items = [...addonItems, ...items]; + mergeMessages(result, items, lang); if (require.main === module) { // We only log it if called as script console.log(`Merging ${addon} locales for ${lang}`); @@ -164,32 +196,9 @@ function poToJson({ registry, addonMode }) { }); } } - // Merge project locales, the project customization wins - const lib = `node_modules/@plone/volto/${filename}`; - if (fs.existsSync(lib)) { - const libItems = Pofile.parse(fs.readFileSync(lib, 'utf8')).items; - items = [...libItems, ...items]; - } - - // Write the corresponding language JSON, cover the special EN use case for including - // defaults if not present - fs.writeFileSync( - `locales/${lang}.json`, - JSON.stringify( - zipObject( - map(items, (item) => item.msgid), - map(items, (item) => - lang === 'en' - ? item.msgstr[0] || - (item.comments[0] - ? item.comments[0].replace('defaultMessage: ', '') - : '') - : item.msgstr[0], - ), - ), - ), - ); + mergeMessages(result, projectLocalesItems, lang); + fs.writeFileSync(`locales/${lang}.json`, JSON.stringify(result)); }); } diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 95c68bb612..6d8ed40cf6 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -9,7 +9,7 @@ } ], "license": "MIT", - "version": "2.3.0", + "version": "3.0.0", "repository": { "type": "git", "url": "git@github.com:plone/volto.git" @@ -68,8 +68,7 @@ "fs-extra": "10.1.0", "git-url-parse": "^11.6.0", "mrs-developer": "*", - "pofile": "1.0.10", - "simple-git": "3.15.0" + "pofile": "1.0.10" }, "devDependencies": { "release-it": "14.2.1" diff --git a/packages/scripts/yarn.lock b/packages/scripts/yarn.lock index ed87c69c84..778e6ca55c 100644 --- a/packages/scripts/yarn.lock +++ b/packages/scripts/yarn.lock @@ -1941,7 +1941,6 @@ __metadata: mrs-developer: "*" pofile: 1.0.10 release-it: 14.2.1 - simple-git: 3.15.0 bin: addon: ./addon/index.js changelogupdater: ./changelogupdater.cjs @@ -2183,6 +2182,13 @@ __metadata: languageName: node linkType: hard +"async@npm:^3.2.4": + version: 3.2.4 + resolution: "async@npm:3.2.4" + checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -2464,7 +2470,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -2577,13 +2583,6 @@ __metadata: languageName: node linkType: hard -"colors@npm:^1.4.0": - version: 1.4.0 - resolution: "colors@npm:1.4.0" - checksum: 98aa2c2418ad87dedf25d781be69dc5fc5908e279d9d30c34d8b702e586a0474605b3a189511482b9d5ed0d20c867515d22749537f7bc546256c6014f3ebdcec - languageName: node - linkType: hard - "combined-stream@npm:^1.0.8": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" @@ -2683,7 +2682,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.4": +"debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -3244,9 +3243,9 @@ __metadata: linkType: hard "http-cache-semantics@npm:^4.0.0": - version: 4.1.0 - resolution: "http-cache-semantics@npm:4.1.0" - checksum: 974de94a81c5474be07f269f9fd8383e92ebb5a448208223bfb39e172a9dbc26feff250192ecc23b9593b3f92098e010406b0f24bd4d588d631f80214648ed42 + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 languageName: node linkType: hard @@ -3599,23 +3598,12 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2": - version: 2.2.0 - resolution: "json5@npm:2.2.0" - dependencies: - minimist: ^1.2.5 - bin: - json5: lib/cli.js - checksum: e88fc5274bb58fc99547baa777886b069d2dd96d9cfc4490b305fd16d711dabd5979e35a4f90873cefbeb552e216b041a304fe56702bedba76e19bc7845f208d - languageName: node - linkType: hard - -"json5@npm:^2.2.1": - version: 2.2.1 - resolution: "json5@npm:2.2.1" +"json5@npm:^2.1.2, json5@npm:^2.2.1": + version: 2.2.3 + resolution: "json5@npm:2.2.3" bin: json5: lib/cli.js - checksum: 74b8a23b102a6f2bf2d224797ae553a75488b5adbaee9c9b6e5ab8b510a2fc6e38f876d4c77dea672d4014a44b2399e15f2051ac2b37b87f74c0c7602003543b + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 languageName: node linkType: hard @@ -3835,15 +3823,15 @@ __metadata: linkType: hard "minimatch@npm:^3.0.4": - version: 3.0.4 - resolution: "minimatch@npm:3.0.4" + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: ^1.1.7 - checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5": +"minimist@npm:^1.2.0": version: 1.2.6 resolution: "minimist@npm:1.2.6" checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb @@ -3851,14 +3839,15 @@ __metadata: linkType: hard "mrs-developer@npm:*": - version: 1.6.0 - resolution: "mrs-developer@npm:1.6.0" + version: 2.1.0 + resolution: "mrs-developer@npm:2.1.0" dependencies: - colors: ^1.4.0 - simple-git: ^1.132.0 + async: ^3.2.4 + chalk: ^2.4.2 + simple-git: ^3.3.0 bin: missdev: src/command.js - checksum: 7154612bfa0f316b7a443bf4bc698bf46ba953900a5f134c67048974134a678218a0624e92c81ec1d84f5b923593b6a2c0d768a72d6ea4199fa769a30fe9530a + checksum: 11a47dee219fb4986a591195ea18d47602741f90d66ccb94378d619979c0bc52284590cc11f48da60fbbd463765904fc60a3800fb5f786caa9c5a5610cbece86 languageName: node linkType: hard @@ -4620,23 +4609,14 @@ __metadata: languageName: node linkType: hard -"simple-git@npm:3.15.0": - version: 3.15.0 - resolution: "simple-git@npm:3.15.0" +"simple-git@npm:^3.3.0": + version: 3.17.0 + resolution: "simple-git@npm:3.17.0" dependencies: "@kwsites/file-exists": ^1.1.1 "@kwsites/promise-deferred": ^1.1.1 debug: ^4.3.4 - checksum: 4733d1b769965a7608254c3a5b27532e02e60d4369bc9b397ce47159dd153344a3774739fd2602f693947ed64631b30145b970988fb007b5b779459e9abcdee8 - languageName: node - linkType: hard - -"simple-git@npm:^1.132.0": - version: 1.132.0 - resolution: "simple-git@npm:1.132.0" - dependencies: - debug: ^4.0.1 - checksum: 717d7cf7919ebe771b2562ed70c79c3971ac650d9577a15c47052472f8e549a088aea593b6a7245d73af0425a202106e6c236d35a73dc4c48dce99bf7b4f939a + checksum: 977a05cb0b5087296348b5afa682ce552f43234f5fd29b44c3d7f56b3682d10dcb03752a418e508aaffcbdb6ea2e304a3ef10095197d6743d2353adb85f32592 languageName: node linkType: hard diff --git a/packages/volto-slate/package.json b/packages/volto-slate/package.json index e4ad38ef6e..0fb36fb86f 100644 --- a/packages/volto-slate/package.json +++ b/packages/volto-slate/package.json @@ -1,6 +1,6 @@ { "name": "@plone/volto-slate", - "version": "17.0.0-alpha.1", + "version": "17.0.0-alpha.5", "description": "Slate.js integration with Volto", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", diff --git a/packages/volto-slate/src/blocks/Table/index.js b/packages/volto-slate/src/blocks/Table/index.js index baaef940bd..d2525926be 100644 --- a/packages/volto-slate/src/blocks/Table/index.js +++ b/packages/volto-slate/src/blocks/Table/index.js @@ -2,6 +2,7 @@ import TableBlockEdit from './TableBlockEdit'; import TableBlockView from './TableBlockView'; import { extractTables } from './deconstruct'; import { normalizeTable } from './extensions/normalizeTable'; +import { normalizeExternalData } from '../Text/extensions'; import tableSVG from '@plone/volto/icons/table.svg'; @@ -25,6 +26,7 @@ export default function install(config) { // withDeserializers, // breakList, normalizeTable, + normalizeExternalData, ], }; diff --git a/packages/volto-testing/CHANGELOG.md b/packages/volto-testing/CHANGELOG.md index ff65a00722..c2077bdbf7 100644 --- a/packages/volto-testing/CHANGELOG.md +++ b/packages/volto-testing/CHANGELOG.md @@ -3,7 +3,7 @@ diff --git a/razzle.config.js b/razzle.config.js index 34f84a95ce..78ad60f619 100644 --- a/razzle.config.js +++ b/razzle.config.js @@ -8,6 +8,7 @@ const fs = require('fs'); const RootResolverPlugin = require('./webpack-plugins/webpack-root-resolver'); const RelativeResolverPlugin = require('./webpack-plugins/webpack-relative-resolver'); const createAddonsLoader = require('./create-addons-loader'); +const createThemeAddonsLoader = require('./create-theme-addons-loader'); const AddonConfigurationRegistry = require('./addon-registry'); const CircularDependencyPlugin = require('circular-dependency-plugin'); const TerserPlugin = require('terser-webpack-plugin'); @@ -245,6 +246,28 @@ const defaultModify = ({ 'lodash-es': path.dirname(require.resolve('lodash')), }; + const [ + addonsThemeLoaderVariablesPath, + addonsThemeLoaderMainPath, + ] = createThemeAddonsLoader(registry.getCustomThemeAddons()); + + // Automatic Theme Loading + if (registry.theme) { + // The themes should be located in `src/theme` + const themePath = registry.packages[registry.theme].modulePath; + const themeConfigPath = `${themePath}/theme/theme.config`; + config.resolve.alias['../../theme.config$'] = themeConfigPath; + config.resolve.alias['../../theme.config'] = themeConfigPath; + + // We create an alias for each custom theme insertion point (variables, main) + config.resolve.alias[ + 'addonsThemeCustomizationsVariables' + ] = addonsThemeLoaderVariablesPath; + config.resolve.alias[ + 'addonsThemeCustomizationsMain' + ] = addonsThemeLoaderMainPath; + } + config.performance = { maxAssetSize: 10000000, maxEntrypointSize: 10000000, diff --git a/requirements-docs.txt b/requirements-docs.txt index 7c4e331ab9..d4596cb251 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -5,7 +5,8 @@ lesscpy linkify-it-py myst-parser sphinx-autobuild -sphinx-book-theme +pydata-sphinx-theme<=0.8.99 +sphinx-book-theme==0.3.3 sphinx-copybutton sphinx-sitemap sphinx-togglebutton diff --git a/src/actions/language/language.js b/src/actions/language/language.js index 6ea855c8b2..e62d4be472 100644 --- a/src/actions/language/language.js +++ b/src/actions/language/language.js @@ -7,6 +7,7 @@ export function changeLanguageCookies(language, req) { const cookieOptions = getCookieOptions({ secure: req?.protocol?.startsWith('https') ? true : false, + sameSite: 'strict', }); if (!req) { diff --git a/src/actions/querystringsearch/querystringsearch.js b/src/actions/querystringsearch/querystringsearch.js index 9dff75b72d..6b178436f7 100644 --- a/src/actions/querystringsearch/querystringsearch.js +++ b/src/actions/querystringsearch/querystringsearch.js @@ -31,24 +31,30 @@ export function getQueryStringResults(path, data, subrequest, page) { } } + const query = { + ...requestData, + ...(!requestData.b_size && { + b_size: settings.defaultPageSize, + }), + ...(page && { + b_start: requestData.b_size + ? data.b_size * (page - 1) + : settings.defaultPageSize * (page - 1), + }), + query: requestData?.query, + }; + return { type: GET_QUERYSTRING_RESULTS, subrequest, request: { - op: 'post', - path: `${path}/@querystring-search`, - data: { - ...requestData, - ...(!requestData.b_size && { - b_size: settings.defaultPageSize, - }), - ...(page && { - b_start: requestData.b_size - ? data.b_size * (page - 1) - : settings.defaultPageSize * (page - 1), - }), - query: requestData?.query, - }, + op: settings.querystringSearchGet ? 'get' : 'post', + path: `${path}/@querystring-search${ + settings.querystringSearchGet + ? `?query=${encodeURIComponent(JSON.stringify(query))}` + : '' + }`, + data: settings.querystringSearchGet ? null : query, }, }; } diff --git a/src/components/manage/BlockChooser/BlockChooser.jsx b/src/components/manage/BlockChooser/BlockChooser.jsx index 5c97683981..921d6b79a6 100644 --- a/src/components/manage/BlockChooser/BlockChooser.jsx +++ b/src/components/manage/BlockChooser/BlockChooser.jsx @@ -89,14 +89,18 @@ const BlockChooser = ({ function blocksAvailableFilter(blocks) { return blocks.filter( (block) => - getFormatMessage(block.title).toLowerCase().includes(filterValue) || + getFormatMessage(block.title) + .toLowerCase() + .includes(filterValue.toLowerCase()) || filterVariations(block)?.length, ); } function filterVariations(block) { return block.variations?.filter( (variation) => - getFormatMessage(variation.title).toLowerCase().includes(filterValue) && + getFormatMessage(variation.title) + .toLowerCase() + .includes(filterValue.toLowerCase()) && !variation.title.toLowerCase().includes('default'), ); } diff --git a/src/components/manage/Blocks/Listing/Edit.jsx b/src/components/manage/Blocks/Listing/Edit.jsx index 9f3d632b75..29fefe54cc 100644 --- a/src/components/manage/Blocks/Listing/Edit.jsx +++ b/src/components/manage/Blocks/Listing/Edit.jsx @@ -26,35 +26,16 @@ const messages = defineMessages({ const Edit = React.memo( (props) => { const { data, onChangeBlock, block, selected, pathname } = props; - const intl = useIntl(); - - // componentDidMount - React.useEffect(() => { - if (!data.query) { - onChangeBlock(block, { - ...data, - query: [], - block, - }); - } - /* eslint-disable react-hooks/exhaustive-deps */ - }, []); - const placeholder = data.placeholder || (data?.querystring?.query?.length ? intl.formatMessage(messages.results) : intl.formatMessage(messages.items)); - const HeadlineTag = data.headlineTag || 'h2'; - return ( <>

{placeholder}

- {data.headline && ( - {data.headline} - )} { ? variation.noResultsComponent : config.blocks?.blocksConfig['listing'].noResultsComponent; - return listingItems?.length > 0 ? ( -
- - {totalPages > 1 && ( -
- { - !isEditMode && - listingRef.current.scrollIntoView({ behavior: 'smooth' }); - onPaginationChange(e, { activePage }); - }} - firstItem={null} - lastItem={null} - prevItem={{ - content: , - icon: true, - 'aria-disabled': !prevBatch, - className: !prevBatch ? 'disabled' : null, - }} - nextItem={{ - content: , - icon: true, - 'aria-disabled': !nextBatch, - className: !nextBatch ? 'disabled' : null, - }} + const HeadlineTag = data.headlineTag || 'h2'; + + return ( + <> + {data.headline && ( + 0, + })} + > + {data.headline} + + )} + {listingItems?.length > 0 ? ( +
+ + {totalPages > 1 && ( +
+ { + !isEditMode && + listingRef.current.scrollIntoView({ behavior: 'smooth' }); + onPaginationChange(e, { activePage }); + }} + firstItem={null} + lastItem={null} + prevItem={{ + content: , + icon: true, + 'aria-disabled': !prevBatch, + className: !prevBatch ? 'disabled' : null, + }} + nextItem={{ + content: , + icon: true, + 'aria-disabled': !nextBatch, + className: !nextBatch ? 'disabled' : null, + }} + /> +
+ )} +
+ ) : isEditMode ? ( +
+ {isFolderContentsListing && ( + + )} + {hasLoaded && NoResults && ( + + )} + + + + + +
+ ) : ( +
+ {hasLoaded && NoResults && ( + + )} + + + + +
)} -
- ) : isEditMode ? ( -
- {isFolderContentsListing && ( - - )} - {hasLoaded && NoResults && ( - - )} - - - - - -
- ) : ( -
- {hasLoaded && NoResults && ( - - )} - - - - - -
+ ); }); diff --git a/src/components/manage/Blocks/Listing/View.jsx b/src/components/manage/Blocks/Listing/View.jsx index 5c69b38b0d..b70adfdf0b 100644 --- a/src/components/manage/Blocks/Listing/View.jsx +++ b/src/components/manage/Blocks/Listing/View.jsx @@ -7,15 +7,11 @@ import { ListingBlockBody as ListingBody } from '@plone/volto/components'; const View = (props) => { const { data, path, pathname, className } = props; - const HeadlineTag = data.headlineTag || 'h2'; return (
- {data.headline && ( - {data.headline} - )}
); diff --git a/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap b/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap index d91cbc9314..e81db3c83f 100644 --- a/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap +++ b/src/components/manage/Blocks/Listing/__snapshots__/ListingBody.test.jsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders a ListingBody component 1`] = ` -
+
{ +const getListingBlockAsyncData = ({ + dispatch, + id, + data, + path, + blocksConfig, +}) => { const { resolvedExtensions } = resolveBlockExtensions(data, blocksConfig); return [ @@ -14,8 +20,10 @@ export default ({ dispatch, data, path, blocksConfig }) => { ? { fullobjects: 1 } : { metadata_fields: '_all' }), }, - data.block, + id, ), ), ]; }; + +export default getListingBlockAsyncData; diff --git a/src/components/manage/Blocks/Listing/withQuerystringResults.jsx b/src/components/manage/Blocks/Listing/withQuerystringResults.jsx index d675fc050a..1b552e674b 100644 --- a/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +++ b/src/components/manage/Blocks/Listing/withQuerystringResults.jsx @@ -14,11 +14,16 @@ function getDisplayName(WrappedComponent) { export default function withQuerystringResults(WrappedComponent) { function WithQuerystringResults(props) { - const { data = {}, properties: content, path, variation } = props; + const { + data = {}, + id = data.block, + properties: content, + path, + variation, + } = props; const { settings } = config; const querystring = data.querystring || data; // For backwards compat with data saved before Blocks schema. Note, this is also how the Search block passes data to ListingBody - const { block } = data; const { b_size = settings.defaultPageSize } = querystring; // batchsize // save the path so it won't trigger dispatch on eager router location change @@ -45,32 +50,32 @@ export default function withQuerystringResults(WrappedComponent) { const folderItems = content?.is_folderish ? content.items : []; const hasQuery = querystring?.query?.length > 0; - const hasLoaded = hasQuery ? !querystringResults?.[block]?.loading : true; + const hasLoaded = hasQuery ? !querystringResults?.[id]?.loading : true; const listingItems = - querystring?.query?.length > 0 && querystringResults?.[block] - ? querystringResults?.[block]?.items || [] + querystring?.query?.length > 0 && querystringResults?.[id] + ? querystringResults?.[id]?.items || [] : folderItems; const showAsFolderListing = !hasQuery && content?.items_total > b_size; const showAsQueryListing = - hasQuery && querystringResults?.[block]?.total > b_size; + hasQuery && querystringResults?.[id]?.total > b_size; const totalPages = showAsFolderListing ? Math.ceil(content.items_total / b_size) : showAsQueryListing - ? Math.ceil(querystringResults[block].total / b_size) + ? Math.ceil(querystringResults[id].total / b_size) : 0; const prevBatch = showAsFolderListing ? content.batching?.prev : showAsQueryListing - ? querystringResults[block].batching?.prev + ? querystringResults[id].batching?.prev : null; const nextBatch = showAsFolderListing ? content.batching?.next : showAsQueryListing - ? querystringResults[block].batching?.next + ? querystringResults[id].batching?.next : null; const isImageGallery = @@ -80,7 +85,7 @@ export default function withQuerystringResults(WrappedComponent) { useDeepCompareEffect(() => { if (hasQuery) { dispatch( - getQueryStringResults(initialPath, adaptedQuery, block, currentPage), + getQueryStringResults(initialPath, adaptedQuery, id, currentPage), ); } else if (isImageGallery && !hasQuery) { // when used as image gallery, it doesn't need a query to list children @@ -98,14 +103,14 @@ export default function withQuerystringResults(WrappedComponent) { }, ], }, - block, + id, ), ); } else { dispatch(getContent(initialPath, null, null, currentPage)); } }, [ - block, + id, isImageGallery, adaptedQuery, hasQuery, @@ -118,7 +123,7 @@ export default function withQuerystringResults(WrappedComponent) { setCurrentPage(activePage)} - total={querystringResults?.[block]?.total} + total={querystringResults?.[id]?.total} batch_size={b_size} currentPage={currentPage} totalPages={totalPages} diff --git a/src/components/manage/Blocks/Search/SearchBlockEdit.jsx b/src/components/manage/Blocks/Search/SearchBlockEdit.jsx index 3f5b57bf91..0a3f222e9b 100644 --- a/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +++ b/src/components/manage/Blocks/Search/SearchBlockEdit.jsx @@ -1,5 +1,4 @@ -import React from 'react'; -import useDeepCompareEffect from 'use-deep-compare-effect'; +import React, { useEffect } from 'react'; import { defineMessages } from 'react-intl'; import { compose } from 'redux'; @@ -60,9 +59,11 @@ const SearchBlockEdit = (props) => { }; const { query = {} } = data || {}; - useDeepCompareEffect(() => { + // We don't need deep compare here, as this is just json serializable data. + const deepQuery = JSON.stringify(query); + useEffect(() => { onTriggerSearch(); - }, [query, onTriggerSearch]); + }, [deepQuery, onTriggerSearch]); return ( <> diff --git a/src/components/manage/Blocks/Search/SearchBlockView.jsx b/src/components/manage/Blocks/Search/SearchBlockView.jsx index 49135a6fe6..55580cd79a 100644 --- a/src/components/manage/Blocks/Search/SearchBlockView.jsx +++ b/src/components/manage/Blocks/Search/SearchBlockView.jsx @@ -57,7 +57,7 @@ const applyDefaults = (data, root) => { }; const SearchBlockView = (props) => { - const { data, searchData, mode = 'view', variation } = props; + const { id, data, searchData, mode = 'view', variation } = props; const Layout = variation.view; @@ -89,6 +89,7 @@ const SearchBlockView = (props) => { setSelectedView={setSelectedView} > (kvp.i === 'SearchableText' ? acc : [...acc, kvp]), - [], - ); + // Note Ideally the searchtext functionality should be restructured as being just + // another facet. But right now it's the same. This means that if a searchText + // is provided, it will override the SearchableText facet. + // If there is no searchText, the SearchableText in the query remains in effect. + // TODO eventually the searchText should be a distinct facet from SearchableText, and + // the two conditions could be combined, in comparison to the current state, when + // one overrides the other. if (searchText) { + params.query = params.query.reduce( + // Remove SearchableText from query + (acc, kvp) => (kvp.i === 'SearchableText' ? acc : [...acc, kvp]), + [], + ); params.query.push({ i: 'SearchableText', o: 'plone.app.querystring.operation.string.contains', @@ -278,8 +282,14 @@ const withSearch = (options) => (WrappedComponent) => { const timeoutRef = React.useRef(); const facetSettings = data?.facets; + const deepQuery = JSON.stringify(data.query); const onTriggerSearch = React.useCallback( - (toSearchText, toSearchFacets, toSortOn, toSortOrder) => { + ( + toSearchText = undefined, + toSearchFacets = undefined, + toSortOn = undefined, + toSortOrder = undefined, + ) => { if (timeoutRef.current) clearTimeout(timeoutRef.current); timeoutRef.current = setTimeout( () => { @@ -287,7 +297,7 @@ const withSearch = (options) => (WrappedComponent) => { id, query: data.query || {}, facets: toSearchFacets || facets, - searchText: toSearchText, + searchText: toSearchText || searchText, sortOn: toSortOn || sortOn, sortOrder: toSortOrder || sortOrder, facetSettings, @@ -301,11 +311,14 @@ const withSearch = (options) => (WrappedComponent) => { toSearchFacets ? inputDelay / 3 : inputDelay, ); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ - data.query, + // Use deep comparison of data.query + deepQuery, facets, id, setLocationSearchData, + searchText, sortOn, sortOrder, facetSettings, diff --git a/src/components/manage/Blocks/ToC/Edit.jsx b/src/components/manage/Blocks/ToC/Edit.jsx index 8932e9919b..fa31414fb6 100644 --- a/src/components/manage/Blocks/ToC/Edit.jsx +++ b/src/components/manage/Blocks/ToC/Edit.jsx @@ -26,6 +26,7 @@ class Edit extends Component { }} onChangeBlock={this.props.onChangeBlock} formData={this.props.data} + block={this.props.block} /> diff --git a/src/components/manage/Contents/Contents.jsx b/src/components/manage/Contents/Contents.jsx index 3e8c7708a2..291ed46c62 100644 --- a/src/components/manage/Contents/Contents.jsx +++ b/src/components/manage/Contents/Contents.jsx @@ -290,6 +290,10 @@ const messages = defineMessages({ id: 'This Page is referenced by the following items:', defaultMessage: 'This Page is referenced by the following items:', }, + deleteItemCountMessage: { + id: 'Total items to be deleted:', + defaultMessage: 'Total items to be deleted:', + }, deleteItemMessage: { id: 'Items to be deleted:', defaultMessage: 'Items to be deleted:', @@ -418,6 +422,8 @@ class Contents extends Component { this.paste = this.paste.bind(this); this.fetchContents = this.fetchContents.bind(this); this.orderTimeout = null; + this.deleteItemsToShowThreshold = 10; + this.state = { selected: [], showDelete: false, @@ -427,6 +433,7 @@ class Contents extends Component { showProperties: false, showWorkflow: false, itemsToDelete: [], + showAllItemsToDelete: true, items: this.props.items, filter: '', currentPage: 0, @@ -456,7 +463,6 @@ class Contents extends Component { this.fetchContents(); this.setState({ isClient: true }); } - async componentDidUpdate(_, prevState) { if ( this.state.itemsToDelete !== prevState.itemsToDelete && @@ -468,6 +474,8 @@ class Contents extends Component { this.getFieldById(item, 'UID'), ), ), + showAllItemsToDelete: + this.state.itemsToDelete.length < this.deleteItemsToShowThreshold, }); } } @@ -788,18 +796,20 @@ class Contents extends Component { */ onMoveToTop(event, { value }) { const id = this.state.items[value]['@id']; - value = this.state.currentPage * this.state.pageSize + value; - this.props.orderContent( - getBaseUrl(this.props.pathname), - id.replace(/^.*\//, ''), - -value, - ); - this.setState( - { - currentPage: 0, - }, - () => this.fetchContents(), - ); + this.props + .orderContent( + getBaseUrl(this.props.pathname), + id.replace(/^.*\//, ''), + 'top', + ) + .then(() => { + this.setState( + { + currentPage: 0, + }, + () => this.fetchContents(), + ); + }); } /** @@ -810,18 +820,21 @@ class Contents extends Component { * @returns {undefined} */ onMoveToBottom(event, { value }) { - this.onOrderItem( - this.state.items[value]['@id'], - value, - this.state.items.length - 1 - value, - false, - ); - this.onOrderItem( - this.state.items[value]['@id'], - value, - this.state.items.length - 1 - value, - true, - ); + const id = this.state.items[value]['@id']; + this.props + .orderContent( + getBaseUrl(this.props.pathname), + id.replace(/^.*\//, ''), + 'bottom', + ) + .then(() => { + this.setState( + { + currentPage: 0, + }, + () => this.fetchContents(), + ); + }); } /** @@ -1188,16 +1201,35 @@ class Contents extends Component {

{this.props.intl.formatMessage( - messages.deleteItemMessage, - )} + messages.deleteItemCountMessage, + ) + ` ${this.state.itemsToDelete.length}`}

    - {map(this.state.itemsToDelete, (item) => ( -
  • - {this.getFieldById(item, 'title')} -
  • - ))} + {map( + this.state.showAllItemsToDelete + ? this.state.itemsToDelete + : this.state.itemsToDelete.slice( + 0, + this.deleteItemsToShowThreshold, + ), + (item) => ( +
  • + {this.getFieldById(item, 'title')} +
  • + ), + )}
+ {!this.state.showAllItemsToDelete && ( + + )} {this.state.linkIntegrityBreakages.length > 0 ? (

diff --git a/src/components/manage/Controlpanels/AddonsControlpanel.jsx b/src/components/manage/Controlpanels/AddonsControlpanel.jsx index a1f8a8b384..1248c90cbf 100644 --- a/src/components/manage/Controlpanels/AddonsControlpanel.jsx +++ b/src/components/manage/Controlpanels/AddonsControlpanel.jsx @@ -43,7 +43,7 @@ const messages = defineMessages({ addAddons: { id: 'Add Addons', defaultMessage: - 'To make new add-ons show up here, add them to your buildout configuration, run buildout, and restart the server process. For detailed instructions see', + 'To make new add-ons show up here, add them to your configuration, build, and restart the server process. For detailed instructions see', }, addonsSettings: { id: 'Add-ons Settings', @@ -380,11 +380,11 @@ class AddonsControlpanel extends Component {   diff --git a/src/components/manage/Controlpanels/Controlpanels.jsx b/src/components/manage/Controlpanels/Controlpanels.jsx index ce248ee66e..a2a883b133 100644 --- a/src/components/manage/Controlpanels/Controlpanels.jsx +++ b/src/components/manage/Controlpanels/Controlpanels.jsx @@ -270,7 +270,7 @@ class Controlpanels extends Component { {group} , - + {map(filter(controlpanels, { group }), (controlpanel) => ( diff --git a/src/components/manage/Controlpanels/__snapshots__/AddonsControlpanel.test.jsx.snap b/src/components/manage/Controlpanels/__snapshots__/AddonsControlpanel.test.jsx.snap index 220fa5bff8..78ea65bb56 100644 --- a/src/components/manage/Controlpanels/__snapshots__/AddonsControlpanel.test.jsx.snap +++ b/src/components/manage/Controlpanels/__snapshots__/AddonsControlpanel.test.jsx.snap @@ -31,10 +31,10 @@ exports[`AddonsControlpanel renders an addon control component 1`] = ` > Activate and deactivate add-ons in the lists below.

- To make new add-ons show up here, add them to your buildout configuration, run buildout, and restart the server process. For detailed instructions see + To make new add-ons show up here, add them to your configuration, build, and restart the server process. For detailed instructions see   diff --git a/src/components/manage/Controlpanels/__snapshots__/Controlpanels.test.jsx.snap b/src/components/manage/Controlpanels/__snapshots__/Controlpanels.test.jsx.snap index e8accacfc2..aafd79a1dd 100644 --- a/src/components/manage/Controlpanels/__snapshots__/Controlpanels.test.jsx.snap +++ b/src/components/manage/Controlpanels/__snapshots__/Controlpanels.test.jsx.snap @@ -24,7 +24,7 @@ exports[`Controlpanels renders a controlpanels component 1`] = ` className="ui attached segment" >
{ +const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex, uid) => { // Because of the margin rendering rules, there is no easy // way to calculate the offset of the placeholder. // @@ -13,12 +13,16 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => { // // To get a placeholder that looks good in all cases, we // fill up the space between the previous and the next element. - const childrenArray = [...draggedDOM.parentNode.children]; + const queryAttr = 'data-rbd-droppable-id'; + const domQuery = `[${queryAttr}='${uid}']`; + const parentDOM = document.querySelector(domQuery); + + const childrenArray = [...parentDOM.children]; // Remove the source element childrenArray.splice(sourceIndex, 1); // Also remove the placeholder that the library always inserts at the end childrenArray.splice(-1, 1); - const parentRect = draggedDOM.parentNode.getBoundingClientRect(); + const parentRect = parentDOM.getBoundingClientRect(); const prevNode = childrenArray[destinationIndex - 1]; const nextNode = childrenArray[destinationIndex]; let top, bottom; @@ -40,9 +44,7 @@ const getPlaceholder = (draggedDOM, sourceIndex, destinationIndex) => { return { clientY: top, clientHeight: bottom - top, - clientX: parseFloat( - window.getComputedStyle(draggedDOM.parentNode).paddingLeft, - ), + clientX: parseFloat(window.getComputedStyle(parentDOM).paddingLeft), clientWidth: draggedDOM.clientWidth, }; }; @@ -63,17 +65,22 @@ const DragDropList = (props) => { // queueing timed action const timer = useRef(null); - const onDragStart = React.useCallback((event) => { - clearTimeout(timer.current); - const queryAttr = 'data-rbd-draggable-id'; - const domQuery = `[${queryAttr}='${event.draggableId}']`; - const draggedDOM = document.querySelector(domQuery); - if (!draggedDOM) { - return; - } - const sourceIndex = event.source.index; - setPlaceholderProps(getPlaceholder(draggedDOM, sourceIndex, sourceIndex)); - }, []); + const onDragStart = React.useCallback( + (event) => { + clearTimeout(timer.current); + const queryAttr = 'data-rbd-draggable-id'; + const domQuery = `[${queryAttr}='${event.draggableId}']`; + const draggedDOM = document.querySelector(domQuery); + if (!draggedDOM) { + return; + } + const sourceIndex = event.source.index; + setPlaceholderProps( + getPlaceholder(draggedDOM, sourceIndex, sourceIndex, uid), + ); + }, + [uid], + ); const onDragEnd = React.useCallback( (result) => { @@ -84,30 +91,33 @@ const DragDropList = (props) => { [onMoveItem], ); - const onDragUpdate = React.useCallback((update) => { - clearTimeout(timer.current); - setPlaceholderProps({}); - if (!update.destination) { - return; - } - const draggableId = update.draggableId; - const queryAttr = 'data-rbd-draggable-id'; - const domQuery = `[${queryAttr}='${draggableId}']`; - const draggedDOM = document.querySelector(domQuery); - if (!draggedDOM) { - return; - } - const sourceIndex = update.source.index; - const destinationIndex = update.destination.index; - // Wait until the animations have finished, to make it look good. - timer.current = setTimeout( - () => - setPlaceholderProps( - getPlaceholder(draggedDOM, sourceIndex, destinationIndex), - ), - 250, - ); - }, []); + const onDragUpdate = React.useCallback( + (update) => { + clearTimeout(timer.current); + setPlaceholderProps({}); + if (!update.destination) { + return; + } + const draggableId = update.draggableId; + const queryAttr = 'data-rbd-draggable-id'; + const domQuery = `[${queryAttr}='${draggableId}']`; + const draggedDOM = document.querySelector(domQuery); + if (!draggedDOM) { + return; + } + const sourceIndex = update.source.index; + const destinationIndex = update.destination.index; + // Wait until the animations have finished, to make it look good. + timer.current = setTimeout( + () => + setPlaceholderProps( + getPlaceholder(draggedDOM, sourceIndex, destinationIndex, uid), + ), + 250, + ); + }, + [uid], + ); const AsDomComponent = as; return ( @@ -116,7 +126,18 @@ const DragDropList = (props) => { onDragUpdate={onDragUpdate} onDragEnd={onDragEnd} > - + { + const index = rubric.source.index; + return children({ + child: childList[index][1], + childId: childList[index][0], + index, + draginfo: provided, + }); + }} + > {(provided, snapshot) => ( +