diff --git a/.github/ISSUE_TEMPLATE/PLIP.md b/.github/ISSUE_TEMPLATE/PLIP.md new file mode 100644 index 0000000000..ba65da284c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/PLIP.md @@ -0,0 +1,64 @@ +--- +name: "\U0001F680 PLIP" +about: Plone Improvement Proposal +title: '' +labels: '' +assignees: '' + +--- + +## PLIP (Plone Improvement Proposal) + + + +## Responsible Persons + +### Proposer: + +### Seconder: + +## Abstract + + + +## Motivation + + + +## Assumptions + + + +## Proposal & Implementation + + + +## Deliverables + + + +## Risks + + + +## Participants + + diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index bf63dd0a24..cea3058c29 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -1,13 +1,15 @@ 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 strategy: + fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] steps: - uses: actions/checkout@v3 @@ -22,7 +24,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -39,7 +41,7 @@ jobs: start: | make start-test-acceptance-server make start-test-acceptance-frontend - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -55,12 +57,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] steps: - uses: actions/checkout@v3 @@ -75,7 +79,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -92,7 +96,7 @@ jobs: start: | make start-test-acceptance-server make start-test-acceptance-frontend - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -108,12 +112,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] steps: - uses: actions/checkout@v3 @@ -125,10 +131,10 @@ jobs: cache: 'yarn' ## node install - - run: yarn --frozen-lockfile + - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -145,7 +151,7 @@ jobs: start: | make start-test-acceptance-server make start-test-acceptance-frontend - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -161,11 +167,13 @@ 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: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -180,7 +188,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -192,12 +200,12 @@ jobs: record: true parallel: false # Since they run on different node versions, we can't parallel browser: chrome - group: Core Basic - Plone 6 + group: Core Basic - Plone 5 spec: cypress/tests/core/basic/**/*.js start: | make start-test-acceptance-server-5 make start-test-acceptance-frontend - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -213,13 +221,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] - python-version: [3.7] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -232,32 +241,8 @@ jobs: - run: yarn --immutable - # python setup (temporary, while p.volto coresandbox changes are in a PR) - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v1 - # with: - # python-version: ${{ matrix.python-version }} - - # # python cache - # - uses: actions/cache@v1 - # with: - # path: ~/.cache/pip - # key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - # restore-keys: | - # ${{ runner.os }}-pip- - # # python install - # - run: pip install virtualenv - # - name: pip install - # working-directory: api - # run: pip install -r requirements.txt - # - name: buildout - # working-directory: api - # run: buildout - # env: - # CI: true - - name: Cypress Coresandbox Acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -274,7 +259,7 @@ jobs: start: | make start-test-acceptance-server-coresandbox make start-test-acceptance-frontend-coresandbox - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -290,12 +275,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -310,7 +297,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_API: guillotina @@ -328,7 +315,7 @@ jobs: start: | make start-test-acceptance-server-guillotina make start-test-acceptance-frontend-guillotina - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:8081 http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:8081 http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -344,12 +331,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -364,7 +353,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -381,7 +370,7 @@ jobs: start: | make start-test-acceptance-server-multilingual make start-test-acceptance-frontend-multilingual - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -397,12 +386,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] # python-version: [3.7] steps: - uses: actions/checkout@v3 @@ -442,7 +433,7 @@ jobs: # CI: true - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -459,7 +450,7 @@ jobs: start: | make start-test-acceptance-server-workingcopy make start-test-acceptance-frontend-workingcopy - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -475,12 +466,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] env: generator-directory: ./packages/generator-volto project-directory: ./my-volto-app @@ -530,7 +523,7 @@ jobs: working-directory: ${{env.project-directory}} - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -547,7 +540,7 @@ jobs: start: | make start-test-acceptance-server make start-test-acceptance-frontend-project - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 @@ -569,12 +562,14 @@ 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 strategy: + fail-fast: false matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -589,7 +584,7 @@ jobs: - run: yarn --immutable - name: Cypress acceptance tests - uses: cypress-io/github-action@v4 + uses: cypress-io/github-action@v5 env: BABEL_ENV: production CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} @@ -608,7 +603,7 @@ jobs: make start-test-acceptance-server make start-test-acceptance-frontend-seamless make start-test-acceptance-webserver-seamless - wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000 http://localhost' + wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000 http://localhost' # Upload Cypress screenshots - uses: actions/upload-artifact@v1 diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index a358cc3303..9b4db344de 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -1,12 +1,13 @@ 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: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -24,11 +25,12 @@ 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: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 @@ -46,11 +48,12 @@ 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: matrix: - node-version: [16.x] + node-version: [18.x] steps: - uses: actions/checkout@v3 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/towncrier.yml b/.github/workflows/towncrier.yml new file mode 100644 index 0000000000..16f68d2cf5 --- /dev/null +++ b/.github/workflows/towncrier.yml @@ -0,0 +1,32 @@ +name: Towncrier check +on: + pull_request: + types: [assigned, opened, synchronize, reopened, labeled, unlabeled] + branches: + - master + +env: + node-version: 16.x + +jobs: + towncrier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + # Fetch all history + fetch-depth: '0' + + - name: Install towncrier + run: pip install towncrier + + - name: Check for presence of a Change Log fragment (only pull requests) + run: | + # Fetch the pull request' base branch so towncrier will be able to + # compare the current branch with the base branch. + # Source: https://github.com/actions/checkout/#fetch-all-branches. + git fetch --no-tags origin master + towncrier check --compare-with origin/master + env: + BASE_BRANCH: ${{ github.base_ref }} + if: github.event_name == 'pull_request' diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 3f75baa2ba..97428e6fe3 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -1,12 +1,14 @@ 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: + fail-fast: false matrix: - node-version: [14.x, 16.x] + node-version: [16.x, 18.x] steps: - uses: actions/checkout@v3 @@ -28,4 +30,3 @@ jobs: - uses: jackyef/bundlewatch-gh-action@master with: bundlewatch-github-token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }} - diff --git a/.gitignore b/.gitignore index cec0add449..ebcc210125 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ junit.xml eslint.xml yarn-error.log build +.changelog.draft # yarn 3 .pnp.* @@ -28,6 +29,8 @@ lighthouse-report.html .vscode/ .#* *~ +/.settings/ +.*project # Python /api/.installed.cfg @@ -72,6 +75,7 @@ selenium-screenshot-*.png /selenium/ cypress/videos/ cypress/screenshots +/styles/Microsoft # Local environment setup .env @@ -80,3 +84,4 @@ public/critical.css # Sphinx and MyST docs/_build/ /.python-version +/.tool-versions diff --git a/.storybook/main.js b/.storybook/main.js index cc042c2800..7109389c34 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -3,14 +3,10 @@ const fs = require('fs'); const path = require('path'); const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder'); const fileLoaderFinder = makeLoaderFinder('file-loader'); - const projectRootPath = path.resolve('.'); -const createAddonsLoader = require('../create-addons-loader'); const lessPlugin = require('../webpack-plugins/webpack-less-plugin'); - const createConfig = require('../node_modules/razzle/config/createConfigAsync.js'); const razzleConfig = require(path.join(projectRootPath, 'razzle.config.js')); - const SVGLOADER = { test: /icons\/.*\.svg$/, use: [ @@ -21,16 +17,22 @@ const SVGLOADER = { loader: 'svgo-loader', options: { plugins: [ - { removeTitle: true }, - { convertPathData: false }, - { removeUselessStrokeAndFill: true }, - { removeViewBox: false }, + { + name: 'preset-default', + params: { + overrides: { + convertPathData: false, + removeViewBox: false, + }, + }, + }, + 'removeTitle', + 'removeUselessStrokeAndFill', ], }, }, ], }; - const defaultRazzleOptions = { verbose: false, debug: {}, @@ -46,97 +48,80 @@ const defaultRazzleOptions = { staticCssInDev: false, emitOnErrors: false, disableWebpackbar: false, - browserslist: [ - '>1%', - 'last 4 versions', - 'Firefox ESR', - 'not ie 11', - 'not dead', - ], + browserslist: ['>1%', 'last 4 versions', 'Firefox ESR', 'not ie 11', 'not dead'] }; - module.exports = { stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], addons: ['@storybook/addon-links', '@storybook/addon-essentials'], - webpackFinal: async (config, { configType }) => { + staticDirs: ['./static'], + webpackFinal: async (config, { + configType + }) => { // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION' // You can change the configuration based on that. // 'PRODUCTION' is used when building the static version of storybook. // Make whatever fine-grained changes you need let baseConfig; - baseConfig = await createConfig( - 'web', - 'dev', - { - // clearConsole: false, - modifyWebpackConfig: razzleConfig.modifyWebpackConfig, - plugins: razzleConfig.plugins, - }, - webpack, - false, - undefined, - [], - defaultRazzleOptions, - ); + baseConfig = await createConfig('web', 'dev', { + // clearConsole: false, + modifyWebpackConfig: razzleConfig.modifyWebpackConfig, + plugins: razzleConfig.plugins + }, webpack, false, undefined, [], defaultRazzleOptions); const AddonConfigurationRegistry = require('../addon-registry'); - const registry = new AddonConfigurationRegistry(projectRootPath); - - config = lessPlugin({ registry }).modifyWebpackConfig({ - env: { target: 'web', dev: 'dev' }, + config = lessPlugin({ + registry + }).modifyWebpackConfig({ + env: { + target: 'web', + dev: 'dev' + }, webpackConfig: config, webpackObject: webpack, - options: {}, + options: {} }); - // putting SVG loader on top, fix the fileloader manually (Volto plugin does not - // work) since it needs to go first + // Put the SVG loader on top and prevent the asset/resource rule + // from processing the app's SVGs config.module.rules.unshift(SVGLOADER); - const fileLoader = config.module.rules.find(fileLoaderFinder); - fileLoader.exclude = [/\.(config|variables|overrides)$/, /icons\/.*\.svg$/]; - - config.plugins.unshift( - new webpack.DefinePlugin({ - __DEVELOPMENT__: true, - __CLIENT__: true, - __SERVER__: false, - }), - ); - + const fileLoaderRule = config.module.rules.find(rule => rule.test.test('.svg')); + fileLoaderRule.exclude = /icons\/.*\.svg$/; + config.plugins.unshift(new webpack.DefinePlugin({ + __DEVELOPMENT__: true, + __CLIENT__: true, + __SERVER__: false + })); const resultConfig = { ...config, resolve: { ...config.resolve, - alias: { ...config.resolve.alias, ...baseConfig.resolve.alias }, - }, + alias: { + ...config.resolve.alias, + ...baseConfig.resolve.alias + } + } }; // Addons have to be loaded with babel - const addonPaths = registry.addonNames.map((addon) => - fs.realpathSync(registry.packages[addon].modulePath), - ); - resultConfig.module.rules[1].exclude = (input) => + const addonPaths = registry.addonNames.map(addon => fs.realpathSync(registry.packages[addon].modulePath)); + resultConfig.module.rules[1].exclude = input => // exclude every input from node_modules except from @plone/volto /node_modules\/(?!(@plone\/volto)\/)/.test(input) && // If input is in an addon, DON'T exclude it - !addonPaths.some((p) => input.includes(p)); - + !addonPaths.some(p => input.includes(p)); return resultConfig; }, - babel: async (options) => { + babel: async options => { return { ...options, - plugins: [ - ...options.plugins, - [ - './node_modules/babel-plugin-root-import/build/index.js', - { - rootPathSuffix: './src', - }, - ], - ], + plugins: [...options.plugins, ['./node_modules/babel-plugin-root-import/build/index.js', { + rootPathSuffix: './src' + }]] // any extra options you want to set }; }, -}; + core: { + builder: 'webpack5' + } +}; \ No newline at end of file diff --git a/.storybook/static/previewImage.svg b/.storybook/static/previewImage.svg new file mode 100644 index 0000000000..4405bade78 --- /dev/null +++ b/.storybook/static/previewImage.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + 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 8c23ee6892..f47070e07f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,964 @@ -# Change Log +# Volto Release Notes -## 16.0.0 (unreleased) + + + + +## 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 + +- - 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) +- Use popperjs in BlockChooser, move the markup to the bottom of the body tag. @sneridagh [#4141](https://github.com/plone/volto/issues/4141) +- Improvements to the dev API proxy: + - Prefer RAZZLE_INTERNAL_API_PATH over RAZZLE_API_PATH as the target of the proxy. + The target of the API proxy is now always logged on startup, even in production mode. + - Support proxying to a backend served over https. For this configuration it + might be necessary to set RAZZLE_DEV_PROXY_INSECURE=1 if the backend + certificate can't be verified. + + [davisagli] [#4434](https://github.com/plone/volto/issues/4434) + +### Bugfix + +- fix: newsitem and event views wrapper classNames @nzambello [#4443](https://github.com/plone/volto/issues/4443) +- Fix weird GHA failure on config option not supported @sneridagh [#4466](https://github.com/plone/volto/issues/4466) +- Fix history view dropdown for first entry, showing 'Revert to this version option' always @sneridagh [#4471](https://github.com/plone/volto/issues/4471) +- Fix order of row of long table in edit and view mode @iFlameing [#4473](https://github.com/plone/volto/issues/4473) +- Improve flaky test in autofocus Cypress tests @sneridagh [#4475](https://github.com/plone/volto/issues/4475) + +### Documentation + +- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/issues/4461) +- Change from links to inline literals in `CHANGELOG.md` to fix linkcheckbroken. @stevepiercy [#4470](https://github.com/plone/volto/issues/4470) + + +## 17.0.0-alpha.0 (2023-03-04) + +### Breaking + +- Volto 17 drops support for NodeJS 14, and adds support for NodeJS 18. + Please see the [upgrade guide](https://6.docs.plone.org/volto/upgrade-guide/index.html) + for more information. + + Volto 17 now uses Webpack 5. [#4086](https://github.com/plone/volto/issues/4086) + +### Internal + +- Add HI-ERN website to "Volto in Production" section in README @steffenri [#4172](https://github.com/plone/volto/issues/4172) + +### Documentation + +- Add a new Volto site to the README @erral [#4158](https://github.com/plone/volto/issues/4158), [#4170](https://github.com/plone/volto/issues/4170) +- Add new websites Lanku and UEU + [erral] [#4310](https://github.com/plone/volto/issues/4310) +- Fix English and MyST grammar and syntax from PR #4285 @stevepiercy [#4331](https://github.com/plone/volto/issues/4331) +- Use a universal static path for both documentation and volto repos. @stevepiercy [#4376](https://github.com/plone/volto/issues/4376) + + +## 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 + +- Improvements to the dev API proxy: + - Prefer RAZZLE_INTERNAL_API_PATH over RAZZLE_API_PATH as the target of the proxy. + The target of the API proxy is now always logged on startup, even in production mode. + - Support proxying to a backend served over https. For this configuration it + might be necessary to set RAZZLE_DEV_PROXY_INSECURE=1 if the backend + certificate can't be verified. + + [davisagli] [#4434](https://github.com/plone/volto/issues/4434) + +### Bugfix + +- fix: newsitem and event views wrapper classNames @nzambello [#4443](https://github.com/plone/volto/issues/4443) +- Fix weird GHA failure on config option not supported @sneridagh [#4466](https://github.com/plone/volto/issues/4466) +- Fix history view dropdown for first entry, showing 'Revert to this version option' always @sneridagh [#4471](https://github.com/plone/volto/issues/4471) +- Fix order of row of long table in edit and view mode @iFlameing [#4473](https://github.com/plone/volto/issues/4473) + +### Documentation + +- Complete teaser docs, add new section in `Blocks`: `Core Blocks developers notes` @sneridagh [#4461](https://github.com/plone/volto/issues/4461) + + +## 16.14.0 (2023-03-03) + +### Feature + +- Add `Teaser` block @sneridagh [#3706](https://github.com/plone/volto/issues/3706) + + +## 16.13.0 (2023-03-02) + +### Feature + +- Added a default Component to show when the Listing block has no results, and another only for the ImageGallery variation. Both of them registered in the block registration config. @ionlizarazu [#3602](https://github.com/plone/volto/issues/3602) +- Add GHA Towncrier syntax checker @sneridagh [#4450](https://github.com/plone/volto/issues/4450) + +### Bugfix + +- On SSR-generated error pages, don't change the user's language to the default site language @tiberiuichim [#4425](https://github.com/plone/volto/issues/4425) + +### Internal + +- Expose a named export for the App component, separate its default wrappers as a separate `connectAppComponent` function. @tiberiuichim [#4413](https://github.com/plone/volto/issues/4413) +- Use latest plone/server breed images @sneridagh [#4454](https://github.com/plone/volto/issues/4454) + +### Documentation + +- Fix links, convert features to definition list, add link to issue for TODO. @stevepiercy [#4431](https://github.com/plone/volto/issues/4431) +- Update link to Yarn 3 Workspaces to avoid redirect to Yarn Classic 1.x. @stevepiercy [#4441](https://github.com/plone/volto/issues/4441) + + +## 16.12.0 (2023-02-21) + +### Feature + +- Provide disabled props to all widgets, and pass disabled props in to babel views. @iFlameing [#4396](https://github.com/plone/volto/issues/4396) + +### Bugfix + +- fix : Restrictive propTypes for widgets . @suman9893 [#4150](https://github.com/plone/volto/issues/4150) +- Add the intl string 'Uploading image' to the image block @bipoza [#4180](https://github.com/plone/volto/issues/4180) +- Fix link integrity overlay is too narrowed @iFlameing [#4399](https://github.com/plone/volto/issues/4399) +- Fix External link Icon shows up in Grid-text block @iRohitSingh [#4400](https://github.com/plone/volto/issues/4400) +- Fix broken links: `babeljs.io/…` @ksuess [#4414](https://github.com/plone/volto/issues/4414) + +### Documentation + +- Remove inclusion of `CHANGELOG.md` for volto repo only. Fixes https://github.com/plone/documentation/issues/1431. @stevepiercy [#4404](https://github.com/plone/volto/issues/4404) + + +## 16.11.0 (2023-02-13) + +### Feature + +- Add open external link in a new tab config option. @robgietema [#4379](https://github.com/plone/volto/issues/4379) +- Add scss support in core @sneridagh [#4383](https://github.com/plone/volto/issues/4383) +- Use open in new tab setting for link types. @robgietema [#4384](https://github.com/plone/volto/issues/4384) + +### Bugfix + +- Fix Cannot read properties of undefined (reading 'translations') @avoinea [#4377](https://github.com/plone/volto/issues/4377) + + +## 16.10.0 (2023-02-06) + +### Feature + +- Option for opening /edit with the same vertical offset like the page in view mode before. @ksuess [#3662](https://github.com/plone/volto/issues/3662) +- Add option to add an action button to the top of the toolbar and to add a menu button to the bottom of the toolbar. @ksuess [#4333](https://github.com/plone/volto/issues/4333) +- Update to latest versions in the backend for testing and the convenience api folder @sneridagh [#4361](https://github.com/plone/volto/issues/4361) +- Content Rules: Support server-provided schema for condition and action @ericof [#4368](https://github.com/plone/volto/issues/4368) + +### Bugfix + +- Fix react-error-overlay resolution @sneridagh [#4360](https://github.com/plone/volto/issues/4360) + +### Documentation + +- Add documentation for copy, cut, and paste blocks in Volto. @MAX-786 [#3827](https://github.com/plone/volto/issues/3827) +- Fixed Grammar error @SaiRev0 [#4272](https://github.com/plone/volto/issues/4272) + + +## 16.9.0 (2023-01-27) + +### Feature + +- Enable scrolling to ids via hashes in internal links @jackahl [#4165](https://github.com/plone/volto/issues/4165) +- Read listing block schema from configuration registry @pnicolli [#4231](https://github.com/plone/volto/issues/4231) +- Add displayName when registering a component @sneridagh [#4282](https://github.com/plone/volto/issues/4282) +- Support for all default expanders (breadcrumbs, navigation, actions, types) in actions/reducers. Conditional loading of actions if the expanders are present. @sneridagh [#4285](https://github.com/plone/volto/issues/4285) +- Add `addNewBlock` Cypress support command @sneridagh [#4313](https://github.com/plone/volto/issues/4313) + +### Bugfix + +- Fixed maxLength validation for string type fields @pnicolli [#4189](https://github.com/plone/volto/issues/4189) +- bugfix : add pathname as required proptype in Blocks/Edit @akshatgarg12 [#4194](https://github.com/plone/volto/issues/4194) +- (Fix) Select Widgets scrolls the page when the options are not visible @dobri1408 [#4223](https://github.com/plone/volto/issues/4223) +- Updated volto-slate to check for slateSettings before falling back to config @danalvrz [#4311](https://github.com/plone/volto/issues/4311) +- Fix bug where label of search facet wasn't translated when the content object is being translated @robgietema [#4306](https://github.com/plone/volto/issues/4306) + +### Internal + +- Updated 4 Dependencies @SaiRev0 [#4104](https://github.com/plone/volto/issues/4104) + + +## 16.8.1 (2023-01-18) + +### Bugfix + +- Fix StyleWrapper extenders, the classNames were not being re-fed into the pipe @sneridagh [#4275](https://github.com/plone/volto/issues/4275) + + +## 16.8.0 (2023-01-18) + +### Feature + +- Autocomplete widget support for QueryStringWidget @sneridagh [#4177](https://github.com/plone/volto/issues/4177) +- Enhance the StyleWrapper classNames generator by adding look around classNames depending on the sorounding previous/next blocks. @sneridagh [#4260](https://github.com/plone/volto/issues/4260) + +### Bugfix + +- Fix typo in 4260 @sneridagh [#4268](https://github.com/plone/volto/issues/4268) + +### Documentation + +- Update links to docs to use correct versions. [stevepiercy] [#4256](https://github.com/plone/volto/issues/4256) + + +## 16.7.0 (2023-01-11) + +### Feature + +- Show project name and version in control panel @sneridagh [#4176](https://github.com/plone/volto/issues/4176) +- Enhance Cypress content creation command @sneridagh [#4210](https://github.com/plone/volto/issues/4210) + +### Bugfix + +- Use Grid instead of Table in Diffview @erral +- Improve matching in keyboard slash menu. [davisagli] [#4187](https://github.com/plone/volto/issues/4187) +- (fix): sidebar is not displaying correctly when clicking on a lead image field. @dobri1408 [#4191](https://github.com/plone/volto/issues/4191) +- Cleanup `package.json` scripts section @sneridagh [#4193](https://github.com/plone/volto/issues/4193) +- Fixed condition to select without vocabulary @SaraBianchi [#4200](https://github.com/plone/volto/issues/4200) +- fix iframe covering the page due to a react-error-overlay bug @reebalazs [#4242](https://github.com/plone/volto/issues/4242) + +### Documentation + +- Add description for different types of blocks. @MAX-786 [#3827](https://github.com/plone/volto/issues/3827) +- Update makefile to use Vale for spell, grammar, and style checking. Fix linkcheckbroken to return the correct exit code for broken links. Fix broken links. [stevepiercy] [#4181](https://github.com/plone/volto/issues/4181) +- Add todo regarding management of Plone's backend. Update versions. [stevepiercy] [#4198](https://github.com/plone/volto/issues/4198) +- Pin Sphinx<5,>=3 due to sphinx-book-theme 0.3.3 requirement. [stevepiercy] [#4199](https://github.com/plone/volto/issues/4199) +- Add message about the status of Volto and Plone 6 Installation docs, directing the reader to the main Plone 6 docs. [stevepiercy] [#4209](https://github.com/plone/volto/issues/4209) +- Clean up Glossary and integrate with main docs. See https://github.com/plone/documentation/issues/1415. [stevepiercy] [#4211](https://github.com/plone/volto/issues/4211) +- Add some instructions for dealing with untranspiled add-ons and a lazy loading example for functional components. [cguardia] [#4233](https://github.com/plone/volto/issues/4233) + + +## 16.6.0 (2022-12-23) + +### Feature + +- Allow passing the `step` prop to NumberWidget @tiberiuichim [#4152](https://github.com/plone/volto/issues/4152) + +### Bugfix + +- Fix categorization list is not readable when there are longer values or filtering @iFlameing [#4113](https://github.com/plone/volto/issues/4113) +- Add scroll into view settings @robgietema [#4140](https://github.com/plone/volto/issues/4140) +- Remove searching capabilities of SortOn component of Search Block @iFlameing [#4162](https://github.com/plone/volto/issues/4162) +- Fixed externalRoutes short version @pnicolli [#4182](https://github.com/plone/volto/issues/4182) + +### Documentation + +- Fix URLs to Plone 6 docs. @stevepiercy [#4143](https://github.com/plone/volto/issues/4143) +- Fix Sphinx warning Document headings start at H2, not H1 [myst.header]. @stevepiercy [#4145](https://github.com/plone/volto/issues/4145) + + +## 16.5.0 (2022-12-16) + +### Feature + +- Update pt_BR translation @rafahela [#4121](https://github.com/plone/volto/issues/4121) + +### Bugfix + +- Update SlashMenu to include block title in shortcut search; and prevent default on keydown for Arrows and Enter @danalvrz [#4116](https://github.com/plone/volto/issues/4116) +- Fix removing of toast notification of logout when user login once again. @iFlameing [#4125](https://github.com/plone/volto/issues/4125) + +### Internal + +- Upgrade testbed and convenience api folder to Plone 6 final @sneridagh [#4105](https://github.com/plone/volto/issues/4105) + + +## 16.4.1 (2022-12-13) + +### Bugfix + +- For hot reloading purposes when developing code, the Volto package is no longer excluded @tiberiuichim [#4108](https://github.com/plone/volto/issues/4108) +- Remove clean-css from the CSS minimizing step, use css-minimizer-webpack-plugin one instead @sneridagh [#4115](https://github.com/plone/volto/issues/4115) + + +## 16.4.0 (2022-12-12) + +### Feature + +- Update Traefik version and make volume mount (docker-compose) read-only [#4067](https://github.com/plone/volto/issues/4067) +- Allow addons to provide an `eslint.extend.js` file that customizez eslint configuration @tiberiuichim [#4072](https://github.com/plone/volto/issues/4072) + +### Bugfix + +- Update Chinese translation @adam139 [#4009](https://github.com/plone/volto/issues/4009) +- Reset value of search field after submit. [@MAX-786] [#4028](https://github.com/plone/volto/issues/4028) +- Don't crash the view page when dealing with unknown blocks @tiberiuichim [#4070](https://github.com/plone/volto/issues/4070) +- Bump version for plone-backend version used in Makefile @tiberiuichim [#4071](https://github.com/plone/volto/issues/4071) +- Properly handle whitespace in HTML (richtext) slate-based widget @tiberiuichim [#4082](https://github.com/plone/volto/issues/4082) +- Add Finnish translation (contributed by @rioksane) + [erral] [#4084](https://github.com/plone/volto/issues/4084) +- Fix typo in english translation and add missing french translation + [mpeeters, jchandelle] [#4085](https://github.com/plone/volto/issues/4085) + +### Internal + +- Make Volto compatible with pnpm as package manager [#4023](https://github.com/plone/volto/issues/4023) + +### Documentation + +- Add content for user-manual of Volto, Plone 6 frontend. [@MAX-786] [#3827](https://github.com/plone/volto/issues/3827) +- Remove duplicate `H1`-level page title, and inherit from Volto's `CHANGELOG.md`. @stevepiercy [#4048](https://github.com/plone/volto/issues/4048) + + +## 16.3.0 (2022-12-05) + +### Feature + +- Add towncrier support. Create `RELEASING.md` and move and update Releasing section from `README.md` into it. @sneridagh @stevepiercy [#3985](https://github.com/plone/volto/issues/3985) +- Translation of roles in user and group control panel. Fix https://github.com/plone/volto/issues/4002 @wesleybl [#4002](https://github.com/plone/volto/issues/4002) +- Use the component registry for `Container` component in DefaultView @sneridagh [#4032](https://github.com/plone/volto/issues/4032) +- Update missing german translations @steffenri + +### Bugfix + +- Fix GitHub release notes in new Towncrier release config @sneridagh [#3989](https://github.com/plone/volto/issues/3989) +- Clear error message when canceling user add. Fix https://github.com/plone/volto/issues/4006 @wesleybl [#4006](https://github.com/plone/volto/issues/4006) +- Fix subscript and supscript active at same time. @iFlameing [#4011](https://github.com/plone/volto/issues/4011) +- Complete eu translation + [erral] [#4015](https://github.com/plone/volto/issues/4015) +- Complete es translation + [erral] [#4016](https://github.com/plone/volto/issues/4016) +- Add `cypress.config.js` to generator templates @sneridagh [#4021](https://github.com/plone/volto/issues/4021) +- Bump Volto core packages with the current Volto version on Volto release @sneridagh [#4025](https://github.com/plone/volto/issues/4025) + +### Internal + +- Remove unused dangling root appExtras from configuration registry @sneridagh [#4024](https://github.com/plone/volto/issues/4024) + +### Documentation + +- Rewrite "Upgraded core to use Cypress 11" section. @stevepiercy [#3979](https://github.com/plone/volto/issues/3979) +- Include `CHANGELOG.md` at the correct path, depending on context of entire Plone 6 documentation or only Volto documentation. @stevepiercy [#3992](https://github.com/plone/volto/issues/3992) +- Close the open Glossary list. @stevepiercy [#3995](https://github.com/plone/volto/issues/3995) +- Added docs for proper usage of draftjs for richtext widgets. @pnicolli [#4001](https://github.com/plone/volto/issues/4001) +- Document how to change the base font and the font for headings. Describe how to host the font. @ksuess [#4013](https://github.com/plone/volto/issues/4013) + + +## 16.2.0 (2022-11-25) + +### Feature + +- Internationalization of descriptions of user add form fields. @wesleybl +- Add tooltip to multivalue labels in select facet @reebalazs +- Provide a default View/Edit component for blocks @avoinea, @tiberiuichim + +### Bugfix + +- Improve collapsing of whitespace when pasting to slate text block @tiberiuichim +- Avoid warning for missing value in NumberWidget @tiberiuichim +- Fix crash in Slate link editing in a dexterity field @tiberiuichim +- Fix select widget loosing focus when the value has changed @reebalazs + +## 16.1.0 (2022-11-23) + +### Feature + +- Support for drilled down current state and updater function from schema in `ObjectListWidget`. This allows to sync the current object selected from the UI and the block settings and viceversa @sneridagh +- Allow custom style wrapper classnames via fieldname suffixes. Added `config.settings.styleClassNameConverters` to register new suffix converters @tiberiuichim + +### Bugfix + +- Fix jest moduleNameMapper for `@plone/volto/babel` @tiberiuichim +- Fix addons loader test @tiberiuichim +- Pass down `onChangeBlock` prop to all stock blocks in core @sneridagh +- Fix user search by full name in users control panel @reebalazs + +## 16.0.0 (2022-11-22) + +### Breaking + +- Deprecate NodeJS 12 since it's out of LTS since April 30, 2022 @sneridagh +- Move all cypress actions to the main `Makefile`, providing better meaningful names. Remove them from `package.json` script section. @sneridagh +- Remove `div` as default if `as` prop from `RenderBlocks`. Now the default is a `React.Fragment` instead. This could lead to CSS inconsistencies if taken this div into account, specially if used in custom add-ons without. In order to avoid them, set the `as` property always in your add-ons. @sneridagh +- Removed `date-fns` from dependencies, this was in the build because `Cypress` depended on it. After the `Cypress` upgrade it no longer depends on it. If your project still depends on it, add it as a dependency of your project. @sneridagh +- Removed all usage of `date-fns` from core. @sneridagh +- Rename `src/components/manage/Widgets/ColorPicker.jsx` component to `src/components/manage/Widgets/ColorPickerWidget.jsx` @sneridagh +- Remove the style wrapper around the `` component in Edit mode, moved to the main edit wrapper @sneridagh +- New `cloneDeepSchema` helper @sneridagh +- Action `listUsers`to be called with Object. Distinguish between search for id or search for fullname, email, username @ksuess +- Integrate volto-state add-on. @tiberiuichim @razvanmiu @eea +- Staticize Poppins font to be compliant with EU privacy. Import from GoogleFont is disabled in site.variables. @giuliaghisini +- Remove the `callout` button (the one with the megaphone icon) from the slate toolbar since it has the same styling as `blockquote`. If you need it anyway, you can bring it back in your addon. @sneridagh +- Using volto-slate Headline / Subheadline buttons strips all elements in the selection @tiberiuichim +- Use `Cypress` 10.3.0 (migrate from 9.x.x). Cypress 10 has some interesting goodies, being the native support of Apple Silicon Computers the main of it. See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. @sneridagh +- The complete configuration registry is passed to the add-ons and the project configuration pipeline @sneridagh +- Refactor the component registry API in the configuration registry @sneridagh @tiberiuichim +- 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 +- This is an UI/UX breaking change. It changes the back button in folder contents from using a cross icon to using a back icon. The rationale behind is because the cross evoque "cancel" when what happens is a change of view. It's also consistent with both PastanagaUI and QuantaUI style guide. @robgietema +- Main workflow change menu changed from Pastanaga UI simplification to classic Plone implementation. @sneridagh +- Move Layout constants to `config.views.layoutViewsNamesMapping`. Complete the list. i18n the list. Improve Display component. @sneridagh +- `react-window` no longer a Volto dependency @sneridagh +- Upgrade to Razzle 4 @davisagli +- Jest downgraded from 27 to 26 @davisagli +- Sentry integration is now lazy-loaded. The `sentryOptions` key from the `settings` registry becomes a callable that passes resolved sentry libraries. @tiberiuichim +- Change history route name to `historyview` (same as classic) in order to allow content to have 'history' as `id` @danielamormocea +- The listing block icon has been improved to avoid confusions with the normal text list @sneridagh +- Remove the means to enable the StyleWrapper in favor of defining it through the block schema. @sneridagh +- 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 +- Restrict css selector for error message (volto-slate) #3838 @mamico +- Upgrade `husky` to latest version @sneridagh +- 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. + +### Feature + +- added default placeholder for videos to embed them more lightly @giuliaghisini +- Added new Block Style Wrapper. This implementation is marked as **experimental** during Volto 16 alpha period. The components, API and the styling are subject to change **without issuing a breaking change**. You can start using it in your projects and add-ons, but taking this into account. See documentation for more information. @sneridagh +- Add default widget views for all type of fields and improve the DefaultView @ionlizarazu +- added configurable identifier field for password reset in config.js. @giuliaghisini +- Add `expandToBackendURL` helper @sneridagh +- added 'show total results' option in Search block configuration. @giuliaghisini +- Added viewableInBrowserObjects setting to use in alternative to downloadableObjects, if you want to view file in browser intstead downloading. @giuliaghisini +- Disable already chosen criteria in querystring widget @kreafox +- Added X-Forwarded-\* headers to superagent requests. @mamico +- Updated Brazilian Portuguese translation @ericof +- Forward `HTTP Range` headers to the backend. @mamico +- Add default value to color picker, if `default` is present in the widget schema. @sneridagh +- Inject the classnames of the StyleWrapper into the main edit wrapper (it was wrapping directly the Edit component before). This way, the flexibility is bigger and you can act upon the whole edit container and artifacts (handlers, etc) @sneridagh +- Refactor image block: make it schema extensible @nileshgulia1 @sneridagh +- Add control panel via config.settings @ksuess https://github.com/plone/volto/issues/3426 +- Add noindex metadata tag @steffenri +- Adding Schema for Maps Block in Sidebar @iRohitSingh +- Add a Pluggable to the sharing page @JeffersonBledsoe #3372 +- Add listing variation schemaEnhancer to the search block schema @ionlizarazu +- Use the local blocksConfig for extensions, fallback to the config object one. This allows to override local blocks config in nested blocks (blocks in a block, eg. accordion, grid, row) @sneridagh +- Use type info instead of id type as icon title in the folder contents. @mamico +- Remove transifex configuration for Volto translations @erral +- Add missing support for inner `blocksConfig` in block extensions resolutions @sneridagh +- Add schema to video block sidebar @iRohitSingh @danielamormocea +- Add user group membership control panel @ksuess +- Action `listUsers`: Support search for fullname, email, username. @ksuess +- Added the `Undo controlpanel` to the controlpanels which can be used to undo transactions. @MdSahil-oss +- Send extra data coming from listing block schemaEnhancer from searchBlock to the listing variation @ionlizarazu +- support for many_users and many_groups flag in user controlpanel and group controlpanel @nileshgulia1 +- Show the content type of the content object you are adding/editing in the sidebar @robgietema +- Remove soft hyphens from the title tag @davisagli +- handle 'no connection' available error (408 error). @giuliaghisini +- Add support for OpenStreet Maps in Maps block @sneridagh +- Make `internalApiPath` client aware, since there are some corner cases when the client needs to know it to properly handle API server URLs @sneridagh +- Add initialPath support to ObjectBrowser widget @robgietema +- Added placeholder param to widget, to change default placeholder @giuliaghisini +- Add clear formatting button to slate @robgietema +- Support for getting `selectableTypes` and `maximumSelectionSize` from `widgetProps` @sneridagh +- Added placeholder param to widget, to change default placeholder @giuliaghisini +- Add a headline (`headline` field) to the listing block schema by default @sneridagh +- Add scroll into view setting to slate @robgietema +- Use absolute dates instead of "x hours ago" in History view @steffenri +- Complete eu translation @erral +- Complete es translation. @erral +- Added new components `Aliases` for aliases control in Volto. Alias management in both controlpanel and object view. @andreiggr @avoinea +- Added resetOnCancel functionality in Form component @MdSahil-oss +- volto-slate: introduce style-menu @nileshgulia1 +- Show result of the addon install/uninstall/upgrade actions @erral +- Working copy actions now render errors if they fail @pnicolli +- lazyloading of rrule lib. @giuliaghisini +- Complete eu translation. @erral +- Complete spanish translation @erral +- Added an option for users to set their own password through a confirmation email in the Add Users modal within the Users control panel. @JeffersonBledsoe #3710 +- Accept a `querystring` object in `apiExpanders` config object settings @sneridagh +- Add a dynamic user form based in @userschema endpoint @erral @nileshgulia1 +- Send missing variation data to the listing variation @ionlizarazu +- Logout action in personal tools points to the same pathname, now it logout in place, not in the root. @sneridagh +- Object browser: image search should only show images @reebalazs +- Updated spanish translation @macagua +- Add Dutch translation @spereverde +- Added link integrity potential breakage warning message when deleting a referenced page @danielamormocea +- Added new components & interfaces for content-rules `Rules` control in Volto. Rules management in both controlpanel and object view. @andreiggr +- Updated Spanish translation @macagua +- Introduce `TextLineEdit` component @sneridagh +- Add a popup tooltip for tokenized options in Select widget values @sneridagh +- Add `image-narrow` svg icon useful for align widget actions @ichim-david +- Use `View comments` and `Reply to item` permissions in `Comments` component. @razvanMiu +- Added portrait middleware adapter. @instification +- Allow dumping the addon dependency graph to a .dot file. Start Volto with `DEBUG_ADDONS_LOADER=true yarn start`, `addon-dependency-graph.dot` will be created in your project folder. @tiberiuichim +- Add clear button in search field of Folder content view @iFlameing +- consume site_actions from restapi @nileshgulia1 +- Updated Spanish translation @macagua +- Japanese translation updated @terapyon +- Improve the `AlignWidget`, add `narrow` fix default support @sneridagh +- Add support for loading core add-ons from the `packages` folder defined in Volto's `package.json` @sneridagh +- Implement the Upgrade Control Panel @ericof +- Allow addons to customize modules from the project root, via the `@root` namespace and folder @tiberiuichim +- Brazilian Portuguese translation updated @ericof +- Improvement of the `ContentsBreadcrumbs` component, add child `ContentsBreadcrumbsRootItem` and `ContentsBreadcrumbsHomeItem` for easy customization of these single elements in projects @sneridagh +- Add german translation for group membership panel. @ksuess +- Fix general german translations: Address user polite. Correct 'listing template' to 'listing variant'. Add missing translations. @ksuess +- Allow passing ariaHidden, id and style to an Icon's SVG @JeffersonBledsoe #3908 +- All Fields now understand the `default` prop as a fallback value in case their data value is missing. As a convenience, the `defaultValue` is also used as a fallback, but this shouldn't proliferate. @tiberiuichim +- There is an experimental setting to move the button for adding a new block to show below any selected block, instead of only on the left of empty text blocks. Set `config.experimental.addBlockButton.enabled = true` to enable it. @davisagli +- Allow custom style wrapper classnames via fieldname suffixes. Added `config.settings.styleClassNameConverters` to register new suffix converters @tiberiuichim +- Support for drilled down current state and updater function from schema in `ObjectListWidget`. This allows to sync the current object selected from the UI and the block settings and viceversa @sneridagh + +### Bugfix + +- Fix Search page visit crashes /contents view @dobri1408 +- Fix sidebar full size bottom opacity on edit page when sidebar is collapsed @ichim-david +- Fix toolbar bottom opacity on edit page when toolbar is collapsed @ichim-david +- Fix content view regression, height issue @danielamormocea +- Fixed secure cookie option. @giuliaghisini +- Changed addon order in addon controlpanel to mimic Classic UI @erral +- Fixed error when loading content in a language for which a Volto translation is not available. @davisagli +- Fix for clipped dropdown menus when the table has few or no records in Contents view @mihaislobozeanu +- fixed view video list from youtube in Video block. @giuliaghisini +- Fixed ICS URL in event view in seamless mode @sneridagh +- Fix `withStylingSchemaEnhancer` enhancer mechanism @sneridagh +- Add correct query parameters to the redirect @robgietema +- Fix RenderBlocks: path @ksuess +- Fix field id creation in dexterity control panel to have slugified id @erral +- Changed to get intl.locale always from state @ionlizarazu +- Fix regression, compound lang names (eg. `pt-BR`) no longer working @sneridagh +- fix TokenWidget choices when editing a recently created content. @giuliaghisini +- Fix color picker defaults implementation #2 @sneridagh +- Enable default color in `backgroundColor` default StyleWrapper field which wasn't sync with the default value setting @sneridagh +- Fix Block style wrapper: Cannot read properties of undefined (reading 'toString') @avoinea #3410 +- fix schema when content contains lock informations. @giuliaghisini +- Don't render junk when no facets are added to the search block @tiberiuichim +- Fix visibility of toolbar workflow dropdown for more states as fitting in .toolbar-content. @ksuess +- Fix the video block for anonymous user @iFlameing +- Use `cloneDeepSchema` helper for schema cloning operations, this fixes the error thrown in the use case of having JSX in the schema while cloning schema operations @sneridagh +- Fix CSS bundling in production mode to be consistent with the current policy in the client bundle. Right now the order of the CSS resources matches this chain: Loading of `import my-less.less` in add-ons (following the add-on order) -> Loading of the Semantic UI defaults -> Loading of the local theme (either project or add-on based). We are forcing now the bundling of all the CSS in one chunk, so it behaves the same than in dev mode (using the style-loader). @sneridagh +- Fixed the description field not being included in the navigation action/ reducer @JeffersonBledsoe #3454 +- Fixed a11y of Maps block (#3467) @iRohitSingh +- Prevent the `defaultView` to show anything if the content is not loaded yet. This fixes showing the non-blocks enabled view for a fraction of a second before showing the blocks-enabled one once the content is loaded. @sneridagh +- Fix typo in de locale @wolbernd +- Add some more messages to be able to translate them @erral +- Fix typo in de locale @wolbernd +- [generator] Improvements to the addon generator: Now it wires up the addon automatically for immediate local development @sneridagh +- complete eu translation @erral +- complete es translation @erral +- [generator] Add .editorconfig and .prettierignore to generated projects and addons. @ericof +- Make `crypto-random-string` a direct dep, fixing a hidden error since some updated dependency was requiring it directly but not anymore. @sneridagh +- Fix edge cases in Cypress flaky tests when the Edit component was loaded without loading the type schema. @sneridagh & @davisagli +- Fix edge cases in Cypress flaky tests when the Edit component was loaded for the wrong content path. @davisagli +- complete pt_BR translation @ericof +- Fix action `listUsers`. Provide default. @ksuess +- Provide the correct id to the blocks wrapped by StyleWrapper. @razvanMiu +- Remove console deprecation notice for 'host' property usage coming from Express @sneridagh +- Make Search page title translatable @erral +- Changed storeProtectLoadUtils location from src/storeProtectLoadUtils to src/middleware/storeProtectLoadUtils @MdSahil-oss +- Fix ArrayWidget choices when editing a recently created content item. @davisagli +- Fix content loading in `DefaultView` infinite loop if a listing block with no query is present. @sneridagh +- Fix login form redirect when it was loaded with a trailing slash @davisagli +- Better de translation for Site Setup @davisagli +- Fix overlapping for long words in Control Panel titles (added word-wrapping) @sneridagh +- Fix sitemap.xml.gz @robgietema +- Fix Image gallery listing block variation only gets 25 if no query is set @sneridagh +- Fix array widget translation @robgietema +- Fix: TTW DX Layout disables IBlocks behavior and with it all the indexers and transformers @avoinea +- Fix: Slate Editor: can not delete bullet point after adding it by typing "- " #3597 @dobri1408 +- Fix literal for the listing block edit mode message telling if the results are contained items (no query) or query results ones (query present) @sneridagh +- Fix grouping of the "users and groups" control panels (plone-users category) @sneridagh +- Improve `Display` and `Workflow` widgets in `More` menu. Fix alignments. @sneridagh +- Fixed searching in the sharing page not showing any results @JeffersonBledsoe #3579 +- Fix types menu on mobile for many types. Specific menuStyle for 'more' menu. @ksuess +- Fix types menu on desktop when menu overflows the viewport, adding scroll to it @sneridagh +- Fix "cannot have two html5 backends at the same time" error @davisagli +- Reset filter in folder contents when navigating @robgietema +- Fix bug showing incorrect history after a revert action @robgietema +- Fix and edge case, in case a `RelationList` has no default, on empty fields, after the object has been created, it saves an empty (None/null) value. Make sure that internally, if that's the case, it's an empty array always. @sneridagh +- Fix workflow and display select in toolbar in case that the option spans several lines @sneridagh +- Fix Press Enter in some blocks does not focus on the text block below #3647 @dobri1408 +- Add `matchAllRoutes` to AsyncConnect so that it matches all configured `asyncPropsExtenders` @tiberiuichim +- Fix acceptence test groups controlpanel @ksuess +- Fix the typo in change workflow status dialog in "de" @iRohitSingh +- Fix selection error when pressing backspace @robgietema +- Fix sidebarTab in Toc Block @iRohitSingh +- Fix virtualization (windowing) when displaying options with long titles for select widgets. (The virtualization happen when the number of options is greater than 25). Add dynamic height aware options using `react-virtualized`. @sneridagh +- Fix email validation to ensure all addresses are correctly validated @instification +- Fix number widget when the value is 0 @iRohitSingh +- Fix the typo in change workflow status dialog in "de" @iRohitSingh +- Show unauthorized message when accessing the diff view without permission @robgietema +- Fix i18n in title of Aliases control panel @sneridagh +- The styling schema is now applied before the block variations schema enhancers, to allow those enhancers a chance to tweak the styling schema @tiberiuichim +- Fix avatar URL in `PersonalTools`. Now works with the new `portrait` endpoint @sneridagh +- Fix `listing` block in SSR, now that it is fully variations aware and the configuration is passed to the SSR `querystring` action. @sneridagh +- Remove wrapping ul or ol when deselecting list style @robgietema +- Fix call to `@plone/scripts/i18n` (now a commonJS module) @sneridagh +- Concatenate multilingualRoutes and externalRoutes (if available) to defaultRoutes @erral #3653 +- Fixed the `description` field not appearing in control panel fieldsets @JeffersonBledsoe #3696 +- Fixed "more" always show root contents @MdSahil-oss #3365 +- Add missing `--noninteractive` in the `build` script in package.json @sneridagh +- Fix replace `` anchor element with the `UniversalLink` component in `DefaultTemplate.jsx` @Dnouv +- Extend Id widget validation rules to accept a dot "." @reebalazs +- Fix history page error for unauthenticated @reebalazs +- Fix unlock after changing the id and saving a page @reebalazs +- Group routes so React does not see them as a different Route and triggers a full remount. This is specially important in `Contents` @sneridagh +- Add default to `null` for `token` prop in `Navigation` component. This prevents the component to shoot an extra call when the logout happens @sneridagh +- Fix a double slash present in the `PersonalTools` component @sneridagh +- Fix UniversalLink storybook @tiberiuichim +- Fix logout to stay on the same page where the user was @reebalazs +- Change sentry chunk name to avoid ad blockers. Only load sentry if env vars exist @tiberiuichim +- SearchTags uses invalid vocabulary API @silviubogan +- Fix autocomplete widget with an empty search result @reebalazs +- Make sure that the store is reset on history reducer `PENDING` state @sneridagh +- Prefer views assigned explicitly with `layout` over views based on the `@type` @iRohitSingh +- Fix `schemaEnhancer` not being applied if nested `blocksConfig` is present @sneridagh +- Ensure the view component is always replaced after navigating to a different page. @davisagli +- Be more robust towards invalid block configuration @reebalazs +- Remove slate's builtin undo support, as it conflicts with Volto's undo manager. This fixes crashes when undoing in text blocks and slate's undo stack is empty and "crosses" into Volto's undo stack. This is a temporary workaround, ideally the two undo managers would be delimited so they each work together. @tiberiuichim +- Fix highlighting of selection when the Slate editor is not DOM-focused. @tiberiuichim +- Improve the algorithm that calculates the position of the Slate Toolbar @tiberiuichim +- The `_unwrapElement` of the volto-slate `ElementEditor` will return an updated range (selection) of the unwrapped element. @tiberiuichim +- Replace the main client entry point in `start-client.jsx` anonymous function for a named one. @sneridagh +- Fix `currentPath` option for `openObjectBrowser`. @iFlameing +- Fix updating the listing block when the variation is changed while editing @tiberiuichim +- fix(warning): StyleMenu dropdown item to use data-attr instead of custom @nileshgulia1 +- Added --canary flag in plone/install.sh. @MdSahil-oss +- Fix condition in `applySchemaDefaults` @tiberiuichim @sneridagh +- Load core add-ons configuration as any other add-on. @sneridagh +- Fix `FormValidation` error object, use field `id` instead of field `title` @sneridagh +- Revert #2828 PR change of the default `showSearchButton` Search block behavior (see [#3883](https://github.com/plone/volto/issues/3883)) @sneridagh +- Fix `package.json` `postinstall` in core @sneridagh +- Hide control panel settings that are not relevant to Volto @danalvrz +- Hide not relevant for Volto control panels from site setup, further refine not used inner settings for site control panel @sneridagh +- Fix ObjectWidget handling of `default` values coming from schemas. @tiberiuichim +- Overhaul how block defaults are computed. See https://github.com/plone/volto/pull/3925 for more details @tiberiuichim +- Fix image tag for Plone 5.2.x, use 5.2.9 for now @sneridagh +- Cover an additional edge case for defaults @tiberiuichim +- Fix issue when using list markdown when list is already active (volto-slate) @robgietema +- Fix translation spelling of toggle @iFlameing +- Fix keyboard accessibility issue of Clear button in Folder content view @iFlameing + +### Internal + +- Improve Cypress integration, using Cypress official Github Action. Improve some flaky tests that showed up, and were known as problematic. Refactor and rename all the Github actions giving them meaningful names, and group them by type. Enable Cypress Dashboard for Volto. @sneridagh +- Stop using `xmlrpc` library for issuing the setup/teardown in core, use a `cy.request` instead. @sneridagh +- Added Cypress environment variables for adjusting the backend URL of commands @JeffersonBledsoe #3271 +- Reintroduce Plone 6 acceptance tests using the latests `plone.app.robotframework` 2.0.0a6 specific Volto fixture. @datakurre @ericof @sneridagh +- Upgrade all tests to use `plone.app.robotframework` 2.0.0a6 @sneridagh +- Upgrade Sentry to latest version because of [#3346](https://github.com/plone/volto/issues/3346) @sneridagh +- Update `Cypress` to version 9.6.1 @sneridagh +- Missing change from the last breaking change (Remove the style wrapper around the `` component in Edit mode, moved to the main edit wrapper). Now, really move it to the main edit wrapper @sneridagh +- Fix warning because missing key in `VersionOverview` component @sneridagh +- Mock all loadable libraries. @mamico +- Update json-schema including transitive dependencies @davisagli +- Update release-it @davisagli +- Deduplicate dependencies using yarn-deduplicate @davisagli +- Fix `defaultBlockType` entry in default config, set it to slate. @sneridagh +- Allow passing `allowedChildren` option to the BlockButton, to strip elements in headlines @tiberiuichim +- Upgrade to latest `@plone/scripts` @sneridagh +- Update browserlist definitions @sneridagh +- Fix propTypes for Pagination component @davisagli +- Test against Plone 5.2.9 and 6.0.0b1 @davisagli +- Use latest 1.6.0 `@plone/scripts` @sneridagh +- Add classname of variation in edit mode @iFlameing +- Use component registry for default image, fallback to the local import @sneridagh +- Remove Razzle as direct dependency from @plone/scripts @sneridagh +- Fix storybook build for Razzle 4 @sneridagh +- Update `@plone/scripts` to 2.1.1 @sneridagh +- Run yarn deduplicate on dependencies. @davisagli +- Comment out flaky test for now regarding many users/groups @sneridagh +- Add reverse proxy conf with `traefik` to demo compose file @sneridagh +- More disable flaky test regarding many users/groups @sneridagh +- Remove no longer present option in cypress github action, by default, headless is true @sneridagh +- Add proper webserver with reverse proxy with seamless mode @sneridagh +- Update to Plone 6 beta3 @sneridagh +- Upgrade Cypress to latest @sneridagh +- Upgrade dependency rrule (optional dependency luxon removed) @ksuess +- Set `.nvmrc` to not use `lts/*` but a specific one `lts/gallium` +- Update to @plone/scripts 2.1.2 @sneridagh +- Remove all the useless security bits from blocks configuration definitions @sneridagh +- Add translation for `pending` state @iFlameing +- Add `composeSchema`, a helper to compose multiple schemaEnhancers @tiberiuichim +- Upgrade to `plone.voltoa14` @sneridagh +- Upgrade dependencies to latest released slate libraries. Make sure to pass down `ref` to rendered slate elements, as ref is now a function @tiberiuichim +- Add `editableProps` prop to the `SlateEditor` component, to pass down props to the base Slate `Editable` component. @tiberiuichim +- Clean, re-enable block-slate-format-link Cypress tests @tiberiuichim +- Rewrite some anonymous functions as named functions, to remove warning about Hot Reloading. @tiberiuichim +- Add translation for objectlist `Add` text @iFlameing +- Add translations for facet widget value @iFlameing +- Ignore `.tool-versions` file +- Minor updates to dependencies +- Update Cypress 11 @sneridagh +- Update to Plone 6 RC1 @sneridagh + +### Documentation + +- Move Cypress documentation from `README.md` to the docs. Improve the docs with the new `Makefile` commands. +- Improve English grammar and syntax in backend docs. @stevepiercy +- Fix JSX syntax highlighting. Remove duplicate heading. @stevepiercy +- fix make task `docs-linkcheckbroken` if grep has exit code 1 (no lines found) +- Updated `simple.md` @MdSahil-oss +- Fix indentation in nginx configuration in `simple.md` @stevepiercy +- Remove sphinx_sitemap configuration because Volto's docs are now imported into the main docs, making this setting unnecessary. @stevepiercy +- Set the ogp_site_url to main docs, instead of training. @stevepiercy +- `aria-*` attributes are now parsed correctly by jsx-lexer 2.0. @stevepiercy +- volto-slate documentation @nileshgulia1 +- Fix redirect on YouTube, broken link after merge and deleted branch. @stevepiercy +- Add upgrade guide documentation for dealing with `volto-slate` upgrades for Volto 16 alpha 15 onwards. @sneridagh +- Minor clean up of volto-slate upgrade guide. @stevepiercy +- Rework documentation on how to write a Slate plugin @ksuess +- Documentation of the new component registry API @sneridagh +- Fix copy / paste text in list @robgietema +- Make links relative to `_static` so that `plone/documentation` can pull them in, and fix broken link. @stevepiercy +- Align `html_static_path` with `plone/documentation` and image path so that images render when docs build in both repos. @stevepiercy +- Undo html_static_path configuration in `plone/documentation`, and restore image and its referenced path in `plone/volto`. @stevepiercy +- Clean up "design principles" and "contributing" +- Bring back "Guidelines for Contributing" +- Fix Sphinx warning `WARNING: glossary terms must not be separated by empty lines` by closing unclosed glossary directive's triple backticks. @stevepiercy +- Fix broken links to nvm releases. @stevepiercy +- Ignore redirect that requires login to GitHub. @stevepiercy +- Added controls for the `actions` property of the `AlignWidget` storybook @JeffersonBledsoe #3671 +- Generic Setup -> `GenericSetup`. @stevepiercy +- Upgrade to Plone 6 beta 2 @sneridagh +- Flip testing matrix for acceptance tests, make Plone 6 principal subject, Plone 5 as secondary @sneridagh +- Update README with latest versions, point to Plone 6 as recommended default @sneridagh +- Trigger a new deploy core Plone documentation when Volto documentation is updated @esteele +- Update supported Python versions. @stevepiercy +- Add NodeJS 18 (LTS) usage notice @sneridagh +- Fix Netlify build @sneridagh +- Fix grammar in Theming Strategy. Fixes #954. @stevepiercy +- Fix wording in About Semantic UI. Fixes #953. @stevepiercy +- Add missing pieces of the upgrade to use yarn 3 for projects @sneridagh +- Complete docs about the yarn 3 upgrade @sneridagh +- Add additional components to storybook @danalvrz +- Add `@plone/scripts` as a mandatory devDependency for projects to the upgrade guide @sneridagh +- Document `Sentry` integration move from Volto core to add-on `@plone-collective/volto-sentry` in configuration, upgrade and deployment. @ksuess +- Remove `sentryOptions` from settings reference. Clean up `deploying/sentry.md`. @stevepiercy +- Tidy up `upgrade-guide/index.md`. @stevepiercy +- Fix some MyST syntax and English grammar. @stevepiercy + +## 16.0.0-rc.3 (2022-11-22) + +### Bugfix + +- Fix keyboard accessibility issue of Clear button in Folder content view @iFlameing +- Fix issue when using list markdown when list is already active (volto-slate) @robgietema +- Fix translation spelling of toggle @iFlameing + +### Documentation + +- Document experimental features @davisagli + +## 16.0.0-rc.2 (2022-11-20) + +### Bugfix + +- Overhaul how block defaults are computed. See https://github.com/plone/volto/pull/3925 for more details @tiberiuichim +- Cover an additional edge case for defaults @tiberiuichim + +### Internal + +- Update to Plone 6 RC1 @sneridagh + +### Documentation + +- Document `Sentry` integration move from Volto core to add-on `@plone-collective/volto-sentry` in configuration, upgrade and deployment. @ksuess +- Remove `sentryOptions` from settings reference. Clean up `deploying/sentry.md`. @stevepiercy +- Tidy up `upgrade-guide/index.md`. @stevepiercy +- Fix some MyST syntax and English grammar. @stevepiercy +- Add contributing branch policy information @sneridagh @stevepiercy +- Add component to storybook @danalvrz + +## 16.0.0-rc.1 (2022-11-18) + +### Feature + +- Releasing RC1 @sneridagh + +## 16.0.0-alpha.53 (2022-11-18) + +### Feature + +- There is an experimental setting to move the button for adding a new block to show below any selected block, instead of only on the left of empty text blocks. Set `config.experimental.addBlockButton.enabled = true` to enable it. @davisagli + +## 16.0.0-alpha.52 (2022-11-18) + +### Bugfix + +- Revert "Configure Jest's moduleNameMapper with AddonConfigurationRegistry" (#3913) due to a regression in projects @sneridagh + +## 16.0.0-alpha.51 (2022-11-18) ### Breaking +- 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 + ### Feature +- Improvement of the `ContentsBreadcrumbs` component, add child `ContentsBreadcrumbsRootItem` and `ContentsBreadcrumbsHomeItem` for easy customization of these single elements in projects @sneridagh +- Add german translation for group membership panel. @ksuess +- Fix general german translations: Address user polite. Correct 'listing template' to 'listing variant'. Add missing translations. @ksuess +- Allow passing ariaHidden, id and style to an Icon's SVG @JeffersonBledsoe #3908 +- All Fields now understand the `default` prop as a fallback value in case their data value is missing. As a convenience, the `defaultValue` is also used as a fallback, but this shouldn't proliferate. @tiberiuichim + ### Bugfix +- Hide control panel settings that are not relevant to Volto @danalvrz +- Hide not relevant for Volto control panels from site setup, further refine not used inner settings for site control panel @sneridagh +- Fix ObjectWidget handling of `default` values coming from schemas. @tiberiuichim + ### Internal +- Ignore `.tool-versions` file +- Minor updates to dependencies +- Update Cypress 11 @sneridagh + +### Documentation + +- Add `@plone/scripts` as a mandatory devDependency for projects to the upgrade guide @sneridagh + +## 16.0.0-alpha.50 (2022-11-15) + +### Feature + +- Brazilian Portuguese translation updated @ericof + +### Bugfix + +- Fix condition in `applySchemaDefaults` @tiberiuichim @sneridagh +- Load core add-ons configuration as any other add-on. @sneridagh +- Fix `FormValidation` error object, use field `id` instead of field `title` @sneridagh +- Revert #2828 PR change of the default `showSearchButton` Search block behavior (see [#3883](https://github.com/plone/volto/issues/3883)) @sneridagh +- Fix `package.json` `postinstall` in core @sneridagh + ### Documentation - Add missing pieces of the upgrade to use yarn 3 for projects @sneridagh +- Complete docs about the yarn 3 upgrade @sneridagh +- Add additional components to storybook @danalvrz ## 16.0.0-alpha.49 (2022-11-11) @@ -22,8 +968,6 @@ - Upgrade `husky` to latest version @sneridagh - Enable the use of yarn 3 in the build by default @sneridagh -See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more information. - ### Feature - Japanese translation updated @terapyon @@ -38,7 +982,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa - Remove slate's builtin undo support, as it conflicts with Volto's undo manager. This fixes crashes when undoing in text blocks and slate's undo stack is empty and "crosses" into Volto's undo stack. This is a temporary workaround, ideally the two undo managers would be delimited so they each work together. @tiberiuichim - Fix highlighting of selection when the Slate editor is not DOM-focused. @tiberiuichim - Improve the algorithm that calculates the position of the Slate Toolbar @tiberiuichim -- The `_unwrapElement` of the volto-slate `ElementEditor` will return an updated range (selection) of the unwrapped element. @tiberiuichim +- The `_unwrapElement` of the volto-slate `ElementEditor` will return an updated range (selection) of the unwrapped element. @tiberiuichim - Replace the main client entry point in `start-client.jsx` anonymous function for a named one. @sneridagh - Fix `currentPath` option for `openObjectBrowser`. @iFlameing - Fix updating the listing block when the variation is changed while editing @tiberiuichim @@ -105,6 +1049,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ### Bugfix - Prefer views assigned explicitly with `layout` over views based on the `@type` @iRohitSingh +- Improve collapsing of whitespace when pasting to slate text block @tiberiuichim ### Internal @@ -325,8 +1270,6 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ## 16.0.0-alpha.34 (2022-09-17) -### Breaking - ### Feature - Added new components `Aliases` for aliases control in Volto. Alias management in both controlpanel and object view. @andreiggr @avoinea @@ -514,7 +1457,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ### Breaking - The complete configuration registry is passed to the add-ons and the project configuration pipeline - See https://docs.voltocms.com/upgrade-guide/ for more information. @sneridagh + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. @sneridagh - Refactor the component registry API in the configuration registry @sneridagh @tiberiuichim ### Bugfix @@ -539,7 +1482,7 @@ See https://6.dev-docs.plone.org/volto/upgrade-guide/index.html for more informa ### Breaking -- Use `Cypress` 10.3.0 (migrate from 9.x.x). Cypress 10 has some interesting goodies, being the native support of Apple Silicon Computers the main of it. See https://docs.voltocms.com/upgrade-guide/ for more information. @sneridagh +- Use `Cypress` 10.3.0 (migrate from 9.x.x). Cypress 10 has some interesting goodies, being the native support of Apple Silicon Computers the main of it. See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. @sneridagh ### Bugfix @@ -803,8 +1746,8 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp ### Documentation -- Updated simple.md @MdSahil-oss -- Fix indentation in nginx configuration in simple.md @stevepiercy +- Updated `simple.md` @MdSahil-oss +- Fix indentation in nginx configuration in `simple.md` @stevepiercy ## 16.0.0-alpha.3 (2022-05-16) @@ -1058,7 +2001,7 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp ### Documentation -- Updated README.md @ktsrivastava29 +- Updated `README.md` @ktsrivastava29 - Added language to code-blocks in md files @ktsrivastava29 - Added html_meta values and labels for Intersphinx cross-references from Trainings. @stevepiercy - Replaced `docs.voltocms.com` with MyST references. @stevepiercy @@ -1274,7 +2217,7 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp ### Breaking - Lazyload draftjs library. See the upgrade guide on how that impacts you, in case you have extended the rich text editor configuration @tiberiuichim @kreafox - See https://docs.voltocms.com/upgrade-guide/ for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -1287,7 +2230,7 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp - 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://docs.voltocms.com/upgrade-guide/ for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Internal @@ -1333,7 +2276,7 @@ Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alp ### Breaking - Upgrade `react-cookie` to latest version. @sneridagh @robgietema - See https://docs.voltocms.com/upgrade-guide/ for more information. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ## 14.10.0 (2022-02-08) @@ -1462,7 +2405,7 @@ new users/evaluators. @fredvd ### Internal - Fix URL for Climate-Energy, a Volto website @tiberiuichim -- Fix quirky Cypress test in "DX control panel schema" (see https://github.com/plone/volto/runs/4803206906?check_suite_focus=true) @sneridagh +- Fix quirky Cypress test in "DX control panel schema" (see https://github.com/plone/volto/actions/runs/1692689792/jobs/2306969715) @sneridagh ## 14.2.1 (2022-01-12) @@ -1526,11 +2469,11 @@ new users/evaluators. @fredvd ### Breaking -- Remove compatibility for old configuration (based on imports) system. Migrate your configuration to the new configuration system for your project before upgrading to Volto 14. See https://docs.voltocms.com/upgrade-guide/#volto-configuration-registry @sneridagh +- Remove compatibility for old configuration (based on imports) system. Migrate your configuration to the new configuration system for your project before upgrading to Volto 14. See https://6.docs.plone.org/volto/upgrade-guide/index.html#volto-configuration-registry @sneridagh - Content locking is not a breaking change, but it's worth noting that Volto 14 comes with locking support enabled by default. Latest `plone.restapi` version is required. @avoinea - Revisited, rethought and refactored Seamless mode @sneridagh For more information, please read the deploying guide - https://docs.voltocms.com/deploying/seamless-mode/ + https://6.docs.plone.org/volto/deploying/seamless-mode.html - Listing block no longer use `fullobjects` to retrieve backend data. It uses the catalog data instead. This improves the performance of the listing block. @plone/volto-team - Removed pagination in vocabularies widgets (SelectWidget, ArrayWidget, TokenWidget) and introduced subrequest to vocabulary action. @giuliaghisini - Use the block's title as the source of the translation instead of using the id of the block. See upgrade guide for more information @sneridagh @@ -1542,14 +2485,14 @@ new users/evaluators. @fredvd - Use title instead of id as a source of translation in "Variation" field in block enhancers @sneridagh - Move `theme.js` import to top of the client code, so it take precedence over any other inline imported CSS. This is not an strict breaking change, but it's worth to mention it as might be important and kept in mind. @sneridagh -See https://docs.voltocms.com/upgrade-guide/ for more information about all the breaking changes. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information about all the breaking changes. ### Feature - Support Node 16 @timo - Content locking support for Plone (`plone.locking`) @avoinea - Add the new search block @tiberiuichim @kreafox @sneridagh -- Provide Server-Side Rendering capabilities for blocks with async-based content (such as the listing block). A block needs to provide its own `getAsyncData` implementation, which is similar to an `asyncConnect` wrapper promise. @tiberiuichim @sneridagh +- Provide server-side rendering capabilities for blocks with async-based content (such as the listing block). A block needs to provide its own `getAsyncData` implementation, which is similar to an `asyncConnect` wrapper promise. @tiberiuichim @sneridagh - Defaults are observed in block data if `InlineForm` or `BlockDataForm` are used. @sneridagh @tiberiuichim - Apply form defaults from RenderBlocks and block Edit using a new helper, `applyBlockDefaults` @tiberiuichim - Now each block config object can declare a schema factory (a function that can produce a schema) and this will be used to derive the default data for the block @tiberiuichim @@ -1559,7 +2502,7 @@ See https://docs.voltocms.com/upgrade-guide/ for more information about all the - 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 @@ -1689,7 +2632,7 @@ See https://docs.voltocms.com/upgrade-guide/ for more information about all the ### 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 @@ -1902,7 +2845,7 @@ See https://docs.voltocms.com/upgrade-guide/ for more information about all the ### Feature -- Provide Server-Side Rendering capabilities for blocks with async-based content (such as the listing block). A block needs to provide its own `getAsyncData` implementation, which is similar to an `asyncConnect` wrapper promise. @tiberiuichim @sneridagh +- Provide server-side rendering capabilities for blocks with async-based content (such as the listing block). A block needs to provide its own `getAsyncData` implementation, which is similar to an `asyncConnect` wrapper promise. @tiberiuichim @sneridagh ## 14.0.0-alpha.25 (2021-11-01) @@ -1977,10 +2920,10 @@ See https://docs.voltocms.com/upgrade-guide/ for more information about all the - Revisited, rethought and refactored Seamless mode @sneridagh For more information, please read the deploying guide - https://docs.voltocms.com/deploying/seamless-mode/ + https://6.docs.plone.org/volto/deploying/seamless-mode.html -and the upgrade guide -https://docs.voltocms.com/upgrade-guide/ + and the upgrade guide + https://6.docs.plone.org/volto/upgrade-guide/index.html ### Bugfix @@ -2024,7 +2967,7 @@ https://docs.voltocms.com/upgrade-guide/ - Adjusted main `Logo` component styling @sneridagh For more information, please read the upgrade guide -https://docs.voltocms.com/upgrade-guide/ +https://6.docs.plone.org/volto/upgrade-guide/index.html ### Feature @@ -2035,7 +2978,7 @@ https://docs.voltocms.com/upgrade-guide/ - Improved developer documentation. Proof read several chapters, most importantly the upgrade guide @ichim-david - Use Plone logo (Closes #2632) @ericof - Updated Brazilian Portuguese translations @ericof -- Footer: Point to plone.org instead of plone.com @ericof +- Footer: Point to `plone.org` instead of `plone.com` @ericof - Fix "make start-frontend" @tisto - Update all the tests infrastructure for the new `volto-guillotina` addon @sneridagh @@ -2168,8 +3111,8 @@ https://docs.voltocms.com/upgrade-guide/ ### Breaking -- Remove compatibility for old configuration (based on imports) system. Migrate your configuration to the new configuration system for your project before upgrading to Volto 14. See https://docs.voltocms.com/upgrade-guide/#volto-configuration-registry @sneridagh -- Content locking is not a breaking change, but it's worth noting that Volto 14 comes with locking support enabled by default. Latest `plone.restapi` versions is required. See https://docs.voltocms.com/upgrade-guide/ for more information +- Remove compatibility for old configuration (based on imports) system. Migrate your configuration to the new configuration system for your project before upgrading to Volto 14. See https://6.docs.plone.org/volto/upgrade-guide/index.html#volto-configuration-registry @sneridagh +- Content locking is not a breaking change, but it's worth noting that Volto 14 comes with locking support enabled by default. Latest `plone.restapi` versions is required. See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information ### Feature @@ -2219,7 +3162,7 @@ https://docs.voltocms.com/upgrade-guide/ - Disabled all the other configuration options when user did not choose any criteria in listing block @iFlameing - Updated Brazilian Portuguese translations @ericof -- Footer: Point to plone.org instead of plone.com @ericof +- Footer: Point to `plone.org` instead of `plone.com` @ericof - Array and token widget available as named widget @nzambello ## 13.12.0 (2021-08-20) @@ -2492,7 +3435,7 @@ https://docs.voltocms.com/upgrade-guide/ - Refactored `Listing` block using the new `src/components/manage/Widgets/QuerystringWidget`. Introducing a new `showLinkMore` block option opt-in for the additional feature instead of always-in. Deprecated `ListingSidebar` and `src/components/manage/Blocks/Listing/QuerystringWidget` in favor of the new `src/components/manage/Widgets/QuerystringWidget` @sneridagh For a more information, please read the upgrade guide -https://docs.voltocms.com/upgrade-guide/ +https://6.docs.plone.org/volto/upgrade-guide/index.html ### Feature @@ -2606,7 +3549,7 @@ https://docs.voltocms.com/upgrade-guide/ - Refactored `Listing` block using the new `src/components/manage/Widgets/QuerystringWidget`. Introducing a new `showLinkMore` block option opt-in for the additional feature instead of always-in. Deprecated `ListingSidebar` and `src/components/manage/Blocks/Listing/QuerystringWidget` in favor of the new `src/components/manage/Widgets/QuerystringWidget` @sneridagh For a more information, please read the upgrade guide -https://docs.voltocms.com/upgrade-guide/ +https://6.docs.plone.org/volto/upgrade-guide/index.html ### Bugfix @@ -2656,7 +3599,7 @@ https://docs.voltocms.com/upgrade-guide/ - Get rid of the font icons in the control panels overview @sneridagh For a complete list of actions to follow, please read the upgrade guide -https://docs.voltocms.com/upgrade-guide/ +https://6.docs.plone.org/volto/upgrade-guide/index.html ### Feature @@ -2807,7 +3750,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Internal -- Add Storybook to the main docs (docs.voltocms.com/storybook) build @sneridagh +- Add Storybook to the main docs (https://6.docs.plone.org/storybook/) build @sneridagh ## 12.5.0 (2021-03-31) @@ -2955,7 +3898,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Breaking - Introduction of the new Volto Configuration Registry @sneridagh @tiberiuichim - For more information about this breaking change: https://docs.voltocms.com/upgrade-guide/#upgrading-to-volto-12xx + For more information about this breaking change: https://6.docs.plone.org/volto/upgrade-guide/index.html#upgrading-to-volto-12-x-x ### Feature @@ -2970,7 +3913,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Breaking - Introduction of the new Volto Configuration Registry @sneridagh @tiberiuichim - For more information about this breaking change: https://docs.voltocms.com/upgrade-guide/#upgrading-to-volto-12xx + For more information about this breaking change: https://6.docs.plone.org/volto/upgrade-guide/index.html#upgrading-to-volto-12-x-x ## 11.1.0 (2021-02-08) @@ -3250,7 +4193,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Breaking - Removal of the Razzle patch that was introduced in 9.0.0 @sneridagh - See https://docs.voltocms.com/upgrade-guide/ for more details. + See https://6.docs.plone.org/volto/upgrade-guide/index.html for more details. - Fetched content with `getContent` no longer includes fullobjects by default @tiberiuichim ### Bugfix @@ -3270,7 +4213,7 @@ https://docs.voltocms.com/upgrade-guide/ ## 9.2.0 (2020-11-24) **This is a brown bag release and should not be used, upgrade to Volto 10.x.x instead.** -See https://docs.voltocms.com/upgrade-guide/ for more information. +See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. ### Feature @@ -3331,7 +4274,7 @@ See https://docs.voltocms.com/upgrade-guide/ for more information. - @babel/plugin-proposal-function-sent For a complete list of actions to follow, please read the upgrade guide -https://docs.voltocms.com/upgrade-guide/ +https://6.docs.plone.org/volto/upgrade-guide/index.html ### Feature @@ -3417,7 +4360,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Feature -- Add support for the new active LTS NodeJS version 14. NodeJS 10 eol will happen on 2021-04-30 and Volto will update accordingly. More information on https://nodejs.org/en/about/releases @sneridagh +- Add support for the new active LTS NodeJS version 14. NodeJS 10 eol will happen on 2021-04-30 and Volto will update accordingly. More information on https://github.com/nodejs/release#release-schedule @sneridagh ## 8.7.1 (2020-10-29) @@ -3941,7 +4884,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Feature -- Provide a new webpack alias, `volto-themes`, which points to Volto's theme folder. See details in the https://docs.voltocms.com/upgrade-guide/ +- Provide a new webpack alias, `volto-themes`, which points to Volto's theme folder. See details in the https://6.docs.plone.org/volto/upgrade-guide/index.html ### Internal @@ -4021,7 +4964,7 @@ https://docs.voltocms.com/upgrade-guide/ - 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 [Customizing Express](docs/source/customizing/express.md) @tiberiuichim +- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.dev-docs.plone.org/volto/recipes/express.html) @tiberiuichim ### Bugfix @@ -4090,7 +5033,7 @@ https://docs.voltocms.com/upgrade-guide/ ### Breaking - Removed support for CSS modules, since Razzle 3.1.x do not support them @sneridagh -- Updated Volto dependencies - See https://docs.voltocms.com/upgrade-guide/ for more information @sneridagh +- Updated Volto dependencies - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information @sneridagh - By adding `react-beautiful-dnd` in the block editor we are introducing new wrappers (belonging to the lib machinery) in the structure. The original structure and class names are still in there for maintain maximum backwards compatibility. Those might be @@ -4560,7 +5503,7 @@ refer to all of them in https://github.com/plone/volto/releases ### Internal -- Added forest.eea.europa.eu as deployed Volto in production @tiberiuichim +- Added `forest.eea.europa.eu` as deployed Volto in production @tiberiuichim - Add SemanticUI responsive variables to the responsive utils @sneridagh - Added `yarnhook` to the build @sneridagh @@ -4607,7 +5550,7 @@ refer to all of them in https://github.com/plone/volto/releases ### Added -- Lead image behavior block @sneridagh sponsored by CMSCOM.jp @terapyon +- Lead image behavior block @sneridagh sponsored by `CMSCOM.jp` @terapyon ### Changes @@ -4919,7 +5862,7 @@ refer to all of them in https://github.com/plone/volto/releases ### Internal - Add complete husky config @sneridagh -- Add COC.md file @timo +- Add `COC.md` file @timo ## 4.0.0-alpha.5 (2019-09-28) diff --git a/Makefile b/Makefile index 60c3df4b5b..6ef4a70b87 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # https://tech.davis-hansson.com/p/make/ SHELL:=bash .ONESHELL: -.SHELLFLAGS:=-xeu -o pipefail -O inherit_errexit -c +.SHELLFLAGS:=-eu -o pipefail -c .SILENT: .DELETE_ON_ERROR: MAKEFLAGS+=--warn-undefined-variables @@ -13,14 +13,16 @@ MAKEFLAGS+=--no-builtin-rules # Project settings INSTANCE_PORT=8080 -DOCKER_IMAGE=plone/plone-backend:6.0.0b3 -KGS=plone.restapi==8.32.0 plone.volto==4.0.0a14 -TESTING_ADDONS=plone.app.robotframework==2.0.0b2 plone.app.testing==7.0.0a3 +DOCKER_IMAGE=plone/server-dev:6.0.2 +DOCKER_IMAGE_ACCEPTANCE=plone/server-acceptance:6.0.2 +KGS= NODEBIN = ./node_modules/.bin +SCRIPTSPACKAGE = ./packages/scripts # Plone 5 legacy -DOCKER_IMAGE5=plone/plone-backend:5.2.9 -KGS5=plone.restapi==8.32.0 plone.volto==4.0.0a14 plone.rest==2.0.0 +DOCKER_IMAGE5=plone/plone-backend:5.2.10 +KGS5=plone.restapi==8.35.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 # You can set these variables from the command line. @@ -31,6 +33,7 @@ SPHINXAUTOBUILD = $(realpath bin/sphinx-autobuild) DOCS_DIR = ./docs/source/ BUILDDIR = ../_build/ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . +VALEFILES := $(shell find $(DOCS_DIR) -type f -name "*.md" -print) # Recipe snippets for reuse @@ -83,7 +86,7 @@ build: .PHONY: build-frontend build-frontend: - yarn && RAZZLE_API_PATH=http://localhost:55001/plone yarn build + yarn && RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build .PHONY: build-backend build-backend: ## Build Plone 5.2 @@ -137,17 +140,17 @@ docs-linkcheck: bin/python ## Run linkcheck .PHONY: docs-linkcheckbroken docs-linkcheckbroken: bin/python ## Run linkcheck and show only broken links - cd $(DOCS_DIR) && $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | GREP_COLORS='0;31' grep -wi "broken\|redirect" --color=auto || test $$? = 1 + cd $(DOCS_DIR) && $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck | GREP_COLORS='0;31' grep -wi "broken\|redirect" --color=always | GREP_COLORS='0;31' grep -vi "https://github.com/plone/volto/issues/" --color=always && if test $$? = 0; then exit 1; fi || test $$? = 1 @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/ ." -.PHONY: docs-spellcheck -docs-spellcheck: bin/python ## Run spellcheck - cd $(DOCS_DIR) && LANGUAGE=$* $(SPHINXBUILD) -b spelling -j 4 $(ALLSPHINXOPTS) $(BUILDDIR)/spellcheck/$* +.PHONY: docs-vale +docs-vale: ## Run Vale style, grammar, and spell checks + vale sync + vale --no-wrap $(VALEFILES) @echo - @echo "Spellcheck is finished; look for any errors in the above output " \ - " or in $(BUILDDIR)/spellcheck/ ." + @echo "Vale is finished; look for any errors in the above output." .PHONY: netlify netlify: @@ -155,12 +158,22 @@ netlify: cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) ../$(BUILDDIR)/html .PHONY: docs-test -docs-test: docs-clean docs-linkcheckbroken docs-spellcheck ## Clean docs build, then run linkcheckbroken, spellcheck +docs-test: docs-clean docs-linkcheckbroken docs-vale ## Clean docs build, then run linkcheckbroken, vale .PHONY: storybook-build storybook-build: yarn build-storybook -o docs/_build/storybook +.PHONY: patches +patches: + /bin/bash patches/patchit.sh > /dev/null 2>&1 ||true + +##### Release + +.PHONY: corepackagebump +corepackagebump: + node $(SCRIPTSPACKAGE)/corepackagebump.js packages/volto-slate $(VERSION) + ##### Docker containers .PHONY: start-backend-docker @@ -190,7 +203,7 @@ start-test-all: ## Start Test .PHONY: start-test-frontend start-test-frontend: ## Start Test Volto Frontend @echo "$(GREEN)==> Start Test Volto Frontend$(RESET)" - RAZZLE_API_PATH=http://localhost:55001/plone yarn build && NODE_ENV=production node build/server.js + RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && NODE_ENV=production yarn start:prod .PHONY: start-test-backend start-test-backend: ## Start Test Plone Backend (api folder) @@ -209,17 +222,17 @@ test-acceptance-server-old: .PHONY: start-test-acceptance-frontend-dev start-test-acceptance-frontend-dev: ## Start the Core Acceptance Frontend Fixture in dev mode - RAZZLE_API_PATH=http://localhost:55001/plone yarn start + RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn start ######### Core Acceptance tests .PHONY: start-test-acceptance-server test-acceptance-server start-test-acceptance-server test-acceptance-server: ## Start Test Acceptance Server Main Fixture (docker container) - docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS) $(TESTING_ADDONS)' -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:default-homepage -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors $(DOCKER_IMAGE) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + docker run -i --rm -p 55001:55001 $(DOCKER_IMAGE_ACCEPTANCE) .PHONY: start-test-acceptance-frontend start-test-acceptance-frontend: ## Start the Core Acceptance Frontend Fixture - RAZZLE_API_PATH=http://localhost:55001/plone yarn build && yarn start:prod + RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && yarn start:prod .PHONY: test-acceptance test-acceptance: ## Start Core Cypress Acceptance Tests @@ -231,7 +244,7 @@ test-acceptance-headless: ## Start Core Cypress Acceptance Tests in headless mod .PHONY: full-test-acceptance full-test-acceptance: ## Runs Core Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server" http-get://localhost:55001/plone "make start-test-acceptance-frontend" http://localhost:3000 "make test-acceptance-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server" http-get://127.0.0.1:55001/plone "make start-test-acceptance-frontend" http://127.0.0.1:3000 "make test-acceptance-headless" ######### Seamless Core Acceptance tests @@ -249,24 +262,28 @@ start-test-acceptance-webserver-seamless: ## Start the seamless webserver .PHONY: full-test-acceptance-seamless full-test-acceptance-seamless: ## Runs Seamless Core Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server" http-get://localhost:55001/plone "make start-test-acceptance-frontend-seamless" http://localhost:3000 "make test-acceptance-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server" http-get://127.0.0.1:55001/plone "make start-test-acceptance-frontend-seamless" http://127.0.0.1:3000 "make test-acceptance-headless" ######### Project Acceptance tests .PHONY: start-test-acceptance-frontend-project start-test-acceptance-frontend-project: ## Start the Project Acceptance Frontend Fixture - cd my-volto-app && RAZZLE_API_PATH=http://localhost:55001/plone yarn build && yarn start:prod + cd my-volto-app && RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && yarn start:prod ######### CoreSandbox Acceptance tests .PHONY: start-test-acceptance-server-coresandbox test-acceptance-server-coresandbox start-test-acceptance-server-coresandbox test-acceptance-server-coresandbox: ## Start CoreSandbox Test Acceptance Server Fixture (docker container) - docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS) $(TESTING_ADDONS)' -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:default-homepage,plone.volto:coresandbox -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors,plone.volto.coresandbox $(DOCKER_IMAGE) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + docker run -i --rm -p 55001:55001 -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:default-homepage,plone.volto:coresandbox -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors,plone.volto.coresandbox $(DOCKER_IMAGE_ACCEPTANCE) # ZSERVER_PORT=55001 CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors,plone.volto.coresandbox APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:default-homepage,plone.volto:coresandbox ./api/bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING .PHONY: start-test-acceptance-frontend-coresandbox start-test-acceptance-frontend-coresandbox: ## Start the CoreSandbox Acceptance Frontend Fixture - ADDONS=coresandbox RAZZLE_API_PATH=http://localhost:55001/plone yarn build && yarn start:prod + ADDONS=coresandbox RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && yarn start:prod + +.PHONY: start-test-acceptance-frontend-coresandbox-dev +start-test-acceptance-frontend-coresandbox-dev: ## Start the CoreSandbox Acceptance Frontend Fixture in dev mode + ADDONS=coresandbox RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn start .PHONY: test-acceptance-coresandbox test-acceptance-coresandbox: ## Start CoreSandbox Cypress Acceptance Tests @@ -278,17 +295,17 @@ test-acceptance-coresandbox-headless: ## Start CoreSandbox Cypress Acceptance Te .PHONY: full-test-acceptance-coresandbox full-test-acceptance-coresandbox: ## Runs CoreSandbox Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server-coresandbox" http-get://localhost:55001/plone "make start-test-acceptance-frontend-coresandbox" http://localhost:3000 "make test-acceptance-coresandbox-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server-coresandbox" http-get://127.0.0.1:55001/plone "make start-test-acceptance-frontend-coresandbox" http://127.0.0.1:3000 "make test-acceptance-coresandbox-headless" ######### Multilingual Acceptance tests .PHONY: start-test-acceptance-server-multilingual test-acceptance-server-multilingual start-test-acceptance-server-multilingual test-acceptance-server-multilingual: ## Start Multilingual Acceptance Server Multilingual Fixture (docker container) - docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS) $(TESTING_ADDONS)' -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:multilingual -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors $(DOCKER_IMAGE) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + docker run -i --rm -p 55001:55001 -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:multilingual $(DOCKER_IMAGE_ACCEPTANCE) .PHONY: start-test-acceptance-frontend-multilingual start-test-acceptance-frontend-multilingual: ## Start the Multilingual Acceptance Frontend Fixture - ADDONS=coresandbox:multilingualFixture RAZZLE_API_PATH=http://localhost:55001/plone yarn build && yarn start:prod + ADDONS=coresandbox:multilingualFixture RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && yarn start:prod .PHONY: test-acceptance-multilingual test-acceptance-multilingual: ## Start Multilingual Cypress Acceptance Tests @@ -300,18 +317,18 @@ test-acceptance-multilingual-headless: ## Start Multilingual Cypress Acceptance .PHONY: full-test-acceptance-multilingual full-test-acceptance-multilingual: ## Runs Multilingual Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server-multilingual" http-get://localhost:55001/plone "make start-test-acceptance-frontend-multilingual" http://localhost:3000 "make test-acceptance-multilingual-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server-multilingual" http-get://127.0.0.1:55001/plone "make start-test-acceptance-frontend-multilingual" http://127.0.0.1:3000 "make test-acceptance-multilingual-headless" ######### WorkingCopy Acceptance tests .PHONY: start-test-acceptance-server-workingcopy test-acceptance-server-workingcopy start-test-acceptance-server-workingcopy test-acceptance-server-workingcopy : ## Start the WorkingCopy Acceptance Server Fixture (docker container) - docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS) $(TESTING_ADDONS)' -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.app.iterate:default,plone.volto:default-homepage -e CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.volto,plone.volto.cors $(DOCKER_IMAGE) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + docker run -i --rm -p 55001:55001 -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.app.iterate:default,plone.volto:default-homepage $(DOCKER_IMAGE_ACCEPTANCE) # ZSERVER_PORT=55001 CONFIGURE_PACKAGES=plone.app.contenttypes,plone.restapi,plone.app.iterate,plone.volto,plone.volto.cors APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.app.iterate:default,plone.volto:default-homepage ./api/bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING .PHONY: start-test-acceptance-frontend-workingcopy start-test-acceptance-frontend-workingcopy: ## Start the WorkingCopy Acceptance Frontend Fixture - ADDONS=coresandbox:workingCopyFixture RAZZLE_API_PATH=http://localhost:55001/plone yarn build && yarn start:prod + ADDONS=coresandbox:workingCopyFixture RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build && yarn start:prod .PHONY: test-acceptance-workingcopy test-acceptance-workingcopy: ## Start WorkingCopy Cypress Acceptance Tests @@ -323,7 +340,7 @@ test-acceptance-workingcopy-headless: ## Start WorkingCopy Cypress Acceptance Te .PHONY: full-test-acceptance-workingcopy full-test-acceptance-workingcopy: ## Runs WorkingCopy Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server-workingcopy" http-get://localhost:55001/plone "make start-test-acceptance-frontend-workingcopy" http://localhost:3000 "make test-acceptance-workingcopy-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server-workingcopy" http-get://127.0.0.1:55001/plone "make start-test-acceptance-frontend-workingcopy" http://127.0.0.1:3000 "make test-acceptance-workingcopy-headless" ######### Guillotina Acceptance tests @@ -333,7 +350,7 @@ start-test-acceptance-server-guillotina: ## Start Guillotina Test Acceptance Ser .PHONY: start-test-acceptance-frontend-guillotina start-test-acceptance-frontend-guillotina: ## Start the Guillotina Acceptance Frontend Fixture - ADDONS=volto-guillotina RAZZLE_API_PATH=http://localhost:8081/db/web RAZZLE_LEGACY_TRAVERSE=true yarn build && yarn start:prod + ADDONS=volto-guillotina RAZZLE_API_PATH=http://127.0.0.1:8081/db/web RAZZLE_LEGACY_TRAVERSE=true yarn build && yarn start:prod .PHONY: test-acceptance-guillotina test-acceptance-guillotina: ## Start the Guillotina Cypress Acceptance Tests @@ -345,7 +362,7 @@ test-acceptance-guillotina-headless: ## Start the Guillotina Cypress Acceptance .PHONY: full-test-acceptance-guillotina full-test-acceptance-guillotina: ## Runs the Guillotina Full Acceptance Testing in headless mode - $(NODEBIN)/start-test "make start-test-acceptance-server-guillotina" http-get://localhost:8081 "make start-test-acceptance-frontend-guillotina" http://localhost:3000 "make test-acceptance-guillotina-headless" + $(NODEBIN)/start-test "make start-test-acceptance-server-guillotina" http-get://127.0.0.1:8081 "make start-test-acceptance-frontend-guillotina" http://127.0.0.1:3000 "make test-acceptance-guillotina-headless" ######### Plone 5 Acceptance tests diff --git a/README.md b/README.md index 7af56783d5..8cdca13cbe 100644 --- a/README.md +++ b/README.md @@ -53,20 +53,16 @@ First get all the requirements installed on your system. ### Prerequisites -- [Node.js LTS (16.x)](https://nodejs.org/) +- [Node.js LTS (18.x)](https://nodejs.org/) - [Python](https://python.org/) - See below for specific versions. - [Docker](https://www.docker.com/get-started) (if using the Plone docker images) -*UPDATE 2022-10-25*: Since 2022-10-25, NodeJS 18 is in LTS state (https://github.com/nodejs/release#release-schedule). However, due to changes in internal SSL libraries, some Volto dependencies have been deprecated and need to be updated in order to continue working in NodeJS 18, mainly Webpack 4 (see: https://github.com/webpack/webpack/issues/14532#issuecomment-947525539 for further information). You can still use it, but NodeJS should be run under a special flag: `NODE_OPTIONS=--openssl-legacy-provider`. See also Volto's PR: https://github.com/plone/volto/pull/3699 for more information. - The versions of Python that are supported in Volto depend on the version of Plone that you use. | Plone | Python | Volto | |---|---|---| | 5.2 | 2.7, 3.6-3.8 | 15.0 | -| 6.0 (beta) | 3.8-3.10 | 16.0 (alpha) | - -At the time of this writing, Volto 16 is still in alpha status, and Plone 6 is in beta status. +| 6.0 | 3.8-3.11 | 16.0 | ### Create a Volto project using the generator @@ -90,7 +86,7 @@ cd myvoltoproject You can bootstrap a ready Docker Plone container with all the dependencies and ready for Volto use. We recommend to use the Plone docker builds based in `pip` [plone/plone-backend](https://github.com/plone/plone-backend) image: ```shell -docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e PROFILES="plone.volto:default-homepage" plone/plone-backend:6.0.0b3 +docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e PROFILES="plone.volto:default-homepage" plone/plone-backend:6.0.1 ``` or as an alternative if you have experience with Plone and you have all the @@ -105,7 +101,7 @@ make build-backend Volto is the default UI for Plone 6, so it will work for all Plone 6 released versions. -For the Plone 5 series, the latest released version of Plone 5 (with Python 3) is recommended (at the time of writing 5.2.9). +For the Plone 5 series, the latest released version of Plone 5 (with Python 3) is recommended (at the time of writing 5.2.10). #### KGS (known good set of versions) for backend packages @@ -113,14 +109,14 @@ On Plone 6, we recommend using the known good set (KGS) of package versions that On Plone 5, Volto is currently tested with the following packages pinned to specific versions, and we recommend using the same versions, which are: -- plone.restapi 8.30.0 -- plone.rest 2.0.0a5 -- plone.volto 4.0.0a13 +- plone.restapi 8.32.6 +- plone.rest 2.0.0 +- plone.volto 4.0.3 This would be the docker command to spawn a Plone 5 container with the right KGS versions: ```shell -docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e ADDONS="plone.restapi==8.30.0 plone.volto==4.0.0a13 plone.rest==2.0.0a5 plone.app.iterate==4.0.2 plone.app.vocabularies==4.3.0" -e PROFILES="plone.volto:default-homepage" plone/plone-backend +docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e ADDONS="plone.restapi==8.32.6 plone.volto==4.0.3 plone.rest==2.0.0" -e PROFILES="plone.volto:default-homepage" plone/plone-backend ``` ### Start Volto @@ -138,7 +134,7 @@ Go to [http://localhost:3000](http://localhost:3000) in your browser. Volto is actively developed since 2017 and used in production since 2018 on the following websites: - [VHS Ehrenamtsportal](https://vhs-ehrenamtsportal.de) (Website to help volunteers that help refugees for the [German Adult Education Association](https://www.dvv-vhs.de/en/home/), developed by [kitconcept GmbH](https://kitconcept.com), 2018) -- [Zeelandia](https://zeelandia.de) (Corporate website for one of the leading backery ingrediences manufactors in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2019) +- [Zeelandia](https://zeelandia.de) (Corporate website for one of the leading backery ingredients manufacturers in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2019) - [Excellence at Humboldt-Universität zu Berlin](https://www.alles-beginnt-mit-einer-frage.de) (Website for the excellence initiative of the [Humboldt University Berlin](https://hu-berlin.de), developed by [kitconcept GmbH](https://kitconcept.com), 2019) - [Forest Information System for Europe](https://forest.eea.europa.eu) (Thematic website focusing on European forests, developed by [Eau de Web](https://www.eaudeweb.ro), 2019) - [Industrial Emissions portal for Europe](https://industry.eea.europa.eu) (Thematic website focusing on European industrial emissions, developed by [Eau de Web](https://www.eaudeweb.ro), 2020) @@ -153,7 +149,7 @@ Volto is actively developed since 2017 and used in production since 2018 on the - [Jobfamilie MEDICE](https://jobfamilie.medice.de/de) (Carrer website for MEDICE Arzneimittel Pütter GmbH & Co. KG), developed by [Werkbank GmbH](https://werkbank.de/), 2020) - [Baccanale Imola](https://www.baccanaleimola.it) (Baccanale is a food fair that happens every year in Imola, Italy. Developed by [RedTurtle](https://redturtle.it), 2020) - [ResOU](https://resou.osaka-u.ac.jp) (ResOU is introducing official researched releases by the University of Osaka, Japan. Developed by [CMScom](https://www.cmscom.jp), 2020) -- [Humboldt Labor](https://www.humboldt-labor.de/) (The Humboldt Lab is a website where the Humboldt University Berlin presents its latest reaseach projects and findings. Developed by [WLDX](https://wldx.de/) and [kitconcept GmbH](https://kitconcept.com), 2020) +- [Humboldt Labor](https://www.humboldt-labor.de/) (The Humboldt Lab is a website where the Humboldt University Berlin presents its latest research projects and findings. Developed by [WLDX](https://wldx.de/) and [kitconcept GmbH](https://kitconcept.com), 2020) - [Osaka University](https://www.osaka-u.ac.jp/en) (Osaka University is considered one of the most prestigious universities in Japan. Developed by [CMScom](https://www.cmscom.jp), 2021) - [Comune di Modena](https://www.comune.modena.it/) (Website of the Municipality of Modena. Developed by [RedTurtle](https://redturtle.it), 2020) - [Comune di Camposanto](https://www.comune.camposanto.mo.it/) (Website of the Municipality of Camposanto. Developed by [RedTurtle](https://redturtle.it), 2021) @@ -171,11 +167,16 @@ Volto is actively developed since 2017 and used in production since 2018 on the - [RawMaterial](https://rawmaterial.it/en) (Company's website. Developed by [RawMaterial](https://rawmaterial.it/en), 2021) - [WISE-Freshwater](https://water.europa.eu/freshwater) (WISE-Freshwater, the Freshwater Information System for Europe. Developed by [Eau de web](https://eaudeweb.ro) for the European Environmental Agency, 2021) - [EEA-IMSv4](https://www.eea.europa.eu/ims) (EEA Indicator Management System v4. Developed by [Eau de web](https://eaudeweb.ro) for the European Environmental Agency, 2021) -- [Memori](https://memori.ai/en) (Corporate website for Memori, startup specialising in technologies applied to the experience of memory through the development of Artificial Intelligences. Developed by [RawMaterial](https://rawmaterial.it/en), 2021) +- [Memori](https://memori.ai/en) (Corporate website for Memori, startup specializing in technologies applied to the experience of memory through the development of Artificial Intelligences. Developed by [RawMaterial](https://rawmaterial.it/en), 2021) - [TwinCreator](https://twincreator.com/en) (TwinCreator allows you to design and train multiple AI’s through simple conversation through NLP. Developed by [RawMaterial](https://rawmaterial.it/en), 2021) - [MemoryTwin](https://memorytwin.com/en) (Product website, MemoryTwin allows you to create your personal artificial intelligence, able to remember and speak. Developed by [RawMaterial](https://rawmaterial.it/en), 2022) - [Forschungszentrum Jülich](https://fz-juelich.de) (Website for Forschungzentrum Jülich, which is one of the largest research institutions in Europe, developed by [kitconcept GmbH](https://kitconcept.com), 2022) - [ILPO](https://ilpo.jyu.fi/) (the registration portal of continuous learning at the University of Jyväskylä. Developed by University of Jyväskylä, 2022) +- [Debabarreneko mankomunitatea](https://debabarrena.eus) (Website of the Commonwealth of Debabarrena, community of municipalities to centralize waste handling services, developed by [CodeSyntax](https://www.codesyntax.com/en), 2022) +- [Debako Udala / Ayuntamiento de Deba](https://www.deba.eus) (Website of the municipality of Deba, developed by [CodeSyntax](https://www.codesyntax.com/en), 2022) +- [Helmholtz-Institut Erlangen-Nürnberg für Erneuerbare Energien (HI-ERN)](https://www.hi-ern.de) (Website for HI ERN, a research institution for renewable energies, developed by [kitconcept GmbH](https://kitconcept.com), 2022) +- [Lanku](https://www.lanku.eus) (Website for Lanku Kultur Zerbitzuak, a company offering cultural services and improvised Basque verse singing sessions across the Basque Country, developed by [CodeSyntax](https://www.codesyntax.com/en), 2023) +- [UEU](https://www.ueu.eus) (Website for Udako Euskal Unibertsitatea, a non-profit University offering all its service only in Basque: courses, publications, ... developed by [CodeSyntax](https://www.codesyntax.com/en), 2023) Please create a new [issue](https://github.com/plone/volto/issues/new) or [pull request](https://github.com/plone/volto/pulls) to add your Volto-site here! @@ -189,14 +190,14 @@ On the [Plone Trainings Website](https://training.plone.org) you'll find Volto-dedicated open training materials, plus React and other JavaScript-centered trainings. -- [Mastering Plone 6 Development](https://training.plone.org/5/mastering-plone/) +- [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/5/voltohandson/index.html) -- [Volto Add-ons Development](https://training.plone.org/5/voltoaddons/index.html) +- [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/5/react/index.html) +- [React](https://training.plone.org/react/index.html) - [JavaScript For Plone Developers](https://training.plone.org/5/javascript/index.html) ## Talks @@ -229,10 +230,11 @@ JavaScript-centered trainings. ## Node Support +- Node 18: Supported since Volto 17 - Node 16: Supported since Volto 14 -- Node 14: Supported since Volto 8.8.0 -- Node 12: Deprecated from Volto 16 onwards. It was supported since Volto 4 -- Node 10: Deprecated from Volto 13 onwards. It was supported since Volto 1 (and its predecessor "plone-react") +- Node 14: No longer supported. It was supported from Volto 8.8.0 - 16 +- Node 12: No longer supported. It was supported from Volto 4 - 15 +- Node 10: No longer supported. It was supported from Volto 1 - 12 ## Browser support @@ -267,7 +269,7 @@ yarn Either using a Docker command: ```shell -docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e PROFILES="plone.volto:default-homepage" plone/plone-backend:6.0.0b3 +docker run -it --rm --name=plone -p 8080:8080 -e SITE=Plone -e PROFILES="plone.volto:default-homepage" plone/plone-backend:6.0.1 ``` or using the convenience makefile command: @@ -278,7 +280,7 @@ make start-backend-docker or running Plone on your machine (advanced), additional dependencies might be required, only for Plone experienced integrators/developers. Check the [Plone -Installation Documentation](https://docs.plone.org/manage/installing/installation.html). +Installation Documentation](https://6.docs.plone.org/install/index.html). ```shell make build-backend @@ -314,37 +316,6 @@ Browse to [http://localhost:3000](http://localhost:3000) in your browser. yarn test ``` -### Releasing - -For ease the release process, we use `release-it` utility that helps with the process. - -https://www.npmjs.com/package/release-it - -For using it and start a release you need to fulfill the requirements: - -- Have permissions to push on master branch -- Have permissions on the @plone org on npmjs.com -- Have a environment variable (`GITHUB_TOKEN`) with a GitHub personal token with permissions to - write the Volto Release page on GitHub (https://www.npmjs.com/package/release-it#github-releases) - -Then the command for release: - -```shell -yarn release -``` - -a dry-release command for testing the output is also available: - -```shell -yarn dry-release -``` - -and alpha release can also be cut using: - -```shell -yarn release-alpha -``` - ## Acceptance testing Here you can find a guide on how acceptance testing is done in Volto: diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000000..6e5b7cbd04 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,73 @@ +# Releasing + +To ease the release process, we use the utility [`release-it`](https://www.npmjs.com/package/release-it) which helps with the process, and [`towncrier`](https://towncrier.readthedocs.io) for creating and maintaining change logs. + +## Release requirements + +To start a release, you must fulfill the following requirements: + +- Have permission to push to `master` branch +- Have permission on the [`@plone` organization on npm](https://www.npmjs.com/org/plone). +- Have an environment variable `GITHUB_TOKEN` with a GitHub personal token with permissions to write to the [Volto Release page on GitHub](https://github.com/plone/volto/releases). +- Install [`pipx`](https://pypa.github.io/pipx/) in your system. + +To request these permissions, on GitHub tag `@plone/release-team`, or in Discord post to the [`release-team` channel](https://discord.com/channels/786421998426521600/897549410521714760). + +### Permission to push to `master` branch + +The release process involves pushing directly to the `master` branch. +Volto's `master` branch is protected, so the releaser needs to have permission for pushing to it. +At the moment of this writing, members of the GitHub group `@plone/volto-team` have permission to push to `master`. + +### Permission to release Volto to npm registry + +We push Volto's releases to the npm registry. +The releaser has to have permissions for pushing a release in the [`@plone` organization on npm](https://www.npmjs.com/org/plone). +Only the current Owners of this organization can grant permissions to the releaser. + +### Have a GitHub personal token with permissions to write the Volto's Releases + +The `release-it` library takes care of creating and pushing a GitHub Release for each release. +It requires you to get a GitHub personal token with permission to write to the Volto's Releases. +This can be acquired in your GitHub profile page. +When making a release, export the environment variable `GITHUB_TOKEN` in your shell session. + +```shell +export GITHUB_TOKEN="my_looooong_github_token" +``` + +See `release-it` documentation of [GitHub releases](https://www.npmjs.com/package/release-it#github-releases) and GitHub documentation [About releases](https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases). + +### Install `pipx` in your system + +The release process calls `towncrier`. +It is a Python library that uses the Python utility `pipx`. +This utility allows you to call and execute Python modules without installing them as a prerequisite in your system. +It works similar to the NodeJS `npx` utility. +On macOS, you can install `pipx` into your system: + +```shell +brew install pipx +``` + +Or follow detailed instructions in the `pipx` documentation for [Installation](https://pypa.github.io/pipx/installation/). + +## Running the release process + +These are the commands to make a Volto release: + +```shell +yarn release +``` + +A dry-release command for testing the output is also available: + +```shell +yarn dry-release +``` + +An alpha release can be cut using: + +```shell +yarn release-alpha +``` diff --git a/__tests__/create-addons-loader.test.js b/__tests__/create-addons-loader.test.js index 4500ec887e..c98f61d107 100644 --- a/__tests__/create-addons-loader.test.js +++ b/__tests__/create-addons-loader.test.js @@ -133,7 +133,7 @@ function transpile(fpath) { const code = fs.readFileSync(fpath, 'utf-8'); // console.log('original code', code); const output = transform(code, { - root: '../', + root: '.', plugins: ['@babel/plugin-transform-modules-commonjs'], }); fs.writeFileSync(fpath, output.code); diff --git a/__tests__/volto-slate/deserialize.test.js b/__tests__/volto-slate/deserialize.test.js new file mode 100644 index 0000000000..4ccea708a4 --- /dev/null +++ b/__tests__/volto-slate/deserialize.test.js @@ -0,0 +1,393 @@ +import config from '@plone/volto/registry'; + +import { JSDOM } from 'jsdom'; +import { deserialize } from '@plone/volto-slate/editor/deserialize'; +import * as htmlUtils from '@plone/volto-slate/editor/utils'; +import { makeEditor } from '@plone/volto-slate/utils/editor'; +import installSlate from '@plone/volto-slate/index'; + +const tojson = (html) => { + const parsed = new JSDOM(html); + const document = parsed.window.document; + const editor = makeEditor(); + const body = + document.getElementsByTagName('google-sheets-html-origin').length > 0 + ? document.querySelector('google-sheets-html-origin > table') + : document.body; + const json = deserialize(editor, body); + return json; +}; + +describe('deserialize', () => { + beforeEach(() => { + config.blocks.blocksConfig = { + table: { + id: 'table', + }, + }; + installSlate(config); + }); + + it('accepts a DOM element', () => { + const html = '

Hello world

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [ + { + text: 'Hello world', + }, + ], + }, + ]); + }); + + it('two root tags', () => { + const html = '

Hello world

something

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [ + { + text: 'Hello world', + }, + ], + }, + { + type: 'p', + children: [ + { + text: 'something', + }, + ], + }, + ]); + }); + + it('takes inline elements', () => { + const html = 'hello'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'strong', + children: [ + { + text: 'hello', + }, + ], + }, + ]); + }); + + it('strips unknown elements', () => { + const html = 'hello'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'strong', + children: [{ text: 'hello' }], + }, + ]); + }); + + it('#1: strips all spaces and tabs immediately before and after a line break', () => { + const html = '

Hello \n\t\t\t\t World!\t

'; + + expect(htmlUtils.removeSpaceBeforeAfterEndLine(html)).toBe( + '

Hello\n World!\t

', + ); + }); + + it('#2: convert all tabs to spaces', () => { + const html = '

Hello\n World!\t

'; + + expect(htmlUtils.convertTabsToSpaces(html)).toBe( + '

Hello\n World!

', + ); + }); + + it('#3: convert line breaks spaces', () => { + const html = '

Hello\n World!

'; + + expect(htmlUtils.convertLineBreaksToSpaces(html)).toBe( + '

Hello World!

', + ); + }); + + it('#4: remove space follows space in sibling text node', () => { + const html = '

Hello World!

'; + + const dom = new JSDOM(html); + const body = dom.window.document.body; + const span = body.querySelector('span'); + + expect(htmlUtils.removeSpaceFollowSpace(' World!', span)).toBe('World!'); + }); + + it('#4: remove space follows space in sibling inline node', () => { + const html = '

Hello World!

'; + + const dom = new JSDOM(html); + const body = dom.window.document.body; + const span = body.querySelector('span'); + const b = body.querySelector('b'); + + expect(htmlUtils.removeSpaceFollowSpace('Hello ', b)).toBe('Hello '); + expect(htmlUtils.removeSpaceFollowSpace(' World!', span)).toBe('World!'); + }); + + it('#4: remove space in text node follows space in sibling inline node', () => { + const html = '

Hello World!

'; + + const dom = new JSDOM(html); + const body = dom.window.document.body; + const b = body.querySelector('b'); + + const textNode = b.nextSibling; + expect(textNode.textContent).toBe(' World! '); + + expect(htmlUtils.removeSpaceFollowSpace(' World! ', textNode)).toBe( + 'World! ', + ); + }); + + it('#5. Remove space at beginning of element', () => { + const html = '

Hello World!

'; + + const dom = new JSDOM(html); + const body = dom.window.document.body; + const h1 = body.querySelector('h1'); + + const textNode = h1.firstChild; + expect(textNode.textContent).toBe(' Hello '); + + expect(htmlUtils.removeElementEdges(' Hello ', textNode)).toBe('Hello '); + }); + + it('#5. Remove space at end of element', () => { + const html = '

Hello World!

'; + + const dom = new JSDOM(html); + const body = dom.window.document.body; + const h1 = body.querySelector('h1'); + + const textNode = h1.lastChild; + expect(textNode.textContent).toBe(' '); + + expect(htmlUtils.removeElementEdges(' ', textNode)).toBe(''); + }); + + it('collapses multiple consecutive spaces', () => { + const html = 'hello world'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'strong', + children: [{ text: 'hello world' }], + }, + ]); + }); + + it('preserves spaces between two inline nodes', () => { + const html = 'hello world'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'i', + children: [{ text: 'hello' }], + }, + { text: ' ' }, + { + type: 'i', + children: [{ text: 'world' }], + }, + ]); + }); + + it('preserves spaces between one block and one inline node', () => { + const html = '

hello

world'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [{ text: 'hello' }], + }, + { text: ' ' }, + { + type: 'i', + children: [{ text: 'world' }], + }, + ]); + }); + + it('preserves spaces between one inline node and one block node', () => { + const html = 'hello

world

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'i', + children: [{ text: 'hello' }], + }, + { text: ' ' }, + { + type: 'p', + children: [{ text: 'world' }], + }, + ]); + }); + + it('replaces a single newline inside text with a space', () => { + const html = 'hello\nworld'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'i', + children: [{ text: 'hello world' }], + }, + ]); + }); + + it('replaces multiple newlines inside text with a space', () => { + const html = 'hello\n\n\nworld'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'i', + children: [{ text: 'hello world' }], + }, + ]); + }); + + it('removes whitespace between block elements', () => { + const html = '

hello

\n \n

world

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [{ text: 'hello' }], + }, + { + type: 'p', + children: [{ text: 'world' }], + }, + ]); + }); + + it('transforms newlines at beginning of tags to space', () => { + const html = 'hello\nworld'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'b', + children: [{ text: 'hello' }], + }, + { + type: 'i', + children: [{ text: ' world' }], + }, + ]); + }); + + it('transforms newlines after a space', () => { + const html = '

Lorem Ipsum\nis simply dummy text\n

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [ + { + type: 'strong', + children: [{ text: 'Lorem Ipsum' }], + }, + { text: ' is simply dummy text' }, + ], + }, + ]); + }); + + it('transforms newlines to space after an inline tag', () => { + const html = '

Lorem Ipsum\nis simply dummy text

'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'p', + children: [ + { + type: 'strong', + children: [{ text: 'Lorem Ipsum' }], + }, + { text: ' is simply dummy text' }, + ], + }, + ]); + }); + + it('it removes new lines at beginning of text of block nodes', () => { + const html = 'hello

\n world\n

dot'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'b', + children: [{ text: 'hello' }], + }, + { + type: 'p', + children: [{ text: 'world' }], + }, + { + type: 'i', + children: [{ text: 'dot' }], + }, + ]); + }); + + it('it removes consecutive space in inline nodes', () => { + const html = `hello world`; + // console.log(JSON.stringify(tojson(html), null, 2)); + + expect(tojson(html)).toStrictEqual([ + { + type: 'b', + children: [{ text: 'hello ' }], + }, + { + type: 'i', + children: [{ text: 'world' }], + }, + ]); + }); + + it('it handles text fragments', () => { + const html = + 'Lorem Ipsum\nis simply dummy text of the printing and typesetting industry.'; + + expect(tojson(html)).toStrictEqual([ + { + type: 'strong', + children: [{ text: 'Lorem Ipsum' }], + }, + { + text: ' is simply dummy text of the printing and typesetting industry.', + }, + ]); + }); + + it('handles chrome + firefox style copy', () => { + const html = `Hello world`; + + expect(tojson(html)).toStrictEqual([ + { + type: 'strong', + children: [{ text: 'Hello' }], + }, + { + text: ' ', + }, + { + text: 'world', + }, + ]); + }); +}); diff --git a/__tests__/webpack-relative-resolver.test.js b/__tests__/webpack-relative-resolver.test.js index 41519c4c53..960d81a28a 100644 --- a/__tests__/webpack-relative-resolver.test.js +++ b/__tests__/webpack-relative-resolver.test.js @@ -120,10 +120,16 @@ describe('functions as a Webpack resolver plugin', () => { const resolved = []; const resolver = { - plugin(typ, resolveCallback) { - resolveCallback(req, () => flag.push(true)); + ensureHook(typ) { + return this; }, - doResolve(type, req, _, callback) { + getHook(typ) { + return this; + }, + tapAsync: (name, callback) => { + callback(req, {}); + }, + doResolve(type, req, _, resolveContext, callback) { flag.push(true); resolved.push(req.request); }, @@ -143,10 +149,16 @@ describe('functions as a Webpack resolver plugin', () => { const resolved = []; const resolver = { - plugin(typ, resolveCallback) { - resolveCallback(req, () => flag.push(true)); + ensureHook(typ) { + return this; + }, + getHook(typ) { + return this; + }, + tapAsync: (name, callback) => { + callback(req, {}, () => flag.push(true)); }, - doResolve(type, req, _, callback) { + doResolve(type, req, _, resolveContext, callback) { flag.push(true); resolved.push(req.request); }, diff --git a/addon-registry.js b/addon-registry.js index 3dfea21f45..666c0bcd04 100644 --- a/addon-registry.js +++ b/addon-registry.js @@ -148,7 +148,7 @@ class AddonConfigurationRegistry { }, ); - this.initRazzleExtenders(); + this.initAddonExtenders(); } /** @@ -310,18 +310,26 @@ class AddonConfigurationRegistry { } /** - * Allow addons to provide razzle.config extenders. These extenders - * modules (named razzle.extend.js) need to provide two functions: + * Allow addons to provide various extenders. + * + * The razzle.extend.js modules (named razzle.extend.js) needs to provide + * two functions: * `plugins(defaultPlugins) => plugins` and * `modify(...) => config` + * + * The eslint.extend.js */ - initRazzleExtenders() { + initAddonExtenders() { this.getAddons().forEach((addon) => { const base = path.dirname(addon.packageJson); const razzlePath = path.resolve(`${base}/razzle.extend.js`); if (fs.existsSync(razzlePath)) { addon.razzleExtender = razzlePath; } + const eslintPath = path.resolve(`${base}/eslint.extend.js`); + if (fs.existsSync(eslintPath)) { + addon.eslintExtender = eslintPath; + } }); } @@ -340,6 +348,12 @@ class AddonConfigurationRegistry { .filter((e) => e); } + getEslintExtenders() { + return this.getAddons() + .map((o) => o.eslintExtender) + .filter((e) => e); + } + /** * Returns a mapping name:diskpath to be uses in webpack's resolve aliases */ diff --git a/api/Makefile b/api/Makefile index fbe15f133d..3820acf081 100644 --- a/api/Makefile +++ b/api/Makefile @@ -4,7 +4,7 @@ # https://tech.davis-hansson.com/p/make/ SHELL:=bash .ONESHELL: -.SHELLFLAGS:=-xeu -o pipefail -O inherit_errexit -c +.SHELLFLAGS:=-eu -o pipefail -c .SILENT: .DELETE_ON_ERROR: MAKEFLAGS+=--warn-undefined-variables diff --git a/api/README.rst b/api/README.rst index c249527cbc..3203aea283 100644 --- a/api/README.rst +++ b/api/README.rst @@ -45,7 +45,7 @@ are required for cryptography, image handling/scaling support and compression. You can find more up to date details on installing these necessary libraries for linux systems in the 'Mastering Plone' training at --> https://training.plone.org/5/mastering-plone/installation.html#installing-plone-backend +-> https://training.plone.org/mastering-plone/installation.html#installing-plone-backend For Windows you could try WSL (Windows subsystem for Linux) and for Mac OS X for example Homebrew to install these necessary support libraries. diff --git a/api/buildout.cfg b/api/buildout.cfg index fba6d75667..feb689d278 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.0b3/versions.cfg + http://dist.plone.org/release/6.0.2/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 2541a60e2c..d404ee2ec3 100644 --- a/api/versions.cfg +++ b/api/versions.cfg @@ -5,8 +5,8 @@ async-generator = 1.10 collective.folderishtypes = 3.0.0 collective.recipe.plonesite = 1.12.0 h11 = 0.12.0 -plone.restapi = 8.32.0 -plone.volto = 4.0.0a13 +plone.restapi = 8.35.1 +plone.volto = 4.0.7 prompt-toolkit = 2.0.10 pyOpenSSL = 21.0.0 robotframework-debuglibrary = 2.2.2 diff --git a/cypress.config.js b/cypress.config.js index 8e6be41a2b..4f2286287f 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -5,7 +5,7 @@ module.exports = defineConfig({ chromeWebSecurity: false, projectId: 'hvviu4', e2e: { - baseUrl: 'http://localhost:3000', + baseUrl: 'http://127.0.0.1:3000', excludeSpecPattern: ['*~'], specPattern: 'cypress/tests/**/*.{js,jsx,ts,tsx}', }, diff --git a/cypress/fixtures/halfdome2022.jpg b/cypress/fixtures/halfdome2022.jpg new file mode 100644 index 0000000000..58c9411ca2 Binary files /dev/null and b/cypress/fixtures/halfdome2022.jpg differ diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 5739a60e38..cd2e6f23d4 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -2,7 +2,7 @@ import '@testing-library/cypress/add-commands'; import { getIfExists } from '../helpers'; import { ploneAuth } from './constants'; -const HOSTNAME = Cypress.env('BACKEND_HOST') || 'localhost'; +const HOSTNAME = Cypress.env('BACKEND_HOST') || '127.0.0.1'; const GUILLOTINA_API_URL = `http://${HOSTNAME}:8081/db/web`; const PLONE_SITE_ID = Cypress.env('SITE_ID') || 'plone'; const PLONE_API_URL = @@ -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], @@ -46,9 +51,12 @@ Cypress.Commands.add( contentType, contentId, contentTitle, + contentDescription, path = '', allow_discussion = false, transition = '', + bodyModifier = (body) => body, + image = false, }) => { let api_url, auth; if (Cypress.env('API') === 'guillotina') { @@ -61,40 +69,44 @@ Cypress.Commands.add( api_url = PLONE_API_URL; auth = ploneAuthObj; } + + const defaultParams = { + method: 'POST', + url: `${api_url}/${path}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + body: { + '@type': contentType, + id: contentId, + title: contentTitle, + description: contentDescription, + allow_discussion: allow_discussion, + }, + }; + if (contentType === 'File') { - return cy.request({ - method: 'POST', - url: `${api_url}/${path}`, - headers: { - Accept: 'application/json', - }, - auth: auth, - body: { - '@type': contentType, - id: contentId, - title: contentTitle, + const params = { + ...defaultParams, + body: bodyModifier({ + ...defaultParams.body, file: { data: 'dGVzdGZpbGUK', encoding: 'base64', filename: 'lorem.txt', 'content-type': 'text/plain', }, - allow_discussion: allow_discussion, - }, - }); + }), + }; + + return cy.request(params); } if (contentType === 'Image') { - return cy.request({ - method: 'POST', - url: `${api_url}/${path}`, - headers: { - Accept: 'application/json', - }, - auth: auth, - body: { - '@type': contentType, - id: contentId, - title: contentTitle, + const params = { + ...defaultParams, + body: bodyModifier({ + ...defaultParams.body, image: { data: 'iVBORw0KGgoAAAANSUhEUgAAANcAAAA4CAMAAABZsZ3QAAAAM1BMVEX29fK42OU+oMvn7u9drtIPisHI4OhstdWZyt4fkcXX5+sAg74umMhNp86p0eJ7vNiKw9v/UV4wAAAAAXRSTlMAQObYZgAABBxJREFUeF7tmuty4yAMhZG4X2zn/Z92J5tsBJwWXG/i3XR6frW2Y/SBLIRAfaQUDNt8E5tLUt9BycfcKfq3R6Mlfyimtx4rzp+K3dtibXkor99zsEqLYZltblTecciogoh+TXfY1Ve4dn07rCDGG9dHSEEOg/GmXl0U1XDxTKxNK5De7BxsyyBr6gGm2/vPxKJ8F6f7BXKfRMp1xIWK9A+5ks25alSb353dWnDJN1k35EL5f8dVGifTf/4tjUuuFq7u4srmXC60yAmldLXIWbg65RKU87lcGxJCFqUPv0IacW0PmSivOZFLE908inPToMmii/roG+MRV/O8FU88i8tFsxV3a06MFUw0Qu7RmAtdV5/HVVaOVMTWNOWSwMljLhzhcB6XIS7OK5V6AvRDNN7t5VJWQs1J40UmalbK56usBG/CuCHSYuc+rkUGeMCViNRARPrzW52N3oQLe6WifNliSuuGaH3czbVNudI9s7ZLUCLHVwWlyES522o1t14uvmbblmVTKqFjaZYJFSTPP4dLL1kU1z7p0lzdbRulmEWLxoQX+z9ce7A8GqEEucllLxePuZwdJl1Lezu0hoswvTPt61DrFcRuujV/2cmlxaGBC7Aw6cpovGANwRiSdOAWJ5AGy4gLL64dl0QhUEAuEUNws+XxV+OKGPdw/hESGYF9XEGaFC7sNLMSXWJjHsnanYi87VK428N2uxpOjOFANcagLM5l+7mSycM8KknZpKLcGi6jmzWGr/vLurZ/0g4u9AZuAoeb5r1ceQhyiTPY1E4wUR6u/F3H2ojSpXMMriBPT9cezTto8Cx+MsglHL4fv1Rxrb1LVw9yvyQpJ3AhFnLZfuRLH2QsOG3FGGD20X/th/u5bFAt16Bt308KjF+MNOXgl/SquIEySX3GhaZvc67KZbDxcCDORz2N8yCWPaY5lyQZO7lQ29fnZbt3Xu6qoge4+DjXl/MocySPOp9rlvdyznahRyHEYd77v3LhugOXDv4J65QXfl803BDAdaWBEDhfVx7nKofjoVCgxnUAqw/UAUDPn788BDvQuG4TDtdtUPvzjSlXAB8DvaDOhhrmhwbywylXAm8CvaouikJTL93gs3y7Yy4VYbIxOHrcMizPqWOjqO9l3Uz52kibQy4xxOgqhJvD+w5rvokOcAlGvNCfeqCv1ste1stzLm0f71Iq3ZfTrPfuE5nhPtF+LvQE2lffQC7pYtQy3tdzdrKvd5TLVVzDetScS3nEKmmwDyt1Cev1kX3YfbvzNK4fzrlw+cB6vm+uiUgf2zdXI62241LawCb7Pi5FXFPF8KpzDoF/Sw2lg+GrHNbno1mhPu+VCF/vfMnw06PnUl6j48dVHD3jHNHPua+fc3o/5yp/zsGi0vYtzi3Pz5mHd4T6BWMIlewacd63AAAAAElFTkSuQmCC', @@ -102,38 +114,75 @@ Cypress.Commands.add( filename: 'image.png', 'content-type': 'image/png', }, - }, - }); + }), + }; + + return cy.request(params); } if ( ['Document', 'News Item', 'Folder', 'CMSFolder'].includes(contentType) ) { - return cy - .request({ - method: 'POST', - url: `${api_url}/${path}`, - headers: { - Accept: 'application/json', + const params = { + ...defaultParams, + body: { + ...defaultParams.body, + blocks: { + 'd3f1c443-583f-4e8e-a682-3bf25752a300': { '@type': 'title' }, + '7624cf59-05d0-4055-8f55-5fd6597d84b0': { '@type': 'slate' }, }, - auth: auth, - body: { - '@type': contentType, - id: contentId, - title: contentTitle, - blocks: { - 'd3f1c443-583f-4e8e-a682-3bf25752a300': { '@type': 'title' }, - '7624cf59-05d0-4055-8f55-5fd6597d84b0': { '@type': 'slate' }, - }, - blocks_layout: { - items: [ - 'd3f1c443-583f-4e8e-a682-3bf25752a300', - '7624cf59-05d0-4055-8f55-5fd6597d84b0', - ], - }, - allow_discussion: allow_discussion, + blocks_layout: { + items: [ + 'd3f1c443-583f-4e8e-a682-3bf25752a300', + '7624cf59-05d0-4055-8f55-5fd6597d84b0', + ], }, - }) - .then(() => { + }, + }; + + if (image) { + let sourceFilename = 'cypress/fixtures/halfdome2022.jpg'; + let imageObject = { + encoding: 'base64', + filename: 'image.jpg', + 'content-type': 'image/jpg', + }; + if (typeof image === 'object') { + sourceFilename = image.sourceFilename; + imageObject = { + ...imageObject, + ...image, + }; + } + cy.readFile(sourceFilename, 'base64').then((encodedImage) => { + const withImageParams = { + ...params, + body: bodyModifier({ + ...params.body, + preview_image: { + ...imageObject, + data: encodedImage, + }, + }), + }; + + return cy.request(withImageParams).then(() => { + if (transition) { + cy.setWorkflow({ + path: path || contentId, + review_state: transition, + }); + } + console.log(`${contentType} created`); + }); + }); + } else { + const documentParams = { + ...params, + body: bodyModifier({ + ...params.body, + }), + }; + return cy.request(documentParams).then(() => { if (transition) { cy.setWorkflow({ path: path || contentId, @@ -142,6 +191,7 @@ Cypress.Commands.add( } console.log(`${contentType} created`); }); + } } else { return cy .request({ @@ -151,12 +201,12 @@ Cypress.Commands.add( Accept: 'application/json', }, auth: auth, - body: { + body: bodyModifier({ '@type': contentType, id: contentId, title: contentTitle, allow_discussion: allow_discussion, - }, + }), }) .then(() => { if (transition) { @@ -195,10 +245,34 @@ Cypress.Commands.add('removeContent', ({ path = '' }) => { }); }); +// Get content +Cypress.Commands.add('getContent', ({ path = '' }) => { + let api_url, auth; + if (Cypress.env('API') === 'guillotina') { + api_url = GUILLOTINA_API_URL; + auth = { + user: 'root', + pass: 'root', + }; + } else { + api_url = PLONE_API_URL; + auth = ploneAuthObj; + } + + return cy.request({ + method: 'get', + url: `${api_url}/${path}`, + headers: { + Accept: 'application/json', + }, + auth: auth, + }); +}); + // --- Add DX Content-Type ---------------------------------------------------------- Cypress.Commands.add('addContentType', (name) => { let api_url, auth; - api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:8080/Plone'; auth = ploneAuthObj; return cy @@ -219,7 +293,7 @@ Cypress.Commands.add('addContentType', (name) => { // --- Remove DX behavior ---------------------------------------------------------- Cypress.Commands.add('removeContentType', (name) => { let api_url, auth; - api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:8080/Plone'; auth = ploneAuthObj; return cy @@ -238,7 +312,7 @@ Cypress.Commands.add('removeContentType', (name) => { // --- Add DX field ---------------------------------------------------------- Cypress.Commands.add('addSlateJSONField', (type, name) => { let api_url, auth; - api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:8080/Plone'; auth = ploneAuthObj; return cy @@ -263,7 +337,7 @@ Cypress.Commands.add('addSlateJSONField', (type, name) => { // --- Remove DX field ---------------------------------------------------------- Cypress.Commands.add('removeSlateJSONField', (type, name) => { let api_url, auth; - api_url = Cypress.env('API_PATH') || 'http://localhost:8080/Plone'; + api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:8080/Plone'; auth = ploneAuthObj; return cy @@ -291,7 +365,7 @@ Cypress.Commands.add( password = 'password', roles = ['Member', 'Reader', 'Editor'], groups = { - '@id': 'http://localhost:3000/@users', + '@id': 'http://127.0.0.1:3000/@users', items: [ { id: 'AuthenticatedUsers', @@ -375,7 +449,7 @@ Cypress.Commands.add( password = ploneAuth[1], roles = ['Member', 'Reader'], users = { - '@id': 'http://localhost:3000/@groups', + '@id': 'http://127.0.0.1:3000/@groups', items: [], items_total: 0, }, @@ -589,7 +663,7 @@ Cypress.Commands.add( (query, htmlContent) => { return cy .wrap(query) - .type(' ') + .type(' {backspace}') .trigger('paste', createHtmlPasteEvent(htmlContent)); }, ); @@ -737,6 +811,12 @@ function createHtmlPasteEvent(htmlContent) { ); } +Cypress.Commands.add('addNewBlock', (blockName, createNewSlate = false) => { + let block; + block = cy.getSlate(createNewSlate).type(`/${blockName}{enter}`); + return block; +}); + Cypress.Commands.add('navigate', (route = '') => { return cy.window().its('appHistory').invoke('push', route); }); @@ -749,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/support/guillotina.js b/cypress/support/guillotina.js index 5300ff21cd..f8f9275e3f 100644 --- a/cypress/support/guillotina.js +++ b/cypress/support/guillotina.js @@ -3,7 +3,7 @@ export function setupGuillotina() { Authorization: 'Basic cm9vdDpyb290', 'Content-Type': 'application/json', }; - const api_url = 'http://localhost:8081/db'; + const api_url = 'http://127.0.0.1:8081/db'; cy.request({ method: 'POST', @@ -62,7 +62,7 @@ export function tearDownGuillotina({ allowFail = false } = {}) { Authorization: 'Basic cm9vdDpyb290', 'Content-Type': 'application/json', }; - const api_url = 'http://localhost:8081/db'; + const api_url = 'http://127.0.0.1:8081/db'; cy.request({ method: 'DELETE', diff --git a/cypress/support/reset-fixture.js b/cypress/support/reset-fixture.js index a9a5fad79c..ebe6fffaf6 100644 --- a/cypress/support/reset-fixture.js +++ b/cypress/support/reset-fixture.js @@ -1,5 +1,5 @@ function setup() { - const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + const api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:55001/plone'; cy.request({ method: 'POST', url: `${api_url}/RobotRemote`, @@ -10,7 +10,7 @@ function setup() { } function teardown() { - const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + const api_url = Cypress.env('API_PATH') || 'http://127.0.0.1:55001/plone'; cy.request({ method: 'POST', url: `${api_url}/RobotRemote`, diff --git a/cypress/support/upgradetests.js b/cypress/support/upgradetests.js index 8d8d976636..03205a9c70 100644 --- a/cypress/support/upgradetests.js +++ b/cypress/support/upgradetests.js @@ -6,7 +6,7 @@ export const getsystemNeedsUpgrade = { plone_gs_metadata_version_file_system: '6008', plone_gs_metadata_version_installed: '6006', plone_restapi_version: '8.32.0', - plone_version: '6.0.0b3', + plone_version: '6.0.0', python_version: '3.9.14 (main, Sep 13 2022, 03:20:56) \n[GCC 10.2.1 20210110]', upgrade: true, diff --git a/cypress/tests/core/basic/autologin.js b/cypress/tests/core/basic/autologin.js index 214d03e478..2e3a5627ee 100644 --- a/cypress/tests/core/basic/autologin.js +++ b/cypress/tests/core/basic/autologin.js @@ -2,7 +2,7 @@ import { ploneAuth } from '../../../support/constants'; describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:55001/plone'; + const api_url = 'http://127.0.0.1:55001/plone'; const user = ploneAuth[0]; const password = ploneAuth[1]; diff --git a/cypress/tests/core/basic/language-controlpanel.js b/cypress/tests/core/basic/language-controlpanel.js new file mode 100644 index 0000000000..fb734abde2 --- /dev/null +++ b/cypress/tests/core/basic/language-controlpanel.js @@ -0,0 +1,26 @@ +describe('Language control-panel', () => { + beforeEach(() => { + cy.visit('/'); + cy.autologin(); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + }); + + it('Displays all valid fields in language control-panel', () => { + cy.visit('/controlpanel/language'); + cy.get('main').within(() => { + cy.get('.field-wrapper-default_language').should('be.visible'); + cy.get('.field-wrapper-available_languages').should('be.visible'); + cy.get('.field-wrapper-use_combined_language_codes').should('be.visible'); + }); + }); + + it('Does not display unwanted fields in language control-panel', () => { + cy.visit('/controlpanel/language'); + cy.get('main').within(() => { + cy.get('.field-wrapper-always_show_selector').should('not.exist'); + cy.get('.field-wrapper-display_flags').should('not.exist'); + }); + }); +}); diff --git a/cypress/tests/core/basic/sharing.js b/cypress/tests/core/basic/sharing.js index de532dacf2..423f1e5beb 100644 --- a/cypress/tests/core/basic/sharing.js +++ b/cypress/tests/core/basic/sharing.js @@ -67,7 +67,7 @@ describe('Sharing Tests', () => { cy.visit('/logout'); cy.wait('@logout'); - cy.autologin('test-user'); + cy.autologin('test-user', 'correct horse battery staple'); cy.visit('/my-page'); cy.findByRole('heading', { name: /my page/i }).should('exist'); }); diff --git a/cypress/tests/core/blocks/blocks-autofocus.js b/cypress/tests/core/blocks/blocks-autofocus.js index 225942ae5f..9e9c27be21 100644 --- a/cypress/tests/core/blocks/blocks-autofocus.js +++ b/cypress/tests/core/blocks/blocks-autofocus.js @@ -17,15 +17,10 @@ describe('New Block Auto Focus Tests', () => { cy.navigate('/my-page/edit'); cy.intercept('GET', '/**/my-page').as('content'); cy.intercept('PATCH', '*').as('save'); - // when I add a text block - //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); }); it('Press Enter on a description block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Text').click(); - cy.get('.blocks-chooser .text').contains('Description').click(); + cy.addNewBlock('description'); cy.get('.documentDescription').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -35,8 +30,10 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a text block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Text').click(); - cy.get('.blocks-chooser .text').contains('Text').click(); + cy.getSlate().click(); + cy.get('button.block-add-button').click(); + cy.get('.blocks-chooser .title').contains('Text').click({ force: true }); + cy.get('.blocks-chooser .text').contains('Text').click({ force: true }); cy.get('.text-slate-editor-inner').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -46,8 +43,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a image block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Media').click(); - cy.get('.blocks-chooser .media').contains('Image').click(); + cy.addNewBlock('image'); cy.get('.block-editor-image').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -57,8 +53,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a video block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Media').click(); - cy.get('.blocks-chooser .media').contains('Video').click(); + cy.addNewBlock('video'); cy.get('.block-editor-video').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -68,8 +63,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a listing block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); cy.get('.block-editor-listing').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -79,8 +73,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a table of contents block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Table of Contents').click(); + cy.addNewBlock('contents'); cy.get('.block-editor-toc').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -90,8 +83,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a maps block adds new autofocused default block', () => { - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); cy.get('.block-editor-maps').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -101,9 +93,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a html block adds new autofocused default block', () => { - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('HTML').click(); + cy.addNewBlock('html'); cy.get('.block-editor-html').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) @@ -113,9 +103,7 @@ describe('New Block Auto Focus Tests', () => { }); it('Press Enter on a search block adds new autofocused default block', () => { - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Search').click(); + cy.addNewBlock('search'); cy.get('.block-editor-search').first().click().type('{enter}'); cy.get('*[class^="block-editor"]') .eq(2) diff --git a/cypress/tests/core/blocks/blocks-chooser.js b/cypress/tests/core/blocks/blocks-chooser.js new file mode 100644 index 0000000000..f5816a8db7 --- /dev/null +++ b/cypress/tests/core/blocks/blocks-chooser.js @@ -0,0 +1,62 @@ +describe('Blocks Tests', () => { + beforeEach(() => { + cy.intercept('POST', '*').as('saveImage'); + cy.intercept('GET', '/**/image.png/@@images/image').as('getImage'); + // given a logged in editor and a page in edit mode + cy.visit('/'); + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'my-page', + contentTitle: 'My Page', + }); + cy.visit('/my-page'); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('my-page'); + cy.navigate('/my-page/edit'); + }); + + it('Add image block', () => { + // when I add an image block + cy.getSlate().click(); + cy.get('.ui.basic.icon.button.block-add-button').click(); + cy.get('.ui.basic.icon.button.image').contains('Image').click(); + cy.get('.block.image .ui.input input[type="text"]').type( + `https://github.com/plone/volto/raw/master/logos/volto-colorful.png{enter}`, + ); + cy.get('#toolbar-save').click(); + cy.url().should('eq', Cypress.config().baseUrl + '/my-page'); + + // then the page view should contain the image block + cy.get('#page-document img').should( + 'have.attr', + 'src', + 'https://github.com/plone/volto/raw/master/logos/volto-colorful.png', + ); + + cy.get('#page-document img') + .should('be.visible') + .and(($img) => { + // "naturalWidth" and "naturalHeight" are set when the image loads + expect($img[0].naturalWidth).to.be.greaterThan(0); + }); + }); + + it('Press Enter on a listing block adds new autofocused default block', () => { + cy.getSlate().click(); + cy.get('button.block-add-button').click(); + cy.get('.blocks-chooser .title').contains('Common').click(); + cy.get('.blocks-chooser .common') + .contains('Listing') + .click({ force: true }); + cy.get('.block-editor-listing').first().click().type('{enter}'); + cy.get('*[class^="block-editor"]') + .eq(2) + .within(() => { + return cy.get('.selected'); + }); + }); +}); diff --git a/cypress/tests/core/blocks/blocks-copypaste.js b/cypress/tests/core/blocks/blocks-copypaste.js index 6cfa17154f..8b1f0d7091 100644 --- a/cypress/tests/core/blocks/blocks-copypaste.js +++ b/cypress/tests/core/blocks/blocks-copypaste.js @@ -20,10 +20,7 @@ describe('Blocks copy/paste', () => { cy.intercept('PATCH', '/**/my-page').as('save'); cy.intercept('GET', '/**/my-page').as('content'); // GIVEN: A page with multiple blocks - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); cy.get(`.block.maps .toolbar-inner .ui.input input`) .type( '', @@ -62,10 +59,7 @@ describe('Blocks copy/paste', () => { // GIVEN: A page with multiple blocks cy.intercept('PATCH', '/**/my-page').as('save'); cy.intercept('GET', '/**/my-page').as('content'); - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); cy.get(`.block.maps .toolbar-inner .ui.input input`) .type( '', @@ -105,10 +99,7 @@ describe('Blocks copy/paste', () => { cy.intercept('PATCH', '/**/my-page').as('save'); cy.intercept('GET', '/**/my-page').as('content'); // GIVEN: A page with multiple blocks - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); cy.get(`.block.maps .toolbar-inner .ui.input input`) .type( '', diff --git a/cypress/tests/core/blocks/blocks-listing.js b/cypress/tests/core/blocks/blocks-listing.js index c6de188ce0..bea65dac47 100644 --- a/cypress/tests/core/blocks/blocks-listing.js +++ b/cypress/tests/core/blocks/blocks-listing.js @@ -55,10 +55,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('My title'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //verify before save cy.get(`.block.listing .listing-body:first-of-type`).contains( @@ -115,10 +112,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('My title'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //verify before save cy.get(`.block.listing .listing-body:first-of-type`).contains( @@ -137,7 +131,7 @@ describe('Listing Block Tests', () => { ); }); - it.only('Add Listing block - results preview', () => { + it('Add Listing block - results preview', () => { cy.intercept('PATCH', '/**/my-page').as('save'); cy.intercept('GET', '/**/my-page').as('content'); cy.intercept('GET', '/**/@types/Document').as('schema'); @@ -171,10 +165,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('My title'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); cy.get('.sidebar-container .tabs-wrapper .menu .item') .contains('Block') @@ -250,10 +241,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('My title'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //verify before save cy.get(`.block.listing .listing-body:first-of-type`).contains( @@ -308,10 +296,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('My title'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //******** add Type criteria filter cy.get('.querystring-widget .fields').contains('Add criteria').click(); @@ -372,10 +357,7 @@ describe('Listing Block Tests', () => { //add listing block cy.scrollTo('bottom'); - cy.getSlate(true).click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing', true); //******** add Type criteria filter cy.get('.sidebar-container .tabs-wrapper .menu .item') @@ -451,10 +433,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('Listing block - Test Criteria: short-name'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //******** add short-name criteria filter cy.get('.sidebar-container .tabs-wrapper .menu .item') @@ -544,10 +523,7 @@ describe('Listing Block Tests', () => { ); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //******** add location criteria filter cy.get('.sidebar-container .tabs-wrapper .menu .item') @@ -636,10 +612,7 @@ describe('Listing Block Tests', () => { ); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //******** add location criteria filter cy.get('.sidebar-container .tabs-wrapper .menu .item') @@ -730,10 +703,7 @@ describe('Listing Block Tests', () => { cy.wait('@schema'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //******** add location criteria filter cy.get('.sidebar-container .tabs-wrapper .menu .item') @@ -816,10 +786,7 @@ describe('Listing Block Tests', () => { cy.clearSlateTitle().type('Listing block - respect batching and limits'); //add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); //verify before save cy.get(`.block.listing .listing-body:first-of-type`).contains('My Folder'); diff --git a/cypress/tests/core/blocks/blocks-map.js b/cypress/tests/core/blocks/blocks-map.js index c4872e9671..9644513af9 100644 --- a/cypress/tests/core/blocks/blocks-map.js +++ b/cypress/tests/core/blocks/blocks-map.js @@ -18,10 +18,8 @@ describe('Map Block Tests', () => { it('Add maps block - Google Maps', () => { // when I add a maps block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); + cy.get(`.block.maps .toolbar-inner .ui.input input`) .type( '', @@ -43,10 +41,8 @@ describe('Map Block Tests', () => { it('Add maps block - OpenStreet Maps', () => { // when I add a maps block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Maps').click(); + cy.addNewBlock('maps'); + cy.get(`.block.maps .toolbar-inner .ui.input input`) .type( '
View Larger Map', diff --git a/cypress/tests/core/blocks/blocks-search.js b/cypress/tests/core/blocks/blocks-search.js index 9fe55fe871..d4ca23f8a9 100644 --- a/cypress/tests/core/blocks/blocks-search.js +++ b/cypress/tests/core/blocks/blocks-search.js @@ -43,10 +43,7 @@ describe('Search Block Tests', () => { cy.getSlateTitle().focus().click().type('My Search Page'); // Add Search listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Search').click(); + cy.addNewBlock('search'); // Add search query criteria cy.get('#blockform-fieldset-searchquery').click(); diff --git a/cypress/tests/core/blocks/blocks.js b/cypress/tests/core/blocks/blocks.js index 7e0912118d..e206dbc965 100644 --- a/cypress/tests/core/blocks/blocks.js +++ b/cypress/tests/core/blocks/blocks.js @@ -67,10 +67,7 @@ describe('Blocks Tests', () => { it('Add HTML block', () => { // when I add a maps block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('HTML').click(); + cy.addNewBlock('html'); cy.get(`.block.html .npm__react-simple-code-editor__textarea`).type( `
This is HTML
`, ); @@ -92,10 +89,7 @@ describe('Blocks Tests', () => { cy.intercept('PATCH', '*').as('save'); cy.intercept('GET', '/**/my-page').as('content'); // Edit - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.ui.buttons .button.slateTable').click(); + cy.addNewBlock('table'); cy.wait(2000); cy.get( '.celled.fixed.table thead tr th:first-child() [contenteditable="true"]', @@ -235,4 +229,19 @@ describe('Blocks Tests', () => { // 'header-two', // ); // }); + + it('Handles unknown blocks', () => { + cy.createContent({ + contentType: 'Document', + contentId: 'test-doc', + contentTitle: 'my test document', + bodyModifier(body) { + body.blocks['abc'] = { '@type': 'missing' }; + body.blocks_layout.items.push('abc'); + return body; + }, + }); + cy.visit('/test-doc'); + cy.get('#page-document div').should('have.text', 'Unknown Block missing'); + }); }); diff --git a/cypress/tests/core/blocks/hero.js b/cypress/tests/core/blocks/hero.js index d93012c22b..445dbc13f3 100644 --- a/cypress/tests/core/blocks/hero.js +++ b/cypress/tests/core/blocks/hero.js @@ -29,10 +29,7 @@ describe('Blocks Tests', () => { cy.navigate('/my-page/edit'); cy.wait('@schema'); - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .hero').contains('Hero').click(); + cy.addNewBlock('hero'); // cy.fixture(expectedFile).then(fileContent => { // cy.get(`.block.${block} [data-cy="dropzone]`).upload( diff --git a/cypress/tests/core/blocks/teaser.js b/cypress/tests/core/blocks/teaser.js new file mode 100644 index 0000000000..60a4c13a4c --- /dev/null +++ b/cypress/tests/core/blocks/teaser.js @@ -0,0 +1,49 @@ +context('Blocks Acceptance Tests', () => { + beforeEach(() => { + cy.visit('/'); + cy.viewport('macbook-16'); + cy.createContent({ + contentType: 'Document', + contentId: 'document', + contentTitle: 'Document', + }); + cy.autologin(); + }); + + it('As editor I can add a (standalone) Teaser block', () => { + // GIVEN a Document with the title document and a Document to reference with the title Blue Orchidees + cy.createContent({ + contentType: 'Document', + contentId: 'blue-orchidees', + contentTitle: 'Blue Orchidees', + contentDescription: 'are growing on the mountain tops', + image: true, + path: '/document', + }); + cy.visit('/document/edit'); + // WHEN I create a Teaser block + cy.get('.block .slate-editor [contenteditable=true]').click(); + cy.get('.button .block-add-button').click({ force: true }); + cy.get('.blocks-chooser .mostUsed .button.teaser') + .contains('Teaser') + .click({ force: true }); + cy.get( + '.objectbrowser-field[aria-labelledby="fieldset-default-field-label-href"] button[aria-label="Open object browser"]', + ).click(); + cy.get('[aria-label="Select Blue Orchidees"]').dblclick(); + cy.wait(500); + cy.get('.align-buttons .ui.buttons button[aria-label="Center"]').click(); + cy.get('#toolbar-save').click(); + + // THEN I can see the Teaser block + cy.visit('/document'); + cy.get('.block.teaser').should('have.class', 'has--align--center'); + cy.get('.block.teaser .image-wrapper img') + .should('have.attr', 'src') + .and('include', '/document/blue-orchidees/@@images/preview_image-'); + cy.get('.block.teaser .content h2').contains('Blue Orchidees'); + cy.get('.block.teaser .content p').contains( + 'are growing on the mountain tops', + ); + }); +}); diff --git a/cypress/tests/core/guillotina/autologin.js b/cypress/tests/core/guillotina/autologin.js index 67eb37e9be..fce720381b 100644 --- a/cypress/tests/core/guillotina/autologin.js +++ b/cypress/tests/core/guillotina/autologin.js @@ -1,6 +1,6 @@ describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:8081/db/web'; + const api_url = 'http://127.0.0.1:8081/db/web'; const user = 'admin'; const password = 'admin'; diff --git a/cypress/tests/core/volto-slate/09-block-slate-slashmenu.js b/cypress/tests/core/volto-slate/09-block-slate-slashmenu.js new file mode 100644 index 0000000000..8cce4cb989 --- /dev/null +++ b/cypress/tests/core/volto-slate/09-block-slate-slashmenu.js @@ -0,0 +1,14 @@ +import { slateBeforeEach } from '../../../support/e2e'; + +describe('SlashMenu Test: Shortcuts', () => { + beforeEach(slateBeforeEach); + + it('As editor I can create a Table block using the SlashMenu shortcut', function () { + // Use SlashMenu shortcut to create a table block + cy.getSlateEditorAndType('/t').type('{enter}'); + cy.toolbarSave(); + + // then the page view should contain a table + cy.get('#page-document table').should('be.visible'); + }); +}); diff --git a/cypress/tests/core/volto-slate/24-block-slate-format-boldlists.js b/cypress/tests/core/volto-slate/24-block-slate-format-boldlists.js index 1ebb4fb339..1971244b8f 100644 --- a/cypress/tests/core/volto-slate/24-block-slate-format-boldlists.js +++ b/cypress/tests/core/volto-slate/24-block-slate-format-boldlists.js @@ -40,31 +40,31 @@ describe('Block Tests: Bold Bulleted lists', () => { 'sleep furiously.', ); }); + it('As editor I can paste internal(slate formatted) formatted bulleted lists', function () { // Complete chained commands - cy.getSlateEditorAndType('This is slate"s own bold content'); - cy.setSlateSelection('This is slate"s own'); + cy.getSlateEditorAndType("This is slate's own bold content"); + cy.setSlateSelection("This is slate's own"); //create a bold bullted list cy.clickSlateButton('Bulleted list'); cy.clickSlateButton('Bold'); //copy content "This is slate"s own" - cy.setSlateCursor('content') - .type('{enter}') - .pasteClipboard( - 'This is slate"s own', - ); + cy.setSlateCursor('content').type('{enter}'); + cy.getSlate().pasteClipboard( + "This is slate's own", + ); // Save cy.toolbarSave(); cy.get('[id="page-document"] ul li:nth-child(1) strong').contains( - 'This is slate"s own', + "This is slate's own", ); //pasted content cy.get('[id="page-document"] ul li:nth-child(2) strong').contains( - 'This is slate"s own', + "This is slate's own", ); }); @@ -83,6 +83,7 @@ describe('Block Tests: Bold Bulleted lists', () => { // Save cy.toolbarSave(); + // cy.pause(); cy.get('[id="page-document"] ul li:nth-child(1) strong').contains( 'This is slate"s own bold content', diff --git a/cypress/tests/core/volto-slate/27-block-slate-paste-html.js b/cypress/tests/core/volto-slate/27-block-slate-paste-html.js new file mode 100644 index 0000000000..74a815f29c --- /dev/null +++ b/cypress/tests/core/volto-slate/27-block-slate-paste-html.js @@ -0,0 +1,47 @@ +import { slateBeforeEach } from '../../../support/e2e'; + +describe('Block Tests: external text containing html contents/tags ', () => { + beforeEach(slateBeforeEach); + + it('should paste external text containing html', function () { + // cy.getSlateEditorAndType('Let"s paste external html texts'); + // cy.setSlateCursor('texts').type('{enter}'); + cy.getSlate().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(); + + cy.get('[id="page-document"] p').should('have.length', 1); + }); + + it('should paste external formatted text and does not split the blocks', function () { + // The idea is pasteClipboard should only apply on its attached slate block + // by not splitting them into blocks. + cy.getSlate().pasteClipboard( + `

Lorem Ipsum +is simply dummy text of the printing and typesetting industry. +

`, + ); + + // Save + cy.toolbarSave(); + cy.get('[id="page-document"] > p:nth-of-type(1)').should( + 'have.html', + `Lorem Ipsum is simply dummy text of the printing and typesetting industry.`, + ); + }); + + it('should paste external text containing empty anchor links', function () { + cy.getSlate().pasteClipboard( + ` + `, + ); + + // Save + cy.toolbarSave(); + + cy.get('[id="page-document"] p a').should('have.length', 1); + }); +}); 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/cypress/tests/coresandbox/autologin.js b/cypress/tests/coresandbox/autologin.js index 45c13788ca..bc4d02606d 100644 --- a/cypress/tests/coresandbox/autologin.js +++ b/cypress/tests/coresandbox/autologin.js @@ -2,7 +2,7 @@ import { ploneAuth } from '../../support/constants'; describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:55001/plone'; + const api_url = 'http://127.0.0.1:55001/plone'; const user = ploneAuth[0]; const password = ploneAuth[1]; diff --git a/cypress/tests/coresandbox/defaultview.js b/cypress/tests/coresandbox/defaultview.js new file mode 100644 index 0000000000..e3955c0dce --- /dev/null +++ b/cypress/tests/coresandbox/defaultview.js @@ -0,0 +1,39 @@ +context('Block Default View / Edit Acceptance Tests', () => { + describe('Block Default View / Edit', () => { + beforeEach(() => { + // given a logged in editor and a page in edit mode + cy.visit('/'); + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'document', + contentTitle: 'Test document', + }); + cy.visit('/document'); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('document'); + cy.navigate('/document/edit'); + cy.getSlateTitle(); + }); + + it('I can add a block with Default View / Edit based on schema and interact with it', function () { + cy.getSlate().click(); + cy.get('.button .block-add-button').click({ force: true }); + cy.get('.blocks-chooser .mostUsed .button.testBlockDefaultView').click(); + + cy.get('#field-fieldAfterObjectList') + .click() + .type('Colorless green ideas sleep furiously.'); + + cy.get('.page-block').contains('Colorless green ideas sleep furiously.'); + + cy.get('#toolbar-save').click(); + cy.get('[id="page-document"]').contains( + 'Colorless green ideas sleep furiously.', + ); + }); + }); +}); diff --git a/cypress/tests/coresandbox/fields.js b/cypress/tests/coresandbox/fields.js index 7770b54596..ddf4230bd2 100644 --- a/cypress/tests/coresandbox/fields.js +++ b/cypress/tests/coresandbox/fields.js @@ -1,4 +1,106 @@ context('Special fields Acceptance Tests', () => { + describe('Form with default values', () => { + beforeEach(() => { + // given a logged in editor and a page in edit mode + cy.visit('/'); + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'document', + contentTitle: 'Test document', + }); + cy.visit('/document'); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('document'); + cy.navigate('/document/edit'); + cy.getSlateTitle(); + }); + + it('As an editor I can add a block that has default values', () => { + cy.intercept('PATCH', '/**/document').as('save'); + cy.intercept('GET', '/**/@types/Document').as('schema'); + cy.getSlate().click(); + cy.get('.button .block-add-button').click({ force: true }); + cy.wait(100); + cy.get('.blocks-chooser .mostUsed .button.testBlock').click(); + + cy.findByLabelText('Field with default').click(); + cy.get('#field-firstWithDefault').should( + 'have.value', + 'Some default value', + ); + + cy.findByLabelText('Add item').click(); + cy.findAllByText('Item #1').should('have.length', 1); + + cy.findByLabelText('Extra').should('have.value', 'Extra default'); + cy.get('#toolbar-save').click(); + cy.wait('@save'); + + cy.navigate('/document/edit'); + cy.wait('@schema'); + + cy.findAllByText('Test Block Edit').click(); + + cy.get('#field-firstWithDefault').should( + 'have.value', + 'Some default value', + ); + cy.findByLabelText('Extra').should('have.value', 'Extra default'); + + cy.getContent({ path: '/document' }).should((response) => { + const { body } = response; + const [, testBlock] = Object.entries(body.blocks).find( + ([, block]) => block['@type'] === 'testBlock', + ); + expect(testBlock.style).to.deep.equal({ color: 'red' }); + expect(testBlock.slides[0].extraDefault).to.deep.equal('Extra default'); + }); + }); + }); + + describe('HTML Richtext Widget', () => { + beforeEach(() => { + // given a logged in editor and a page in edit mode + cy.visit('/'); + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'document', + contentTitle: 'Test document', + }); + cy.visit('/document'); + cy.waitForResourceToLoad('@navigation'); + cy.waitForResourceToLoad('@breadcrumbs'); + cy.waitForResourceToLoad('@actions'); + cy.waitForResourceToLoad('@types'); + cy.waitForResourceToLoad('document'); + cy.navigate('/document/edit'); + cy.getSlateTitle(); + }); + + it('Handles whitespaces properly', () => { + cy.intercept('PATCH', '/**/document').as('save'); + cy.getSlate().click(); + cy.get('.button .block-add-button').click({ force: true }); + cy.get('.blocks-chooser .mostUsed .button.testBlock').click(); + cy.get('#fieldset-default-field-label-html').click(); + cy.get('.slate_wysiwyg_box [contenteditable=true]').type( + ' hello world ', + ); + cy.get('#toolbar-save').click(); + cy.wait('@save'); + + cy.get('.test-block').should( + 'contain.text', + '

hello world

', + ); + }); + }); + describe('ObjectListWidget', () => { beforeEach(() => { // given a logged in editor and a page in edit mode @@ -53,6 +155,7 @@ context('Special fields Acceptance Tests', () => { cy.findAllByText('Item #3').should('have.length', 0); }); }); + describe('Variation field', () => { beforeEach(() => { // given a logged in editor and a page in edit mode @@ -83,6 +186,7 @@ context('Special fields Acceptance Tests', () => { cy.findByText('Custom'); }); }); + describe('ObjectBrowserWidget', () => { beforeEach(() => { // given a logged in editor and a page in edit mode @@ -108,6 +212,7 @@ context('Special fields Acceptance Tests', () => { cy.navigate('/document/edit'); cy.getSlateTitle(); }); + it('As editor I can add a block with an objetBrowserWidget and the context path is preserved', function () { cy.getSlate().click(); cy.get('.button .block-add-button').click({ force: true }); diff --git a/cypress/tests/coresandbox/listingblock.js b/cypress/tests/coresandbox/listingblock.js index a49dc6ad3e..82fe619aec 100644 --- a/cypress/tests/coresandbox/listingblock.js +++ b/cypress/tests/coresandbox/listingblock.js @@ -40,10 +40,7 @@ context('Listing block tests', () => { cy.navigate('/document/edit'); // Add listing block - cy.getSlate().click(); - cy.get('button.block-add-button').click(); - cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.addNewBlock('listing'); // select variation cy.get('#field-variation') @@ -88,10 +85,13 @@ context('Listing block tests', () => { cy.navigate('/document/edit'); // Add listing block + cy.addNewBlock('listing'); cy.getSlate().click(); cy.get('button.block-add-button').click(); cy.get('.blocks-chooser .title').contains('Common').click(); - cy.get('.blocks-chooser .common').contains('Listing').click(); + cy.get('.blocks-chooser .common') + .contains('Listing') + .click({ force: true }); // select variation cy.get('#field-variation') diff --git a/cypress/tests/guillotina/autologin.js b/cypress/tests/guillotina/autologin.js index 67eb37e9be..fce720381b 100644 --- a/cypress/tests/guillotina/autologin.js +++ b/cypress/tests/guillotina/autologin.js @@ -1,6 +1,6 @@ describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:8081/db/web'; + const api_url = 'http://127.0.0.1:8081/db/web'; const user = 'admin'; const password = 'admin'; diff --git a/cypress/tests/multilingual/autologin.js b/cypress/tests/multilingual/autologin.js index 45c13788ca..bc4d02606d 100644 --- a/cypress/tests/multilingual/autologin.js +++ b/cypress/tests/multilingual/autologin.js @@ -2,7 +2,7 @@ import { ploneAuth } from '../../support/constants'; describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:55001/plone'; + const api_url = 'http://127.0.0.1:55001/plone'; const user = ploneAuth[0]; const password = ploneAuth[1]; diff --git a/cypress/tests/workingCopy/autologin.js b/cypress/tests/workingCopy/autologin.js index 45c13788ca..bc4d02606d 100644 --- a/cypress/tests/workingCopy/autologin.js +++ b/cypress/tests/workingCopy/autologin.js @@ -2,7 +2,7 @@ import { ploneAuth } from '../../support/constants'; describe('Autologin Tests', () => { it('Autologin as an standalone test', function () { - const api_url = 'http://localhost:55001/plone'; + const api_url = 'http://127.0.0.1:55001/plone'; const user = ploneAuth[0]; const password = ploneAuth[1]; diff --git a/docker-compose.yml b/docker-compose.yml index 7bd820f2bd..82a49830b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,14 +2,13 @@ version: '3.3' services: backend: - image: plone/plone-backend:6.0.0b2 + image: plone/plone-backend:6.0.1 # Plone 5.2 series can be used too - # image: plone/plone-backend:5.2.9 + # image: plone/plone-backend:5.2.10 ports: - '8080:8080' environment: - SITE=Plone - - 'ADDONS=plone.restapi==8.29.0 plone.volto==4.0.0a13 plone.rest==2.0.0a5' - 'PROFILES=plone.volto:default-homepage' labels: - traefik.enable=true @@ -47,7 +46,7 @@ services: reverse-proxy: # The official v2 Traefik docker image - image: traefik:v2.8 + image: traefik:v2.9 # Enables the web UI and tells Traefik to listen to docker command: --api.insecure=true --providers.docker ports: @@ -57,7 +56,7 @@ services: - "8888:8080" volumes: # So that Traefik can listen to the Docker events - - /var/run/docker.sock:/var/run/docker.sock + - /var/run/docker.sock:/var/run/docker.sock:ro labels: - traefik.http.middlewares.gzip.compress=true - traefik.http.middlewares.gzip.compress.excludedcontenttypes=image/png, image/jpeg, font/woff2 diff --git a/docs/source/_static/copy.svg b/docs/source/_static/copy.svg new file mode 100644 index 0000000000..3e9fd912ba --- /dev/null +++ b/docs/source/_static/copy.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/source/_static/custom.css b/docs/source/_static/custom.css index 0f540ff020..d792d49f36 100644 --- a/docs/source/_static/custom.css +++ b/docs/source/_static/custom.css @@ -35,6 +35,12 @@ figure img, width: 200px; margin-bottom: 1rem; } + +img.inline { + margin: 0; + height: 1em; +} + span.linenos { padding-right: 1em; } @@ -234,3 +240,7 @@ span.guilabel, span.menuselection { font-style: italic; white-space: nowrap; } + +video { + width: 100%; +} diff --git a/docs/source/_static/cut.svg b/docs/source/_static/cut.svg new file mode 100644 index 0000000000..6a3b112b14 --- /dev/null +++ b/docs/source/_static/cut.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/source/_static/paste.svg b/docs/source/_static/paste.svg new file mode 100644 index 0000000000..91e9435607 --- /dev/null +++ b/docs/source/_static/paste.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/source/_static/user-manual/blocks/add-new-block.gif b/docs/source/_static/user-manual/blocks/add-new-block.gif new file mode 100644 index 0000000000..29425365e9 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/add-new-block.gif differ diff --git a/docs/source/_static/user-manual/blocks/block-copy-cut.mp4 b/docs/source/_static/user-manual/blocks/block-copy-cut.mp4 new file mode 100644 index 0000000000..2a6a0658eb Binary files /dev/null and b/docs/source/_static/user-manual/blocks/block-copy-cut.mp4 differ diff --git a/docs/source/_static/user-manual/blocks/block-left-add-icon.png b/docs/source/_static/user-manual/blocks/block-left-add-icon.png new file mode 100644 index 0000000000..bcb7c63d93 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/block-left-add-icon.png differ diff --git a/docs/source/_static/user-manual/blocks/block-paste.mp4 b/docs/source/_static/user-manual/blocks/block-paste.mp4 new file mode 100644 index 0000000000..05ffbc66e6 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/block-paste.mp4 differ diff --git a/docs/source/_static/user-manual/blocks/block-types-menu.png b/docs/source/_static/user-manual/blocks/block-types-menu.png new file mode 100644 index 0000000000..7bd3a57916 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/block-types-menu.png differ diff --git a/docs/source/_static/user-manual/blocks/grid-block-manage-blocks.png b/docs/source/_static/user-manual/blocks/grid-block-manage-blocks.png new file mode 100644 index 0000000000..46554cffd1 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/grid-block-manage-blocks.png differ diff --git a/docs/source/_static/user-manual/blocks/grid-block-number-of-columns.png b/docs/source/_static/user-manual/blocks/grid-block-number-of-columns.png new file mode 100644 index 0000000000..9d3e887867 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/grid-block-number-of-columns.png differ diff --git a/docs/source/_static/user-manual/blocks/hero-block.png b/docs/source/_static/user-manual/blocks/hero-block.png new file mode 100644 index 0000000000..6b284bac90 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/hero-block.png differ diff --git a/docs/source/_static/user-manual/blocks/html-block.png b/docs/source/_static/user-manual/blocks/html-block.png new file mode 100644 index 0000000000..64481f922f Binary files /dev/null and b/docs/source/_static/user-manual/blocks/html-block.png differ diff --git a/docs/source/_static/user-manual/blocks/image-block-configuration-options.png b/docs/source/_static/user-manual/blocks/image-block-configuration-options.png new file mode 100644 index 0000000000..555308d43d Binary files /dev/null and b/docs/source/_static/user-manual/blocks/image-block-configuration-options.png differ diff --git a/docs/source/_static/user-manual/blocks/image-block.png b/docs/source/_static/user-manual/blocks/image-block.png new file mode 100644 index 0000000000..2cdba7290b Binary files /dev/null and b/docs/source/_static/user-manual/blocks/image-block.png differ diff --git a/docs/source/_static/user-manual/blocks/images-grid-block-manage-images.png b/docs/source/_static/user-manual/blocks/images-grid-block-manage-images.png new file mode 100644 index 0000000000..efa356c7cd Binary files /dev/null and b/docs/source/_static/user-manual/blocks/images-grid-block-manage-images.png differ diff --git a/docs/source/_static/user-manual/blocks/images-grid-block-number-of-columns.png b/docs/source/_static/user-manual/blocks/images-grid-block-number-of-columns.png new file mode 100644 index 0000000000..9d3e887867 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/images-grid-block-number-of-columns.png differ diff --git a/docs/source/_static/user-manual/blocks/listing-block-configuration.png b/docs/source/_static/user-manual/blocks/listing-block-configuration.png new file mode 100644 index 0000000000..4ef4628d93 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/listing-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/listing-block.png b/docs/source/_static/user-manual/blocks/listing-block.png new file mode 100644 index 0000000000..8073df0fbd Binary files /dev/null and b/docs/source/_static/user-manual/blocks/listing-block.png differ diff --git a/docs/source/_static/user-manual/blocks/map-blocks-configuration.png b/docs/source/_static/user-manual/blocks/map-blocks-configuration.png new file mode 100644 index 0000000000..c6213fe009 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/map-blocks-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/maps-block.png b/docs/source/_static/user-manual/blocks/maps-block.png new file mode 100644 index 0000000000..fd08e0b62e Binary files /dev/null and b/docs/source/_static/user-manual/blocks/maps-block.png differ diff --git a/docs/source/_static/user-manual/blocks/search-block-configuration.png b/docs/source/_static/user-manual/blocks/search-block-configuration.png new file mode 100644 index 0000000000..43f174a8df Binary files /dev/null and b/docs/source/_static/user-manual/blocks/search-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/search-block.png b/docs/source/_static/user-manual/blocks/search-block.png new file mode 100644 index 0000000000..70c6e72ea7 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/search-block.png differ diff --git a/docs/source/_static/user-manual/blocks/table-block-configuration.png b/docs/source/_static/user-manual/blocks/table-block-configuration.png new file mode 100644 index 0000000000..236762bf2c Binary files /dev/null and b/docs/source/_static/user-manual/blocks/table-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/table-block.png b/docs/source/_static/user-manual/blocks/table-block.png new file mode 100644 index 0000000000..ca73e45924 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/table-block.png differ diff --git a/docs/source/_static/user-manual/blocks/table-of-contents-block-configuration.png b/docs/source/_static/user-manual/blocks/table-of-contents-block-configuration.png new file mode 100644 index 0000000000..6da6c6ad64 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/table-of-contents-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/table-of-contents-block.png b/docs/source/_static/user-manual/blocks/table-of-contents-block.png new file mode 100644 index 0000000000..73faaba5da Binary files /dev/null and b/docs/source/_static/user-manual/blocks/table-of-contents-block.png differ diff --git a/docs/source/_static/user-manual/blocks/teaser-block-configuration.png b/docs/source/_static/user-manual/blocks/teaser-block-configuration.png new file mode 100644 index 0000000000..55c21c78cd Binary files /dev/null and b/docs/source/_static/user-manual/blocks/teaser-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/teaser-block.png b/docs/source/_static/user-manual/blocks/teaser-block.png new file mode 100644 index 0000000000..b8a500982b Binary files /dev/null and b/docs/source/_static/user-manual/blocks/teaser-block.png differ diff --git a/docs/source/_static/user-manual/blocks/video-block-configuration.png b/docs/source/_static/user-manual/blocks/video-block-configuration.png new file mode 100644 index 0000000000..b6c5283ca3 Binary files /dev/null and b/docs/source/_static/user-manual/blocks/video-block-configuration.png differ diff --git a/docs/source/_static/user-manual/blocks/video-block.png b/docs/source/_static/user-manual/blocks/video-block.png new file mode 100644 index 0000000000..870ac385bc Binary files /dev/null and b/docs/source/_static/user-manual/blocks/video-block.png differ diff --git a/docs/source/addons/best-practices.md b/docs/source/addons/best-practices.md index ae5bcbe773..e58eb3c8e2 100644 --- a/docs/source/addons/best-practices.md +++ b/docs/source/addons/best-practices.md @@ -24,7 +24,7 @@ register the most basic configuration of that widget with a name that can be used. On more complicated cases, see if you can structure your code to use the -`settings` configuration registry, or stash your configuration in your block +`settings` {term}`configuration registry`, or stash your configuration in your block registration, for example. As an example: let's say we're building a Color Picker widget and we want to @@ -36,7 +36,7 @@ multiple instances of that color widget with custom color palettes. ### Provide additional configuration -An add-on can ship with multiple Volto configuration loaders. This makes it +An add-on can ship with multiple {term}`Volto configuration loader`s. This makes it possible to provide configuration methods for demo purposes, for example, or to ship with a default "shallow" integration, then provide another separate configuration loader for a deeper integration. diff --git a/docs/source/addons/index.md b/docs/source/addons/index.md index de1b615520..cf456c215b 100644 --- a/docs/source/addons/index.md +++ b/docs/source/addons/index.md @@ -19,86 +19,86 @@ best-practices There are several advanced scenarios where we might want to have more control and flexibility beyond using the plain Volto project to build a site. -We can build Volto add-on products and make them available as generic -Javascript packages that can be included in any Volto project. By doing so we +We can build Volto {term}`add-on` products and make them available as generic +JavaScript packages that can be included in any Volto project. By doing so we can provide code and component reutilization across projects and, of course, benefit from open source collaboration. ```{note} -By declaring a Javascript package as a "Volto addon", Volto provides +By declaring a JavaScript package as a Volto add-on, Volto provides several integration features: language features (so they can be transpiled by Babel), whole-process customization via razzle.extend.js and -integration with Volto's configuration registry. +integration with Volto's {term}`configuration registry`. ``` -The addon can be published to an NPM registry or directly installed from github +The add-on can be published to an NPM registry or directly installed from github by Yarn. By using [mrs-develop](https://github.com/collective/mrs-developer), it's possible to have a workflow similar to zc.buildout's mr.developer, where -you can "checkout" an addon for development. +you can "checkout" an add-on for development. -An addon can be almost anything that a Volto project can be. They can: +An add-on can be almost anything that a Volto project can be. They can: - provide additional views and blocks - override or extend Volto's builtin views, blocks, settings -- shadow (customize) Volto's (or another addon's) modules +- shadow (customize) Volto's (or another add-on's) modules - register custom routes -- provide custom Redux actions and reducers +- provide custom {term}`Redux` actions and reducers - register custom Express middleware for Volto's server process - tweak Volto's Webpack configuration, load custom Razzle and Webpack plugins - even provide a custom theme, just like a regular Volto project does. -## Configuring a Volto project to use an addon +## Configuring a Volto project to use an add-on -You can install a Volto addon just like any other JS package: +You can install a Volto add-on just like any other JS package: ```shell -yarn add name-of-addon +yarn add name-of-add-on ``` -If the addon is not published on NPM, you can retrieve it directly from Github: +If the add-on is not published on NPM, you can retrieve it directly from Github: ```shell yarn add collective/volto-dropdownmenu ``` -Next, you'll need to add the addon (identified by its JS package name) to the +Next, you'll need to add the add-on (identified by its JS package name) to the `addons` key of your Volto project's `package.json`. More details in the next section. -### Loading addon configuration +### Loading add-on configuration -As a convenience, an addon can export configuration functions that can mutate, -in-place, the overall Volto configuration registry. An addon can export multiple +As a convenience, an add-on can export configuration functions that can mutate, +in-place, the overall Volto {term}`configuration registry`. An add-on can export multiple configurations methods, making it possible to selectively choose which specific -addon functionality you want to load. +add-on functionality you want to load. -In your Volto project's ``package.json`` you can allow the addon to alter the -global configuration by adding, in the ``addons`` key, a list of volto addon +In your Volto project's ``package.json`` you can allow the add-on to alter the +global configuration by adding, in the `addons` key, a list of volto add-on package names, like: ```js { "name": "my-nice-volto-project", - ... + "addons": [ - "acme-volto-foo-addon", - "@plone/some-addon", - "collective-another-volto-addon" + "acme-volto-foo-add-on", + "@plone/some-add-on", + "collective-another-volto-add-on" ], - ... + } ``` ```{warning} -Adding the addon package to the `addons` key is obligatory! It allows Volto +Adding the add-on package to the `addons` key is mandatory! It allows Volto to treat that package properly and provide it with BabelJS language features. In Plone terminology, it is like including a Python egg to the `zcml` section of zc.buildout. ``` -Some addons might choose to allow the Volto project to selectively load some of +Some add-ons might choose to allow the Volto project to selectively load some of their configuration, so they may offer additional configuration functions, -which you can load by overloading the addon name in the ``addons`` package.json +which you can load by overloading the add-on name in the `addons` package.json key, like so: ```{code-block} json @@ -107,23 +107,23 @@ key, like so: { "name": "my-nice-volto-project", "addons": [ - "acme-volto-foo-addon:loadOptionalBlocks,overrideSomeDefaultBlock", + "acme-volto-foo-add-on:loadOptionalBlocks,overrideSomeDefaultBlock", "volto-ga" ], } ``` ```{note} -The additional comma-separated names should be exported from the addon +The additional comma-separated names should be exported from the add-on package's ``index.js``. The main configuration function should be exported as -the default. An addon's default configuration method will always be loaded. +the default. An add-on's default configuration method will always be loaded. ``` -If for some reason, you want to manually load the addon, you could always do, +If for some reason, you want to manually load the add-on, you could always do, in your project's ``config.js`` module: ```js -import loadExampleAddon, { enableOptionalBlocks } from 'volto-example-addon'; +import loadExampleAddon, { enableOptionalBlocks } from 'volto-example-add-on'; import * as voltoConfig from '@plone/volto/config'; const config = enableOptionalBlocks(loadExampleAddon(voltoConfig)); @@ -131,7 +131,6 @@ const config = enableOptionalBlocks(loadExampleAddon(voltoConfig)); export blocks = { ...config.blocks, } -... ``` As this is a common operation, Volto provides a helper method for this: @@ -151,26 +150,27 @@ export blocks = { ``` The `applyConfig` helper ensures that each configuration methods returns the -config object, avoiding odd and hard to track errors when developing addons. +config object, avoiding odd and hard to track errors when developing add-ons. -## Creating addons +## Creating add-ons -Volto addon packages are just CommonJS packages. The only requirement is that +Volto add-on packages are just CommonJS packages. The only requirement is that they point the `main` key of their `package.json` to a module that exports, as -a default function that acts as a Volto configuration loader. +a default function that acts as a {term}`Volto configuration loader`. -Although you could simply use `npm init` to generate an addon initial code, +Although you could simply use `npm init` to generate an add-on initial code, we now have a nice [Yeoman-based generator](https://github.com/plone/generator-volto) that you can use: -``` +```shell npm install -g @plone/generator-volto yo @plone/volto:addon [] [options] ``` + Volto will automatically provide aliases for your (unreleased) package, so that once you've released it, you don't need to change import paths, since you can use the final ones from the very beginning. This means that you can use imports -such as `import { Something } from '@plone/my-volto-addon'` without any extra +such as `import { Something } from '@plone/my-volto-add-on'` without any extra configuration. ### Use mrs-developer to manage the development cycle @@ -181,23 +181,24 @@ configuration. which provides a way to pull a package from git and set it up as a dependency for the current project codebase. -To facilitate addon development lifecycle we recommend using +To facilitate add-on development lifecycle we recommend using [mrs-developer](https://www.npmjs.com/package/mrs-developer). By doing this, you can develop both the project and the add-on product as if they were both part of the current codebase. Once the add-on development is done, you can publish the package to an npm repository. -``` -$ yarn add mrs-developer +```shell +yarn add mrs-developer ``` Then, in `package.json`: -```json hl_lines="2" - "scripts": { - "develop": "missdev --config=jsconfig.json --output=addons", - } +```{code-block} json +:emphasize-lines: 2 +"scripts": { + "develop": "missdev --config=jsconfig.json --output=addons", +} ``` We can configure `mrs-developer` to use any directory that you want. Here we @@ -211,9 +212,9 @@ to pull the packages. So, create `mrs.developer.json` and add: ```json { - "acme-volto-foo-addon": { - "package": "@acme/volto-foo-addon", - "url": "git@github.com:acme/my-volto-addon.git", + "acme-volto-foo-add-on": { + "package": "@acme/volto-foo-add-on", + "url": "git@github.com:acme/my-volto-add-on.git", "path": "src" } } @@ -221,15 +222,15 @@ to pull the packages. So, create `mrs.developer.json` and add: Then run: -```bash +```shell yarn develop ``` -Now the addon is found in `src/addons/`. +Now the add-on is found in `src/addons/`. ```{note} `package` property is optional, set it up only if your package has a scope. -`src` is required if the content of your addon is located in the `src` +`src` is required if the content of your add-on is located in the `src` directory (but, as that is the convention recommended for all Volto add-on packages, you will always include it) ``` @@ -245,14 +246,14 @@ to use mrs-developer, you'll have to add something like this to your ```json { - "compilerOptions": { - "paths": { - "acme-volto-foo-addon": [ - "addons/acme-volto-foo-addon/src" - ] - }, - "baseUrl": "src" - } + "compilerOptions": { + "paths": { + "acme-volto-foo-add-on": [ + "addons/acme-volto-foo-add-on/src" + ] + }, + "baseUrl": "src" + } } ``` @@ -268,20 +269,20 @@ in `package.json` to the `index.js` file in `src/index.js`. ### Customizations -Addon packages can include customization folders, just like the Volto projects. -The customizations are resolved in the order: addons (as sorted in the `addons` +add-on packages can include customization folders, just like the Volto projects. +The customizations are resolved in the order: add-ons (as sorted in the `addons` key of your project's `package.json`) then the customizations in the Volto project, last one wins. ```{tip} See the {ref}`advanced-customization-scenarios-label` section on how to enhance this pattern and how to include customizations -inside addons. +inside add-ons. ``` -### Providing addon configuration +### Providing add-on configuration -The default export of your addon main `index.js` file should be a function with +The default export of your add-on main `index.js` file should be a function with the signature ``config => config``. That is, it should take the ``global`` configuration object and return it, possibly mutated or changed. So your main `index.js` will look like: @@ -303,7 +304,7 @@ export default function applyConfig(config) { } ``` -And the `package.json` file of your addon: +And the `package.json` file of your add-on: ```json { @@ -312,12 +313,12 @@ And the `package.json` file of your addon: ``` ```{warning} -An addon's default configuration method will always be loaded. +An add-on's default configuration method will always be loaded. ``` -#### Multiple addon configurations +#### Multiple add-on configurations -You can export additional configuration functions from your addon's main +You can export additional configuration functions from your add-on's main `index.js`. ```js @@ -327,11 +328,9 @@ export { loadOptionalBlocks, overrideSomeDefaultBlock }; export default applyConfig; ``` -## Add third-party dependencies to your addon +## Add third-party dependencies to your add-on -If you're developing the addon and you wish to add an external dependency, -you'll have to switch your project to be a [Yarn Workspaces -root](https://classic.yarnpkg.com/en/docs/workspaces/). +If you're developing the add-on and you wish to add an external dependency, you'll have to switch your project to be a [Yarn Workspaces root](https://yarnpkg.com/features/workspaces). So you'll need to add, in your Volto project's `package.json`: @@ -340,18 +339,18 @@ So you'll need to add, in your Volto project's `package.json`: "workspaces": [], ``` -Then populate the `workspaces` key with the path to your development addons: +Then populate the `workspaces` key with the path to your development add-ons: ```json "workspaces": [ - "src/addons/my-volto-addon" + "src/addons/my-volto-add-on" ] ``` -You'll have to manage the addon dependencies via the workspace root (your Volto +You'll have to manage the add-on dependencies via the workspace root (your Volto project). For example, to add a new dependency: ```shell -yarn workspace @plone/my-volto-addon add some-third-party-package +yarn workspace @plone/my-volto-add-on add some-third-party-package ``` You can run `yarn workspaces info` to see a list of workspaces defined. @@ -363,12 +362,12 @@ to run the `yarn add` command with the `-W` switch: yarn add -W some-dependency ``` -## Extending Razzle from an addon +## Extending Razzle from an add-on Just like you can extend Razzle's configuration from the project, you can do so -with an addon, as well. You should provide a `razzle.extend.js` file in your -addon root folder. An example of such file where the theme.config alias is -changed, to enable a custom Semantic theme inside the addon: +with an add-on, as well. You should provide a `razzle.extend.js` file in your +add-on root folder. An example of such file where the theme.config alias is +changed, to enable a custom Semantic theme inside the add-on: ```js @@ -400,29 +399,129 @@ module.exports = { }; ``` -## Addon dependencies +## Extending Eslint configuration from an add-on + +Starting with Volto v16.4.0, you can also customize the Eslint configuration +from an add-on. You should provide a `eslint.extend.js` file in your +add-on root folder, which exports a `modify(defaultConfig)` function. For +example, to host some code outside the regular `src/` folder of your add-on, +this `eslint.extend.js` file is needed: + +```js +const path = require('path'); + +module.exports = { + modify(defaultConfig) { + const aliasMap = defaultConfig.settings['import/resolver'].alias.map; + const addonPath = aliasMap.find( + ([name]) => name === '@plone-collective/some-volto-add-on', + )[1]; + + const extraPath = path.resolve(`${addonPath}/../extra`); + aliasMap.push(['@plone-collective/extra', extraPath]); + + return defaultConfig; + }, +}; +``` + +This would allow the `@plone-collective/some-volto-add-on` to host some code +outside of its normal `src/` folder, let's say in the `extra` folder, and that +code would be available under the `@plone-collective/extra` name. Note: this is +taking care only of the Eslint integration. For proper language support, you'll +still need to do it in the `razzle.extend.js` of your add-on. -Sometimes your addon depends on another addon. You can declare addon dependency -in your addon's `addons` key, just like you do in your project. By doing so, -that other addon's configuration loader is executed first, so you can depend on +## add-on dependencies + +Sometimes your add-on depends on another add-on. You can declare add-on dependency +in your add-on's `addons` key, just like you do in your project. By doing so, +that other add-on's configuration loader is executed first, so you can depend on the configuration being already applied. Another benefit is that you'll have -to declare only the "top level" addon in your project, the dependencies will be -discovered and automatically treated as Volto addons. For example, volto-slate +to declare only the "top level" add-on in your project, the dependencies will be +discovered and automatically treated as Volto add-ons. For example, volto-slate depends on volto-object-widget's configuration being already applied, so -volto-slate can declare in its package.json: +volto-slate can declare in its `package.json`: -``` +```json { "name": "volto-slate", - ... - "addons": ['@eeacms/volto-object-widget'] + + "addons": ["@eeacms/volto-object-widget"] } ``` -And of course, the dependency addon can depend, on its turn, on other addons +And of course, the dependency add-on can depend, on its turn, on other add-ons which will be loaded as well. Circular dependencies should be avoided. -## Testing addons +## Problems with untranspiled add-on dependencies + +When using external add-ons in your project, sometimes you will run into add-ons +that are not securely transpiled or haven't been transpiled at all. In that case +you might see an error like the following: + +```console +Module parse failed: Unexpected token (10:41) in @react-leaflet/core/esm/path.js +... +const options = props.pathOptions ?? {}; +... +``` + +Babel automatically transpiles the code in your add-on, but `node_modules` are +excluded from this process, so we need to include the add-on path in the list of +modules to be transpiled. This can be accomplished by customizing the webpack +configuration in the `razzle.config.js` file in your add-on. For example, +suppose that we want to use react-leaflet, which has a known transpilation +issue: + +```js +const path = require('path'); +const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder'); + +const babelLoaderFinder = makeLoaderFinder('babel-loader'); + +const jsConfig = require('./jsconfig').compilerOptions; + +const pathsConfig = jsConfig.paths; +let voltoPath = './node_modules/@plone/volto'; +Object.keys(pathsConfig).forEach((pkg) => { + if (pkg === '@plone/volto') { + voltoPath = `./${jsConfig.baseUrl}/${pathsConfig[pkg][0]}`; + } +}); + +const { modifyWebpackConfig, plugins } = require(`${voltoPath}/razzle.config`); + +const customModifyWebpackConfig = ({ env, webpackConfig, webpackObject, options }) => { + const config = modifyWebpackConfig({ + env, + webpackConfig, + webpackObject, + options, + }); + const babelLoader = config.module.rules.find(babelLoaderFinder); + const { include } = babelLoader; + const corePath = path.join( + path.dirname(require.resolve('@react-leaflet/core')), + '..', + ); + const esmPath = path.join( + path.dirname(require.resolve('react-leaflet')), + '..', + ); + + include.push(corePath); + include.push(esmPath); + return config; +}; + +module.exports = { modifyWebpackConfig: customModifyWebpackConfig, plugins }; +``` + +First we need some setup to get the webpack configuration from Volto's configuration. +Once we have that, we need to resolve the path to the desired add-ons and push it +into the Babel loader include list. After this, the add-ons will load correctly. + +## Testing add-ons We should let jest know about our aliases and make them available to it to resolve them, so in `package.json`: @@ -430,14 +529,14 @@ resolve them, so in `package.json`: ```{code-block} json :emphasize-lines: 6 - "jest": { - "moduleNameMapper": { - "@plone/volto/(.*)$": "/node_modules/@plone/volto/src/$1", - "@package/(.*)$": "/src/$1", - "@plone/some-volto-addon/(.*)$": "/src/addons/@plone/some-volto-addon/src/$1", - "my-volto-addon/(.*)$": "/src/addons/my-volto-addon/src/$1", - "~/(.*)$": "/src/$1" - }, +"jest": { + "moduleNameMapper": { + "@plone/volto/(.*)$": "/node_modules/@plone/volto/src/$1", + "@package/(.*)$": "/src/$1", + "@plone/some-volto-add-on/(.*)$": "/src/addons/@plone/some-volto-add-on/src/$1", + "my-volto-add-on/(.*)$": "/src/addons/my-volto-add-on/src/$1", + "~/(.*)$": "/src/$1" + }, ``` ```{tip} @@ -445,7 +544,7 @@ We're in the process of moving the default scaffolding generators to provide a `jest.config.js` file in Volto, making this step unneeded. ``` -You can use `yarn test src/addons/addon-name` to run tests. +You can use `yarn test src/addons/add-on-name` to run tests. ## Code linting diff --git a/docs/source/backend/index.md b/docs/source/backend/index.md index 3f3eb9c9be..4b5c35a609 100644 --- a/docs/source/backend/index.md +++ b/docs/source/backend/index.md @@ -9,38 +9,33 @@ myst: # Integration with the backend -## Plone backend integration - -Integration with the Plone CMS is provided by the Plone API framework, namely -[`plone.restapi`](https://github.com/plone/plone.restapi) and its lower-level -[`plone.rest]`(https://github.com/plone/plone.rest). For details please check -the [`plone.restapi` documentation website](https://plonerestapi.readthedocs.io/en/latest/). - -Some of the more interesting integration features that you can look up in the -`plone.restapi` documentation include the following. - -- **Endpoints**: the equivalent of Plone "views", these are REST API endpoints - that you can call from the frontend. The response should be in JSON format. - You'll use these for any type of interaction with the backend. -- **Content expansions**: additional information that can be added to the main - response. For example, when fetching "content" information, you may want to - also include information about the author. You could write an expansion that - automatically inserts that information if the HTTP GET parameter `?expand=author` is present in - the request. It is also possible to create expansion elements that will - automatically insert their content in the response, without the need for the - request parameter. -- **Block transformers**: these are named subscribers that can be used to - automatically change the information that is sent to the frontend for some of - the blocks. They can also do the opposite, to process the information - coming from the frontend on create or update operations, and change the way - the block value is stored in the database. There are multiple use cases for - this type of feature. For example to automatically convert incoming links in - block values to resolveuid-based links, and to convert them back to absolute - URLs when retrieving the block value from the frontend. -- **Search and indexing integration**: by providing the right adapters, you can - extract searchable text from blocks. - -### Proxied backend routes +Integration with the Plone CMS is provided by the Plone API framework, namely [`plone.restapi`](https://github.com/plone/plone.restapi) and its lower-level [`plone.rest`](https://github.com/plone/plone.rest). +For details, check the {doc}`plone.restapi/docs/source/index` documentation. + +Some of the more interesting integration features that you can look up in the `plone.restapi` documentation include the following. + +Endpoints +: The equivalent of Plone "views", these are REST API endpoints that you can call from the frontend. + The response should be in JSON format. + You'll use these for any type of interaction with the backend. + +Content expansions +: Additional information that can be added to the main response. + For example, when fetching "content" information, you may want to also include information about the author. + You could write an expansion that automatically inserts that information if the HTTP GET parameter `?expand=author` is present in the request. + It is also possible to create expansion elements that will automatically insert their content in the response, without the need for the request parameter. + +Block transformers +: These are named subscribers that can be used to automatically change the information that is sent to the frontend for some of the blocks. + They can also do the opposite, to process the information coming from the frontend on create or update operations, and change the way the block value is stored in the database. + There are multiple use cases for this type of feature. + For example to automatically convert incoming links in block values to resolveuid-based links, and to convert them back to absolute URLs when retrieving the block value from the frontend. + +Search and indexing integration +: By providing the right adapters, you can extract searchable text from blocks. + + +## Proxied backend routes Access to images and files are a special use case in Volto. Usually in plain HTML, `src` and `href` attributes resource calls cannot be wrapped in a JavaScript backend call. @@ -54,4 +49,5 @@ Thus the Node Express server takes care of proxying and enhancing them at the sa ```{todo} This section contains pointers for backend integration with Plone. Contributions for the Guillotina backend are needed. +See https://github.com/plone/volto/issues/4430 ``` diff --git a/docs/source/blocks/anatomy.md b/docs/source/blocks/anatomy.md index 64a2099749..4c17b89ce9 100644 --- a/docs/source/blocks/anatomy.md +++ b/docs/source/blocks/anatomy.md @@ -77,3 +77,25 @@ The edit component of a block receives these props from the Blocks Engine: You can use all these props to render your edit block and model its behavior. +## Default block edit and view components + +Volto later then 16.0.0 ships with a set of default Edit and View components. +The view component is mostly a placeholder, with an auto-generated listing of +the block fields, while the default Edit component is the most interesting, as +it can use the `schema` that you can specify in the block configuration to +automatically render a form for the Block settings, in the Volto Sidebar. In +the main editing area, it will render the view component, so for many blocks +you can just develop a schema and the View component. + +To use the default Edit and/or View component, just don't set any value in the +block configuration: + +```js +config.blocks.blocksConfig.myBlock = { + id: 'myBlock', + title: "My block", + edit: null, // or simply omit it + view: null, // or simply omit it + // ... the rest of the settings +} +``` diff --git a/docs/source/blocks/block-style-wrapper.md b/docs/source/blocks/block-style-wrapper.md index 8420f4f9f3..e3e825207e 100644 --- a/docs/source/blocks/block-style-wrapper.md +++ b/docs/source/blocks/block-style-wrapper.md @@ -7,7 +7,9 @@ myst: "keywords": "Volto, Plone, frontend, React, Blocks, Edit, Style, Wrapper, components" --- -# Blocks - Style Wrapper +(block-style-wrapper-label)= + +# Block style wrapper The block style wrapper is part of a block anatomy. It allows you to inject styles from the block schema into the block wrapper in the form of class names. @@ -62,7 +64,7 @@ const stylingSchema = { } ``` -The `addStyling` helper adds the (empty) `styles` field inside the `Styling` fieldset for you, so when defining your block schema you can do: +The `addStyling` schemaEnhancer adds the (empty) `styles` field inside the `Styling` fieldset for you, so when defining your block schema you can do: ```js import { addStyling } from '@plone/volto/helpers/Extensions/withBlockSchemaEnhancer'; @@ -90,6 +92,19 @@ export const TeaserSchema = ({ intl }) => { You can add a set of style fields defining your block styles—such as alignment, background color, and so on—in your block schema by adding them to the `styles` object field as shown above. +In case you decide to create reusable sets of styling controls for your blocks, you can use the `composeSchema` helper to compose multiple schemaEnhancers: + +```js +import { composeSchema } from '@plone/volto/helpers'; + +// ... +config.blocks.blocksConfig.listing.schemaEnhancer = composeSchema( + config.blocks.blocksConfig.listing.schemaEnhancer, + addStyling, + addMyCustomColorStylingField, +) +``` + ## The `styles` field The `styles` field is mapped to an `objectWidget`. @@ -132,9 +147,24 @@ The resultant HTML would be the following: ```html
``` - Then it's at your discretion how you define the CSS class names in your theme. +If you need other style of classnames generated, you can use the classname +converters defined in `config.settings.styleClassNameConverters`, by +registering fieldnames suffixed with the converter name. For example, a style +data like: + +``` +{ + "styles": { + "theme:noprefix": "primary", + "inverted:bool": true, + } +} +``` + +will generate classnames `primary inverted` + ## Align class injection There is an automatic class name injection happening at the same time the style wrapper class names injection. diff --git a/docs/source/blocks/core/index.md b/docs/source/blocks/core/index.md new file mode 100644 index 0000000000..03c2b19613 --- /dev/null +++ b/docs/source/blocks/core/index.md @@ -0,0 +1,19 @@ +--- +myst: + html_meta: + "description": "Core blocks provided in Volto by default" + "property=og:description": "Core blocks provided in Volto by default" + "property=og:title": "Core blocks provided in Volto by default" + "keywords": "Volto, Plone, frontend, React, blocks, default, core" +--- + +# Core Blocks developer notes + +This part of the documentation describes how to develop the core blocks in Volto. + +```{toctree} +:maxdepth: 1 + +listing +teaser +``` diff --git a/docs/source/blocks/core/listing.md b/docs/source/blocks/core/listing.md new file mode 100644 index 0000000000..5472fd9fd2 --- /dev/null +++ b/docs/source/blocks/core/listing.md @@ -0,0 +1,65 @@ +--- +myst: + html_meta: + "description": "The listing block provides an additional extension letting the developer modify the default 'No results found' message using the configuration of the block" + "property=og:description": "The listing block provides an additional extension letting the developer modify the default 'No results found' message using the configuration of the block" + "property=og:title": "Listing block extensions mechanism" + "keywords": "Volto, Plone, frontend, React, Upgrade, Guide, Block extensions, variations, schema enhancers, listing block" +--- + +(listing-block)= + +# Listing block + +The listing block is a special block that can be configured to run a catalog query in the backend and show the results of that search. + +Apart from the {ref}`standard variation ` and {ref}`schema enchancing extensions `, the listing block provides a configurable way to handle the "No results" message. + +When the listing block configured search returns no results, Volto presents a default "No results found" message. +But sometimes you want to change such a message to offer more meaningful messages, or do some other fancy stuff in that case. +For instance, you may want to show a "There are no future events" or "There are no images in the gallery" message for a given listing block. + +To achieve that, you can configure a new `noResultsComponent` when configuring the listing block, and provide a custom component to render such a message. +To do that, you need to reconfigure that option in the configuration of your project: + +```jsx +import { FormattedMessage } from 'react-intl'; + +const MyNoResultsComponent = (props) => { + return ( + + ); +}; + +const applyConfig = (config) => { + config.blocks.listing['noResultsComponent'] = MyNoResultsComponent; + return config; +}; +``` + +In addition to that, each variation configured for the listing block can have a custom no results template. +This way you can provide specific no results messages per-variation. +This can be done, like in the earlier step, stating that in the configuration: + +```jsx +import { FormattedMessage } from 'react-intl'; + +const MyNoResultsComponent = (props) => { + return ( + + ); +}; + +const applyConfig = (config) => { + config.blocks.listing.variations.default[ + 'noResultsComponent' + ] = MyNoResultsComponent; + return config; +}; +``` diff --git a/docs/source/blocks/core/teaser.md b/docs/source/blocks/core/teaser.md new file mode 100644 index 0000000000..352bc151f1 --- /dev/null +++ b/docs/source/blocks/core/teaser.md @@ -0,0 +1,175 @@ +--- +myst: + html_meta: + "description": "Volto Teaser Block description and developer notes" + "property=og:description": "Volto Teaser Block description and developer notes" + "property=og:title": "Volto Teaser Block" + "keywords": "Volto, React, blocks, teaser, Plone" +--- + +(teaser-block)= + +# Teaser Block + +```{versionadded} Volto 16.14.0 +``` + +Volto comes with a Teaser block, which when given a content object as a target, is able to pull information from the targeted content object and show it in the block. +By default, this information includes the `title`, `description`, `head_title`, and `preview_image` fields. +It shows them in a summary layout, with the image on the left, and the head title, title, and description on the right in order from top to bottom. + +## Settings + +The Teaser has the following settings: + +Target +: The target is either an existing content item in your Plone site, or an external URL + +Title +: The title is the title of the Teaser block. +By default is copied over from the Teaser target. + +Head title +: The head title is a heading that appears above the title of the Teaser Block. +By default is copied over from the Teaser target. + +Description +: The description is plain text that summarizes or describes the Teaser. +By default is copied over from the Teaser target. + +Image override +: The image override is either an existing image in your Plone site, or an external URL. +It overrides the image provided by the Teaser target. + +## Style wrapper properties + +The Teaser has a styling property to align the image. +The image can be aligned to the left (default), right, or top. + +The styling wrapper properties can be extended using the {ref}`block-style-wrapper-label`. + +## Variations + +A Teaser block has a default variation. +A variation can be extended using {ref}`extensions-block-variations`. + +## Data adapter + +The Teaser has a data adapter function that allows you to both tap into the changes in the settings and issue changes in other settings fields. +This is valuable in the Teaser block because it saves an internal cache of the target element. +If you select the target, these values are updated. +When you update the target, by default these values remain, but you can issue another behavior. + +The data adapter function is defined in the block's setting `dataAdapter`. +You can override it and add your own function, if required. +The following is the default adapter. +You should stick to this signature in your custom adapters. + +```js +import { isEmpty } from 'lodash'; + +export const TeaserBlockDataAdapter = ({ + block, + data, + id, + onChangeBlock, + value, +}) => { + let dataSaved = { + ...data, + [id]: value, + }; + if (id === 'href' && !isEmpty(value) && !data.title && !data.description) { + dataSaved = { + ...dataSaved, + title: value[0].Title, + description: value[0].Description, + head_title: value[0].head_title, + }; + } + onChangeBlock(block, dataSaved); +}; +``` + +## Custom components in registry + +The Teaser block looks up a couple of components in the {ref}`component-registry` that you can provide in case you want to modify the default behavior. + +### Image component + +The image component used in the Teaser can be overridden using your own custom image component. +By default, it uses an `` tag with the following signature. + +```jsx + +``` + +You can register your as: + +```js + import Image from './components/Image/MyImageComponent'; + + ... + + config.registerComponent({ + name: 'Image', + component: Image, + }); +``` + +### Content type dependent `Body` component + +The Teaser component supports specifying a custom component depending on the target content type. + +You can provide your own component, registering a component, for example, in your add-on configuration as shown below. + +```js +import NewsItem from './components/Blocks/Teaser/NewsItem'; + +... + + config.registerComponent({ + name: 'Teaser', + component: NewsItem, + dependencies: 'News Item', + }); +``` + +The `name` must be `Teaser`, but then as a dependency you must provide the name of the content type. + +After this, if you select a content type `News Item` as the target of the teaser, the `Body` component used will be `NewsItem` instead of the default one. + +## Custom `Body` component + +The Teaser body provides a default `Body` component that can be overridden. +Although it can be done via component shadowing, it is recommended that you override it using the `variations` block setting field. + +```js +import CustomTeaserBlockDefaultBody from './components/Blocks/Teaser'; + +... + + variations: [ + { + id: 'default', + isDefault: true, + title: 'Default', + template: CustomTeaserBlockDefaultBody, + }, + ], +``` + +The custom content type `Body` component mentioned in the previous section is compatible with this customization. +In this case, the content type customization will take precedence, if it matches with the content type of the target. + +## Migration from `volto-blocks-grid` + +From Volto 16.14.0 the Teaser block, as it's in the `volto-blocks-grid` add-on version 7.0.0, is included in Volto core. + +Because of the add-on configuration priority, if you have `volto-blocks-grid` installed in your project, the Teaser block from the add-on (and your project amendments to the configuration, if any) will be applied and used. + +In case you want to use the core Teaser block, you need to re-apply the core configuration for the Teaser block in your project or add-ons. diff --git a/docs/source/blocks/editcomponent.md b/docs/source/blocks/editcomponent.md index 1c65e77beb..daae5580b7 100644 --- a/docs/source/blocks/editcomponent.md +++ b/docs/source/blocks/editcomponent.md @@ -104,11 +104,11 @@ To render this form and make it available to the edit component: ```jsx import schema from './schema'; -import InlineForm from '@plone/volto/components/manage/Form/InlineForm'; +import BlockDataForm from '@plone/volto/components/manage/Form/BlockDataForm'; import { Icon } from '@plone/volto/components'; - } schema={schema} title={schema.title} @@ -120,7 +120,9 @@ import { Icon } from '@plone/volto/components'; [id]: value, }); }} + onChangeBlock={onChangeBlock} formData={this.props.data} + block={block} /> ; ``` diff --git a/docs/source/blocks/index.md b/docs/source/blocks/index.md index be691f9b1c..2a8e485349 100644 --- a/docs/source/blocks/index.md +++ b/docs/source/blocks/index.md @@ -19,4 +19,5 @@ editcomponent block-style-wrapper extensions ssr +core/index ``` 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 8cc44a84d7..933dccb1c6 100644 --- a/docs/source/blocks/ssr.md +++ b/docs/source/blocks/ssr.md @@ -10,7 +10,7 @@ myst: # Server-side rendering for async blocks By default blocks that depend on async-fetched data won't be rendered fully in -the server-side rendering phase. For the main "content", Volto provides +the {term}`server-side rendering` phase. For the main "content", Volto provides a mechanism for async rendering in the form of `asyncConnect` and `asyncPropExtenders`. @@ -31,5 +31,5 @@ export default ({ dispatch, data, path }) => { ``` All promises returned will be awaited before the rendering of that block, so -the strategy is to dispatch the data-fetching actions so that the Redux store +the strategy is to dispatch the data-fetching actions so that the {term}`Redux` store gets populated. diff --git a/docs/source/cheatsheet.md b/docs/source/cheatsheet.md index f2708476b6..f7b8601d7d 100644 --- a/docs/source/cheatsheet.md +++ b/docs/source/cheatsheet.md @@ -14,7 +14,7 @@ myst: # Cheatsheet ```{seealso} -{doc}`plone:contributing/writing-docs-guide` +{doc}`plone:contributing/documentation/myst-reference` ``` @@ -102,25 +102,10 @@ Click the reference {ref}`volto-demo-label` to jump to the target. ); } ); - ``` ```python - def asdas: - """ """ -``` - -## Toggle paragraph (Exercises / FAQ) - -````{admonition} This is a title -:class: toggle - -```{code-block} python -:linenos: -:emphasize-lines: 1, 3 - -a = 2 -print("my 1st line") -print(f"my {a}nd line") +def somefunction: +"""mydocstring""" + pass ``` -```` diff --git a/docs/source/conf.py b/docs/source/conf.py index d5a274aaca..679833e9a9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -56,11 +56,12 @@ extensions = [ "myst_parser", "sphinx.ext.autodoc", + "sphinx.ext.ifconfig", "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx_copybutton", - "sphinxcontrib.spelling", "sphinxext.opengraph", + "sphinxcontrib.video", ] @@ -86,6 +87,7 @@ r"https://github.com/plone/documentation/issues/new/choose", # requires auth # Ignore specific anchors r"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors#Identifying_the_issue", + r"https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0", r"https://github.com/browserslist/browserslist#queries", r"https://github.com/nodejs/release#release-schedule", r"https://github.com/plone/plone.docker#for-basic-usage", @@ -117,6 +119,7 @@ "spelling_wordlist.txt", "**/CHANGES.rst", "**/LICENSE.rst", + "contributing/branch-policy.md", ] html_extra_path = [ @@ -137,6 +140,7 @@ "linkify", # Identify “bare” web URLs and add hyperlinks. "colon_fence", # You can also use ::: delimiters to denote code fences,\ # instead of ```. + "html_image", ] @@ -153,9 +157,9 @@ # https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html # intersphinx_mapping = { - "plone": ("https://6.dev-docs.plone.org/", None), + "plone": ("https://6.docs.plone.org/", None), "python": ("https://docs.python.org/3/", None), - "training": ("https://training.plone.org/5/", None), + "training": ("https://training.plone.org/", None), } @@ -166,9 +170,9 @@ # -- OpenGraph configuration ---------------------------------- -ogp_site_url = "https://6.dev-docs.plone.org/" +ogp_site_url = "https://6.docs.plone.org/" ogp_description_length = 200 -ogp_image = "https://docs.plone.org/_static/Plone_logo_square.png" +ogp_image = "https://6.docs.plone.org/_static/Plone_logo_square.png" ogp_site_name = "Plone Documentation" ogp_type = "website" ogp_custom_meta_tags = [ @@ -199,7 +203,7 @@ # Announce that we have an opensearch plugin # https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-html_use_opensearch -html_use_opensearch = "https://docs.plone.org" +html_use_opensearch = "https://6.docs.plone.org" html_theme_options = { # TODO: Either get a separate GA ID or enable this one once it is in production. @@ -246,3 +250,6 @@ # The name of an image file (relative to this directory) to place at the top of # the title page. latex_logo = "_static/logo_2x.png" + +def setup(app): + app.add_config_value("context", "volto", "env") diff --git a/docs/source/configuration/component-registry.md b/docs/source/configuration/component-registry.md index 25d39e7abb..1043115cdc 100644 --- a/docs/source/configuration/component-registry.md +++ b/docs/source/configuration/component-registry.md @@ -1,11 +1,22 @@ -# Component Registry +--- +myst: + html_meta: + "description": "Volto provides an integrated component registry that stores named references to components, allowing them to be queried programmatically." + "property=og:description": "Volto provides an integrated component registry that stores named references to components, allowing them to be queried programmatically." + "property=og:title": "Component registry in Volto" + "keywords": "Volto, Plone, frontend, React, registry, component" +--- -The configuration registry has a component registry integrated on itself. +(component-registry)= + +# Component registry + +The {term}`configuration registry` has a component registry integrated on itself. These registry stores by a given name the components. Later you can retrieve them by this name, and use them in your code. The idea behind is to provide an alternative and more convenient way to customize components. -You can override programatically such registrations from your add-on or projects because it's stored in the configuration registry. -You can customize a component without using shadowing at all, if the code that calls the component retrieves the information of the component to use from the component registry. +You can override programmatically such registrations from your add-on or projects because it's stored in the configuration registry. +You can customize a component without using {term}`shadowing` at all, if the code that calls the component retrieves the information of the component to use from the component registry. You can even have modifiers to the component registrations: dependencies. So you can "adapt" the call given an array of such dependencies. ## Registering components by name using `config.registerComponent` diff --git a/docs/source/configuration/environmentvariables.md b/docs/source/configuration/environmentvariables.md index ec1c82bd06..4cb8f8b028 100644 --- a/docs/source/configuration/environmentvariables.md +++ b/docs/source/configuration/environmentvariables.md @@ -101,7 +101,7 @@ Set `DEBUG_ADDONS_LOADER=true` to have Volto generate a file, `addon-dependency- dot addon-dependency-graph.dot -Tsvg -o out.svg ``` -#### Component Shadowing errors (shadowing) +#### Component shadowing errors (shadowing) It displays the errors of the non-compliant customizations (in server console) if you are experiencing problems with a customization not working. diff --git a/docs/source/configuration/experimental.md b/docs/source/configuration/experimental.md new file mode 100644 index 0000000000..103e8a1be9 --- /dev/null +++ b/docs/source/configuration/experimental.md @@ -0,0 +1,36 @@ +--- +myst: + html_meta: + "description": "Enable experimental features in Volto's configuration object" + "property=og:description": "Enable experimental features in Volto's configuration object" + "property=og:title": "Experimental features" + "keywords": "Volto, Plone, frontend, experimental, features" +--- + +# Experimental features + +Experimental features are planned for inclusion in a future release of Volto, +but are not yet considered mature by the community. +An experimental feature gives users an easy way to install it and see if anything breaks before we make a new stable release that includes it. + +## Volto configuration + +You can enable an experimental feature—also called a "feature flag"—in Volto's configuration object as shown below. + +```js +import config from '@plone/volto/registry' + +config.experimental.addBlockButton.enabled = true; +``` + +Currently the following experimental features are available: + +```{glossary} +:sorted: + +addBlockButton + Enables a new UI for adding blocks. + The button to add a block is now shown below any selected block. + A text block can also be added by clicking in the empty area at the bottom of the content area. + +``` diff --git a/docs/source/configuration/how-to.md b/docs/source/configuration/how-to.md index ead54e6081..12d3bfae16 100644 --- a/docs/source/configuration/how-to.md +++ b/docs/source/configuration/how-to.md @@ -9,7 +9,7 @@ myst: # The configuration registry -Volto has a centralized configuration registry used to parameterize Volto. It has the +Volto has a centralized {term}`configuration registry` used to parameterize Volto. It has the form of a singleton that can be called and queried from anywhere in your code like this: ```js diff --git a/docs/source/configuration/index.md b/docs/source/configuration/index.md index 421c36f0d3..fde6916ff3 100644 --- a/docs/source/configuration/index.md +++ b/docs/source/configuration/index.md @@ -14,6 +14,7 @@ myst: how-to settings-reference +experimental zero-config-builds component-registry internalproxy diff --git a/docs/source/configuration/internalproxy.md b/docs/source/configuration/internalproxy.md index a5f4820236..93f4c0c9af 100644 --- a/docs/source/configuration/internalproxy.md +++ b/docs/source/configuration/internalproxy.md @@ -9,7 +9,7 @@ myst: # Internal proxy to content backend API -The server side Volto SSR process (based on Razzle) has an internal proxy to the backend API +The server side Volto {term}`SSR` process (based on Razzle) has an internal proxy to the backend API enabled by default. It provides a better developer experience out of the box, so the developer doesn't has to @@ -20,7 +20,7 @@ To understand the need for the internal proxy, there are three processes running 1. A frontend web application running in your browser (Javascript) 2. A Node.js server process that delivers the javascript to the client and does - Server Side Rendering (SSR) of your pages on first request (Javascript, the + {term}`server-side rendering` (SSR) of your pages on first request (Javascript, the Razzle package is used for SSR) 3. A Plone server process that stores and delivers all content through a REST API (Python) diff --git a/docs/source/configuration/settings-reference.md b/docs/source/configuration/settings-reference.md index cc43b0a37e..d5d989f356 100644 --- a/docs/source/configuration/settings-reference.md +++ b/docs/source/configuration/settings-reference.md @@ -28,39 +28,12 @@ navDepth defaultBlockType The default block type in Volto is "text", which uses the current DraftJS-based implementation for the rich text editor. Future alternative rich text editors will need to use this setting and replace it with their block type. The block definition should also include the `blockHasValue` function, which is needed to activate the Block Chooser functionality. See this function signature in [Blocks > Settings](../blocks/settings.md). + sentryOptions - Sentry configuration: + In Volto 16.0.0.alpha.45, Sentry integration was moved from core to the add-on [`@plone-collective/volto-sentry`](https://www.npmjs.com/package/@plone-collective/volto-sentry). - ```js - import { - settings as defaultSettings, - } from '@plone/volto/config'; - - const settings = { - ...defaultSettings, - sentryOptions: { - ...defaultSettings.sentryOptions, - dsn: 'https://key@sentry.io/1', - environment: 'production', - release: '1.2.3', - serverName: 'volto', - tags: { - site: 'foo.bar', - app: 'test_app', - logger: 'volto', - }, - extras: { - key: 'value', - }, - integrations: [ - ...defaultSettings.sentryOptions.integrations, - // new MyAwesomeIntegration() - ] - } - }; - ``` ```{seealso} - See more about [Sentry integration](../deploying/sentry.md). + See {doc}`../deploying/sentry`. ``` contentIcons @@ -105,7 +78,7 @@ persistentReducers maxResponseSize The library that we use to get files and images from the backend (superagent) has a response size limit of 200 mb, so if you want to get a file bigger than 200 mb - from Plone, the SSR will throw an error. + from Plone, the {term}`SSR` will throw an error. You can edit this limit in the `settings` object setting a new value in bytes (for example, to set 500 mb you need to write 5000000000). @@ -145,7 +118,7 @@ storeExtenders asyncPropsExtenders Per-route customizable `asyncConnect` action dispatcher. These enable - proper server-side rendering of content that depends on additional async + proper {term}`server-side rendering` of content that depends on additional async props coming from backend calls. It is a list of route-like configuration objects (they are matched using [matchRoutes](https://github.com/remix-run/react-router/blob/ea44618e68f6a112e48404b2ea0da3e207daf4f0/packages/react-router-config/modules/matchRoutes.js). @@ -227,6 +200,13 @@ controlpanels The group can be one of the default groups 'General', 'Content', 'Security', 'Add-on Configuration', 'Users and Groups' or a custom group. +filterControlPanelsSchema + A schema factory for a control panel. It is used internally, to tweak the schemas provided by the controlpanel endpoint, to make them fit for Volto. + +errorHandlers + A list of error handlers that will be called when there is an unhandled exception. Each error handler is a function that + receives a single argument, the `error` object. + workflowMapping It's an object that defines the mapping between workflow states/transitions and the color that should show in the change Workflow dropdown. This is the default: @@ -246,11 +226,157 @@ workflowMapping It's meant to be extended with your own workflows/transitions. It is recommended to assign the same color to the transition as the destination state, so the user can have the visual hint to which state are they transitioning to. -errorHandlers - A list of error handlers that will be called when there is an unhandled exception. Each error handler is a function that - receives a single argument, the `error` object. + +styleClassNameConverters + An object with functions used by the style wrapper helpers to convert style + data to actual class names. You can customize the generated classname by + registering fieldnames with names such as `:`, + where the converter is registered here. + +styleClassNameExtenders + An array containing functions that extends how the StyleWrapper builds a list of styles. These functions have the signature `({ block, content, data, classNames }) => classNames`. Here are some examples of useful ones, for simplicity, they are compacted in one extender: + + ```js + import { getPreviousNextBlock } from '@plone/volto/helpers'; + + config.settings.styleClassNameExtenders = [ + ({ block, content, data, classNames }) => { + let styles = []; + const [previousBlock, nextBlock] = getPreviousNextBlock({ + content, + block, + }); + + // Inject a class depending of which type is the next block + if (nextBlock?.['@type']) { + styles.push(`next--is--${nextBlock['@type']}`); + } + + // Inject a class depending if previous is the same type of block + if (data?.['@type'] === previousBlock?.['@type']) { + styles.push('previous--is--same--block-type'); + } + + // Inject a class depending if next is the same type of block + if (data?.['@type'] === nextBlock?.['@type']) { + styles.push('next--is--same--block-type'); + } + + // Inject a class depending if it's the first of block type + if (data?.['@type'] !== previousBlock?.['@type']) { + styles.push('is--first--of--block-type'); + } + + // Inject a class depending if it's the last of block type + if (data?.['@type'] !== nextBlock?.['@type']) { + styles.push('is--last--of--block-type'); + } + + // Given a StyleWrapper defined `backgroundColor` style + const previousColor = + previousBlock?.styles?.backgroundColor ?? 'transparent'; + const currentColor = data?.styles?.backgroundColor ?? 'transparent'; + const nextColor = nextBlock?.styles?.backgroundColor ?? 'transparent'; + + // Inject a class depending if the previous block has the same `backgroundColor` + if (currentColor === previousColor) { + styles.push('previous--has--same--backgroundColor'); + } else if (currentColor !== previousColor) { + styles.push('previous--has--different--backgroundColor'); + } + + // Inject a class depending if the next block has the same `backgroundColor` + if (currentColor === nextColor) { + styles.push('next--has--same--backgroundColor'); + } else if (currentColor !== nextColor) { + styles.push('next--has--different--backgroundColor'); + } + + return [...classNames, ...styles]; + }, + ]; + ``` + +apiExpanders + You can configure the API expanders in Volto using `settings.apiExpanders`, as in the following example. + + ```jsx + import { GET_CONTENT } from '@plone/volto/constants/ActionTypes'; + + export default function applyConfig (config) { + config.settings.apiExpanders = [ + ...config.settings.apiExpanders, + { + match: '', + GET_CONTENT: ['mycustomexpander'], + }, + { + match: '/de', + GET_CONTENT: ['myothercustomexpander'], + }, + { + match: '/de', + GET_CONTENT: ['navigation'], + querystring: { + 'expand.navigation.depth': 3, + }, + } + ]; + + return config; + } + ``` + + If you want Volto to make only a single request, combining all the expanders in it, then configure `apiExpanders` as shown. + + ```jsx + config.settings.apiExpanders = [ + { + match: '', + GET_CONTENT: ['breadcrumbs', 'navigation', 'actions', 'types'], + }, + ], + ``` + The configuration accepts a list of matchers, with the ability to filter by the request path and action type for maximum flexibility. + It also accepts a `querystring` object that allows configuring the expanders via query string parameters, such as the navigation expander. + +additionalToolbarComponents + For additional toolbar menus, the menu body component needs to be added to the on-demand loaded components. + + ```jsx + config.settings.additionalToolbarComponents = { + bookmarksMenu: { + component: BookmarksEditorComponent, + wrapper: null, + }, + }; + ``` + + The plug: + ```jsx + + {({ onClickHandler }) => { + return ( + + ); + }} + + ``` ``` + ## Views settings They are exposed in `config.views`: @@ -299,7 +425,7 @@ layoutViewsNamesMapping ## Server-specific serverConfig -Settings that are relevant to the Express-powered Volto SSR server are stored +Settings that are relevant to the Express-powered Volto {term}`SSR` server are stored in the `config.settings.serverConfig` object. ```{glossary} @@ -321,5 +447,4 @@ extractScripts For the moment it admits only one property: `errorPages` whose value is a Boolean. If `extractScripts.errorPages` is `true`, the JS will be inserted into the error page. - ``` diff --git a/docs/source/configuration/volto-config-js.md b/docs/source/configuration/volto-config-js.md index bddbca06f1..56bbcf417d 100644 --- a/docs/source/configuration/volto-config-js.md +++ b/docs/source/configuration/volto-config-js.md @@ -1,6 +1,6 @@ # Dynamic Volto Addons Configuration -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, shadowing or the features of other addons available. +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. There is a scapehatch `volto.config.js`. This module exports an object and can have arbitrary code depending on your needs: diff --git a/docs/source/configuration/volto-slate/configuration-settings.md b/docs/source/configuration/volto-slate/configuration-settings.md index bd08d57a52..a6da06c3b2 100644 --- a/docs/source/configuration/volto-slate/configuration-settings.md +++ b/docs/source/configuration/volto-slate/configuration-settings.md @@ -237,4 +237,23 @@ They are not persisted in the final value, so they are useful, for example, to h ```js slate.runtimeDecorators = [([node, path], ranges) => ranges]; -``` \ No newline at end of file +``` + + +(editor-configuration-blocks-initialBlocksFocus-label)= + +## `blocks.initialBlocksFocus` + +Determine which type of block should be selected on edit. + +```js +blocks.initialBlocksFocus === { + : +}; +``` + +Disable selection of any block and prevent scrolling to a block: + +```js +blocks.initialBlocksFocus === null; +``` diff --git a/docs/source/configuration/volto-slate/index.md b/docs/source/configuration/volto-slate/index.md index d728a0018a..98272cf87b 100644 --- a/docs/source/configuration/volto-slate/index.md +++ b/docs/source/configuration/volto-slate/index.md @@ -39,7 +39,7 @@ Some of the main reasons that drove us to create `volto-slate`, instead of enhan We can override core functionality, something that is built in as pluggable, directly in Slate. - Volto's Draft.js-based implementation depends on Redraft for its final output, which comes with its own bugs and issues. While it is nice to have view-mode components, this is something that `volto-slate` implements just as well. -- Because Slate's internal storage uses a tree modeled on the DOM pattern, its final rendered output is very clean. +- Because Slate's internal storage uses a tree modeled on the {term}`DOM` pattern, its final rendered output is very clean. Note: the Slate editor value is a JSON object, similar to the Draft.js-based implementation. diff --git a/docs/source/configuration/volto-slate/writing-plugins.md b/docs/source/configuration/volto-slate/writing-plugins.md index 066276c943..ddae66601f 100644 --- a/docs/source/configuration/volto-slate/writing-plugins.md +++ b/docs/source/configuration/volto-slate/writing-plugins.md @@ -152,7 +152,7 @@ export const TOOLTIP = 'tooltip'; ## Volto configuration registry -Finally register the plugin and the toolbar button in Volto's configuration. +Finally register the plugin and the toolbar button in Volto's {term}`configuration registry`. ```js 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 92% rename from docs/source/developer-guidelines/acceptance-tests.md rename to docs/source/contributing/acceptance-tests.md index 3757adaf2b..de27105552 100644 --- a/docs/source/developer-guidelines/acceptance-tests.md +++ b/docs/source/contributing/acceptance-tests.md @@ -68,7 +68,7 @@ There are some artifacts available for the acceptance tests made accessible to C ### Access History, Redux Store and Settings -We expose the History, Redux Store and Settings from the app (only for Cypress environments) so we can easily access them and execute actions (like navigate using the router), dispatch Redux actions or change app settings "on the fly". +We expose the History, {term}`Redux` Store and Settings from the app (only for Cypress environments) so we can easily access them and execute actions (like navigate using the router), dispatch Redux actions or change app settings "on the fly". #### Navigate using React Router 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/contributing/branch-policy.md b/docs/source/contributing/branch-policy.md new file mode 100644 index 0000000000..d274e78e38 --- /dev/null +++ b/docs/source/contributing/branch-policy.md @@ -0,0 +1,49 @@ +The Volto team enforces the following branch policy when developers contribute to its core. + +Releases of general packages (`@plone/generator-volto`, `@plone/scripts`, and so on) are cut from the `master` branch. + +stable and latest +: The terms _stable_ and _latest_ mean the same thing in this policy. + They refer to the stable and latest released version of Volto. + They have no branch names in git. + +canary +: The term _canary_ refers to the metaphorical canary in a coalmine; if an issue is detected following its release, the damage is limited to only those users who have installed it. + It usually includes experimental and breaking features for testing. + During the development process, a canary release will be cut from the `master` branch. + When it becomes worthy of a beta or release candidate version, a new numbered branch should be cut, and non-breaking changes must be merged into it. + +legacy +: A version that it is unsupported and receives no bug fixes. + It has no branch name in git. + +`master` +: This is the bleeding edge branch in git. + It is the branch upon which future development occurs, and from which future releases shall be cut. + + When we cut a release candidate, we: + + 1. create a new numbered git branch from master, and + 2. cut a release candidate version whose name aligns with the new numbered git branch. + + For example, when we cut the release candidate version 16.0.0-rc.1, we created a git branch `16.x.x`. + We also freeze the release candidate, and stop adding features to it. + This allows us to continue development on `master`, which may include both breaking changes that must not be backported, and bug fixes and feature additions that may be backported but only after the release candidate becomes final. + + When opening a pull request, the contributor must open it against `master`. + If the pull request is a feature or a bugfix, and if the release manager deems it useful to the latest version's branch, they may ask the contributor to backport it to that branch. + +`16.x.x` +: This is the current actively developed branch in git, meaning that it may receive new features and bug fixes. + Its version is currently at 16.0.0-rc.1 as a release candidate. + It will become the stable version upon the final release of version 16.0.0. + +`15.x.x` +: At the moment of this writing, `15.x.x` is the current stable branch in git. + Upon the final release of version 16.0.0, the `15.x.x` branch line will become legacy. + +## Translation contributing policy + +Due to the nature of `master` and `16.x.x` branches, some developments that may land in `master` may not be backported to `16.x.x`. This means that many translations that may come with those developments will be useless in the `16.x.x` branch and thus porting them to `16.x.x` makes no sense. + +So when contributing translations, please create PRs directly from branches created from `16.x.x` and point your PRs to that exact branch instead of `master`. diff --git a/docs/source/developer-guidelines/design-principles.md b/docs/source/contributing/design-principles.md similarity index 97% rename from docs/source/developer-guidelines/design-principles.md rename to docs/source/contributing/design-principles.md index 3d8110b3e6..4252c1ca85 100644 --- a/docs/source/developer-guidelines/design-principles.md +++ b/docs/source/contributing/design-principles.md @@ -64,8 +64,7 @@ In Volto we have a blank page in front of us. Let's work to keep it clean and sh ## Customization and extensibility -Volto should ensure customization every core component via "component shadowing", -whenever it is possible. +Volto should ensure customization of every core component via {term}`component shadowing`, whenever it is possible. Extensibility should also be a requirement on Volto core and in every new added feature, whenever it applies. Volto have to ensure that it can be "pluggable" and provide enough 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 97% rename from docs/source/developer-guidelines/language-features.md rename to docs/source/contributing/language-features.md index 1feac77cad..eb385c8d6d 100644 --- a/docs/source/developer-guidelines/language-features.md +++ b/docs/source/contributing/language-features.md @@ -39,7 +39,7 @@ currently targeting. By doing this, enables the bundles to be smaller, as the resultant code does not need to support old browsers (thus, transform your code to ES5 compatible code) as Babel will apply only the required transforms that your target enviroments need. For more -information: https://babeljs.io/docs/en/babel-preset-env#browserslist-integration +information: https://babeljs.io/docs/babel-preset-env#browserslist-integration Volto project generators use this browserlist by default (you can find it in your local `package.json`): 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 94% rename from docs/source/developer-guidelines/redux.md rename to docs/source/contributing/redux.md index 2b97a99672..2e8a6d1e3f 100644 --- a/docs/source/developer-guidelines/redux.md +++ b/docs/source/contributing/redux.md @@ -16,7 +16,7 @@ gaps! As with any other complex React project, the way global state is handled across all components has a big impact on the overall architecture. Basic -knowledge of Redux is needed to understand this part, but Volto's use of Redux +knowledge of {term}`Redux` is needed to understand this part, but Volto's use of Redux is "typical" and you can find plenty examples in Volto's code base. To access the global state, a component needs to be connected with `connect`. @@ -42,7 +42,7 @@ export default compose( If multiple Higher Order Components need to be used, like in the above example, the `compose` can be used to combine all of them in a final component. -If you're writing Function Components, you can use the `useSelector` hook. See +If you're writing Function Components, you can use the `useSelector` {term}`hook`. See `src/components/theme/OutdatedBrowser/OutdatedBrowser.jsx` for an example. When using the `connect` function, you can `select` parts from the global store @@ -54,7 +54,7 @@ developer extension](https://chrome.google.com/webstore/detail/redux-devtools/lm The code that is used to populate this store is in the `src/reducers` folder. In some parts of Volto you'll see `asyncConnect` being used, which is needed to -enable proper server-side rendering of components. Using it makes sure that the +enable proper {term}`server-side rendering` of components. Using it makes sure that the component will be constructed with the proper data already fetched from the backend and available as props. @@ -77,7 +77,7 @@ Components you can use the `useDispatch` hook. Global state update fetches are typically triggered by components in the mount lifecycle stage. See for example `src/components/theme/Search/Search.jsx` for a component that needs to interact with the backend to show its content. In the -redux flow of information, actions trigger the asynchronous processes and when +Redux flow of information, actions trigger the asynchronous processes and when that content arrives to the global app, it is pushed as props through the `connect` mechanism. So components only deal indirectly with async information: they trigger getting that information and it will arrive as a property once it @@ -115,7 +115,7 @@ special Api middleware, available in `src/middleware/api.js`. ## Customizing the Redux middleware -It is possible to tweak Volto's Redux middleware, for example to add new +It is possible to tweak Volto's {term}`Redux middleware`, for example to add new middleware by using the `config.settings.storeExtender` configuration option. If you have Redux middleware that you want to insert as the first middleware to be used, for example, you could configure your project with: 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 100% rename from docs/source/developer-guidelines/style-guide.md rename to docs/source/contributing/style-guide.md 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/deploying/pm2.md b/docs/source/deploying/pm2.md index caa2df43d6..608de9af46 100644 --- a/docs/source/deploying/pm2.md +++ b/docs/source/deploying/pm2.md @@ -54,7 +54,7 @@ module.exports = { }; ``` -- `mywebsite.com-volto` starts the Node process that is responsible for Volto server-side rendering. +- `mywebsite.com-volto` starts the Node process that is responsible for Volto {term}`server-side rendering`. - `mywebsite.com-api-zeo` starts the ZEO server. - `mywebsite.com-api-instance1` starts the first Zope instance. - `mywebsite.com-api-instance2` starts the second Zope instance. diff --git a/docs/source/deploying/seamless-mode.md b/docs/source/deploying/seamless-mode.md index cf0479cc9c..5c6f0caf1a 100644 --- a/docs/source/deploying/seamless-mode.md +++ b/docs/source/deploying/seamless-mode.md @@ -13,7 +13,7 @@ myst: This was added in Volto 13 as an experimental feature. During the experimental phase, we realized of several issues hard to solve, which made us rethink the feature into its second incarnation, available since Volto 14. -The first implementation wanted to unify both backend and frontend under the same sun, using the `Accept` header to route the requests to the API and the Volto SSR server. As a reference and for the record, these were the major issues we encountered (https://github.com/plone/volto/issues/2706): +The first implementation wanted to unify both backend and frontend under the same sun, using the `Accept` header to route the requests to the API and the Volto {term}`SSR` server. As a reference and for the record, these were the major issues we encountered (https://github.com/plone/volto/issues/2706): - Browsers are unable to differentiate cached responses using the `Accept` header, so the last one (usually the JSON one) was cached, then shown in some situations (like browser restart and open tabs). The back button also showed the JSON responses under some circumstances. - The use of cache servers and services is hard since they do not accept the `Vary` header (Cloudflare) and in Varnish the handling is also difficult to differentiate both requests and cache (and then invalidate) them properly. diff --git a/docs/source/deploying/sentry_backend_message.png b/docs/source/deploying/sentry-backend-message.png similarity index 100% rename from docs/source/deploying/sentry_backend_message.png rename to docs/source/deploying/sentry-backend-message.png diff --git a/docs/source/deploying/sentry_frontend_message.png b/docs/source/deploying/sentry-frontend-message.png similarity index 100% rename from docs/source/deploying/sentry_frontend_message.png rename to docs/source/deploying/sentry-frontend-message.png diff --git a/docs/source/deploying/sentry_messages.png b/docs/source/deploying/sentry-messages.png similarity index 100% rename from docs/source/deploying/sentry_messages.png rename to docs/source/deploying/sentry-messages.png diff --git a/docs/source/deploying/sentry.md b/docs/source/deploying/sentry.md index ea2da02699..c2edd27011 100644 --- a/docs/source/deploying/sentry.md +++ b/docs/source/deploying/sentry.md @@ -4,50 +4,92 @@ myst: "description": "Volto Integration with Sentry" "property=og:description": "Volto Integration with Sentry" "property=og:title": "Integration with Sentry" - "keywords": "Volto, Plone, frontend, React, Integration, Sentry" + "keywords": "Volto, Plone, frontend, React, Integration, Sentry, volto-sentry, add-on" --- # Integration with Sentry +Volto can be configured to work with [Sentry.io](https://sentry.io/welcome/). +Sentry is a monitoring platform that can help identify the cause of errors in your project. + + ## Prerequisities -1. In Sentry create a new organization, and add a project to it -2. On the projects settings page, from Client Keys (DSN), take the SENTRY_DSN -3. Create an API Token: on the top left corner, click on your name -> API keys and create a new token, "project:write" scope should be selected. -**Note:** Instructions tested with Sentry 9.1.2 +1. Install the add-on [`@plone-collective/volto-sentry`](https://www.npmjs.com/package/@plone-collective/volto-sentry). +2. In Sentry, create a new organization, and add a project to it. +3. On the projects settings page, from {guilabel}`Client Keys (DSN)`, take the `SENTRY_DSN`. +4. Create an API Token: in the top-left corner, click on {guilabel}`your name -> API keys`, and create a new token. + {guilabel}`project:write` scope should be selected. + +```{note} +Instructions tested with Sentry 9.1.2. +``` + +```{versionchanged} 16.0.0.alpha.45 +Sentry was moved from Volto core and into a separate add-on [`volto-sentry`](https://github.com/collective/volto-sentry). +``` + ## Setup -Volto creates bundles of the source codes, if an error is sent to sentry, it will only show the traceback in the bundles. To have nice traceback, we have to upload the source code and source map in sentry. -This doesn't have to be done manually, we can configure our volto application to do all the steps automatically. -There are 2 ways to configure the application: +Volto creates bundles of the source codes. +If an error is sent to Sentry, it will only show the traceback in the bundles. +To have a nice traceback, we have to upload the source code and source map to Sentry. +This can be configured in our Volto application to do all the steps automatically. + +There are 2 ways to configure the application. + + +### 1. Build time + +This method can be used when the application is deployed directly on a host machine and built locally. -### 1. Buildtime -This can be used when the application is deployed directly on a host machine, and built locally. +The configuration is done using environment variables. -The configuration is done using environment variables: - - SENTRY_DSN - required to enable the feature - - SENTRY_URL - the url of sentry - - SENTRY_AUTH_TOKEN - the authentication token for sentry - - SENTRY_ORG - the name of the organization in sentry - - SENTRY_PROJECT -the name of the project in sentry - - SENTRY_RELEASE - release number - - SENTRY_FRONTEND_CONFIG - optional, here we can specify TAGS - and ADDITIONAL DATA for the messages from the browser we send to sentry - - SENTRY_BACKEND_CONFIG - same as SENTRY_FRONTEND_CONFIG, but we configure the messages from the backend +`SENTRY_DSN` +: Required to enable the feature. -If these env variables are configured, when the app is built, a new release will be created in sentry, and the source code and source maps will be uploaded it. -After starting the application if an error will occure, the errors will be sent to sentry, and will be linked to the specified release. +`SENTRY_URL` +: The URL of Sentry. -Example of usage: +`SENTRY_AUTH_TOKEN` +: The authentication token for Sentry. -```bash -SENTRY_URL=https://mysentry.com SENTRY_AUTH_TOKEN=foo SENTRY_ORG=my_organization SENTRY_PROJECT=new_project SENTRY_RELEASE=2.0.0 SENTRY_DSN=https://boo@sentry.com/1 yarn build +`SENTRY_ORG` +: The name of the organization in Sentry. + +`SENTRY_PROJECT` +: The name of the project in Sentry. + +`SENTRY_RELEASE` +: The release number. + +`SENTRY_FRONTEND_CONFIG` +: Optional, here we can specify `TAGS` and `ADDITIONAL DATA` for the messages we send to Sentry from the browser. + +`SENTRY_BACKEND_CONFIG` +: Same as `SENTRY_FRONTEND_CONFIG`, but we configure the messages from the backend. + +If these environment variables are configured when the app is built, a new release will be created in Sentry, and the source code and source maps will be uploaded to it. +After starting the application, if an error occurs, the errors will be sent to Sentry, and will be linked to the specified release. + +Example usage: + +```shell +SENTRY_URL=https://mysentry.com \ +SENTRY_AUTH_TOKEN=foo \ +SENTRY_ORG=my_organization \ +SENTRY_PROJECT=new_project \ +SENTRY_RELEASE=2.0.0 \ +SENTRY_DSN=https://boo@sentry.com/1 yarn build node build/server.js ``` + + ### 2. Runtime -Within your Volto project or a dedicated Volto add-on you can configure Sentry via `settings.sentryOptions` configuration key: + +Within your Volto project or a dedicated Volto add-on, you can configure Sentry via the `settings.sentryOptions` configuration key: ```js import { @@ -76,31 +118,51 @@ const settings = { ] } }; -See more about [Sentry Custom Integrations](https://docs.sentry.io/platforms/javascript/configuration/integrations) - -In case you plan to use the application using docker, you will not want to have the sentry setup in the docker image. -The configuration for setting up sentry on runtime is very similar as how we set it up for buildtime, but with some small differences: - - - SENTRY_URL - the url of sentry - - SENTRY_AUTH_TOKEN - the authentication token for sentry - - SENTRY_ORG - the name of the organization in sentry - - SENTRY_PROJECT -the name of the project in sentry - - SENTRY_RELEASE - release number - - RAZZLE_SENTRY_DSN - required to enable the feature - - RAZZLE_SENTRY_FRONTEND_CONFIG - optional, here we can specify TAGS - and ADDITIONAL DATA for the messages from the browser we send to sentry - - RAZZLE_SENTRY_BACKEND_CONFIG - same as RAZZLE_SENTRY_FRONTEND_CONFIG, but we configure the messages from the backend - - RAZZLE_SENTRY_RELEASE - release number, should be the same as SENTRY_RELEASE - -In the entrypoint of our docker image we have to add the ./create-sentry-release.sh script. When the container is started, this script will check in sentry if the specified release already exists, if not, it will create it and upload the source code and the source maps. -The script can be executed also manually and if we want to overwrite the existing files in sentry, we can use the --force flag: - -```bash +``` + +See more about [Sentry Custom Integrations](https://docs.sentry.io/platforms/javascript/configuration/integrations/custom/). + +In case you plan to use the application using Docker, you will not want to have the Sentry setup in the Docker image. +The configuration for setting up Sentry on runtime is very similar to how we set it up for build time, but with some small differences. + +`SENTRY_URL` +: The URL of Sentry. + +`SENTRY_AUTH_TOKEN` +: The authentication token for Sentry. + +`SENTRY_ORG` +: The name of the organization in Sentry. + +`SENTRY_PROJECT` +: The name of the project in Sentry. + +`SENTRY_RELEASE` +: The release number. + +`RAZZLE_SENTRY_DSN` +: Required to enable the feature. + +`RAZZLE_SENTRY_FRONTEND_CONFIG` +: Optional, here we can specify `TAGS` and `ADDITIONAL DATA` for the messages we send to Sentry from the browser. + +`RAZZLE_SENTRY_BACKEND_CONFIG` +: Same as `RAZZLE_SENTRY_FRONTEND_CONFIG`, but we configure the messages from the backend. + +`RAZZLE_SENTRY_RELEASE` + The release number, which should be the same as `SENTRY_RELEASE`. + +In the entrypoint of our Docker image, we have to add the script `./create-sentry-release.sh`. +When the container is started, this script will check in Sentry if the specified release already exists, and if not, it will create it and upload the source code and the source maps. +The script can also be executed manually, and if we want to overwrite the existing files in Sentry, we can use the `--force` flag. + +```shell ./create-sentry-release.sh --force ``` -Example of entrypoint: -```bash +Example of entrypoint. + +```shell #!/usr/bin/env bash set -Ex @@ -129,7 +191,7 @@ echo "Starting Volto" exec "$@" ``` -Starting with docker: +Starting the container with Docker. ```shell docker run -p 3000:3000 -p 3001:3001 \ @@ -162,16 +224,19 @@ services: - RAZZLE_SENTRY_RELEASE=2.0.0 ``` + ## Configuration options -This applies to both SENTRY_FRONTEND_CONFIG and SENTRY_BACKEND_CONFIG +This applies to both `SENTRY_FRONTEND_CONFIG` and `SENTRY_BACKEND_CONFIG`. + +If you are using _build time_ configuration, you have to use `SENTRY_FRONTEND_CONFIG` and `SENTRY_BACKEND_CONFIG`. -**Note:** In case you are using buildtime configuration you have to use SENTRY_FRONTEND_CONFIG and SENTRY_BACKEND_CONFIG. +If you are using _runtime_ configuration, use `RAZZLE_SENTRY_FRONTEND_CONFIG` and `RAZZLE_SENTRY_BACKEND_CONFIG`. -But if you are using runtime configuration, use RAZZLE_SENTRY_FRONTEND_CONFIG and RAZZLE_SENTRY_BACKEND_CONFIG +We have the possibility to add `TAGS` and `ADDITIONAL DATA` for our messages for categorization in Sentry. +We can configure these two variables separately, as we might want to separate the messages from frontend and backend. -We have the possibility to add TAGS and ADDITIONAL DATA for our messages for categorization in SENTRY. We can configure these 2 variables separately, as we might want to separate the messages from frontend and backend. -Example of configurations: +Example of configuration. ```json { @@ -190,7 +255,7 @@ Example of configurations: } ``` -Example of usage with buildtime setup: +Example of usage with build time setup. ```console SENTRY_URL=https://mysentry.com @@ -204,7 +269,7 @@ SENTRY_BACKEND_CONFIG='{"tags":{"site":"www.test.com","app":"test_app"} yarn bui node build/server.js ``` -Example with Docker Compose: +Example with Docker Compose. ```yaml version: '3' @@ -226,11 +291,11 @@ services: - RAZZLE_SENTRY_BACKEND_CONFIG={"tags":{"site":"www.test.com","app":"test_app"},"extras":{"logger":"javascript-backend", "server":"server#1"}} ``` -## Example of messages in SENTRY +## Example messages in Sentry -1. List of messages -![](sentry_messages.png) -2. Messages from the frontend, with its own TAGS and ADDITIONAL DATA -![](sentry_frontend_message.png) -3. Messages from the backend, with its own TAGS and ADDITIONAL DATA -![](sentry_backend_message.png) +1. List of messages + ![](sentry-messages.png) +2. Messages from the frontend, with its own `TAGS` and `ADDITIONAL DATA` + ![](sentry-frontend-message.png) +3. Messages from the backend, with its own `TAGS` and `ADDITIONAL DATA` + ![](sentry-backend-message.png) diff --git a/docs/source/developer-guidelines/contributing.md b/docs/source/developer-guidelines/contributing.md deleted file mode 100644 index 5234987ffd..0000000000 --- a/docs/source/developer-guidelines/contributing.md +++ /dev/null @@ -1,61 +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. - -## 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 note under the `(unreleased)` version under the appropriate subheading of [CHANGELOG.md](https://github.com/plone/volto/blob/master/CHANGELOG.md). -Do not edit already released versions. - -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 e81f734f17..0000000000 --- a/docs/source/developer-guidelines/index.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -myst: - html_meta: - "description": "Developer Guidelines" - "property=og:description": "Developer Guidelines" - "property=og:title": "Developer Guidelines" - "keywords": "Developer, Guidelines" ---- - -# Developer Guidelines - -```{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 97bc9c0ca2..7dd17ff64b 100644 --- a/docs/source/getting-started/install.md +++ b/docs/source/getting-started/install.md @@ -11,6 +11,11 @@ myst: # Getting Started +```{warning} +This chapter of the documentation has been superseded by the official Plone 6 Documentation chapter {ref}`install-index-label`. +This chapter contains some legacy information that may be useful to Plone 5.2 development. +``` + (frontend-getting-started-installing-volto-label)= @@ -18,22 +23,16 @@ myst: Volto can be installed in any operating system assuming that the following pre-requisites are met: -- [Node.js LTS (16.x)](https://nodejs.org/en/) -- [Python](https://python.org/) - See below for specific versions. +- [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) -```{note} -*UPDATE 2022-10-25*: Since 2022-10-25, NodeJS 18 is in LTS state (https://github.com/nodejs/release#release-schedule). However, due to changes in internal SSL libraries, some Volto dependencies have been deprecated and need to be updated in order to continue working in NodeJS 18, mainly Webpack 4 (see: https://github.com/webpack/webpack/issues/14532#issuecomment-947525539 for further information). You can still use it, but NodeJS should be run under a special flag: `NODE_OPTIONS=--openssl-legacy-provider`. See also Volto's PR: https://github.com/plone/volto/pull/3699 for more information. -``` - The versions of Python that are supported in Volto depend on the version of Plone that you use. | Plone | Python | Volto | |---|---|---| | 5.2 | 2.7, 3.6-3.8 | 15.0 | -| 6.0 (beta) | 3.8-3.10 | 16.0 (alpha) | - -At the time of this writing, Volto 16 is still in alpha status, and Plone 6 is in beta status. +| 6.0 | 3.8-3.10 | 16.0 | Depending on the operating system that you are using, some of the following pre-requisites might change. They assume you have a macOS/Linux machine. @@ -47,7 +46,7 @@ There are three processes continuously running when you have a working Volto web 1. A frontend web application running in your browser (JavaScript) 2. A Node.js server process that delivers the JavaScript to the client and does - Server Side Rendering (SSR) of your pages on first request (JavaScript, the + {term}`server-side rendering` (SSR) of your pages on first request (JavaScript, the Razzle package is used for SSR) 3. A Plone server process that stores and delivers all content through a REST API (Python) @@ -90,8 +89,8 @@ it provides easy access to any NodeJS released version. 4. Install any active LTS version of NodeJS (https://github.com/nodejs/release#release-schedule): ```bash - nvm install 16 - nvm use 16 + nvm install 18 + nvm use 18 ``` 5. Test NodeJS: @@ -106,7 +105,7 @@ it provides easy access to any NodeJS released version. ```{note} Volto supports currently active NodeJS LTS versions based on [NodeJS - Releases page](https://github.com/nodejs/release#release-schedule), starting with Node 12 LTS. + Releases page](https://github.com/nodejs/release#release-schedule), starting with Node 16 LTS. ``` @@ -221,23 +220,13 @@ You may choose to install the canary version, which is the latest alpha release, ```bash npm install -g yo @plone/generator-volto - # install latest stable release yo @plone/volto - # or install latest alpha release - yo @plone/volto --canary ``` -2. Answer to the prompted questions and provide the name of the new app (folder) to be created. For the sake of this documentation, provide `myvoltoproject` as project name then. - - ````{note} - You can run the generator with parameters to tailor your requirements. - - ```bash - yo @plone/volto --help - ``` +See the [Creating a project](../recipes/creating-project) page for more +advanced options that can be passed to the generator. - or take a look at the [README](https://github.com/plone/volto/blob/master/packages/generator-volto/README.md) for more information. - ```` +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. 3. Change directory to the newly created folder `myvoltoapp` (or the one you've chosen): ```bash @@ -263,7 +252,7 @@ You may choose to install the canary version, which is the latest alpha release, ## Build the production bundle In production environments, you should build an static version of your (Volto) app. The -app should be run in a node process (because of the server side rendering +app should be run in a node process (because of the {term}`server-side rendering` part), but it also have a client part that is provided and deployed by the server side rendering process. diff --git a/docs/source/getting-started/others.md b/docs/source/getting-started/others.md index 6e5ca53005..3b5fcf48ea 100644 --- a/docs/source/getting-started/others.md +++ b/docs/source/getting-started/others.md @@ -15,14 +15,14 @@ On the [Plone Trainings Website](https://training.plone.org) you'll find Volto-dedicated open training materials plus React and other Javascript-centered trainings. -- [Mastering Plone 6 Development](https://training.plone.org/5/mastering-plone/) +- [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/5/voltohandson/index.html) -- [Volto Add-ons Development](https://training.plone.org/5/voltoaddons/index.html) +- [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/5/react/index.html) +- [React](https://training.plone.org/react/index.html) - [JavaScript For Plone Developers](https://training.plone.org/5/javascript/index.html) ## How does it work under the hood @@ -31,29 +31,38 @@ You can watch the talk during the World Plone Day 2021: -## Presentations at the last two PloneConf's +## Presentations at Plone Conferences (PloneConf) and other events -In recent years the new Volto frontend for Plone has been presented in more and more talks from +In recent years the react based Volto frontend for Plone has been presented in more and more talks at our yearly Conferences: -- [PloneConf 2021 Playlist on YouTube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkQDLQinBwdEXpebDTQCwdGi) +### PloneConf 2022 -- [PloneConf 2020 Playlist on YouTube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkTJPayNdKIZ8lLDm5RVOLV3) +[PloneConf 2022 full Playlist on Youtube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) +Plone 6 site presentations: -## PloneConf 2019 +- [Rai Way: Plone6 supporting the world of italian information, sports and entertainment](https://www.youtube.com/watch?v=hHHGlSjf5O4&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) +- [How Plone Powers Hundreds of Websites at one of the Largest Research Institutions in Europe](https://www.youtube.com/watch?v=bxWt-GEmPcc&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) -PloneConf 2019 and other events have several Volto-relevant presentations, but not stored in a -single playlist: -### Howtos +Developer/intergrator talks: -- [Rob Gietema - How to create your own Volto site!](https://www.youtube.com/watch?v=3QLN8tsjjf4) -- [Rodrigo Ferreira de Souza - Data migration to Plone 5.2 and Volto](https://www.youtube.com/watch?v=kb9SEsnllqE) +- [Anatomy of a Volto project](https://www.youtube.com/watch?v=JtNufyFlgc8&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) +- [Creating a Volto Theme](https://www.youtube.com/watch?v=AMHN74Jr27Y&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) +- [A Deep Dive Into Internals Of Volto](https://www.youtube.com/watch?v=sMeTDRgp3uI&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) +- [DevOps Bird's Eye View on the Plone 6 Backend](https://www.youtube.com/watch?v=L5PvGwWC9P4&list=PLGN9BI-OAQkQxqQcCZeJefMC8XlA_qv3Z) -### Panels and discussions +## Previous PloneConfs -- [Timo Stollenwerk - Breaking New Grounds](https://www.youtube.com/watch?v=9nRxgeCuIDs) -- [Panel - Ask me anything on Volto](https://www.youtube.com/watch?v=jwbpXJlDVOs) -- [Luca Pisani - Plone and React.js: An interview to Volto](https://www.youtube.com/watch?v=JZFUOG843no) -- [Victor Fernandez de Alba - Plone Beyond 2020: Jump into Volto today!](https://www.youtube.com/watch?v=8QrGOgXo1Js) -- [Nicola Zambello - A Volto story: building a website by prototyping](https://www.youtube.com/watch?v=xtxJURICkWc) +- [PloneConf 2021 full Playlist on YouTube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkQDLQinBwdEXpebDTQCwdGi) +- [PloneConf 2020 full Playlist on YouTube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkTJPayNdKIZ8lLDm5RVOLV3) + + +## World Plone Day 2022 + +World Plone Day is a 24-hour streaming event, with the goal was to promote and educate the public about the benefits of using Plone and of being part of the Plone community. [Full World Plone Day 2022 playlist on Youtube](https://www.youtube.com/playlist?list=PLGN9BI-OAQkQmEqf6O8jeyoFY1b2hD1uL) + +- [Plone 6 Volto's Seamless Mode](https://www.youtube.com/watch?v=Mj8pHRBls-w&list=PLGN9BI-OAQkQmEqf6O8jeyoFY1b2hD1uL) +- [Volto add ons separator and carousel](https://www.youtube.com/watch?v=eyTMI5TYcVg&list=PLGN9BI-OAQkQmEqf6O8jeyoFY1b2hD1uL) +- [Weekly Volto Live – Retrospective](https://www.youtube.com/watch?v=WT6OjkSrB20&list=PLGN9BI-OAQkQmEqf6O8jeyoFY1b2hD1uL) +- [Migrating from Classic to Volto](https://www.youtube.com/watch?v=09fg456T90s&list=PLGN9BI-OAQkQmEqf6O8jeyoFY1b2hD1uL) diff --git a/docs/source/getting-started/roadmap.md b/docs/source/getting-started/roadmap.md index 0803e0df02..3af14a07b0 100644 --- a/docs/source/getting-started/roadmap.md +++ b/docs/source/getting-started/roadmap.md @@ -14,7 +14,7 @@ and adjust to the new frontend-centered development. But if you already have some frontend development experience any JS frameworks such as AngularJS, Vue or React, you'll find that Volto is a relatively shallow -framework, structured as a typical Redux-centered React application. Although +framework, structured as a typical {term}`Redux`-centered React application. Although there will be Volto-specific knowledge to be gained along the way, you can be productive in a short time. @@ -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 ca9c536ecd..ee7723015f 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -47,5 +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/appextras.md b/docs/source/recipes/appextras.md index 3d6b1238c9..7455c4bbaf 100644 --- a/docs/source/recipes/appextras.md +++ b/docs/source/recipes/appextras.md @@ -16,7 +16,7 @@ component. ## How to use it -You can either use it by overriding it via Component Shadowing by placing +You can either use it by overriding it via {term}`component shadowing` by placing a custom `src/customizations/components/theme/AppExtras/AppExtras.jsx`... Or you can use the new key of `config.settings`, the `appExtras`. This is diff --git a/docs/source/recipes/creating-project.md b/docs/source/recipes/creating-project.md index 80ea0876f1..c577cedd35 100644 --- a/docs/source/recipes/creating-project.md +++ b/docs/source/recipes/creating-project.md @@ -9,16 +9,27 @@ myst: # Creating a new Volto project -For using Volto for a project (i.e. use Volto as a library), You should use Volto's project generator `@plone/generator-volto`. It's a boilerplate generator based in Yeoman that will provide you with the basic files and folder structure to bootstrap a Volto site. In addition to bootstrapping standalone Volto projects, it can also bootstrap Volto addons. +For using Volto for a project—in other words, use Volto as a library—you should use Volto's project generator `@plone/generator-volto`. +It's a boilerplate generator based in Yeoman that will provide you with the basic files and folder structure to bootstrap a Volto site. +In addition to bootstrapping stand-alone Volto projects, it can also bootstrap Volto add-ons. 1. Open a terminal and execute: - ```shell + ```bash npm install -g yo @plone/generator-volto + # Install the latest and stable release of Volto with the following command yo @plone/volto + # or you can install the "canary" release, including any alpha release + yo @plone/volto --canary + # or you can install any specific released version + yo @plone/volto --volto=15.0.0 + # you can even pass a GitHub repo and specific branch + yo @plone/volto --volto=plone/volto#16.0.0 + # you can bootstrap with add-ons + yo @plone/volto --addon=volto-form-block ``` -2. Answer to the prompted questions and provide the name of the new app (folder) to be created. For the sake of this documentation, provide `myvoltoproject` as 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/customizing-components.md b/docs/source/recipes/customizing-components.md index 6731711675..12864ecb1a 100644 --- a/docs/source/recipes/customizing-components.md +++ b/docs/source/recipes/customizing-components.md @@ -10,7 +10,7 @@ myst: # Customizing Components You are able to customize the existing Volto components using a pattern called -`component shadowing` using the `customizations` folder. You have to identify and locate +{term}`component shadowing` using the `customizations` folder. You have to identify and locate the component that you want to customize, let's say the Logo component in [Volto source code](https://github.com/plone/volto/tree/master/src). diff --git a/docs/source/recipes/express.md b/docs/source/recipes/express.md index 02e2340905..9c15e107f8 100644 --- a/docs/source/recipes/express.md +++ b/docs/source/recipes/express.md @@ -10,7 +10,7 @@ myst: # Custom Express middleware Volto uses the popular [Express](https://expressjs.com/) server for its -Server-Side Rendering implementation and static resource serving. In some +{term}`server-side rendering` implementation and static resource serving. In some cases it is useful to extend this server with new functionality. For example, Volto includes a middleware that proxies the backend and that can be used during development. Other use cases might include a CORS proxy server, a proxy diff --git a/docs/source/recipes/folder-structure.md b/docs/source/recipes/folder-structure.md index aea1dc0e2b..25249e3674 100644 --- a/docs/source/recipes/folder-structure.md +++ b/docs/source/recipes/folder-structure.md @@ -9,13 +9,13 @@ myst: # Folder structure -Volto is based on React, Redux, and React-Router. All of the +Volto is based on React, {term}`Redux`, and React-Router. All of the code is located in the `src` folder. The following convention for locating resources is used. ## Actions -`actions` contains all the redux actions for fetching all backend data like +`actions` contains all the Redux actions for fetching all backend data like content, users and external resources that are pulled into our app in general. ## Components diff --git a/docs/source/recipes/ie11compat.md b/docs/source/recipes/ie11compat.md index 4ff8bcd7b3..6001158ae9 100644 --- a/docs/source/recipes/ie11compat.md +++ b/docs/source/recipes/ie11compat.md @@ -39,7 +39,7 @@ import '@babel/polyfill'; ``` ```{seealso} -See https://babeljs.io/docs/en/babel-polyfill for more updated information +See https://babeljs.io/docs/babel-polyfill for more updated information ``` ## babel-env diff --git a/docs/source/recipes/lazyload.md b/docs/source/recipes/lazyload.md index ba895c12ec..a0195f9a17 100644 --- a/docs/source/recipes/lazyload.md +++ b/docs/source/recipes/lazyload.md @@ -14,7 +14,7 @@ using `@loadable/component` library. You can also benefit from it in your own pr using it. ```{note} -Webpack 4 is already lazy load enabled, using `import()` but @loadable/component makes the process safe since Volto is using Server Side Rendering. The React community is working actively in the React async mode popularly known as Suspense. Suspense will be SSR safe but in the meanwhile it's not ready, `@loadable/component` is the community accepted replacement. +Webpack 4 is already lazy load enabled, using `import()` but @loadable/component makes the process safe since Volto is using {term}`server-side rendering`. The React community is working actively in the React async mode popularly known as Suspense. Suspense will be {term}`SSR` safe but in the meanwhile it's not ready, `@loadable/component` is the community accepted replacement. ``` ## Lazy load a component @@ -84,16 +84,22 @@ located**. ### The useLazyLibs hook -In functional components you can use the `useLazyLibs` hook, which allows +In functional components you can use the `useLazyLibs` {term}`hook`, which allows greater flexibility (the `injectLazyLibs` hook uses `useLazyLibs` internally). You can call the hook like: ```jsx import { useLazyLibs } from '@plone/volto/helpers/Loadable/Loadable'; -useLazyLibs(['toastify', 'reactDnd']) +const loaded = useLazyLibs(['toastify', 'reactDnd']) // or: -useLazyLibs(['toastify', 'reactDnd'], {shouldRerender: false}) +const loaded = useLazyLibs(['toastify', 'reactDnd'], {shouldRerender: false}) + +const reactDnd = loaded?.reactDnd; + +if (reactDnd) { + // The library is now loaded and can be used. +} ``` Passing the `shouldRerender` as false as options will cause the component to diff --git a/docs/source/recipes/widget.md b/docs/source/recipes/widget.md index 842196a6d8..ebb232d0d5 100644 --- a/docs/source/recipes/widget.md +++ b/docs/source/recipes/widget.md @@ -150,6 +150,10 @@ Based on this setup, Volto will render this field with the `TokenWidget`. See [storybook](https://6.dev-docs.plone.org/storybook) with available widgets. ``` +## Widget `isDisabled` Props + +We can disable the input of a widget by passing props `isDisabled: true`. + ## Write a new widget ```{note} diff --git a/docs/source/release-notes/index.md b/docs/source/release-notes/index.md new file mode 100644 index 0000000000..7b40c7d23f --- /dev/null +++ b/docs/source/release-notes/index.md @@ -0,0 +1,13 @@ +--- +myst: + html_meta: + "description": "Volto Release Notes for the Plone content management system" + "property=og:description": "Volto Release Notes for the Plone content management system" + "property=og:title": "Volto Release Notes" + "keywords": "Volto, Plone, frontend, Release Notes, change log, changelog, change history" +--- + +````{ifconfig} context in ("documentation") +```{include} ../../../submodules/volto/CHANGELOG.md +``` +```` diff --git a/docs/source/theming/custom-styling.md b/docs/source/theming/custom-styling.md index 00c90b6481..bd5fd44044 100644 --- a/docs/source/theming/custom-styling.md +++ b/docs/source/theming/custom-styling.md @@ -55,8 +55,8 @@ both) files (including the matching folder structure) in your theme folder. ## Pastanaga UI Theme Volto implements Pastanaga UI theme, a new theme for Content Management Systems -created and designed by [Albert Casado](https://twitter.com/albertcasado). For -more info: +created and designed by [Albert Casado](https://twitter.com/albertcasado). +For more info: * https://pastanaga.io * https://github.com/plone/pastanaga @@ -75,28 +75,67 @@ https://github.com/plone/volto/tree/master/theme/themes/pastanaga Pastanaga Theme is an example on how to customize the default Semantic UI look and feel. + ## Examples: Changing Base Font -We start by creating the file `theme/globals/site.variables`. In this file we -can override any value. We do not need to copy the whole file. We can add -variables we would like to change. When we want to change the base font, we add -the following: +We start by creating the file `theme/globals/site.variables`. +In this file we can override any value. +We do not need to copy the whole file from Volto core. +We can add variables we would like to change. +When we want to change the base font, we add the following: ```less @fontName : 'Comic Sans MS'; ``` -> Make sure you have the 'Comic Sans MS' font installed. This is the -> 'ttf-mscorefonts-installer' package for the Debian linux distribution. +The font 'Comic Sans MS' needs to be either installed on you machine or provided with your app. + +To provide the font with your app, the following steps are necessary: + +1. Get your font and copy the files to `/theme/assets/fonts/`. + +1. Usually the font provider gives you ready made font-face instructions. + Copy these font-face code lines to `/theme/typography.css`. + There are a lot of font providers. + If you choose Google fonts, check [google-webfonts-helper](https://gwfh.mranftl.com/fonts) to generate `font-face` CSS code and download font files to include in your project. + +1. Add to the end of `/theme/theme.config` a function to load your font-faces: + + ```less + .loadThemeFonts() { + @import "./typography.css"; + } + ``` -> If you create a new file, the watcher won't be aware of it, you must restart -> the `yarn start` Volto process again. +1. Call this load function in `/theme/globals/site.overrides`: -You can also point it to any Google Web Font name like: + ```less + .loadThemeFonts(); + ``` + +1. In `/theme/globals/site.variables` you can now override both, the font for headings (h1, h2, h3, …) and the font for the rest. + + ```less + // Do not override @fontName! + // @fontName: 'Raleway', 'Helvetica Neue', Arial, Helvetica, sans-serif; + + @pageFont: 'Raleway', 'Helvetica Neue', Arial, Helvetica, sans-serif; + @headerFont: 'Rubic Microbe', 'Helvetica Neue', Arial, Helvetica, sans-serif; + ``` + +Voilà. +Start your Volto app if you created new files. + +````{tip} +For testing purpose you can refrain from installing the font and from providing the font with your app if the font is a Google font. +With the following two lines you tell Volto to load the font "Montserrat" from `fonts.google.com`. ```less @fontName : 'Montserrat'; +@importGoogleFonts : true; ``` +```` + ## Changing The Breadcrumbs diff --git a/docs/source/upgrade-guide/index.md b/docs/source/upgrade-guide/index.md index 99be41d2cf..31bd17f7f9 100644 --- a/docs/source/upgrade-guide/index.md +++ b/docs/source/upgrade-guide/index.md @@ -11,27 +11,75 @@ myst: # Upgrade Guide -This upgrade guide lists all breaking changes in Volto and explains the - steps that are necessary to upgrade to the latest version. +This upgrade guide lists all breaking changes in Volto and explains the steps that are necessary to upgrade to the latest version. Volto uses Semantic Versioning. For more information see {ref}`volto-versioning-policy`. ```{note} -There are times when updating the Volto boilerplate (the one generated by -`@plone/generator-volto`) is enough to fulfill all the changes. If you haven't -heavily modified it, moving things around and copying over your dependencies might -do when dealing with upgrades. We keep the generator up to date and in sync with -current Volto release. Please notice that the generator is able to tell you when it -runs if it's outdated. The generator is also able to "update" your project with -the latest changes, and propose to you to merge the changes, so you can run it on top of your project by answering the prompt. +There are times when updating the Volto boilerplate (the one generated by `@plone/generator-volto`) is enough to fulfill all the changes. +If you have not heavily modified it, moving things around and copying over your dependencies might do when dealing with upgrades. +We keep the generator up to date and in sync with the current Volto release. +When it runs, the generator will tell you whether it is outdated. +The generator will also "update" your project with the latest changes, and propose to merge the changes. +Thus it is safe to run it on top of your project and answer the prompts. ``` +(volto-upgrade-guide-17.x.x)= + +## Upgrading to Volto 17.x.x + +### Ending support for NodeJS 14 + +Long Term Support for NodeJS 14 by the NodeJS community ends in April 2023. +Volto 17 no longer supports NodeJS 14. +Please update your projects to a NodeJS LTS version, where either 16 or 18 is supported at the moment of this writing. +Version 18 is recommended. + +#### localhost now resolves to an IPv6 address + +NodeJS 18 prefers to resolve `localhost` to an IPv6 address instead of IPv4. +If you are setting `RAZZLE_API_PATH` to a URL that includes `localhost`, +change the hostname to `127.0.0.1` instead. + +### Webpack 5 + +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. + +```{versionadded} 17.0.0-alpha.1 +The `BlockChooser` component now uses `popperjs` library to position itself in the screen. +It spawns at the end of the body instead of inner the block that called it. +This is better from the UI point of view, since any other element can take precedence in the CSS element flow, preventing the block chooser to get overlapped by anything else. +``` + +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 -### `volto-slate` is now core +### `volto-slate` is now in core From Volto 16.0.0-alpha.15 onwards, `volto-slate` is integrated into Volto core and enabled as the default text block. The previous text block `text` based on `draftJS` is now deprecated and is restricted (hidden) in Volto bootstrap. @@ -102,9 +150,12 @@ For projects already using `volto-slate`, take the following steps in your proje You will have to configure your project to continue using `draftJS`, for example, in your `config.js` or in your add-on: ```js +import { WysiwygWidget } from '@plone/volto/components'; + config.settings.defaultBlockType = 'text' config.blocks.blocksConfig.table.restricted = false; config.blocks.blocksConfig.slateTable.restricted = true; +config.widgets.widget.richtext = WysiwygWidget; ``` #### Existing projects using core `draftJS`, opting to start using `slate` without migrating (possible, but not recommended) @@ -129,55 +180,62 @@ Version 16 is recommended. ### Upgraded to Razzle 4 ```{versionadded} 16.0.0-alpha.38 -Volto has upgraded from Razzle 3 to Razzle 4. You should perform these steps in case you are upgrading to this version or above. +Volto has upgraded from Razzle 3 to Razzle 4. +You should perform these steps in case you are upgrading to this version or above. ``` #### Steps after upgrade A few updates may be needed in existing projects: -1. Add the `cache` directory to `.gitignore`. -2. If `package.json` includes scripts that run `razzle test` with the `--env=jest-environment-jsdom-sixteen` option, update them to use `--env=jsdom` instead. -3. Update the `jest` configuration in `package.json` to replace the `jest-css-modules` transform: +1. Add the `cache` directory to `.gitignore`. +2. If `package.json` includes scripts that run `razzle test` with the `--env=jest-environment-jsdom-sixteen` option, update them to use `--env=jsdom` instead. +3. Update the `jest` configuration in `package.json` to replace the `jest-css-modules` transform: -```diff -"jest": { - "transform": { -- "^.+\\.css$": "jest-css-modules", -- "^.+\\.scss$": "jest-css-modules" - }, - "moduleNameMapper": { -+ "\\.(css|less|scss|sass)$": "identity-obj-proxy" - } -} -``` + ```diff + "jest": { + "transform": { + - "^.+\\.css$": "jest-css-modules", + - "^.+\\.scss$": "jest-css-modules" + }, + "moduleNameMapper": { + + "\\.(css|less|scss|sass)$": "identity-obj-proxy" + } + } + ``` -4. Add `--noninteractive` option to the build script +4. Add the option `--noninteractive` to the build script. -```diff -- "build": "razzle build", -+ "build": "razzle build --noninteractive", -``` + ```diff + - "build": "razzle build", + + "build": "razzle build --noninteractive", + ``` -5. If you use custom Razzle plugins, update them to use the new format with multiple functions: https://razzlejs.org/docs/upgrade-guide#plugins (the old format still works, but is deprecated). -6. If you have customized webpack loader configuration related to CSS, make sure it is updated to be compatible with PostCSS 8. -7. It's recommended that you remove your existing `node_modules` and start clean. -8. If the add-ons you are using are not yet updated to latest `@plone/scripts`, it's also recommended that you force the version in your build, setting this in `package.json`: +5. If you use custom Razzle plugins, update them to use the new format with multiple functions. + The old format still works, but is deprecated. -```json - "resolutions": { - "**/@plone/scripts": "^2.0.0" - } -``` + ```{seealso} + See https://razzlejs.org/docs/upgrade-guide#plugins + ``` + +6. If you have customized webpack loader configuration related to CSS, make sure it is updated to be compatible with PostCSS 8. +7. It's recommended that you remove your existing `node_modules` and start clean. +8. If the add-ons you are using are not yet updated to the latest `@plone/scripts`, it's also recommended that you force the version in your build, setting this in `package.json`: + + ```json + "resolutions": { + "**/@plone/scripts": "^2.0.0" + } + ``` #### Upgrade and update add-ons dependency on `@plone/scripts` -```{warning} +```{note} This applies only to Volto add-ons. ``` Most probably you are using `@plone/scripts` in your add-on, since it's used in i18n messageid generation and has other add-on utilities. -When upgrading to Volto 16.0.0-alpha.38 or above, you should upgrade `@plone/scripts` to a version 2.0.0 or above. +When upgrading to Volto 16.0.0-alpha.38 or above, you should upgrade `@plone/scripts` to version 2.0.0 or above. It's also recommended you move it from `dependencies` to `devDependencies`. ```diff @@ -216,77 +274,111 @@ index 2f4e1e8..51bd52b 100644 ### Jest is downgraded from version 27 to 26 -Razzle 4 internal API is only compatible with up to Jest 26. +Razzle 4 internal API is only compatible with Jest up to version 26. ### Upgrade to use yarn 3 Volto was using the old, classic yarn (v1). -It has become quite obsolete and yarn has evolved a lot during the last years. -We are updating Volto to be able to use it, however some changes have to be made in your projects configuration: - -1. Enable yarn 3 in your projects, adding `yarnrc.yml`: - -```yml -defaultSemverRangePrefix: "" - -nodeLinker: node-modules -``` - -Then, if you are using Node >=16.10 run: - -```shell -corepack enable -yarn set version 3.2.3 -``` - -Corepack isn't included with Node.js in versions before 16.10. -To address that, run: - -```shell -npm i -g corepack -``` - -```{note} -It is highly recommended that you use latest Node 16. -``` - -2. Change your root project `Makefile` to include these commands: - -```diff -+.PHONY: preinstall -+preinstall: -+ if [ -f $$(pwd)/mrs.developer.json ]; then if [ -f $$(pwd)/node_modules/.bin/missdev ]; then yarn develop; else yarn develop:npx; fi; fi -+ -+.PHONY: omelette -+omelette: -+ if [ ! -d omelette ]; then ln -sf node_modules/@plone/volto omelette; fi -``` - -3. Change your `package.json` scripts section: - -```diff - "version": "1.0.0", - "scripts": { - "start": "razzle start", -- "preinstall": "if [ -f $(pwd)/mrs.developer.json ]; then if [ -f $(pwd)/node_modules/.bin/missdev ]; then yarn develop; else yarn develop:npx; fi; fi", -+ "preinstall": "make preinstall", - "postinstall": "yarn omelette && yarn patches", -- "omelette": "if [ ! -d omelette ]; then ln -sf node_modules/@plone/volto omelette; fi", -+ "omelette": "make omelette", - "patches": "/bin/bash patches/patchit.sh > /dev/null 2>&1 ||true", -``` - -Yarn 3 no longer support inline bash scripts in the `scripts` section. -We need to move them to the `Makefile` and update the calls. - -4. It doesn't allow to use commands not declared as direct dependencies, so in your projects you should add `razzle` as a dependency: - -```diff -devDependencies: { -+ "razzle": "4.2.17", -``` - -5. Replace your project `yarn.lock` for the Volto's one, then run `yarn` again. +It has become quite obsolete and yarn has evolved a lot in recent years. +We updated Volto to be able to use it, however some changes have to be made in your project's configuration: + +1. Enable yarn 3 in your project, adding `.yarnrc.yml`: + + ```yaml + defaultSemverRangePrefix: "" + + nodeLinker: node-modules + ``` + + Then, if you are using Node >=16.10 run: + + ```shell + corepack enable + yarn set version 3.2.3 + ``` + + Corepack isn't included with Node.js in versions before 16.10. + To address that, run: + + ```shell + npm i -g corepack + ``` + + ```{important} + It is highly recommended that you use the latest Node 16. + ``` + +2. Change your root project `Makefile` to include these commands: + + ```diff + +.PHONY: install + +install: ## Install the frontend + + @echo "Install frontend" + + $(MAKE) omelette + + $(MAKE) preinstall + + yarn install + + + +.PHONY: preinstall + +preinstall: ## Preinstall task, checks if missdev (mrs-developer) is present and runs it + + if [ -f $$(pwd)/mrs.developer.json ]; then make develop; fi + + + + +.PHONY: develop + +develop: ## Runs missdev in the local project (mrs.developer.json should be present) + + npx -p mrs-developer missdev --config=jsconfig.json --output=addons --fetch-https + + + +.PHONY: omelette + +omelette: ## Creates the omelette folder that contains a link to the installed version of Volto (a softlink pointing to node_modules/@plone/volto) + + if [ ! -d omelette ]; then ln -sf node_modules/@plone/volto omelette; fi + + + +.PHONY: patches + +patches: + + /bin/bash patches/patchit.sh > /dev/null 2>&1 ||true + ``` + + You can copy the file over to your project if you have not made any amendment to it. + +3. Change your `package.json` scripts section: + + ```diff + "version": "1.0.0", + "scripts": { + "start": "razzle start", + - "preinstall": "if [ -f $(pwd)/mrs.developer.json ]; then if [ -f $(pwd)/node_modules/.bin/missdev ]; then yarn develop; else yarn develop:npx; fi; fi", + - "omelette": "if [ ! -d omelette ]; then ln -sf node_modules/@plone/volto omelette; fi", + - "patches": "/bin/bash patches/patchit.sh > /dev/null 2>&1 ||true", + - "postinstall": "yarn omelette && yarn patches", + + "postinstall": "make omelette && make patches", + - "patches": "/bin/bash patches/patchit.sh > /dev/null 2>&1 ||true", + ``` + + Yarn 3 no longer supports inline bash scripts in the `scripts` section. + It does not support the `preinstall` lifecycle state, so we cannot trigger things while we run `yarn install` or just `yarn`. + As a result, we moved all the commands related to the `preinstall` actions into `Makefile`, then updated the calls in both files as shown above. + + ````{important} + After making the changes in this step, we will have to modify our development workflow, especially if we use actions that happened during the `preinstall` state. + The most relevant one is updating the code that is managed by `mrs-developer`. + If you follow the code above, you'll need to call these `Makefile` commands before each `yarn install`. + It's recommended to use the `make install` command instead of just `yarn` or `yarn install`. + + ```shell + make install + ``` + + Remember to update your CI scripts accordingly. + ```` + +4. Yarn 3 does not allow the use of commands not declared as direct dependencies. + In your project, you should add `razzle` and `@plone/scripts` as development dependencies: + + ```diff + devDependencies: { + + "@plone/scripts": "^2.1.2", + + "razzle": "4.2.17", + ``` + +5. Replace your project `yarn.lock` with Volto's, then run `yarn` again. ### Removed `date-fns` from build @@ -295,56 +387,67 @@ It was in the build because `Cypress` depended on it. After `Cypress` was upgraded, it no longer depends on `date-fns`. If your project still depends on `date-fns`, add it as a dependency of your project. -```{warning} +````{warning} The `date-fns` version present in the build was quite old (1.x.x series). Beware when using an updated version (2.x.x), as it may contain some breaking changes. -Also take a look at: https://dockyard.com/blog/2020/02/14/you-probably-don-t-need-moment-js-anymore + + +```{seealso} +https://dockyard.com/blog/2020/02/14/you-probably-don-t-need-moment-js-anymore +``` If you need to format dates in Volto, it's recommended to use the `FormattedDate` component in Volto core. It uses modern recommendations for date formatting on the web. -``` +```` -### Upgraded core to use Cypress 10 +### Upgraded core to use Cypress 11 -Cypress has overhauled the testing app and included native support of Apple Silicon Computers from 10.2.0 onwards. -This improves dramatically the launch and test times in these machines. +Cypress has overhauled their testing application, beginning with Cypress 10. +It now includes native support of Apple silicon chip computers. +This dramatically improved the launch and test times on those machines. It also includes the new "component" testing feature that might be appealing in the near future. -The only drawback is that they also overhauled the configuration forcing to migrate from old config based on JSON files to a better JS-based one. They also changed and renamed some of the options. -Luckily, they provide a good reporting when old configuration is in place and an interactive migration wizard. -Core configuration has been updated, but you will require to update your Cypress configuration if you want to use core's Cypress 10. -Could be that forcing your project to use older versions might still work with old configurations. +The only drawback is that they also overhauled the configuration, forcing migration from old configuration based on JSON files to a better JavaScript-based one. +They also changed and renamed some options. +Luckily, Cypress provides both good reporting when an old configuration is in place, and an interactive migration wizard. + +Core configuration has been updated to use Cypress 11. +You will need to update your Cypress configuration from versions older than Cypress 10 if you want to use core's Cypress 11. +If you have already updated your configuration to use Cypress 10 or later in a previous upgrade, your configuration might already work with Cypress 11. +It is possible that forcing your project to use older versions might still work with old configurations. +```{seealso} See https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-version-10-0 for more information. +``` ### The complete configuration registry is passed to the add-ons and the project configuration pipeline -The core in versions prior Volto 16.0.0-alpha.22 was passing a simplified version of the configuration registry (in fact, a plain object primitive) to the add-on list and project configuration pipeline. +The core in versions prior to Volto 16.0.0-alpha.22 passed a simplified version of the configuration registry—in fact, a plain object primitive—to the add-on list and project configuration pipeline. From Volto 16.0.0-alpha.22 onwards, the full configuration registry is passed through the pipeline. -This allows to have access to the advanced registry features, like the new component registry. -You may want to update your configuration in case that you were updating the primitive using basic object operators (spread, etc) in the config object itself. -For example, this won't work anymore: +This allows you to have access to the advanced registry features, like the new component registry. +You may want to update your configuration in case you updated the primitive using basic object operators (spread, and others) in the configuration object itself. +For example, this will not work anymore: ```js - return { - ...config, - blocks: { - ...config.blocks, - blocksConfig: { - ...config.blocks.blocksConfig, - ...addonBlocks, - listing: listing(config), - }, +return { + ...config, + blocks: { + ...config.blocks, + blocksConfig: { + ...config.blocks.blocksConfig, + ...addonBlocks, + listing: listing(config), }, - views: { - ...config.views, - contentTypesViews: { - ...config.views.contentTypesViews, - Folder: NewsAndEvents, - }, + }, + views: { + ...config.views, + contentTypesViews: { + ...config.views.contentTypesViews, + Folder: NewsAndEvents, }, - }; + }, +}; ``` Using the spread operator while you mutate the configuration object is not required. @@ -364,7 +467,7 @@ The other rules apply, so make sure you return the `config` object after mutatin ### Refactor the component registry API in the configuration registry -After a period of testing, this experimental feature has been refactored to adequate better to existing requirements. +After a period of testing, this experimental feature has been refactored to adequate existing requirements. #### Renamed `registry.resolve` to `registry.getComponent` @@ -375,7 +478,7 @@ After a period of testing, this experimental feature has been refactored to adeq #### `registry.getComponent` signature changes -It maintains signature compatibility with `registry.resolve` but introduces new arguments for bigger flexibility. +It maintains signature compatibility with `registry.resolve`, but introduces new arguments for greater flexibility. See documentation for more information. @@ -391,22 +494,22 @@ config.registerComponent({ ``` ```` -### Main workflow change menu changed from Pastanaga UI simplification to classic Plone implementation +### Main workflow change menu changed from Pastanaga UI simplification to Classic UI Plone implementation Pastanaga UI envisioned a simplification of the classic Plone workflow change dropdown. -The idea is that for users, the transition names were too cryptic and it was difficult to infer the destination state from them. -So the simplification was meant to show the destination state as a transition name, simplifying the user experience. +The transition names were too cryptic, and it was difficult to infer the destination state from them. +This simplification was meant to show the destination state as a transition name, simplifying the user experience. -This vision was partially implemented in Volto, bypassing the information coming from Plone, waiting for the next step: introduce this vision in Plone core (thus, change the workflow definitions) including this simplified mode, but maintaining the complete mode, with the full transition names. +This vision was partially implemented in Volto, bypassing the information coming from Plone, waiting for the next step: introduce this vision in Plone core (thus, change the workflow definitions) including this simplified mode, but maintaining the complete mode with the full transition names. -Since this never happened, we are going back to the classic mode, so the dropdown will show the transition names. +Since this never happened, we are going back to the Classic UI mode, so the dropdown will show the transition names. When the simplified vision is implemented, we will revisit it. #### Move Layout constants to `config.views.layoutViewsNamesMapping`. -The `constants` layout module was removed in favor of an object in the Configuration Registry: `config.views.layoutViewsNamesMapping`. +The `constants` layout module was removed in favor of an object in the configuration registry, `config.views.layoutViewsNamesMapping`. -If you have added or modified the Plone layout views literal mapping, you should now use this setting, and you can remove the module shadowing customization. +If you added or modified the Plone layout views literal mapping, you should now use this setting, and you can remove the module shadowing customization. You can now add an i18n `id` for any layout that you create as well, since the `Display` component is now i18n aware. @@ -446,11 +549,11 @@ defineMessages({ }) ``` -### `react-window` no longer a Volto dependency +### `react-window` is no longer a Volto dependency Volto used this library to generate dynamic "windowed/virtualized" select widget options. -It moved to use `react-virtualized` instead of `react-window` because it provides a more broad set of features that Volto required. -If you were using it in your project, you'll have to include it as a direct dependency of it from now on. +It moved to use `react-virtualized` instead of `react-window` because it provides a broader feature set that Volto requires. +If you were using it in your project, you will need to include it as a direct dependency from now on. ### Change the way the style wrapper is enabled and how to add the `styles` field @@ -459,23 +562,30 @@ We decided it is best to deal with it as any other schema field and enhance it v This improves the developer experience, especially when dealing with variations that can provide their own styles and other schema fields. ```{deprecated} 16.0.0-alpha.46 -The options `enableStyling` and `stylesSchema` no longer work. You need to provide them using your own block schema. If you are extending an existing one, you should add it as a normal `schemaEnhancer` modification. +The options `enableStyling` and `stylesSchema` no longer work. +You need to provide them using your own block schema. +If you are extending an existing one, you should add it as a normal `schemaEnhancer` modification. ``` +```{seealso} See https://6.dev-docs.plone.org/volto/blocks/block-style-wrapper.html for more documentation. +``` -### Remove Sentry integration from core +### Sentry integration moved from Volto core to add-on The Sentry integration was implemented in Volto core at a time when Volto did not provide a good add-on story. Since then, the add-on story has improved. It now makes sense to extract this feature into its own add-on. -You can find it in [`@collective/volto-sentry`](https://github.com/collective/volto-sentry). +Integrate Sentry in your app with [`@plone-collective/volto-sentry`](https://www.npmjs.com/package/@plone-collective/volto-sentry). + +```{versionchanged} 16.0.0.alpha.45 +``` ### Upgrade `husky` to latest version -In the case that you are using husky in your projects (like Volto does), you will have to adapt to the new way that `husky` has for defining hooks. +In case you use `husky` in your projects (like Volto does), you must adapt to the new way that `husky` defines {term}`hooks`. -You'll have to add a script in your `package.json` file called `prepare`: +You will have to add a script in your `package.json` file called `prepare`: ```diff "build": "razzle build --noninteractive", @@ -483,7 +593,38 @@ You'll have to add a script in your `package.json` file called `prepare`: "test": "razzle test --maxWorkers=50%", ``` -After execute it, `husky` will install itself in the `.husky` folder of your project. Then you need to create the default hook scripts in `.husky` that you want to execute. You can copy over the Volto ones (take a look in Volto's `.husky` folder). +After executing it, `husky` will install itself in the `.husky` folder of your project. +Then you need to create the default hook scripts in `.husky` that you want to execute. +You can copy over the Volto ones (take a look in Volto's `.husky` folder). + +### Better defaults handling + +````{versionadded} 16.0.0-alpha.51 +Prior to this version, we handled default values in schemas for blocks settings in a faulty and buggy manner. +The state inferred was not deterministic and depended on the fields with defaults present. + +To correct this and allow Volto to handle defaults in a correct way, we have to pass down an additional prop to the `BlockDataForm` whenever we use it in our custom or add-on code, as in the following example. + +```{code-block} jsx +:linenos: +:emphasize-lines: 10 + + { + this.props.onChangeBlock(this.props.block, { + ...this.props.data, + [id]: value, + }); + }} + onChangeBlock={onChangeBlock} + formData={this.props.data} + block={block} + /> +``` +```` + (volto-upgrade-guide-15.x.x)= @@ -492,8 +633,8 @@ After execute it, `husky` will install itself in the `.husky` folder of your pro ### Updated react-cookie library This fixes a use case where cookies could potentially be messed up if your site is under heavy load. -The old `react-cookie` library was not able to handle correctly the SSR part, specially the one that -is shared in "Nobody's land" (not SSR, not under the React tree, actions, Redux middleware). +The old `react-cookie` library was not able to handle correctly the {term}`SSR` part, specially the one that +is shared in "Nobody's land" (not SSR, not under the React tree, actions, {term}`Redux middleware`). Upgrading to the latest version of the `react-cookie` suite (`react-cookie`, `universal-cookie-express` and `universal-cookie`) will fix it. You have to take action only in case you did some development involving cookies. The `react-cookie` @@ -513,41 +654,42 @@ DraftJS libraries are now lazy-loaded, and some changes have been introduced in The old way: ```js - export default function applyConfig(config) { - config.settings = { - ...config.settings, - listBlockTypes = [ - ...config.settings.listBlockTypes, - 'my-list-item', - ] - } - return config; +export default function applyConfig(config) { + config.settings = { + ...config.settings, + listBlockTypes = [ + ...config.settings.listBlockTypes, + 'my-list-item', + ] } + return config; +} ``` The new way: ```js - export default function applyConfig(config) { - const { richtextEditorSettings } = config.settings; - config.settings.richtextEditorSettings = (props) => { - const result = richtextEditorSettings(props); - result.listBlockTypes = [...result.listBlockTypes, 'my-list-item'] - return result; - } - return config; +export default function applyConfig(config) { + const { richtextEditorSettings } = config.settings; + config.settings.richtextEditorSettings = (props) => { + const result = richtextEditorSettings(props); + result.listBlockTypes = [...result.listBlockTypes, 'my-list-item'] + return result; } + return config; +} ``` ### Language Switcher no longer takes care of the sync of the language -This responsibility has been transferred in full to the API Redux middleware, if you have shadowed either `LanguageSwitcher` or `MultilingualRedirector` (during the alpha phase) components, please update them. +This responsibility has been transferred in full to the API {term}`Redux middleware`, if you have shadowed either `LanguageSwitcher` or `MultilingualRedirector` (during the alpha phase) components, please update them. Not doing so won't break your project, but they won't get the latest features and bug fixes, and probably will update the language cookie twice. ### LinkView component markup change -The `LinkView` component has the literal `The link address is: ` is now wrapped in a `

` block instead of a `` block. Please check if you have a CSS bound to that node and adjust accordingly. +The `LinkView` component with the literal `The link address is: ` is now wrapped in a `

` block instead of a `` block. +Please check if you have a CSS bound to that node and adjust accordingly. ### Rename core-sandbox fixture to coresandbox @@ -739,20 +881,20 @@ The `getVocabulary` action has changed API. Before, it used separate positional ## Upgrading to Volto 13.x.x -## Deprecating NodeJS 10 +### Deprecating NodeJS 10 Since April 30th, 2021 NodeJS 10 is out of Long Term Support by the NodeJS community, so we are deprecating it in Volto 13. Please update your projects to a NodeJS LTS version (12 or 14 at the moment of this writing). -## Seamless mode is the default in development mode +### Seamless mode is the default in development mode Not really a breaking change, but it's worth noting it. By default, Volto 13 in development mode uses the internal proxy in seamless mode otherwise configured differently. To learn more about the seamless mode read: {doc}`../deploying/seamless-mode` and {doc}`../configuration/zero-config-builds`. -## Refactored Listing block using schemas and ObjectWidget +### Refactored Listing block using schemas and ObjectWidget The Listing block has been heavily refactored using schema forms and `BlockDataForm` as well as the other new internal artifacts to leverage blocks variations and extensions at the same time @@ -766,7 +908,7 @@ The advantage of this is that now you can use the `QuerystringWidget` with schem data forms in a reusable way in your custom blocks. See the Listing block code for further references. -### Migrate your existing listing blocks +#### Migrate your existing listing blocks **(Updated: 2021/06/12)** If you have an existing Volto installation and you are using listing blocks, you must run an upgrade step in order to match the new listing @@ -849,7 +991,7 @@ When an official integration package exists, these upgrade steps in the backend will be provided in there. ``` -### Update your custom variations (templates) in your project listing blocks +#### Update your custom variations (templates) in your project listing blocks In the case that you have custom templates for your listing blocks in your projects, it's required that you update the definitions to match the new core variations syntax. @@ -879,7 +1021,7 @@ To this: ] ``` -## Control panel icons are now SVG based instead of font based +### Control panel icons are now SVG based instead of font based It was long due, the control panel overview route `/controlpanel` is now using SVG icons from the Pastanaga icon set, instead of the deprecated font ones. If you have customized @@ -893,13 +1035,13 @@ import config from '@plone/volto/registry' config.settings.controlPanelsIcons.mynewcontrolpanelid = myfancyiconSVG; ``` -## Login form UI and accessibility updated +### Login form UI and accessibility updated Not really a breaking change, but it's worth to note that we changed the look and feel of the login form and improved its usability and accessibility. Another move towards the new Quanta look and feel. -## Changes in the Table block feature set and messages +### Changes in the Table block feature set and messages The "inverted" option in Table Block was removed since it was useless with the current CSS set. Better naming of options and labels in table block (English). Updating the i18n @@ -923,7 +1065,7 @@ dependency" problems in Volto, due to the very nature of the solution (importing us. In fact, circular dependencies are common in NodeJS world, and the very nature of how it works make them "workable" thanks to the NodeJS own import resolution algorithm. So the "build" always works, although we have the circular dependencies, but that leads to weird problems -like (just to mention one of them) the HMR (Hot Module Reloader) not working properly. +like (just to mention one of them) the {term}`hot module replacement` (HMR) not working properly. That's why in this version we are introducing the new Volto's Configuration Registry. It's a centralized singleton that is populated from the core config module and can be @@ -1357,7 +1499,7 @@ compiling. Migrate your code or if you want to use the proposal anyways, you'll provide the configuration to your own project (babel.config.js) in your project root folder. -You might still be using the old-style connecting of your components to the Redux store using +You might still be using the old-style connecting of your components to the {term}`Redux` store using `@connect` decorator, in that case, take a look at any connected component in Volto to have a glimpse on how to migrate the code. @@ -1366,7 +1508,7 @@ you are good to go, and you don't have to do anything. ### Hoisting problems on some setups -Some people were experimenting weird hoisting issues when installing dependencies. This +Some people were experimenting weird {term}`hoisting` issues when installing dependencies. This was caused by Babel deprecated proposals packages and its peer dependencies that sometimes conflicted with other installed packages. @@ -2040,7 +2182,9 @@ The blocks engine now takes care of the keyboard navigation of the blocks, so yo The focus management is also transferred to the engine, so it's not needed for your block to manage the focus. However, if your block does indeed require to manage its own focus, then you should mark it with the `blockHasOwnFocusManagement` property in the blocks configuration object: -``` js hl_lines="10" +```{code-block} jsx +:linenos: +:emphasize-lines: 10 text: { id: 'text', title: 'Text', diff --git a/docs/source/user-manual/blocks.md b/docs/source/user-manual/blocks.md new file mode 100644 index 0000000000..9e4c744d4d --- /dev/null +++ b/docs/source/user-manual/blocks.md @@ -0,0 +1,604 @@ +--- +myst: + html_meta: + "description": "User manual for how to edit blocks in Volto, the Plone 6 frontend." + "property=og:description": "User manual for how to edit blocks in Volto, the Plone 6 frontend." + "property=og:title": "How to edit content using Volto blocks" + "keywords": "Volto, Plone, frontend, React, User manual, edit blocks" +--- + +(edit-content-using-blocks-label)= + +# Edit content using blocks + +Volto features the [Pastanaga UI](https://github.com/plone/pastanaga), allowing you to visually compose a page using blocks. +The blocks editor allows you to add, modify, reorder, and delete blocks given your requirements. +Blocks provide the user the ability to display content in a specific way, although they can also define behavior and have specific features. + + +(manage-blocks-label)= + +## Manage blocks + +In Volto, "blocks" are individual pieces of content that can be added to a page or other content area. +These blocks can be used to add different types of content—such as text, images, or multimedia—and can be arranged and customized to create a wide range of different layouts. + +Blocks are a key feature of Volto, and are designed to make it easy for users to add and manage content on their website. +They are created using React components, which are modular pieces of code that can be easily reused and customized. + + +(create-a-block-label)= + +### Create a block + +To create or add an empty block after an existing block, click in the block, then hit the {kbd}`Enter` key. +A new empty block appears. + +```{image} ../_static/user-manual/blocks/add-new-block.gif +:alt: Add new block +``` + +```{note} +There is a new experimental feature that places a `+` below a block when it is active or moused over, and when clicked inserts an empty block below the current block. + +See https://github.com/plone/volto/pull/3815 for details of the feature and how to enable it. +``` + +(configure-a-block-label)= + +### Configure a block + +When you select a block, its block editor appears in the right margin of the page. +Almost all blocks have some configuration options. + + +(rearrange-blocks-label)= + +### Rearrange blocks + +To rearrange blocks, to the right of the block you want to move, click on its drag handle, move the block where you want it in the page, and release the drag handle. + + +(delete-a-block-label)= + +### Delete a block + +To delete a block, to the right of the block, click its delete button, a trash can icon. + + +(default-block-types-label)= + +## Default block types + +Volto offers several default block types out of the box. +You can access and choose a block type to add to your content type when you have an empty block in it. + +Now with your empty block available, you can select its type in one of two ways. + +1. Click the `+` button to the left of the empty block. + + ```{image} ../_static/user-manual/blocks/block-left-add-icon.png + :alt: Add block button + ``` + +2. Type `/` inside the empty block to open the block types menu. + You can type a few letters to filter available block types. + You can use the up and down arrow keys to navigate within the list of block types. + To select the block type, you can click or tap on it, or use the {kbd}`Enter` key. + + ```{image} ../_static/user-manual/blocks/block-types-menu.png + :alt: Block types menu + ``` + + +(user-manual-description-block-label)= + +### Description block + +A description block accepts plain text. +When displayed, it appears as the description in the page, and for search engine optimization in HTML meta tags as `` and ``. + + +(user-manual-grid-block-label)= + +### Grid block + +A grid block creates a single row of columns in a grid, which can be used to display content in a structured, organized way. +You can select the number of columns to insert. + +```{image} ../_static/user-manual/blocks/grid-block-number-of-columns.png +:alt: Choose the number of columns to insert in a grid block. +``` + +After choosing the number of columns to insert in a grid block, you can manage the columns. + +```{image} ../_static/user-manual/blocks/grid-block-manage-blocks.png +:alt: Add a specific block type into a grid block's column +``` + +- Specify the block type in a column by clicking its `+` button. +- Rearrange the order of columns in the grid block by dragging and dropping them. +- Add a column to the grid block by clicking the `+` button above and to the left of it. +- Remove a column from a grid block by clicking its `×` button. + + +(user-manual-html-block-label)= + +### HTML block + +An HTML block allows users to add custom HTML code to a page. +This can be useful for adding custom functionality or styling to a page, or for integrating with external services or applications. +For example, you can insert an HTML snippet or widget from a third party service to embed a calendar, payment or donation button, or social media into a page. + +```{image} ../_static/user-manual/blocks/html-block.png +:alt: HTML block +``` + +To use an HTML block, you need to have some knowledge of how to write HTML, unless you are provided an HTML code snippet from a third party that you can copy and paste into the block. + + +(user-manual-hero-block-label)= + +### Hero block + +A hero block creates a full-width banner or header for a page. +It is typically used to highlight important content or to create a visual impact at the top of a page. + +```{image} ../_static/user-manual/blocks/hero-block.png +:alt: Hero block +``` + +Hero blocks typically include a background image or color. +They can also include a title, description, and links to other pages in your site. + +You can use the block editor to configure its options. +You can set the background image or color, its title and description, and links. +For links, you can enter an external URL or select a page in your site by clicking the list icon, and give the link a title. + + +(user-manual-image-block-label)= + +### Image block + +An image block lets a user insert an image into a page and configure its attributes. + +```{image} ../_static/user-manual/blocks/image-block.png +:alt: Image block +``` + +After inserting an image block, an image must be specified by any of the following methods. +- Choose an existing image in the site by clicking the block's list icon. +- Upload a new image by either clicking the block's upload icon or drag and drop. +- Enter a remote image's URL in the block's text area. + Click the arrow icon to save the URL. + +Once you have specified an image, its configurable options become available. +```{image} ../_static/user-manual/blocks/image-block-configuration-options.png +:alt: Image block configuration options +``` + +Source +: The path or URL to the image. + +Alt text +: Alternative text (alt text) is used by screen readers and search engines to describe the image. + Alt text should not be used for decorative images, as it adds noise to the screen reader. + +Alignment +: Options for alignment include left, right, center, and full width. + +Image size +: The image size determines its relative display width, either small, medium, or large. + +Link to +: You can enter a URL in the text field, or click the list icon and choose a page in your website, as the target for a link. + You can optionally have the link open in a new tab when the user clicks it by checking the checkbox {guilabel}`Open in a new tab`. + + +(user-manual-images-grid-block-label)= + +### Images grid block + +An images grid block displays a row of images on a page. +It is typically used to showcase a collection of images in a visually appealing way. +It can be configured to display the images in different layouts and styles. + +```{image} ../_static/user-manual/blocks/images-grid-block-number-of-columns.png +:alt: Choose the number of images to insert in an images grid block. +``` + +After choosing the number of images to insert in an images grid block, you can configure the images exactly as you would configure a single image in an image block. + +```{image} ../_static/user-manual/blocks/image-block-configuration-options.png +:alt: Image block configuration options +``` + +Source +: The path or URL to the image. + +Alt text +: Alternative text (alt text) is used by screen readers and search engines to describe the image. + Alt text should not be used for decorative images, as it adds noise to the screen reader. + +Alignment +: Options for alignment include left, right, center, and full width. + +Image size +: The image size determines its relative display width, either small, medium, or large. + +Link to +: You can enter a URL in the text field, or click the list icon and choose a page in your website, as the target for a link. + You can optionally have the link open in a new tab when the user clicks it by checking the checkbox {guilabel}`Open in a new tab`. + +You can also manage the images in the images grid block. + +```{image} ../_static/user-manual/blocks/images-grid-block-manage-images.png +:alt: Manage images in an images gride block +``` + +- Rearrange the order of images in the images grid block by dragging and dropping them. +- Add an image to the images grid block by clicking the `+` button above and to the left of it. +- Remove an image from an images grid block by clicking its `×` button. + + +After inserting an image grid block, an image must be specified by any of the following methods. + + +(user-manual-listing-block-label)= + +### Listing block + +A listing block allows users to display a list of content items in your Plone site on a page. +A site editor can configure the criteria to use for retrieving content items, including text, title, dates, and creator. +The retrieved results can be configured with a sort order, limit of results, and whether to batch the results with pagination. + +```{image} ../_static/user-manual/blocks/listing-block.png +:alt: Listing block +``` + +The listing block has several configuration options. + +```{image} ../_static/user-manual/blocks/listing-block-configuration.png +:alt: Listing block configuration +``` + +Variation +: Options for variation include {guilabel}`Default`, {guilabel}`Image gallery`, and {guilabel}`Summary`. + +Headline +: Optionally add a headline to the listing block. + +Headline level +: Headline level sets the level of the headline to either {guilabel}`H2` or {guilabel}`H3`. + +Criteria +: Add criteria for the search. + Options include searching metadata, dates, and text. + Each criterion has its own options. + For example, you can configure a search for content that was created between two dates, or for its location within a path of your Plone site. + +Sort on +: Sort the retrieved results by a given option. + Options include metadata, dates, and text. + +Results limit +: Limit the number of results returned. + +Item batch size +: Batch the search result items into a specified batch size. + + +(user-manual-maps-block-label)= + +### Maps block + +A map block allows a user to add a map to a page. +It is typically used to display a geographic location or region, or provide travel directions. + +```{image} ../_static/user-manual/blocks/maps-block.png +:alt: Maps block +``` + +To use a map block, the third party map service must provide a snippet of HTML code that you can copy and paste into the map block. +Usually the snippet includes an `