diff --git a/.eslintignore b/.eslintignore index 30c8653ae8..7df5c928c1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,6 @@ -webpack/* -karma.conf.js -tests.webpack.js +node_modules +build +packages/volto +packages/volto-guillotina +!.* +dist diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index ca536296b4..0000000000 --- a/.eslintrc +++ /dev/null @@ -1,65 +0,0 @@ -{ - "extends": ["react-app", "prettier", "plugin:jsx-a11y/recommended"], - "plugins": ["prettier", "react-hooks", "jsx-a11y"], - "env": { - "es6": true, - "browser": true, - "node": true, - "mocha": true, - "jasmine": true - }, - "parser": "babel-eslint", - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module", - "ecmaFeatures": { - "legacyDecorators": true - } - }, - "rules": { - "import/no-unresolved": 1, - "no-alert": 1, - "no-console": 1, - "no-debugger": 1, - "prettier/prettier": [ - "error", - { "trailingComma": "all", "singleQuote": true } - ], - "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", - "react/react-in-jsx-scope": "off" - }, - "settings": { - "import/resolver": { - "alias": { - "map": [ - ["@plone/volto", "./src"], - ["@plone/volto-slate", "./packages/volto-slate/src"], - ["@package", "./src"], - ["@root", "./src"] - ], - "extensions": [".js", ".jsx", ".json"] - }, - "babel-plugin-root-import": { - "rootPathSuffix": "src" - } - }, - "import/core-modules": ["load-volto-addons"] - }, - "globals": { - "root": true, - "__DEVELOPMENT__": true, - "__CLIENT__": true, - "__SERVER__": true, - "__DISABLE_SSR__": true, - "__DEVTOOLS__": true, - "__DEBUG__": true, - "__SSR__": true, - "__SENTRY__": true, - "cy": true, - "Cypress": true, - "jest": true, - "socket": true, - "webpackIsomorphicTools": true - } -} diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000000..3a87903fb1 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,76 @@ +// @ts-check + +/** @type {import('eslint').Linter.Config} */ +const config = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 'ESNext', // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + ecmaFeatures: { + jsx: true, // Allows for the parsing of JSX + }, + }, + rules: { + // 'import/no-unresolved': ['error', { ignore: ['^@plone/'] }], + // 'import/extensions': 'off', + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + // e.g. "@typescript-eslint/explicit-function-return-type": "off", + }, + settings: { + react: { + version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use + }, + settings: { + 'import/parsers': { + '@typescript-eslint/parser': ['.ts', '.tsx'], + }, + 'import/resolver': { + // node: { + // extensions: ['.js', '.jsx', '.ts', '.tsx'], + // }, + typescript: { + alwaysTryTypes: true, // always try to resolve types under `@types` directory even it doesn't contain any source code, like `@types/unist` + + // use an array of glob patterns + project: [ + 'packages/*/tsconfig.json', + // 'other-packages/*/tsconfig.json', + ], + }, + }, + }, + }, + overrides: [ + { + files: ['**/*.ts', '**/*.tsx'], + plugins: ['@typescript-eslint', 'import'], + extends: [ + 'plugin:react/recommended', + // 'plugin:@typescript-eslint/eslint-recommended', + // 'plugin:@typescript-eslint/recommended', + // 'plugin:import/recommended', + 'plugin:import/typescript', + 'plugin:prettier/recommended', + 'plugin:react/jsx-runtime', + // 'plugin:storybook/recommended', + ], + }, + { + files: ['**/*.js', '**/*.jsx'], + plugins: ['import'], + extends: [ + 'plugin:react/recommended', + // 'plugin:import/recommended', + 'plugin:prettier/recommended', + 'plugin:react/jsx-runtime', + // 'plugin:storybook/recommended', + ], + rules: { + 'react/prop-types': 0, + 'react/no-unescaped-entities': 0, + }, + }, + ], +}; + +module.exports = config; diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 5ed332f4d6..dc604a76b4 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -9,35 +9,63 @@ jobs: strategy: fail-fast: false matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - ## node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + # We don't want to install until later, + # when the cache and Cypress are in place + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: false # Since they run on different node versions, we can't parallel + working-directory: packages/volto browser: chrome - group: Core ${{ matrix.node-version }} spec: cypress/tests/core/basic/**/*.js start: | make start-test-acceptance-server @@ -49,13 +77,177 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos + + corecontent: + 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 Content + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install + + - name: Cypress acceptance tests + uses: cypress-io/github-action@v6 + env: + BABEL_ENV: production + CYPRESS_RETRIES: 2 + # Recommended: pass the GitHub token lets this action correctly + # determine the unique run id necessary to re-run the checks + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + install: false + working-directory: packages/volto + browser: chrome + spec: cypress/tests/core/content/**/*.js + start: | + make start-test-acceptance-server + make start-test-acceptance-frontend + 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 + if: failure() + with: + name: cypress-screenshots + path: packages/volto/cypress/screenshots + # Upload Cypress videos + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: cypress-videos + path: packages/volto/cypress/videos + + corecontrolpanels: + 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 Control Panels + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install + + - name: Cypress acceptance tests + uses: cypress-io/github-action@v6 + env: + BABEL_ENV: production + CYPRESS_RETRIES: 2 + # Recommended: pass the GitHub token lets this action correctly + # determine the unique run id necessary to re-run the checks + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + install: false + working-directory: packages/volto + browser: chrome + spec: cypress/tests/core/controlpanels/**/*.js + start: | + make start-test-acceptance-server + make start-test-acceptance-frontend + 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 + if: failure() + with: + name: cypress-screenshots + path: packages/volto/cypress/screenshots + # Upload Cypress videos + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: cypress-videos + path: packages/volto/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 @@ -65,36 +257,62 @@ jobs: strategy: fail-fast: false matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - ## node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: false # Since they run on different node versions, we can't parallel + working-directory: packages/volto browser: chrome - group: Core Blocks ${{ matrix.node-version }} - spec: cypress/tests/core/blocks/**/*.js + spec: cypress/tests/core/blocks/*.js start: | make start-test-acceptance-server make start-test-acceptance-frontend @@ -105,52 +323,78 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos - corevoltoslate: + coreblockslisting: 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 + name: Core Blocks - Listing + timeout-minutes: 35 strategy: fail-fast: false matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - ## node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: false # Since they run on different node versions, we can't parallel + working-directory: packages/volto browser: chrome - group: Core Volto Slate ${{ matrix.node-version }} - spec: cypress/tests/core/volto-slate/**/*.js + spec: cypress/tests/core/blocks/listing/*.js start: | make start-test-acceptance-server make start-test-acceptance-frontend @@ -161,53 +405,80 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos - core5: + 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 Basic - Plone 5 + name: Core Volto Slate + timeout-minutes: 45 strategy: fail-fast: false matrix: - node-version: [18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - ## node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: false # Since they run on different node versions, we can't parallel + working-directory: packages/volto browser: chrome - group: Core Basic - Plone 5 - spec: cypress/tests/core/basic/**/*.js + spec: cypress/tests/core/volto-slate/**/*.js start: | - make start-test-acceptance-server-5 + make start-test-acceptance-server make start-test-acceptance-frontend wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' @@ -216,54 +487,80 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos - coresandbox: + 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: Coresandbox - timeout-minutes: 35 + name: Core Basic - Plone 5 strategy: fail-fast: false matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false - - name: Cypress Coresandbox Acceptance tests - uses: cypress-io/github-action@v5 + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install + + - name: Cypress acceptance tests + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Coresandbox - spec: cypress/tests/coresandbox/**/*.js + spec: cypress/tests/core/basic/**/*.js start: | - make start-test-acceptance-server-coresandbox - make start-test-acceptance-frontend-coresandbox + make start-test-acceptance-server-5 + make start-test-acceptance-frontend wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:55001/plone http://127.0.0.1:3000' # Upload Cypress screenshots @@ -271,70 +568,166 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos - guillotina: + coresandbox: 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 + name: Coresandbox timeout-minutes: 35 strategy: fail-fast: false matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - # node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false - - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install + + - name: Cypress Coresandbox Acceptance tests + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_API: guillotina - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Guillotina - spec: cypress/tests/guillotina/**/*.js + spec: cypress/tests/coresandbox/**/*.js start: | - make start-test-acceptance-server-guillotina - make start-test-acceptance-frontend-guillotina - wait-on: 'npx wait-on --httpTimeout 20000 http-get://127.0.0.1:8081 http://127.0.0.1:3000' + make start-test-acceptance-server-coresandbox + make start-test-acceptance-frontend-coresandbox + 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 if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/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: [18.x] + # steps: + # - uses: actions/checkout@v4 + + # # node setup + # - name: Use Node.js ${{ matrix.node-version }} + # uses: actions/setup-node@v4 + # with: + # node-version: ${{ matrix.node-version }} + + # - uses: pnpm/action-setup@v3 + # name: Install pnpm + # with: + # version: 8 + # run_install: false + + # - name: Get pnpm store directory + # shell: bash + # run: | + # echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + # - uses: actions/cache@v4 + # name: Setup pnpm cache + # with: + # path: ${{ env.STORE_PATH }} + # key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + # restore-keys: | + # ${{ runner.os }}-pnpm-store- + + # - run: pnpm i + + # - name: Cypress acceptance tests + # uses: cypress-io/github-action@v6 + # env: + # BABEL_ENV: production + # CYPRESS_API: guillotina + # CYPRESS_RETRIES: 2 + # # Recommended: pass the GitHub token lets this action correctly + # # determine the unique run id necessary to re-run the checks + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # with: + # install: false + # working-directory: packages/volto + # browser: chrome + # spec: cypress/tests/guillotina/**/*.js + # start: | + # make start-test-acceptance-server-guillotina + # make start-test-acceptance-frontend-guillotina + # 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 + # if: failure() + # with: + # name: cypress-screenshots + # path: packages/volto/cypress/screenshots + # # Upload Cypress videos + # - uses: actions/upload-artifact@v1 + # if: failure() + # with: + # name: cypress-videos + # path: packages/volto/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 @@ -346,33 +739,59 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - # node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Multilingual spec: cypress/tests/multilingual/**/*.js start: | make start-test-acceptance-server-multilingual @@ -384,13 +803,13 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/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 @@ -403,17 +822,46 @@ jobs: node-version: [18.x] # python-version: [3.7] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - # node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install # # python setup (temporary, while p.a.iterate changes are in a PR) # - name: Set up Python ${{ matrix.python-version }} @@ -440,20 +888,17 @@ jobs: # CI: true - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Working Copy spec: cypress/tests/workingCopy/**/*.js start: | make start-test-acceptance-server-workingcopy @@ -465,13 +910,13 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 - if: always() + if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/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 @@ -481,28 +926,59 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x] + node-version: [18.x, 20.x] env: generator-directory: ./packages/generator-volto project-directory: ./my-volto-app steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - # Build main Volto environment - - name: Build main Volto environment - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Build packages + run: pnpm build:registry + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install # Generator own tests - name: Generator tests - run: yarn && yarn test + run: pnpm test working-directory: ${{env.generator-directory}} # install Yeoman and the generator @@ -513,38 +989,51 @@ jobs: # create a project - run: yo @plone/volto my-volto-app --description "test volto project" --volto . --skip-install --no-interactive + # When main is canary, make sure we use it in the generator + # - run: yo @plone/volto my-volto-app --description "test volto project" --volto . --skip-install --no-interactive --canary - name: Install yalc run: npm -g install yalc - name: Install a yalc'ed version of the current Volto in the project - publish run: | - yalc publish + yalc publish packages/types + (cd packages/registry && yalc add @plone/types --no-pure && yalc publish) yalc publish packages/scripts + yalc publish packages/volto-slate + (cd packages/volto && yalc add @plone/scripts --no-pure && yalc add @plone/registry --no-pure && yalc add @plone/volto-slate --no-pure && yalc publish) - name: Install a yalc'ed version of the current Volto in the project - add run: | yalc add @plone/volto --no-pure - yalc add @plone/scripts --no-pure working-directory: ${{env.project-directory}} - name: Install a yalc'ed version of the current Volto in the project - install run: yarn config set -H enableImmutableInstalls false && yarn working-directory: ${{env.project-directory}} + - name: Running lint on a project works + run: yarn lint + working-directory: ${{env.project-directory}} + + - name: Running prettier on a project works + run: yarn prettier + working-directory: ${{env.project-directory}} + + - name: Running stylelint on a project works + run: yarn stylelint + working-directory: ${{env.project-directory}} + - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Project Generator spec: cypress/tests/minimal/**/*.js start: | make start-test-acceptance-server @@ -556,14 +1045,14 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos - name: Test if npm packs correctly run: npm pack --dry-run @@ -580,33 +1069,59 @@ jobs: matrix: node-version: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - cache: 'yarn' - # node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install - name: Cypress acceptance tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 env: BABEL_ENV: production - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} CYPRESS_RETRIES: 2 # Recommended: pass the GitHub token lets this action correctly # determine the unique run id necessary to re-run the checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: install: false - record: true - parallel: true + working-directory: packages/volto browser: chrome - group: Seamless spec: cypress/tests/core/basic/**/*.js config: baseUrl=http://localhost start: | @@ -620,10 +1135,94 @@ jobs: if: failure() with: name: cypress-screenshots - path: cypress/screenshots + path: packages/volto/cypress/screenshots + # Upload Cypress videos + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: cypress-videos-seamless + path: packages/volto/cypress/videos + + multilingualseamless: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: Multilingual in Seamless Mode + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + node-version: [18.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Cache Cypress Binary + id: cache-cypress-binary + uses: actions/cache@v4 + with: + path: ~/.cache/Cypress + key: binary-${{ matrix.node-version }}-${{ hashFiles('pnpm-lock.yaml') }} + + - run: pnpm i + + - name: Install Cypress if not in cache + if: steps.cache-cypress-binary.outputs.cache-hit != 'true' + working-directory: packages/volto + run: make cypress-install + + - name: Cypress acceptance tests + uses: cypress-io/github-action@v6 + env: + BABEL_ENV: production + CYPRESS_RETRIES: 2 + # Recommended: pass the GitHub token lets this action correctly + # determine the unique run id necessary to re-run the checks + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + install: false + working-directory: packages/volto + browser: chrome + spec: cypress/tests/multilingual/**/*.js + config: baseUrl=http://localhost + start: | + make start-test-acceptance-server-seamless-multilingual + make start-test-acceptance-frontend-seamless-multilingual + make start-test-acceptance-webserver-seamless + 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 + if: failure() + with: + name: cypress-screenshots + path: packages/volto/cypress/screenshots # Upload Cypress videos - uses: actions/upload-artifact@v1 if: failure() with: name: cypress-videos - path: cypress/videos + path: packages/volto/cypress/videos diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000000..04b8739752 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,117 @@ +name: Changelog check +on: + pull_request: + types: [assigned, opened, synchronize, reopened, labeled, unlabeled] + branches: + - main + +env: + node-version: 20.x + +jobs: + towncrier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # Fetch all history + fetch-depth: '0' + + - name: Install towncrier + run: pip install towncrier + + - uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + volto: + - 'packages/volto/**' + client: + - 'packages/client/**' + registry: + - 'packages/registry/**' + components: + - 'packages/components/**' + types: + - 'packages/types/**' + generator: + - 'packages/generator-volto/**' + scripts: + - 'packages/scripts/**' + voltoSlate: + - 'packages/volto-slate/**' + wrongNews: + - added|modified: 'news/**' + + - name: Volto changelog check + if: steps.filter.outputs.volto == 'true' + 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 main + towncrier check --compare-with origin/main --dir packages/volto + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Client changelog check + if: steps.filter.outputs.client == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/client + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Registry changelog check + if: steps.filter.outputs.registry == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/registry + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Components changelog check + if: steps.filter.outputs.components == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/components + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Types changelog check + if: steps.filter.outputs.types == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/types + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Generator changelog check + if: steps.filter.outputs.generator == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/generator-volto + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: scripts changelog check + if: steps.filter.outputs.scripts == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/scripts + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: volto-slate changelog check + if: steps.filter.outputs.voltoSlate == 'true' + run: | + git fetch --no-tags origin main + towncrier check --compare-with origin/main --dir packages/volto-slate + env: + BASE_BRANCH: ${{ github.base_ref }} + + - name: Wrong location of news changelog check + if: steps.filter.outputs.wrongNews == 'true' + run: echo "News items should be moved from the repository root to the appropriate package root in `packages/package-name`." && exit 1 + env: + BASE_BRANCH: ${{ github.base_ref }} diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml index 9b4db344de..a4dad86bde 100644 --- a/.github/workflows/code-analysis.yml +++ b/.github/workflows/code-analysis.yml @@ -1,71 +1,160 @@ name: Code Analysis Check on: [push, pull_request] + +env: + node-version: 20.x + 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: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' + node-version: ${{ env.node-version }} - # node install - - run: yarn --immutable + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i - name: Prettier check - run: yarn run prettier + run: pnpm 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: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' + version: 8 + run_install: false - # node install - - run: yarn --immutable + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - name: ESlint check - run: yarn run lint + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - name: Main ESlint check + run: pnpm lint + + - name: Volto ESlint check + run: pnpm lint:volto + + stylelint: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: Stylelint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - name: Volto Stylelint check + run: pnpm --filter @plone/volto stylelint + + - name: Components Stylelint check + run: pnpm --filter @plone/components stylelint 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: [18.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache with: - node-version: ${{ matrix.node-version }} - cache: 'yarn' + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- - # node install - - run: yarn --immutable + - run: pnpm i - name: i18n locales in sync - run: yarn run i18n:ci + run: pnpm i18n:ci diff --git a/.github/workflows/deployment_tests.yml b/.github/workflows/deployment_tests.yml new file mode 100644 index 0000000000..7324662881 --- /dev/null +++ b/.github/workflows/deployment_tests.yml @@ -0,0 +1,197 @@ +name: Deployment Tests +on: [push, pull_request] +jobs: + vitessr: + 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: Vite SSR + timeout-minutes: 5 + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + # We don't want to install until later, + # when the cache and Cypress are in place + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build packages + run: pnpm build:deps && pnpm build:components + + - name: Start backend + run: make start-backend-docker-detached + + - name: Build + run: pnpm --filter plone-vite-ssr build + + - name: Start server + run: nohup pnpm --filter plone-vite-ssr start:prod & + + - name: Wait + run: packages/scripts/node_modules/.bin/wait-on --httpTimeout 20000 http-get://127.0.0.1:8080/Plone + + - name: Run tests + run: curl http://localhost:3000 || true + + - name: Run tests + run: curl http://127.0.0.1:3000 || true + + - name: Run tests + run: node packages/scripts/check_deployment.js + + - name: Stop backend + run: make stop-backend-docker-detached + + nextjs: + 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: Next.JS + timeout-minutes: 5 + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + # We don't want to install until later, + # when the cache and Cypress are in place + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build packages + run: pnpm build:deps && pnpm build:components + + - name: Start backend + run: make start-backend-docker-detached + + - name: Build + run: pnpm --filter plone-nextjs build + + - name: Start server + run: nohup pnpm --filter plone-nextjs start:prod & + + - name: Wait + run: packages/scripts/node_modules/.bin/wait-on --httpTimeout 20000 http-get://127.0.0.1:8080/Plone + + - name: Run tests + run: curl http://localhost:3000 || true + + - name: Run tests + run: curl http://127.0.0.1:3000 || true + + - name: Run tests + run: node packages/scripts/check_deployment.js + + - name: Stop backend + run: make stop-backend-docker-detached + + remix: + 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: Remix + timeout-minutes: 5 + strategy: + fail-fast: false + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + # We don't want to install until later, + # when the cache and Cypress are in place + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build packages + run: pnpm build:deps && pnpm build:components + + - name: Start backend + run: make start-backend-docker-detached + + - name: Build + run: pnpm --filter plone-remix build + + - name: Start server + run: nohup pnpm --filter plone-remix start:prod & + + - name: Wait + run: packages/scripts/node_modules/.bin/wait-on --httpTimeout 20000 http-get://127.0.0.1:8080/Plone + + - name: Run tests + run: node packages/scripts/check_deployment.js + + - name: Stop backend + run: make stop-backend-docker-detached diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9770506a89..20ddb58092 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Documentation on: push: branches: - - master + - main paths: - 'docs/**' # Build pull requests @@ -17,12 +17,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10'] + python-version: ['3.12'] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' @@ -31,7 +31,9 @@ jobs: run: pip install virtualenv - name: pip install requirements - run: pip install -r requirements-docs.txt + run: | + pip install -r requirements-docs.txt + sudo snap install --edge vale - name: Check for broken links run: make docs-linkcheckbroken @@ -39,11 +41,8 @@ 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}} + - name: Run vale + run: | + git clone https://github.com/errata-ai/Microsoft.git + cp -r ./Microsoft/Microsoft ./styles + vale --no-exit ./docs diff --git a/.github/workflows/readme-link-check.yml b/.github/workflows/readme-link-check.yml new file mode 100644 index 0000000000..41b0b13f34 --- /dev/null +++ b/.github/workflows/readme-link-check.yml @@ -0,0 +1,23 @@ +# Check links in all README.mds with awesome_bot +# https://github.com/dkhamsing/awesome_bot +name: readme-link-check + +on: + push: + branches: [ '*' ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby 3.2 + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2 + - name: Check links in README.md with awesome_bot + run: | + gem install awesome_bot + awesome_bot --request-delay 1 --allow-dupe --white-list http://localhost:8080/Plone,http://localhost:3000,https://github.com/kitconcept/volto-blocks-grid.git,https://my-server-DNS-name.tld/api --files PACKAGES.md,README.md,packages/blocks/README.md,packages/client/README.md,packages/components/README.md,packages/generator-volto/README.md,packages/parcel-optimizer-react-client/README.md,packages/registry/README.md,packages/scripts/README.md,packages/tsconfig/README.md,packages/types/README.md,packages/volto-slate/README.md,apps/nextjs/README.md,apps/remix/README.md,apps/vite-ssr/README.md diff --git a/.github/workflows/towncrier.yml b/.github/workflows/towncrier.yml deleted file mode 100644 index 16f68d2cf5..0000000000 --- a/.github/workflows/towncrier.yml +++ /dev/null @@ -1,32 +0,0 @@ -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 3bad45b9aa..4ba3638654 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -1,33 +1,216 @@ name: Unit Tests on: [push, pull_request] + +env: + node-version: 20.x + jobs: - unit: + volto: 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 + name: '@plone/volto' runs-on: ubuntu-latest strategy: fail-fast: false matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # node setup - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache with: - # remove workaround for 18.x once https://github.com/nodejs/node/issues/47563 is fixed - node-version: ${{ matrix.node-version == '18.x' && '18.15.0' || matrix.node-version }} - cache: yarn + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i - # node install - - run: yarn --immutable + # Locales in place are needed for the tests to pass + - run: pnpm --filter @plone/volto i18n - # node test - - run: yarn i18n && yarn test:ci + - name: Run unit tests Volto + run: pnpm --filter @plone/volto test # Bundlewatch - - run: yarn build - - uses: jackyef/bundlewatch-gh-action@master + # - run: yarn build + # - uses: jackyef/bundlewatch-gh-action@master + # with: + # bundlewatch-github-token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }} + + registry: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: '@plone/registry' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - name: Run unit tests @plone/registry + run: pnpm --filter @plone/registry test + + components: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: '@plone/components' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm with: - bundlewatch-github-token: ${{ secrets.BUNDLEWATCH_GITHUB_TOKEN }} + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - name: Run unit tests @plone/components + run: pnpm --filter @plone/components test + + client: + name: '@plone/client' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - run: make start-test-acceptance-server-detached + + - run: npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone && pnpm --filter @plone/client test + working-directory: packages/client + + helpers: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name + name: '@plone/helpers' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: [18.x, 20.x] + steps: + - uses: actions/checkout@v4 + + # node setup + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v3 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v4 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - run: pnpm i + + - name: Run unit tests @plone/helpers + run: pnpm --filter @plone/helpers test diff --git a/.github/workflows/update_remote_docs.yml b/.github/workflows/update_remote_docs.yml index 524dfc745d..ec75bd410c 100644 --- a/.github/workflows/update_remote_docs.yml +++ b/.github/workflows/update_remote_docs.yml @@ -3,7 +3,7 @@ name: Trigger build and deploy of Plone 6 documentation on: push: branches: - - "master" + - "main" paths: - "docs/*" @@ -16,4 +16,4 @@ jobs: -H "Authorization: Bearer ${{secrets.DOCUMENTATION_BUILD_APPLICATION_KEY}}" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/plone/documentation/actions/workflows/update_submodule.yml/dispatches \ - -d '{"ref": "6-dev"}' \ No newline at end of file + -d '{"ref": "6-dev"}' diff --git a/.gitignore b/.gitignore index ebcc210125..5d92feff8c 100644 --- a/.gitignore +++ b/.gitignore @@ -21,12 +21,12 @@ build !.yarn/versions # Other +.vscode /cache .yarn/ .DS_Store .idea lighthouse-report.html -.vscode/ .#* *~ /.settings/ @@ -85,3 +85,8 @@ public/critical.css docs/_build/ /.python-version /.tool-versions +docs/source/news + +.turbo +.parcel-cache/ +tsconfig.tsbuildinfo diff --git a/.husky/post-checkout b/.husky/post-checkout index 940595136b..8ec99a06f9 100755 --- a/.husky/post-checkout +++ b/.husky/post-checkout @@ -1,2 +1,2 @@ [ -n "$CI" ] && exit 0 -yarn yarnhook +pnpm lockhook diff --git a/.husky/post-merge b/.husky/post-merge index 940595136b..8ec99a06f9 100755 --- a/.husky/post-merge +++ b/.husky/post-merge @@ -1,2 +1,2 @@ [ -n "$CI" ] && exit 0 -yarn yarnhook +pnpm lockhook diff --git a/.husky/post-rebase b/.husky/post-rebase index 940595136b..8ec99a06f9 100755 --- a/.husky/post-rebase +++ b/.husky/post-rebase @@ -1,2 +1,2 @@ [ -n "$CI" ] && exit 0 -yarn yarnhook +pnpm lockhook diff --git a/.husky/pre-commit b/.husky/pre-commit index 9183f9d3cf..17092dc583 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,2 @@ [ -n "$CI" ] && exit 0 -yarn lint-staged +pnpm lint-staged diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000000..e2d1cf3190 --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,18 @@ +{ + "packages/!(volto)/**/*.{js,jsx,ts,tsx}": [ + "pnpm eslint --max-warnings=0 --fix", + "pnpm prettier --single-quote --write" + ], + "packages/volto/**/*.{js,jsx,ts,tsx}": [ + "pnpm --filter @plone/volto lint:husky", + "pnpm --filter @plone/volto prettier:husky" + ], + "packages/volto/src/**/*.{jsx, tsx}": ["pnpm --filter @plone/volto i18n"], + "packages/!(volto)/**/*.{css,less,scss}": ["pnpm stylelint --fix"], + "packages/volto/**/*.{css,less,scss}": [ + "pnpm --filter @plone/volto stylelint --fix" + ], + "packages/volto/**/*.overrides": [ + "pnpm --filter @plone/volto stylelint --fix" + ] +} diff --git a/.npmignore b/.npmignore deleted file mode 100644 index dd9cd099ac..0000000000 --- a/.npmignore +++ /dev/null @@ -1,132 +0,0 @@ -# https://docs.npmjs.com/using-npm/developers.html#keeping-files-out-of-your-package - -# Directories -api/ -bin/ -build/ -lib/ -g-api/ -tests/ -share/ -.yarn/ -.storybook/ - -# Docs -docs/ -styles/ -.vale.ini -netlify.toml - -# Cypress -cypress/fixtures -cypress/tests -cypress/screenshots -cypress/videos - -# Tests -__tests__/ -*.snap - -# Files -.travis.yml -requirements-docs.txt -requirements-tests.txt -yarn.lock -.editorconfig -.dockerignore -.gitattributes -.yarnrc -.yarnrc.yml -.nvmrc -changelogupdater.js -pip-selfcheck.json -pyvenv.cfg -Dockerfile -CNAME -entrypoint.sh -Jenkinsfile -Makefile -.husky -.changelog.draft -towncrier.toml -jsdoc.json - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# Volto logos -./logos - -# Razzle cache -cache/ - -# Github -.github - -# dotenv environment variables file -.env - -# next.js build output -.next - -styleguide.config -.vscode -packages/* -!packages/volto-slate -.tx - -# yarn 3 -.yarn -.yarn/cache -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 53d838af21..0000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -lts/gallium diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..75e827079f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,9 @@ +**/.next +**/build +**/coverage +**/dist +styles/rules/* +node_modules +packages/volto/types/* +storybook-static +app/vite-ssr/src/routeTree.gen.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..6e778b4fb9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "trailingComma": "all", + "singleQuote": true +} diff --git a/.release-it.json b/.release-it.json new file mode 100644 index 0000000000..2b93e6a44e --- /dev/null +++ b/.release-it.json @@ -0,0 +1,3 @@ +{ + "npm": false +} diff --git a/.storybook/main.js b/.storybook/main.js deleted file mode 100644 index 7109389c34..0000000000 --- a/.storybook/main.js +++ /dev/null @@ -1,127 +0,0 @@ -const webpack = require('webpack'); -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 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: [ - { - loader: 'svg-loader', - }, - { - loader: 'svgo-loader', - options: { - plugins: [ - { - name: 'preset-default', - params: { - overrides: { - convertPathData: false, - removeViewBox: false, - }, - }, - }, - 'removeTitle', - 'removeUselessStrokeAndFill', - ], - }, - }, - ], -}; -const defaultRazzleOptions = { - verbose: false, - debug: {}, - buildType: 'iso', - cssPrefix: 'static/css', - jsPrefix: 'static/js', - enableSourceMaps: true, - enableReactRefresh: true, - enableTargetBabelrc: false, - enableBabelCache: true, - forceRuntimeEnvVars: [], - mediaPrefix: 'static/media', - staticCssInDev: false, - emitOnErrors: false, - disableWebpackbar: false, - 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'], - 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); - const AddonConfigurationRegistry = require('../addon-registry'); - const registry = new AddonConfigurationRegistry(projectRootPath); - config = lessPlugin({ - registry - }).modifyWebpackConfig({ - env: { - target: 'web', - dev: 'dev' - }, - webpackConfig: config, - webpackObject: webpack, - options: {} - }); - - // Put the SVG loader on top and prevent the asset/resource rule - // from processing the app's SVGs - config.module.rules.unshift(SVGLOADER); - 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 - } - } - }; - - // 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 => - // 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)); - return resultConfig; - }, - babel: async options => { - return { - ...options, - 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/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000000..1521c8b765 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1 @@ +dist diff --git a/.vale.ini b/.vale.ini index da6af903f2..0e3bcdf1d5 100644 --- a/.vale.ini +++ b/.vale.ini @@ -8,3 +8,5 @@ Packages = Microsoft [*.md] BasedOnStyles = Vale, Microsoft +Microsoft.Contractions = suggestion +Microsoft.Units = suggestion diff --git a/.yarnrc.yml b/.yarnrc.yml deleted file mode 100644 index 7af626ed79..0000000000 --- a/.yarnrc.yml +++ /dev/null @@ -1,5 +0,0 @@ -defaultSemverRangePrefix: "" - -nodeLinker: node-modules - -yarnPath: .yarn/releases/yarn-3.2.3.cjs diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index cc4be4a142..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,7126 +0,0 @@ -# Volto Release Notes - - - - - -## 17.0.0-alpha.24 (2023-08-09) - -### Breaking - -- Update `@plone/scripts` to 3.0.0. @davisagli [#5040](https://github.com/plone/volto/issues/5040) - -### Bugfix - -- Fix handling of exceptions in reducers. @davisagli [#5069](https://github.com/plone/volto/issues/5069) -- Add missing i18n for ToC block. @davisagli [#5073](https://github.com/plone/volto/issues/5073) - -### Documentation - -- Fix 302 redirect in changelog. @stevepiercy [#5068](https://github.com/plone/volto/issues/5068) - - -## 17.0.0-alpha.23 (2023-07-28) - -### Bugfix - -- Fix regression from v17a22: It was not possible to select a block in a grid - column unless the grid was already selected. @davisagli - - Fix regression from v17a22: Block outline was blocking clicks in some cases. - @davisagli [#5039](https://github.com/plone/volto/issues/5039) - - -## 17.0.0-alpha.22 (2023-07-28) - -### Feature - -- Refactor Delete -@Tishasoumya [#4890](https://github.com/plone/volto/issues/4890) -- Refactor workflow -@Tishasoumya-02 [#4902](https://github.com/plone/volto/issues/4902) -- Refactor Request Reset Password-@Tishasoumya-02 [#4938](https://github.com/plone/volto/issues/4938) -- Refactor Actions-@Tishasoumya-02 [#4939](https://github.com/plone/volto/issues/4939) -- Refactor Blocks/Maps/Edit component -@Tishasoumya-02 [#4958](https://github.com/plone/volto/issues/4958) -- Updated Italian translations @sabrina-bongiovanni [#4987](https://github.com/plone/volto/issues/4987) -- Made selectedView and className props available in the SearchBlockView.jsx to improve styling development. @danalvrz [#4997](https://github.com/plone/volto/issues/4997) - -### Bugfix - -- Fix Volto contents - set properties Exclude from navigation - bad request, set exclude_from_nav to boolean [#4855](https://github.com/plone/volto/issues/4855) -- Add XSendfile headers to files and images middleware @instification [#4984](https://github.com/plone/volto/issues/4984) -- search-block: translate some missing strings to german and fix a typo. @pbauer [#4996](https://github.com/plone/volto/issues/4996) -- Add image block className support (Style wrapper). @sneridagh [#5018](https://github.com/plone/volto/issues/5018) -- Fix for 'no value' entry in table of content field. @satyam4p [#5022](https://github.com/plone/volto/issues/5022) -- Fix updating roles when username contains a period (.). @nileshgulia1 [#5025](https://github.com/plone/volto/issues/5025) -- Fix hover and focused border for block child. @claudiaifrim [#5028](https://github.com/plone/volto/issues/5028) -- Enhance display and repairing of broken relations. @ksuess [#5033](https://github.com/plone/volto/issues/5033) -- Fix selecting grid block when a sub-block is selected. @davisagli [#5036](https://github.com/plone/volto/issues/5036) -- Update versions of semver and release-it. @davisagli [#5053](https://github.com/plone/volto/issues/5053) - -### Documentation - -- Add short comment for easier finding registered components. @ksuess [#5017](https://github.com/plone/volto/issues/5017) - - -## 17.0.0-alpha.21 (2023-07-23) - -### Breaking - -- Added new Image component to render optimized images @pnicolli @davisagli [#3337](https://github.com/plone/volto/issues/3337) - -### Feature - -- Add getFieldURL helper function used to get the url value of a field based on its structure. @razvanMiu [#2252](https://github.com/plone/volto/issues/2252) - -### Bugfix - -- Fix delete confirmation to handle empty `breaches`. @davisagli [#4832](https://github.com/plone/volto/issues/4832) - -### Internal - -- Upgrade to Cypress 12.17.1 (latest) @sneridagh [#4981](https://github.com/plone/volto/issues/4981) - - -## 17.0.0-alpha.20 (2023-07-18) - -### Feature - -- Use all the apiExpanders in use, so we perform a single request for getting all the required data. @sneridagh [#4946](https://github.com/plone/volto/issues/4946) - -### Bugfix - -- Fix the condition deciding on listing pagination format so it takes into account container blocks as well @sneridagh [#4978](https://github.com/plone/volto/issues/4978) - - -## 17.0.0-alpha.19 (2023-07-18) - -### Feature - -- Add /ok route as an express middleware @ionlizarazu [#4375](https://github.com/plone/volto/issues/4375) -- Add `Links to item` view (available via object's more menu) @pgrunewald [#4787](https://github.com/plone/volto/issues/4787) -- Tune 'Links to item' view to 'Links and references' view. Show all relation types. @ksuess @stevepiercy [#4842](https://github.com/plone/volto/issues/4842) -- Update browserlist to latest @sneridagh [#4977](https://github.com/plone/volto/issues/4977) - -### Bugfix - -- Handle condition for yearly frequency in recurrence @BhuvaneshPatil [#4498](https://github.com/plone/volto/issues/4498) -- Fix search block input clear button doesn't reset the search @iFlameing [#4828](https://github.com/plone/volto/issues/4828) - -### Internal - -- Update to latest plone.restapi and Plone 6.0.6 @sneridagh [#4979](https://github.com/plone/volto/issues/4979) -- Remove dangling out of place Guillotina Cypress tests @sneridagh [#4980](https://github.com/plone/volto/issues/4980) - - -## 17.0.0-alpha.18 (2023-07-16) - -### Feature - -- Refactor CommentEdit -@Tishasoumya-02 [#4075](https://github.com/plone/volto/issues/4075) -- Facets should be able to decide themselves if they should show or not. Made defaultShowFacet to be a fallback in case there is no custom function for each facet type. @tedw87 [#4579](https://github.com/plone/volto/issues/4579) -- Add backward compatibility to `slate_richtext` with fields that are plain text @razvanMiu [#4796](https://github.com/plone/volto/issues/4796) -- Refactor-Contact Form @Tishasoumya-02 [#4850](https://github.com/plone/volto/issues/4850) -- Refactor BreadcrumbsComponent @Tishasoumya-02 [#4858](https://github.com/plone/volto/issues/4858) -- Refactor SearchWidget @Tishasoumya-02 [#4864](https://github.com/plone/volto/issues/4864) -- Refactor LinkView -@Tishasoumya-02 [#4866](https://github.com/plone/volto/issues/4866) -- Use container from component registry in content type views, if defined. @sneridagh [#4962](https://github.com/plone/volto/issues/4962) - -### Bugfix - -- Fix temporary rendering of folder contents while query results are loading. @davisagli [#4351](https://github.com/plone/volto/issues/4351) -- Fix isBlacklisted method check for volto externalRoutes [#4725](https://github.com/plone/volto/issues/4725) -- fix(styleMenu): Highlight selected block styles @nileshgulia1 [#4851](https://github.com/plone/volto/issues/4851) -- Fix tablet main menu. [#4859](https://github.com/plone/volto/issues/4859) -- Fix the table of contents block so that if one or more items get out of the viewport, a dropdown menu appears with all the items that do not fit the viewport and also added an option to make the TOC sticky. @MihaelaCretu11 [#4907](https://github.com/plone/volto/issues/4907) -- Add a marker in the props passed to `RenderBlocks` in the Grid block view @sneridagh [#4932](https://github.com/plone/volto/issues/4932) -- Typo in Italian locales @mamico [#4944](https://github.com/plone/volto/issues/4944) -- Fix handling of overriden image in Teaser, improve in case that a custom image component is present. @sneridagh [#4964](https://github.com/plone/volto/issues/4964) -- Fix slateTable still uses old style of sidebar generation @iFlameing [#4972](https://github.com/plone/volto/issues/4972) -- Fix password autocomplete hint for login form. @davisagli [#4976](https://github.com/plone/volto/issues/4976) - -### Internal - -- Upgrade bundlewatch to 0.3.3. @wesleybl [#4967](https://github.com/plone/volto/issues/4967) - -### Documentation - -- Added note that Pluggables are not compatible with server-side rendering (SSR). @Akshat2Jain [#4735](https://github.com/plone/volto/issues/4735) -- Replace broken link for @albertcasado to use GitHub instead of Twitter. @stevepiercy [#4941](https://github.com/plone/volto/issues/4941) -- Exclude video markup from `make text` builder. @stevepiercy [#4966](https://github.com/plone/volto/issues/4966) - - -## 17.0.0-alpha.17 (2023-07-11) - -### Breaking - -- Remove useToken & useContent hooks-@Tishasoumya-02 [#4951](https://github.com/plone/volto/issues/4951) - -### Feature - -- Use container from component registry in content type views, if defined. @sneridagh [#4962](https://github.com/plone/volto/issues/4962) - -### Bugfix - -- Fix temporary rendering of folder contents while query results are loading. @davisagli [#4351](https://github.com/plone/volto/issues/4351) -- Fix isBlacklisted method check for volto externalRoutes [#4725](https://github.com/plone/volto/issues/4725) -- Add a marker in the props passed to `RenderBlocks` in the Grid block view @sneridagh [#4932](https://github.com/plone/volto/issues/4932) -- Fix handling of overriden image in Teaser, improve in case that a custom image component is present. @sneridagh [#4964](https://github.com/plone/volto/issues/4964) - -### Documentation - -- Replace broken link for @albertcasado to use GitHub instead of Twitter. @stevepiercy [#4941](https://github.com/plone/volto/issues/4941) - - -## 17.0.0-alpha.16 (2023-06-28) - -### Feature - -- New block: Grid - A container of blocks, arranged in horizontal direction. @sneridagh - New primitive: Container - A primitive to build blocks containing other blocks. @sneridagh [#3180](https://github.com/plone/volto/issues/3180) - - -## 17.0.0-alpha.15 (2023-06-28) - -### Breaking - -- Use proper heading tag (depending on the headline) in default listing template @sneridagh [#4848](https://github.com/plone/volto/issues/4848) - -### Bugfix - -- Remove anonymous function calls. Remove default exports from. @sneridagh [#4917](https://github.com/plone/volto/issues/4917) -- Fix Annontools StoryBook @sneridagh [#4921](https://github.com/plone/volto/issues/4921) -- Fix the experimental add new block button position, compensate the icon width to center it correctly @sneridagh [#4924](https://github.com/plone/volto/issues/4924) - -### Internal - -- Add Storybook story for useDetectClickOutside hook with several demos @sneridagh [#4923](https://github.com/plone/volto/issues/4923) - - -## 17.0.0-alpha.14 (2023-06-23) - -### Feature - -- Added slug-based linked headings in `volto-slate`. @tiberiuichim, @nileshgulia1 [#4287](https://github.com/plone/volto/issues/4287) -- Refactored Anontools components. @Tishasoumya-02 [#4845](https://github.com/plone/volto/issues/4845) - -### Bugfix - -- Update to version 6.0.5 of Plone backend. @davisagli [#4897](https://github.com/plone/volto/issues/4897) - - -## 17.0.0-alpha.13 (2023-06-15) - -### Feature - -- Add and enforce a new config setting, `maxFileUploadSize`. @davisagli [#4868](https://github.com/plone/volto/issues/4868) - -### Bugfix - -- Fix and improve the `addStyling` helper @sneridagh [#4880](https://github.com/plone/volto/issues/4880) - - -## 17.0.0-alpha.12 (2023-06-14) - -### Feature - -- Allow to deselect color in ColorPickerWidget. @ksuess [#4838](https://github.com/plone/volto/issues/4838) -- Configurable Container component from registry for some key route views. @sneridagh [#4871](https://github.com/plone/volto/issues/4871) - -### Bugfix - -- Fix regression in horizontal scroll in contents view, add it back @sneridagh [#4872](https://github.com/plone/volto/issues/4872) - - -## 17.0.0-alpha.11 (2023-06-09) - -### Bugfix - -- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) - - -## 17.0.0-alpha.10 (2023-06-09) - -### Feature - -- Search Block: Add support for advanced facets that are only displayed on demand. - [pbauer, razvanMiu, claudiaifrim] [#4783](https://github.com/plone/volto/issues/4783) -- Display PAS validation errors. [tschorr] [#4801](https://github.com/plone/volto/issues/4801) -- Added a CSS identifier to the Slate style menu options. @razvanMiu [#4846](https://github.com/plone/volto/issues/4846) -- Use a Container from the registry in the Form component and fallback to the Semantic UI one. @sneridagh [#4849](https://github.com/plone/volto/issues/4849) -- Update Brazilian Portuguese translations @ericof [#4853](https://github.com/plone/volto/issues/4853) - -### Bugfix - -- Convert header class to function. @gomez [#4767](https://github.com/plone/volto/issues/4767) -- Do not break validation on required number field with value 0 @cekk [#4841](https://github.com/plone/volto/issues/4841) - - -## 17.0.0-alpha.9 (2023-06-01) - -### Bugfix - -- Fix special characters in request urls @pnicolli @mamico @luca-bellenghi @cekk [#4825](https://github.com/plone/volto/issues/4825) -- Fix block is undefined in StyleWrapper helper when building classnames @sneridagh [#4827](https://github.com/plone/volto/issues/4827) -- Fix navigation sections in 404 pages @sneridagh [#4836](https://github.com/plone/volto/issues/4836) - -### Documentation - -- Fix glossary warning due to lack of empty line before a term. @stevepiercy [#4820](https://github.com/plone/volto/issues/4820) - - -## 17.0.0-alpha.8 (2023-05-24) - -### Feature - -- Add Finnish translation (contributed by @rioksane) @erral [#4084](https://github.com/plone/volto/issues/4084) - -### Bugfix - -- Fixed the issue "shouldn't use a hook like function name for a variable" @Kaku-g [#4693](https://github.com/plone/volto/issues/4693) -- Fix to not update breadrumbs, navigation, actions, and types when content is fetched as a subrequest and apiExpanders includes these components. @davisagli [#4760](https://github.com/plone/volto/issues/4760) -- Fix bug where editors could not see their own content in the Contents view if it was expired or has a future effective date. @davisagli [#4764](https://github.com/plone/volto/issues/4764) -- Fix bug showing logs at the browsers when richtext widget is use @claytonc [#4780](https://github.com/plone/volto/issues/4780) -- Update relations control panel layout @danalvrz [#4794](https://github.com/plone/volto/issues/4794) -- Fix hot module reloading of changes to `@plone/volto`. @davisagli [#4799](https://github.com/plone/volto/issues/4799) -- Add guard in case of malformed blocks are present (at least id and title should be present) @sneridagh [#4802](https://github.com/plone/volto/issues/4802) -- Fix html tag lang attribute in SSR @sneridagh [#4803](https://github.com/plone/volto/issues/4803) -- Add newest supported languages to `Language` constants list @sneridagh [#4811](https://github.com/plone/volto/issues/4811) - -### Internal - -- Remove max_line_length from .editorconfig @pnicolli [#4776](https://github.com/plone/volto/issues/4776) -- Fix unannounced breaking change in cypress-io/github-action @sneridagh [#4795](https://github.com/plone/volto/issues/4795) - - -## 17.0.0-alpha.7 (2023-05-11) - -### Bugfix - -- Fix language negotiation for language codes that include a region (e.g. `pt-br`). @davisagli [#4644](https://github.com/plone/volto/issues/4644) - - -## 17.0.0-alpha.6 (2023-05-11) - -### Feature - -- Changed control panel list to be fetched server-side not client-side - @JeffersonBledsoe [#3749](https://github.com/plone/volto/issues/3749) - -### Bugfix - -- Apply suggestion from browser for password field @lord2anil [#3990](https://github.com/plone/volto/issues/3990) -- Open all accordion'd content in InlineForm by default, allow arbitrarily close any number of them. @sneridagh [#4178](https://github.com/plone/volto/issues/4178) -- Fix duplicating listing block by removing block uid from blocks data. @ksuess [#4234](https://github.com/plone/volto/issues/4234) -- The tabs for the add page was unresponsive on mobile devices. Fixed this by changing flex-wrap property. @sudhanshu1309 [#4506](https://github.com/plone/volto/issues/4506) -- (fix):Object.normaliseMail: Cannot read properties of null @dobri1408 [#4558](https://github.com/plone/volto/issues/4558) -- Update add-on control panel tranlsations: install -> activate. @ksuess [#4582](https://github.com/plone/volto/issues/4582) -- Fix robot.txt - the sitemap link should respect x-forwarded headers @reebalazs [#4638](https://github.com/plone/volto/issues/4638) -- Fix Move to top of folder ordering in folder content view by searching also @iFlameing [#4690](https://github.com/plone/volto/issues/4690) -- Fix faulty D&D elements in ObjectBrowserList widget @sneridagh [#4703](https://github.com/plone/volto/issues/4703) -- Fix fetching API paths with urlencoded characters in the querystring. @davisagli [#4718](https://github.com/plone/volto/issues/4718) - -### Internal - -- Change conditional checking to optional chaining for a theme icon @nilootpal [#4567](https://github.com/plone/volto/issues/4567) -- Security upgrade for momentjs [#4715](https://github.com/plone/volto/issues/4715) -- Upgrade to Plone 6.0.4 @sneridagh [#4743](https://github.com/plone/volto/issues/4743) - -### Documentation - -- Added documentation regarding the static middleware. @BhardwajAditya-github [#4518](https://github.com/plone/volto/issues/4518) -- Use new URL `6.docs.plone.org`. @stevepiercy [#4726](https://github.com/plone/volto/issues/4726) -- Synch stuff from `16.x.x` branch that should have been in `master` as well. @stevepiercy [#4728](https://github.com/plone/volto/issues/4728) -- Fix link in Volto, remove from linkcheck ignore in Documentation. @stevepiercy [#4742](https://github.com/plone/volto/issues/4742) - - -## 17.0.0-alpha.5 (2023-04-14) - -### Bugfix - -- Generate a split sitemap @reebalazs [#4638](https://github.com/plone/volto/issues/4638) -- Fix Move to top of folder ordering in folder content view @iFlameing [#4690](https://github.com/plone/volto/issues/4690) -- Revert "Add current page parameter to the route in the listing and search block pagination (#4159)" @sneridagh [#4695](https://github.com/plone/volto/issues/4695) -- Fix search block in edit mode re-queries multiple blocks with an empty search text @reebalazs [#4697](https://github.com/plone/volto/issues/4697) - -### Documentation - -- Update links for 2022 Training archive. @stevepiercy [#4635](https://github.com/plone/volto/issues/4635) - - -## 17.0.0-alpha.4 (2023-04-12) - -### Feature - -- DefaultView (view of fields for content types with blocks disabled): Show field name as tip on hover of label. @ksuess [#4598](https://github.com/plone/volto/issues/4598) -- Support RelationList field with named StaticCatalogVocabulary and SelectWidget. @ksuess [#4614](https://github.com/plone/volto/issues/4614) -- Support for declaring a theme in `volto.config.js` or in `package.json` - Add two entry points to allow extension of a theme from other add-ons. @sneridagh [#4625](https://github.com/plone/volto/issues/4625) -- Set sameSite in I18N_LANGUAGE cookie @sneridagh [#4627](https://github.com/plone/volto/issues/4627) -- Added querystring search get option. @robgietema [#4658](https://github.com/plone/volto/issues/4658) - -### Bugfix - -- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) -- Fix regexp that checks valid URLs and improve tests [cekk] [#4601](https://github.com/plone/volto/issues/4601) -- Fixed wrong localization on password reset page @iRohitSingh [#4656](https://github.com/plone/volto/issues/4656) -- fix sitemap.xml.gz not is not compressed @dobri1408 [#4663](https://github.com/plone/volto/issues/4663) - -### Internal - -- Trigger CI workflows to run from external pull requests. @davisagli [#4629](https://github.com/plone/volto/issues/4629) -- Update to p.restapi 8.36.0 and Plone 6.0.3 @sneridagh [#4682](https://github.com/plone/volto/issues/4682) - -### Documentation - -- Added `JavaScript` and `NodeJS` as accepted spellings, and deviations of them as rejected spellings. @utkkkarshhh [#3092](https://github.com/plone/volto/issues/3092) -- Fix documentation build, add pins @sneridagh [#4626](https://github.com/plone/volto/issues/4626) -- Update Volto contributing to align with and refer to the new Plone core code contributing requirements. @stevepiercy [#4634](https://github.com/plone/volto/issues/4634) -- Improve creating views documentation page. @rboixaderg [#4636](https://github.com/plone/volto/issues/4636) -- Razzle upgrade notice in upgrade guide @sneridagh [#4641](https://github.com/plone/volto/issues/4641) -- Rename "Developer Guidelines" to "Contributing". @stevepiercy [#4666](https://github.com/plone/volto/issues/4666) -- Fix broken link to `ReactJS.org`. @stevepiercy [#4667](https://github.com/plone/volto/issues/4667) - - -## 17.0.0-alpha.3 (2023-03-22) - -### Feature - -- Add Vale to CI for spell and style checks. @MAX-786 [#4423](https://github.com/plone/volto/issues/4423) - -### Bugfix - -- Fix Search is case sensitive in Block chooser @iRohitSingh [#4526](https://github.com/plone/volto/issues/4526) -- InternalURl helper method should incorporate externalRoutes settings into consideration. @iFlameing [#4559](https://github.com/plone/volto/issues/4559) -- Update message add-on control panel: remove 'buildout', update reference. @ksuess [#4574](https://github.com/plone/volto/issues/4574) - -### Documentation - -- Deleted duplicate import and fixed training URLs. @yahya-cloud [#4523](https://github.com/plone/volto/issues/4523) -- Fix grammar in PR #4542. @stevepiercy [#4555](https://github.com/plone/volto/issues/4555) -- Fix broken links at `ReactJS.org`. @stevepiercy [#4569](https://github.com/plone/volto/issues/4569) -- Fix video warnings and link errors. @stevepiercy [#4578](https://github.com/plone/volto/issues/4578) - - -## 17.0.0-alpha.2 (2023-03-15) - -### Breaking - -- Add custom CSS animation to hamburger menu. Removed `hamburgers` dependency. @danalvrz [#4433](https://github.com/plone/volto/issues/4433) -- Improve i18n script ordering of addons, so that addons can override translations from their dependencies. @davisagli [#4495](https://github.com/plone/volto/issues/4495) - -### Feature - -- Add option to hide empty listing blocks @ksuess [#4393](https://github.com/plone/volto/issues/4393) - -### Bugfix - -- Update build dependencies (razzle and react-dev-utils) @davisagli [#3997](https://github.com/plone/volto/issues/3997) -- Added block prop to BlockDataForm in the Edit component of ToC. If block is not passed, OnChangeBlock will be called with undefined block id. @tedw87 [#4110](https://github.com/plone/volto/issues/4110) -- Fix focus steal in Form @tedw87 [#4230](https://github.com/plone/volto/issues/4230) -- Fixed paste issue in Table Block and added cypress test for pasting text in Table Block. [#4301](https://github.com/plone/volto/issues/4301) -- Fixed i18n script to avoid overwriting translations with an empty msgstr @danalvrz [#4316](https://github.com/plone/volto/issues/4316) -- bugfix: conditionally render all delete items in confirm widget [#4336](https://github.com/plone/volto/issues/4336) -- Make the Site Setup control panel responsive for small screen devices. @lord2anil [#4484](https://github.com/plone/volto/issues/4484) -- The menu for the contents page was unresponsive on mobile devices. Fixed this by changing the menu overflow to scroll. @sudhanshu1309 [#4492](https://github.com/plone/volto/issues/4492) -- Make Drag and Drop list work with container-type inline-size. @robgietema [#4497](https://github.com/plone/volto/issues/4497) -- (fix): Paste button disappearing while coping from nested blocks @dobri1408 [#4505](https://github.com/plone/volto/issues/4505) -- Patch updates for some dependencies. @davisagli [#4520](https://github.com/plone/volto/issues/4520) -- Fix flaky Cypress test introduced in #4521 @sneridagh [#4522](https://github.com/plone/volto/issues/4522) - -### Documentation - -- Fix training urls @ksuess [#4502](https://github.com/plone/volto/issues/4502) -- Add upgrade guide for 4504 @sneridagh [#4542](https://github.com/plone/volto/issues/4542) - - -## 17.0.0-alpha.1 (2023-03-09) - -### Feature - -- - 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.21.1 (2023-06-23) - -### Bugfix - -- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) - - -## 16.21.0 (2023-06-16) - -### Feature - -- Display PAS validation errors. [tschorr] [#4801](https://github.com/plone/volto/issues/4801) -- Allow to deselect color in ColorPickerWidget. @ksuess [#4838](https://github.com/plone/volto/issues/4838) -- Added a CSS identifier to the Slate style menu options. @razvanMiu [#4846](https://github.com/plone/volto/issues/4846) -- Use a Container from the registry in the Form component and fallback to the Semantic UI one. @sneridagh [#4849](https://github.com/plone/volto/issues/4849) -- Add and enforce a new config setting, `maxFileUploadSize`. @davisagli [#4868](https://github.com/plone/volto/issues/4868) -- Configurable Container component from registry for some key route views. @sneridagh [#4871](https://github.com/plone/volto/issues/4871) - -### Bugfix - -- Do not break validation on required number field with value 0 @cekk [#4841](https://github.com/plone/volto/issues/4841) -- Fix regression in horizontal scroll in contents view, add it back @sneridagh [#4872](https://github.com/plone/volto/issues/4872) -- Fix and improve the `addStyling` helper @sneridagh [#4880](https://github.com/plone/volto/issues/4880) - - -## 16.20.8 (2023-06-01) - -### Bugfix - -- Fix special characters in request urls @pnicolli @mamico @luca-bellenghi @cekk [#4826](https://github.com/plone/volto/issues/4826) -- Fix block is undefined in StyleWrapper helper when building classnames @sneridagh [#4827](https://github.com/plone/volto/issues/4827) -- Fix navigation sections in 404 pages @sneridagh [#4836](https://github.com/plone/volto/issues/4836) - -### Documentation - -- Fix glossary warning due to lack of empty line before a term. @stevepiercy [#4820](https://github.com/plone/volto/issues/4820) - - -## 16.20.7 (2023-05-24) - -### Bugfix - -- Fixed the issue "shouldn't use a hook like function name for a variable" @Kaku-g [#4693](https://github.com/plone/volto/issues/4693) -- Fix to not update breadrumbs, navigation, actions, and types when content is fetched as a subrequest and apiExpanders includes these components. @davisagli [#4760](https://github.com/plone/volto/issues/4760) -- Fix bug where editors could not see their own content in the Contents view if it was expired or has a future effective date. @davisagli [#4764](https://github.com/plone/volto/issues/4764) -- Fix bug showing logs at the browsers when richtext widget is use @claytonc [#4780](https://github.com/plone/volto/issues/4780) -- Add guard in case of malformed blocks are present (at least id and title should be present) @sneridagh [#4802](https://github.com/plone/volto/issues/4802) -- Fix html tag lang attribute in SSR @sneridagh [#4803](https://github.com/plone/volto/issues/4803) -- Add newest supported languages to `Language` constants list @sneridagh [#4811](https://github.com/plone/volto/issues/4811) - -### Internal - -- Remove max_line_length from .editorconfig @pnicolli [#4776](https://github.com/plone/volto/issues/4776) -- Fix unannounced breaking change in cypress-io/github-action @sneridagh [#4795](https://github.com/plone/volto/issues/4795) - - -## 16.20.6 (2023-05-12) - -### Bugfix - -- Fix language negotiation for language codes that include a region (e.g. `pt-br`). @davisagli [#4644](https://github.com/plone/volto/issues/4644) - - -## 16.20.5 (2023-05-12) - -### Bugfix - -- Apply suggestion from browser for password field @lord2anil [#3990](https://github.com/plone/volto/issues/3990) -- The tabs for the add page was unresponsive on mobile devices. Fixed this by changing flex-wrap property. @sudhanshu1309 [#4506](https://github.com/plone/volto/issues/4506) -- (fix):Object.normaliseMail: Cannot read properties of null @dobri1408 [#4558](https://github.com/plone/volto/issues/4558) - -### Internal - -- Upgrade to Plone 6.0.4 @sneridagh [#4743](https://github.com/plone/volto/issues/4743) - -### Documentation - -- Added documentation regarding the static middleware. @BhardwajAditya-github [#4518](https://github.com/plone/volto/issues/4518) -- Backport most documentation differences from `master` to `16.x.x`. @stevepiercy [#4727](https://github.com/plone/volto/issues/4727) -- Fix link in Volto, remove from linkcheck ignore in Documentation. @stevepiercy [#4742](https://github.com/plone/volto/issues/4742) - - -## 16.20.4 (2023-04-20) - -### Bugfix - -- Fix fetching API paths with urlencoded characters in the querystring. @davisagli [#4718](https://github.com/plone/volto/issues/4718) - -### Internal - -- Security upgrade for momentjs [#4716](https://github.com/plone/volto/issues/4716) - - -## 16.20.3 (2023-04-18) - -### Bugfix - -- Revert inadvertently included files from another PR in #4710 @sneridagh [#4713](https://github.com/plone/volto/issues/4713) - - -## 16.20.2 (2023-04-18) - -### Bugfix - -- Fix robot.txt - the sitemap link should respect x-forwarded headers @reebalazs [#4638](https://github.com/plone/volto/issues/4638) -- Fix Move to top of folder ordering in folder content view by searching also @iFlameing [#4690](https://github.com/plone/volto/issues/4690) -- Fix faulty D&D elements in ObjectBrowserList widget @sneridagh [#4703](https://github.com/plone/volto/issues/4703) - - -## 16.20.1 (2023-04-14) - -### Bugfix - -- Generate a split sitemap @reebalazs [#4638](https://github.com/plone/volto/issues/4638) -- Fix Move to top of folder ordering in folder content view @iFlameing [#4690](https://github.com/plone/volto/issues/4690) -- Revert "Add current page parameter to the route in the listing and search block pagination (#4159)" @sneridagh [#4695](https://github.com/plone/volto/issues/4695) -- Fix search block in edit mode re-queries multiple blocks with an empty search text @reebalazs [#4697](https://github.com/plone/volto/issues/4697) - - -## 16.20.0 (2023-04-12) - -### Feature - -- Support RelationList field with named StaticCatalogVocabulary and SelectWidget. @ksuess [#4614](https://github.com/plone/volto/issues/4614) -- Support for declaring a theme in `volto.config.js` or in `package.json` - Add two entry points to allow extension of a theme from other add-ons. @sneridagh [#4625](https://github.com/plone/volto/issues/4625) -- Added querystring search get option. @robgietema [#4658](https://github.com/plone/volto/issues/4658) - -### Bugfix - -- Added current page parameter to route in listing and search block pagination - Fix: #3868 @bipoza [#4159](https://github.com/plone/volto/issues/4159) -- Fixed wrong localization on password reset page @iRohitSingh [#4656](https://github.com/plone/volto/issues/4656) -- fix sitemap.xml.gz not is not compressed @dobri1408 [#4663](https://github.com/plone/volto/issues/4663) - -### Internal - -- Update to p.restapi 8.36.0 and Plone 6.0.3 @sneridagh [#4682](https://github.com/plone/volto/issues/4682) - -### Documentation - -- Update Volto contributing to align with and refer to the new Plone core code contributing requirements. @stevepiercy [#4634](https://github.com/plone/volto/issues/4634) -- Improve creating views documentation page. @rboixaderg [#4636](https://github.com/plone/volto/issues/4636) -- Rename "Developer Guidelines" to "Contributing". @stevepiercy [#4666](https://github.com/plone/volto/issues/4666) -- Fix broken link to `ReactJS.org`. @stevepiercy [#4667](https://github.com/plone/volto/issues/4667) - - -## 16.19.0 (2023-04-04) - -### Feature - -- DefaultView (view of fields for content types with blocks disabled): Show field name as tip on hover of label. @ksuess [#4598](https://github.com/plone/volto/issues/4598) -- Set sameSite in I18N_LANGUAGE cookie @sneridagh [#4627](https://github.com/plone/volto/issues/4627) - -### Bugfix - -- Fix regexp that checks valid URLs and improve tests [cekk] [#4601](https://github.com/plone/volto/issues/4601) - -### Documentation - -- Added `JavaScript` and `NodeJS` as accepted spellings, and deviations of them as rejected spellings. @utkkkarshhh [#3092](https://github.com/plone/volto/issues/3092) -- Fix documentation build, add pins @sneridagh [#4626](https://github.com/plone/volto/issues/4626) - - -## 16.18.0 (2023-03-22) - -### Feature - -- Add Vale to CI for spell and style checks. @MAX-786 [#4423](https://github.com/plone/volto/issues/4423) - -### Bugfix - -- Patch updates for some dependencies. @davisagli [#4520](https://github.com/plone/volto/issues/4520) -- InternalURl helper method should incorporate externalRoutes settings into consideration. @iFlameing [#4559](https://github.com/plone/volto/issues/4559) -- Update message add-on control panel: remove 'buildout', update reference. @ksuess [#4574](https://github.com/plone/volto/issues/4574) - -### Documentation - -- Fix broken links at `ReactJS.org`. @stevepiercy [#4569](https://github.com/plone/volto/issues/4569) -- Fix video warnings and link errors. @stevepiercy [#4578](https://github.com/plone/volto/issues/4578) - - -## 16.17.1 (2023-03-16) - - ### Bugfix - - - Fix Search is case sensitive in Block chooser @iRohitSingh [#4526](https://github.com/plone/volto/issues/4526) - - ### Documentation - - - Deleted duplicate import and fixed training URLs. @yahya-cloud [#4523](https://github.com/plone/volto/issues/4523) - - -## 16.17.0 (2023-03-15) - -### Feature - -- Add option to hide empty listing blocks @ksuess [#4393](https://github.com/plone/volto/issues/4393) - -### Bugfix - -- Added block prop to BlockDataForm in the Edit component of ToC. If block is not passed, OnChangeBlock will be called with undefined block id. @tedw87 [#4110](https://github.com/plone/volto/issues/4110) -- Fix focus steal in Form @tedw87 [#4230](https://github.com/plone/volto/issues/4230) -- Fixed paste issue in Table Block and added cypress test for pasting text in Table Block. [#4301](https://github.com/plone/volto/issues/4301) -- Fixed i18n script to avoid overwriting translations with an empty msgstr @danalvrz [#4316](https://github.com/plone/volto/issues/4316) -- bugfix: conditionally render all delete items in confirm widget [#4336](https://github.com/plone/volto/issues/4336) -- Make the Site Setup control panel responsive for small screen devices. @lord2anil [#4484](https://github.com/plone/volto/issues/4484) -- The menu for the contents page was unresponsive on mobile devices. Fixed this by changing the menu overflow to scroll. @sudhanshu1309 [#4492](https://github.com/plone/volto/issues/4492) -- (fix): Paste button disappearing while coping from nested blocks @dobri1408 [#4505](https://github.com/plone/volto/issues/4505) -- Fix flaky Cypress test introduced in #4521 @sneridagh [#4522](https://github.com/plone/volto/issues/4522) - -### Documentation - -- Fix training urls @ksuess [#4502](https://github.com/plone/volto/issues/4502) - - -## 16.16.0 (2023-03-09) - -### Feature - -- Add directive to cache stable resources in browser or intermediate server for 365 days by default directly in the SSR Express server, static resource that could change after a new deployment for 1 minute. @mamico [#2216](https://github.com/plone/volto/issues/2216) - - -## 16.15.0 (2023-03-08) - -### Feature - -- 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/pull/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.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) - -### Breaking - -- 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 - -### Feature - -- 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 -- Updated Spanish translation @macagua - -### Bugfix - -- 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 - -### Internal - -- 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 - -### Documentation - -## 16.0.0-alpha.48 (2022-11-03) - -### Bugfix - -- Ensure the view component is always replaced after navigating to a different page. @davisagli - -## 16.0.0-alpha.47 (2022-11-02) - -### Feature - -- Add clear button in search field of Folder content view @iFlameing -- consume site_actions from restapi @nileshgulia1 -- Updated Spanish translation @macagua - -### Bugfix - -- Fix `schemaEnhancer` not being applied if nested `blocksConfig` is present @sneridagh - -### Internal - -- Add translation for `pending` state @iFlameing -- Add `composeSchema`, a helper to compose multiple schemaEnhancers @tiberiuichim -- Upgrade to `plone.voltoa14` @sneridagh - -### Documentation - -- Fix grammar in Theming Strategy. Fixes #954. @stevepiercy -- Fix wording in About Semantic UI. Fixes #953. @stevepiercy - -## 16.0.0-alpha.46 (2022-10-28) - -### Breaking - -- 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 - -See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- 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 - -### 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 - -- 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 - -### Documentation - -- Add NodeJS 18 (LTS) usage notice @sneridagh -- Fix Netlify build @sneridagh - -## 16.0.0-alpha.45 (2022-10-24) - -### Feature - -- 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 - -### Bugfix - -- Make sure that the store is reset on history reducer `PENDING` state @sneridagh - -### Documentation - -- Update supported Python versions. @stevepiercy - -## 16.0.0-alpha.44 (2022-10-20) - -### Breaking - -- The listing block icon has been improved to avoid confusions with the normal text list @sneridagh - -### Bugfix - -- SearchTags uses invalid vocabulary API @silviubogan -- Fix autocomplete widget with an empty search result @reebalazs - -## 16.0.0-alpha.43 (2022-10-17) - -### Feature - -- Object browser: image search should only show images @reebalazs -- Updated spanish translation @macagua -- Add Dutch translation @spereverde -- Add control panel for relations. @ksuess - -### Bugfix - -- 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 - -### Internal - -- Upgrade dependency rrule (optional dependency luxon removed) @ksuess - -### Documentation - -- Trigger a new deploy core Plone documentation when Volto documentation is updated @esteele - -## 16.0.0-alpha.42 (2022-10-06) - -### Breaking - -- Change history route name to `historyview` (same as classic) in order to allow content to have 'history' as `id` @danielamormocea - -### Feature - -- 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 - -### Bugfix - -- 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 - -### Internal - -- Update to Plone 6 beta3 @sneridagh -- Upgrade Cypress to latest @sneridagh - -### Documentation - -- Update README with latest versions, point to Plone 6 as recommended default @sneridagh - -## 16.0.0-alpha.41 (2022-10-05) - -### Breaking - -- Sentry integration is now lazy-loaded. The `sentryOptions` key from the `settings` registry becomes a callable that passes resolved sentry libraries. @tiberiuichim - - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- 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 - -### Bugfix - -- Extend Id widget validation rules to accept a dot "." @reebalazs - -### Internal - -- 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 - -## 16.0.0-alpha.40 (2022-10-01) - -### Feature - -- 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 - -### Bugfix - -- 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 - -### Internal - -- Run yarn deduplicate on dependencies. @davisagli - -### Documentation - -- Upgrade to Plone 6 beta 2 @sneridagh -- Flip testing matrix for acceptance tests, make Plone 6 principal subject, Plone 5 as secondary @sneridagh - -## 16.0.0-alpha.39 (2022-09-28) - -### Bugfix - -- Fix call to `@plone/scripts/i18n` (now a commonJS module) @sneridagh - -### Internal - -- Fix storybook build for Razzle 4 @sneridagh -- Update `@plone/scripts` to 2.1.1 @sneridagh - -## 16.0.0-alpha.38 (2022-09-27) - -### Breaking - -- Upgrade to Razzle 4 @davisagli -- Jest downgraded from 27 to 26 @davisagli - -See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Internal - -- Remove Razzle as direct dependency from @plone/scripts @sneridagh - -## 16.0.0-alpha.37 (2022-09-27) - -### Feature - -- Added resetOnCancel functionality in Form component @MdSahil-oss -- volto-slate: introduce style-menu @nileshgulia1 - -### Bugfix - -- 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 - -## 16.0.0-alpha.36 (2022-09-26) - -### Bugfix - -- 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 - -### Documentation - -- Added controls for the `actions` property of the `AlignWidget` storybook @JeffersonBledsoe #3671 -- Generic Setup -> `GenericSetup`. @stevepiercy - -## 16.0.0-alpha.35 (2022-09-21) - -### Breaking - -- `react-window` no longer a Volto dependency @sneridagh - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Bugfix - -- 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 - -### Documentation - -- 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 - -## 16.0.0-alpha.34 (2022-09-17) - -### Feature - -- Added new components `Aliases` for aliases control in Volto. Alias management in both controlpanel and object view. @andreiggr @avoinea - -### Bugfix - -- 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 - -### Internal - -### Documentation - -- Bring back "Guidelines for Contributing" - -## 16.0.0-alpha.33 (2022-09-15) - -### Breaking - -- Move Layout constants to `config.views.layoutViewsNamesMapping`. Complete the list. i18n the list. Improve Display component. @sneridagh - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- Complete eu translation @erral -- Complete es translation. @erral - -### Bugfix - -- 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 - -### Documentation - -- Clean up "design principles" and "contributing" - -## 16.0.0-alpha.32 (2022-09-14) - -### Bugfix - -- 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 - -### Internal - -### Documentation - -Undo html_static_path configuration in `plone/documentation`, and restore image and its referenced path in `plone/volto`. @stevepiercy - -## 16.0.0-alpha.31 (2022-09-12) - -### Bugfix - -- 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 - -### Documentation - -- Align `html_static_path` with `plone/documentation` and image path so that images render when docs build in both repos. @stevepiercy - -## 16.0.0-alpha.30 (2022-09-07) - -### Breaking - -- Main workflow change menu changed from Pastanaga UI simplification to classic Plone implementation. @sneridagh - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- 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 - -### Bugfix - -- 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 - -### Documentation - -- Make links relative to `_static` so that `plone/documentation` can pull them in, and fix broken link. @stevepiercy - -## 16.0.0-alpha.29 (2022-09-02) - -### Feature - -- Support for getting `selectableTypes` and `maximumSelectionSize` from `widgetProps` @sneridagh - -## 16.0.0-alpha.28 (2022-08-31) - -### Feature - -- Add clear formatting button to slate @robgietema - -### Bugfix - -- Fix array widget translation @robgietema -- Fix: TTW DX Layout disables IBlocks behavior and with it all the indexers and transformers @avoinea - -### Internal - -### Documentation - -- Fix copy / paste text in list @robgietema - -## 16.0.0-alpha.27 (2022-08-29) - -### Feature - -- Added placeholder param to widget, to change default placeholder @giuliaghisini - -### Bugfix - -- Fix Image gallery listing block variation only gets 25 if no query is set @sneridagh - -## 16.0.0-alpha.26 (2022-08-24) - -### Breaking - -- 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 - -### Feature - -- Add initialPath support to ObjectBrowser widget @robgietema - -## 16.0.0-alpha.25 (2022-08-24) - -### Feature - -- 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 - -### Bugfix - -- Fix sitemap.xml.gz @robgietema - -### Internal - -- Use component registry for default image, fallback to the local import @sneridagh - -## 16.0.0-alpha.24 (2022-08-22) - -### Feature - -- handle 'no connection' available error (408 error). @giuliaghisini - -### Bugfix - -- Fix overlapping for long words in Control Panel titles (added word-wrapping) @sneridagh - -## 16.0.0-alpha.23 (2022-08-18) - -### Breaking - -- change password-reset url to be consistent with Plone configuration @erral -- Simplify over the existing Component Registry API. The `component` key has been flattened for simplification and now it's mapped directly to the `component` argument of `registerComponent`. @sneridagh - -See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- 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 - -### Bugfix - -- Fix login form redirect when it was loaded with a trailing slash @davisagli -- Better de translation for Site Setup @davisagli - -### Internal - -- 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 - -## 16.0.0-alpha.22 (2022-08-05) - -### Breaking - -- The complete configuration registry is passed to the add-ons and the project configuration pipeline - 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 - -- Fix content loading in `DefaultView` infinite loop if a listing block with no query is present. @sneridagh - -### Documentation - -- Documentation of the new component registry API @sneridagh - -## 16.0.0-alpha.21 (2022-08-03) - -### Bugfix - -- Fix ArrayWidget choices when editing a recently created content item. @davisagli - -### Internal - -- Fix propTypes for Pagination component @davisagli - -## 16.0.0-alpha.20 (2022-08-01) - -### 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://6.docs.plone.org/volto/upgrade-guide/index.html for more information. @sneridagh - -### Bugfix - -- Make Search page title translatable @erral -- Changed storeProtectLoadUtils location from src/storeProtectLoadUtils to src/middleware/storeProtectLoadUtils @MdSahil-oss - -### Documentation - -- Minor clean up of volto-slate upgrade guide. @stevepiercy - -- Rework documentation on how to write a Slate plugin @ksuess - -## 16.0.0-alpha.19 (2022-07-28) - -### Breaking - -- Using volto-slate Headline / Subheadline buttons strips all elements in the selection @tiberiuichim - -### Feature - -- Send extra data coming from listing block schemaEnhancer from searchBlock to the listing variation @ionlizarazu - -### Bugfix - -- 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 - -### Internal - -- Allow passing `allowedChildren` option to the BlockButton, to strip elements in headlines @tiberiuichim -- Upgrade to latest `@plone/scripts` @sneridagh -- Update browserlist definitions @sneridagh - -### Documentation - -- Add upgrade guide documentation for dealing with `volto-slate` upgrades for Volto 16 alpha 15 onwards. @sneridagh - -## 16.0.0-alpha.18 (2022-07-26) - -### Breaking - -- 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 - -### Bugfix - -- 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 - -### Internal - -- Fix `defaultBlockType` entry in default config, set it to slate. @sneridagh - -## 16.0.0-alpha.17 (2022-07-25) - -### Feature - -- Added the `Undo controlpanel` to the controlpanels which can be used to undo transactions. @MdSahil-oss - -### Bugfix - -- Make `crypto-random-string` a direct dep, fixing a hidden error since some updated dependency was requiring it directly but not anymore. @sneridagh - -## 16.0.0-alpha.16 (2022-07-25) - -### Do not use, this is a brown bag release - -See: https://github.com/plone/volto/pull/3505 -Use next release instead: https://github.com/plone/volto/releases/tag/16.0.0-alpha.17 - -### Breaking - -- Staticize Poppins font to be compliant with EU privacy. Import from GoogleFont is disabled in site.variables. @giuliaghisini - -### Bugfix - -- 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 - -### Internal - -- Update json-schema including transitive dependencies @davisagli -- Update release-it @davisagli -- Deduplicate dependencies using yarn-deduplicate @davisagli - -### Documentation - -- Fix redirect on YouTube, broken link after merge and deleted branch. @stevepiercy - -## 16.0.0-alpha.15 (2022-07-21) - -### Breaking - -- Integrate volto-state add-on. @tiberiuichim @razvanmiu @eea - -### Documentation - -- volto-slate documentation @nileshgulia1 - -## 16.0.0-alpha.14 (2022-07-20) - -### Breaking - -- Action `listUsers`to be called with Object. Distinguish between search for id or search for fullname, email, username @ksuess - -### Feature - -- Add user group membership control panel @ksuess -- Action `listUsers`: Support search for fullname, email, username. @ksuess - -### Bugfix - -- Fix typo in de locale @wolbernd - -## 16.0.0-alpha.13 (2022-07-18) - -### Feature - -- Add schema to video block sidebar @iRohitSingh @danielamormocea - -### Bugfix - -- 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 - -### Documentation - -- `aria-*` attributes are now parsed correctly by jsx-lexer 2.0. @stevepiercy - -## 16.0.0-alpha.12 (2022-07-13) - -### Feature - -- 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 - -### Bugfix - -- Fixed the description field not being included in the navigation action/ reducer @JeffersonBledsoe #3454 -- Fixed a11y of Maps block (#3467) @iRohitSingh - -### Internal - -- Mock all loadable libraries. @mamico - -### Documentation - -- 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 - -## 16.0.0-alpha.11 (2022-06-21) - -### Feature - -- 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 - -### Internal - -- Fix warning because missing key in `VersionOverview` component @sneridagh - -## 16.0.0-alpha.10 (2022-06-17) - -### Bugfix - -- 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 - -## 16.0.0-alpha.9 (2022-06-17) - -### Feature - -- New `cloneDeepSchema` helper @sneridagh - -### Bugfix - -- 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 - -## 16.0.0-alpha.8 (2022-06-17) - -### Feature - -- 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 - -### Bugfix - -- 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 - -## 16.0.0-alpha.7 (2022-06-01) - -### Bugfix - -- fix schema when content contains lock informations. @giuliaghisini - -### Internal - -- 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 - -## 16.0.0-alpha.6 (2022-05-31) - -### Breaking - -- 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 - -### Feature - -- 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 - -### Bugfix - -- 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 - -## 16.0.0-alpha.5 (2022-05-25) - -### Bugfix - -- Fix regression, compound lang names (eg. `pt-BR`) no longer working @sneridagh - -## 16.0.0-alpha.4 (2022-05-22) - -### Breaking - -- 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 - -### Feature - -- 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 - -### Bugfix - -- 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 - -### Internal - -- Update `Cypress` to version 9.6.1 @sneridagh - -### Documentation - -- Updated `simple.md` @MdSahil-oss -- Fix indentation in nginx configuration in `simple.md` @stevepiercy - -## 16.0.0-alpha.3 (2022-05-16) - -### Breaking - -- 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 - -## 16.0.0-alpha.2 (2022-05-16) - -### Feature - -- 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 - -### Bugfix - -- fixed view video list from youtube in Video block. @giuliaghisini -- Fixed ICS URL in event view in seamless mode @sneridagh - -### Internal - -- 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 - -### Documentation - -- fix make task `docs-linkcheckbroken` if grep has exit code 1 (no lines found) - -## 16.0.0-alpha.1 (2022-05-09) - -### Feature - -- 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 - -## 16.0.0-alpha.0 (2022-05-06) - -### 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 - -### Feature - -- Allow final users to switch between available views in the search block. A "view" is any of available listing block variations. In the search block configuration you can pick the available views for that block. @tiberiuichim - -### Bugfix - -- Fixes in search block. Disable default live search. Added clear button for search input. Fixed facet dropdown clear button. Removed sort on label customization option. Layout improvements, CSS polishments. @kreafox @tiberiuichim -- added default placeholder for videos to embed them more lightly @giuliaghisini -- Added default placeholder for videos to embed them more lightly @giuliaghisini -- Completed Romanian translation @sboghy - -### 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 missing criteria in QueryWidget. @giuliaghisini -- 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 different querystring filters in the querystring widget @kreafox -- Fix for clipped dropdown menus when the table has few or no records in Contents view @mihaislobozeanu - -### 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 -- Fixed Storybook configuration for add-ons @pnicolli - -### 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 -- Proper case HAProxy, nginx, and Docker Compose. @stevepiercy - -## 15.8.0 (2022-04-30) - -### Feature - -- Handle @@display-file api endpoint like @@download @cekk -- Add calendar link to @ics_view @iFlameing - -## 15.7.0 (2022-04-29) - -### Feature - -- added 'secure' cookie option if site is in https. @giuliaghisini - -## 15.6.1 (2022-04-29) - -### Bugfix - -- Overwrite isValidNewOption of ArrayWidget to allow variants @ksuess - -## 15.6.0 (2022-04-29) - -### Feature - -- Added 'checkAndNormalizeUrl' function in URLUtils. @giuliaghisini - -### Bugfix - -- Used UniversalLink and PreviewImage components where needed, to right handle link and images. @giuliaghisini - -## 15.5.0 (2022-04-25) - -### Feature - -- More Italian translations @giuliaghisini - -### Bugfix - -- Fixed edit internal link and image url in this blocks: image block, leadimage block, video block, objectBrowser. In objectBrowser, if pasted url was internal, it wasn't flatted and wass handled from Plone as an external. @giuliaghisini -- Fix folder content layout @SaraBianchi - -### Documentation - -- Added a `selectableTypes` example to the `ObjectBrowserWidget` storybook @JeffersonBledsoe #3255 -- Add labels for Intersphinx. @stevepiercy - -## 15.4.1 (2022-04-11) - -### Bugfix - -- Fix handling of single reference field in `ObjectBrowser` @robgietema -- Make the parseDateTime function to handle only date as well @iFlameing -- Fix ContextNavigation component with Link type objects @UnaiEtxaburu #3232 - -### Internal - -- Upgrade react-image-gallery to latest to fix a11y problem @sneridagh -- Fixed bug in HTML block edit @giuliaghisini -- Fix cannot read properties of undefined in Content.jsx @iFlameing -- Fix fixed `ObjectBrowserBody` to handle data fields based on `ObjectBrowser` mode @giuliaghisini - -## 15.4.0 (2022-04-08) - -### Feature - -- Add package.json scripts documentation @ksuess - -### Bugfix - -- Fix/Improve the console logging when the server starts. @sneridagh - -### Documentation - -- Added html_meta values to remaining pages. @stevepiercy -- Remove duplicate toctrees and set maxdepth to appropriate values. @stevepiercy - -## 15.3.0 (2022-04-04) - -### Feature - -- Improve the fix for the "user swap" vulnerability @sneridagh @plone/volto-team - Thanks to @ericof and @cekk for their help and efforts at pinpointing the latests culprits! - -### Documentation - -- Added meta-html values in most of the pages. @ktsrivastava29 - -## 15.2.3 (2022-04-01) - -### Bugfix - -- Change which api calls can set specific api errors @robgietema -- Fix helper import. @robgietema -- Move `customStyleMap` to `richtextEditorSettings` -- Pass placeholder and isDisabled properties to EmailWidget and UrlWidget @mihaislobozeanu -- Pass placeholder property to PasswordWidget and NumberWidget @mihaislobozeanu -- Fix getVocabName when vocabNameOrURL is false @avoinea #2955, #2919 - -### Internal - -- Remove offending `Makefile` command that broke on MacOS due to lack of compatibility of the MacOS `make` utility. @tisto -- Upgraded use-deep-compare-effect to version 1.8.1. @pnicolli -- chore(icons): add missing pastanaga icons @nileshgulia1 - -### Documentation - -- Switch from `docs-linkcheckbroken` to `docs-linkcheck` in GitHub Actions because the former is broken. @stevepiercy -- Set the output for storybook to the correct directory. @stevepiercy -- Fix typo in Makefile: docs/\_build @ksuess -- Added language to code-blocks in md files @ktsrivastava29 - -## 15.2.2 (2022-03-23) - -### Bugfix - -- Fix external url append issue of @@download/file @iRohitSingh -- Fix headers in sitemap middleware when errors occur in the sitemap generation @mamico - -## 15.2.1 (2022-03-21) - -### Bugfix - -- `Manage translations` view error on seamless mode, `flattenToAppURL` missing. @sneridagh - -### Documentation - -- Reenable `make docs-linkcheckbroken`. @stevepiercy -- Add html_meta values to add-on best practices, s/addon/add-on. @stevepiercy -- Netlify now only builds on changes to the `./docs/` directory. @stevepiercy -- Replace deprecated `egrep` with `grep` in `make docs-linkcheckbroken`. @stevepiercy - -## 15.2.0 (2022-03-18) - -### Feature - -- Add helper utilities to be used by addons @robgietema - -### Bugfix - -- Fix addon registry regression @sneridagh -- Fix `Bosnian` language @avoinea -- Fix use `settings.internalApiPath` in sitemap genaration @mamico - -### Documentation - -- Reduced build minutes on Netlify by building only on changes to the `docs/**` path on pull requests. See https://github.com/plone/volto/pull/3171. @stevepiercy -- Add "Documentation" heading to the automatic change log updater file `changelogupdater.js`. @stevepiercy - -## 15.1.2 (2022-03-17) - -### Bugfix - -- Fix the alt prop in `PreviewImage` component @sneridagh - -## 15.1.1 (2022-03-16) - -### Bugfix - -- Add optional alt tag to `PreviewImage` props @kindermann -- Remove non add-on names from `addonNames` list in Addons Registry. Update the list in the `addonsInfo` for the addons loader as well. @sneridagh - -## 15.1.0 (2022-03-15) - -### Feature - -- Added a new component, PreviewImage. It renders a preview image for a catalog brain (based on the `image_field` prop). @tiberiuichim - -### Bugfix - -- Clear search results before new query is done. @robgietema - -### Documentation - -- 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 - -## 15.0.0 (2022-03-14) - -### Breaking - -- Upgrade `react-cookie` to the latest version. @sneridagh @robgietema - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. -- Language Switcher no longer takes care of the change of the language on the Redux Store. This responsibility has been unified in the API Redux middleware @sneridagh -- Markup change in `LinkView` component. -- Rename `core-sandbox` to `coresandbox` for sake of consistency @sneridagh -- Extend the original intent and rename `RAZZLE_TESTING_ADDONS` to `ADDONS`. @sneridagh - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. -- Lazyload Draft.js library. See the upgrade guide on how that impacts you, in case you have extended the rich text editor configuration @tiberiuichim @kreafox - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. -- Deprecating `lang` cookie in favor of Plone official one `I18N_LANGUAGE` @sneridagh - -### Feature - -- Add `cookiesExpire` value to config to control the cookie expiration @giuliaghisini -- DatetimeWidget 'noPastDates' option: Take widgetOptions?.pattern_options?.noPastDates of backend schema into account. @ksuess -- Add a new type of filter facet for the Search block. Heavily refactor some searchblock internals. @tiberiuichim -- Add date range facet to the search block @robgietema -- Introduce the new `BUILD_DIR` runtime environment variable to direct the build to run in a specific location, different than `build` folder. @sneridagh -- Handle redirect permanent calls from the backend in the frontend (e.g. when changing the short name) @robgietema -- Added id widget to manage short name @robgietema -- Refactor language synchronizer. Remove it from the React tree, integrate it into the Api Redux middleware @sneridagh -- Add blocks rendering in Event and NewsItem views (rel plone.volto#32) @nzambello @ksuess -- Add internal volto ids to invalid ids @robgietema -- Complete Basque translation @erral -- Complete Spanish translation @erral -- Sort the choices in Facets in the search block @iFlameing - -### Bugfix - -- Fix the `null` error in SelectAutoComplete Widget @iFlameing -- Prevent the `MultilingualRedirector` to force content load when switching the language @reebalazs -- Fix the upload image in contents view @iFlameing -- add "view" id to contact-form container for main content skiplink @ThomasKindermann -- Fix loading indicator positioning on Login form submit @sneridagh -- Fix redirect bug with URLs containing querystrings @robgietema -- Fixed id widget translations @robgietema -- Contents Rename Modal, use `id` Widget type @sneridagh -- Fix overflow of very long file name in `FileWidget` @sneridagh -- Fix overflowing issue in the toolbar @kreafox -- Overwrite current block on insert new block. @robgietema -- Fix hot reload on updates related to the config object because of `VersionOverview` component @sneridagh -- Fix error when lock data is gone after an invariant error. @robgietema -- Protect against ghost content loading and scroll to top @reebalazs - -### Internal - -- Change prop `name` -> `componentName` in component `Component` @sneridagh -- Add new RawMaterial Volto websites in production @nzambello -- House cleanup, remove some unused files in the root @sneridagh -- Move Webpack related files to `webpack-plugins` folder @sneridagh -- Remove unused Dockerfiles @sneridagh -- Update Docker compose to latest images and best practices @sneridagh -- Improve flaky test in coresandbox search Cypress tests @sneridagh -- Better implementation of the add-on load coming from the environment variable `ADDONS` @sneridagh -- Turn `lazyLibraries` action into a thunk. Added a conditional if the library is loaded or in process to be loaded, do not try to load it again. This fixes the lag on load `draftjs` when having a lot of draftjs blocks. @sneridagh -- Use `@root` alias instead of `~` in several module references. Most of the Volto project code no longer needs the root alias, so it makes sense to phase it out at some point @tiberiuichim -- Alias `lodash` to `lodash-es`, as this will include only one copy of lodash in the bundle @tiberiuichim -- Better Readme, updated to 2022 @sneridagh -- Update to latest versions for Python packages @sneridagh -- Add `id` as widget type as well @sneridagh - -### Documentation - -- Upgrade Guide i18n: Make clear what's project, what add-on. @ksuess -- (Experimental) Prepare documentation for MyST and importing into `plone/documentation@6-dev`. @stevepiercy -- Fix broken links and redirects in documentation to be compatible with MyST. @stevepiercy -- Update add-on internationalization. @ksuess -- Add MyST and Sphinx basic configuration for rapid build and comparison against MkDocs builds. @stevepiercy -- Fix many MyST and Sphinx warnings. @stevepiercy -- Remove MkDocs configuration. See https://github.com/plone/volto/issues/3042 @stevepiercy -- Add Plone docs to Intersphinx and fix broken link. @stevepiercy -- Get version from `package.json` @sneridagh -- Remove legacy folder in docs @sneridagh -- Backport docs of RAZZLE_TESTING_ADDONS environment variables. See https://github.com/plone/volto/pull/3067/files#diff-00609ed769cd40cf3bc3d6fcc4431b714cb37c73cedaaea18fe9fc4c1c589597 @stevepiercy -- Add missing developer-guidelines/typescript to toctree @stevepiercy -- Add Netlify for preview of Sphinx builds for pull requests against `master` and `plone6-docs`. @stevepiercy -- Clean up toctree errors by removing obsolete files, adding `:orphan:` field list, and reorganizing some files. @sneridagh and @stevepiercy -- Switch to using netlify.toml to configure Netlify Python environment. @stevepiercy -- Convert admonition syntax from Markdown to MyST. @sneridagh -- Make links build both in Volto and Plone documentation. See https://github.com/plone/volto/pull/3094 @stevepiercy -- Fix broken links. @stevepiercy -- Update Sphinx configuration to check anchors in links and exclude problematic URLs. @sneridagh and @stevepiercy -- Fix StoryBook links @sneridagh -- Clean up `linkcheck_ignore` values. @stevepiercy - -## 15.0.0-alpha.14 (2022-03-10) - -### Bugfix - -- Contents Rename Modal, use `id` Widget type @sneridagh - -### Internal - -- Better Readme, updated to 2022 @sneridagh -- Update to latest versions for Python packages @sneridagh -- Add `id` as widget type as well @sneridagh - -### Documentation - -- Fix broken links. @stevepiercy - -## 15.0.0-alpha.13 (2022-03-09) - -### Feature - -- Sort the choices in Facets in the search block @iFlameing - -### Bugfix - -- Fix overflow of very long file name in `FileWidget` @sneridagh -- Fix overflowing issue in the toolbar @kreafox - -## 15.0.0-alpha.12 (2022-03-07) - -### Feature - -- Add internal volto ids to invalid ids @robgietema -- Complete basque translation @erral -- Complete spanish translation @erral - -### Internal - -- Change prop `name` -> `componentName` in component `Component` @sneridagh - -## 15.0.0-alpha.11 (2022-03-02) - -### Bugfix - -- Fix redirect bug with URLs containing querystrings @robgietema -- Fixed id widget translations @robgietema - -### Internal - -- Use `@root` alias instead of `~` in several module references. Most of the Volto project code no longer needs the root alias, so it makes sense to phase it out at some point @tiberiuichim -- Alias `lodash` to `lodash-es`, as this will include only one copy of lodash in the bundle @tiberiuichim - -## 15.0.0-alpha.10 (2022-02-28) - -### Bugfix - -- Turn `lazyLibraries` action into a thunk. Added a conditional if the library is loaded or in process to be loaded, do not try to load it again. This fixes the lag on load `draftjs` when having a lot of draftjs blocks. @sneridagh - -## 15.0.0-alpha.9 (2022-02-28) - -### Breaking - -- Deprecating `lang` cookie in favor of Plone official one `I18N_LANGUAGE` @sneridagh - -### Feature - -- Added id widget to manage short name @robgietema -- Refactor language syncronizer. Remove it from the React tree, integrate it into the Api Redux middleware @sneridagh -- Add blocks rendering in Event and NewsItem views (rel plone.volto#32) @nzambello @ksuess - -### Bugfix - -- Fix redirect bug with URLs containing querystrings @robgietema - -## 15.0.0-alpha.8 (2022-02-22) - -### Internal - -- Better implementation of the add-on load coming from the environment variable `ADDONS` @sneridagh - -## 15.0.0-alpha.7 (2022-02-22) - -### Feature - -- Introduce the new `BUILD_DIR` runtime environment variable to direct the build to run in an especific location, different than `build` folder. @sneridagh -- Handle redirect permanent calls from the backend in the frontend (e.g. when changing the short name) @robgietema - -## 15.0.0-alpha.6 (2022-02-21) - -### Feature - -- DatetimeWidget 'noPastDates' option: Take widgetOptions?.pattern_options?.noPastDates of backend schema into account. @ksuess -- Add a new type of filter facet for the Search block. Heavily refactor some searchblock internals. @tiberiuichim -- Add date range facet to the search block @robgietema - -### Internal - -- Improve flaky test in coresandbox search Cypress tests @sneridagh - -### Documentation - -- (Experimental) Prepare documentation for MyST and importing into `plone/documentation@6-dev`. @stevepiercy -- Fix broken links and redirects in documentation to be compatible with MyST. @stevepiercy -- Update add-on internationalization. @ksuess -- Add MyST and Sphinx basic configuration for rapid build and comparison against MkDocs builds. @stevepiercy -- Fix many MyST and Sphinx warnings. @stevepiercy -- Remove MkDocs configuration. See https://github.com/plone/volto/issues/3042 @stevepiercy -- Add Plone docs to Intersphinx and fix broken link. @stevepiercy -- Get version from `package.json` @sneridagh -- Remove legacy folder in docs @sneridagh -- Backport docs of RAZZLE_TESTING_ADDONS environment variables. See https://github.com/plone/volto/pull/3067/files#diff-00609ed769cd40cf3bc3d6fcc4431b714cb37c73cedaaea18fe9fc4c1c589597 @stevepiercy -- Add missing developer-guidelines/typescript to toctree @stevepiercy -- Add Netlify for preview of Sphinx builds for pull requests against `master` and `plone6-docs`. @stevepiercy -- Clean up toctree errors by removing obsolete files, adding `:orphan:` field list, and reorganizing some files. @sneridagh and @stevepiercy -- Switch to using netlify.toml to configure Netlify Python environment. @stevepiercy -- Convert admonition syntax from Markdown to MyST. @sneridagh -- Make links build both in Volto and Plone documentation. See https://github.com/plone/volto/pull/3094 @stevepiercy - -## 15.0.0-alpha.5 (2022-02-16) - -### 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://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- Add `cookiesExpire` value to config to control the cookie expiration @giuliaghisini - -## 15.0.0-alpha.4 (2022-02-16) - -### Breaking - -- Markup change in `LinkView` component. -- Rename `core-sandbox` to `coresandbox` for sake of consistency @sneridagh -- Extend the original intent and rename `RAZZLE_TESTING_ADDONS` to `ADDONS`. @sneridagh - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Internal - -- House cleanup, remove some unused files in the root @sneridagh -- Move Webpack related files to `webpack-plugins` folder @sneridagh -- Remove unused Dockerfiles @sneridagh -- Update Docker compose to latest images and best practices @sneridagh - -## 15.0.0-alpha.3 (2022-02-11) - -### Bugfix - -- Fix the upload image in contents view @iFlameing -- add "view" id to contact-form container for main content skiplink @ThomasKindermann -- Fix loading indicator positioning on Login form submit @sneridagh - -### Internal - -- Add new RawMaterial Volto websites in production @nzambello - -## 15.0.0-alpha.2 (2022-02-10) - -### Breaking - -- Language Switcher no longer takes care of the change of the language on the Redux Store. This responsability has been unified in the `MultilingualRedirector` @sneridagh - -### Bugfix - -- Prevent the MultilingualRedirector to force 4 content load when switching the language @reebalazs - -### Documentation - -- Upgrade Guide i18n: Make clear what's project, what add-on. @ksuess - -## 15.0.0-alpha.1 (2022-02-09) - -### Bugfix - -- Fix the `null` error in SelectAutoComplete Widget @iFlameing - -## 15.0.0-alpha.0 (2022-02-09) - -### Breaking - -- Upgrade `react-cookie` to latest version. @sneridagh @robgietema - See https://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -## 14.10.0 (2022-02-08) - -### Feature - -- Add Pluggable to toolbar user menu. @ksuess - -## 14.9.0 (2022-02-08) - -### Feature - -- Show addons installed in control panel @sneridagh -- Added a search input in the block chooser @bipoza - -### Bugfix - -- Fix italian translations in ObjectBrowser @giuliaghisini - -## 14.8.1 (2022-02-04) - -### Bugfix - -- Fix wrong CSS in language independent class selector @sneridagh - -### Internal - -- Cleanup redundant buildout install run. - -## 14.8.0 (2022-02-03) - -### Feature - -- Enable `components` property in Volto's config registry. Does not expose any direct feature but this will open the door to be able to override registered components using the config registry and avoid using shadowing explicitly. @sneridagh -- Add `resolve` and `register` helper methods for the Volto config. They retrieve and register new components in the registry. @tiberiuichim @sneridagh -- Add `Component` component, given a `name` of a component registered in the registry, it renders it, passing down the props. @tiberiuichim -- Syncronize the content language with the UI language in multilingual sites. So when you are accessing a content in a given language the rest of the interface literals follow along (it updates the language cookie). So the UI remains consistent. @sneridagh - -### Bugfix - -- Fix the a11y violation of UrlWidget @iRohitSingh - -### Internal - -- Update volta pins in package.json @fredvd - -## 14.7.1 (2022-02-02) - -### Internal - -- Add CSS body class in Babel view. Improve marker for language independent fields in Babel view too. @sneridagh - -### Docs - -Update documentation for internal proxy & other smaller reorganisation for quicker onboarding of -new users/evaluators. @fredvd - -## 14.7.0 (2022-01-28) - -### Feature - -- Add `` and `` components. Check their Storybook stories for details. This is part of ongoing work to minimize the use of 'deprecated' momentjs. @sneridagh @tiberiuichim - -### Internal - -- Upgrade jest to latest release, 27 major. @tiberiuichim -- Lazyload momentjs. `parseDateTime` helper now requires passing the momentjs library @tiberiuichim - -## 14.6.0 (2022-01-27) - -### Feature - -- Use `volto.config.js` as dynamic configuration for addons. It adds up to the `package.json` `addons` key, allowing dynamic load of addons (eg. via environment variables) @sneridagh - -### Internal - -- Fix ObjectListWidget story bug caused by lazyloading dnd libraries - @tiberiuichim - -## 14.5.0 (2022-01-26) - -### Feature - -- VocabularyTermsWidget: Token is now on creation of term editable, but stays ineditable afterwards. @ksuess - -### Bugfix - -- Fix A11Y violations in Navigation @iRohitSingh -- Fix `language-independent-field` CSS class styling @sneridagh - -### Internal - -- Lazyload react-beautiful-dnd @tiberiuichim -- Lazyload react-dnd @tiberiuichim -- Improve docs on environment variables, add recipes @sneridagh -- Update p.restapi to 8.20.0 and plone.volto to 4.0.0a1 and plone.rest to 2.0.0a2 @sneridagh - -## 14.4.0 (2022-01-21) - -### Feature - -- Language independent fields support in Volto forms @sneridagh - -## 14.3.0 (2022-01-20) - -### Feature - -- Bump semantic-ui-react to v2.0.3 @nileshgulia1 - -## 14.2.3 (2022-01-20) - -### Bugfix - -- Fix ListingBlock to add "No results" message when there are no messages @erral -- Fix overflow table in Content view @giuliaghisini -- Fixed url validation in FormValidation to admit ip addresses. @giuliaghisini -- Upgrade to plone.restapi 8.19.0 (to support the language independent fields serialization) @sneridagh - -## 14.2.2 (2022-01-13) - -### Bugfix - -- Fix home URL item in Navigation, which was evaluating as non-internal @sneridagh -- Improve the request handling in `getAPIResourceWithAuth` and in `Api` helper. This fixes the "Cannot set headers once the content has being sent" @sneridagh -- Fix when you remove the time from DatetimeWidget @iRohitSingh - -### Internal - -- Fix URL for Climate-Energy, a Volto website @tiberiuichim -- Fix quirky Cypress test in "DX control panel schema" @sneridagh - -## 14.2.1 (2022-01-12) - -### Bugfix - -- Fix home URL item in Navigation, which was evaluating as non-internal - -### Internal - -- Use plone-backend docker images for Cypress tests @sneridagh -- Upgrade `query-string` library so it supports Plone `:list` qs marker @sneridagh - -## 14.2.0 (2022-01-04) - -### Feature - -- Allow `creatable` prop to be passed to `ArrayWidgets`, in case they don't have a vocabulary @giuliaghisini -- Added initialBlocksFocus to blocks config, to set default focus on non-first block. @giuliaghisini - -## 14.1.1 (2022-01-03) - -### Internal - -- Update to plone.restapi 8.18.0, remove some defensive code in vocabularies action now that it's fixed in the backend @sneridagh - -## 14.1.0 (2021-12-31) - -### Feature - -- Added custom option to SelectWidget to render custom optionss (for example with icons) @giuliaghisini -- Added form undo support in the form of two buttons in the main toolbar and ctrl+z, ctrl+y as hotkeys for undo/redo. The undo capabilities are provided by a new helper hook, `useUndoManager`. @tiberiuichim - -### Bugfix - -- Fix query data in listing blocks ssr async call @cekk -- In the contact form, only display the "back" button in the toolbar @tiberiuichim -- Fixed selected widget to use isMulti prop @giuliaghisini - -### Internal - -- Allow the draftjs Text block edit to update the editor content when incoming block data is mutated outside the block (to support form undo) @tiberiuichim -- Remove use of internal component state for ArrayWidget, SelectWidget and TokenWidget, (to support form undo) @tiberiuichim -- Use lazy loading of react-dates and momentjs for the DatetimeWidget @tiberiuichim -- Improve widget stories, add a common `WidgetStory` class, show undo capabilities in widget stories @tiberiuichim -- Better SelectAutocompleteWidget and SelectUtils @giuliaghisini @sneridagh @tiberiuichim - -## 14.0.2 (2021-12-22) - -### Internal - -- Better favicon definitions, 2021 bullet proof @sneridagh - -## 14.0.1 (2021-12-21) - -### Bugfix - -- Construct request with list parameters as separate querystring key value pairs according Zope convention @ksuess -- Fix spelling in error message when backend is unreachable @instification - -## 14.0.0 (2021-12-20) - -### 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://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://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 -- New i18n infrastructure in the new `@plone/scripts` package @sneridagh -- Removed `src/i18n.js` in favor of the above change @sneridagh -- Adjusted main `Logo.jsx` default component styling @sneridagh -- Fix logout action using the backend @logout endpoint, effectively removing the `__ac` cookie. It is recommended to upgrade to the latest p.restapi version to take full advantage of this feature @sneridagh -- Improve mobile navigation menu with a nicer interaction and a fixed overlay with a drawer (customizable via CSSTransitionGroup) animation @sneridagh -- 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://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 -- 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 -- Add `volto-guillotina` addon to core @sneridagh -- Make `VocabularyTermsWidget` orderable @ksuess -- Get widget by tagged values utility function in the `Field` decider @ksuess -- 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://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 -- Image block: - - When uploading an image or selecting that from the object browser, Image block will set an empty string as alternative text @nzambello - - Adds a description to the alt-tag with w3c explaination @nzambello -- Support TypeScript usage in Volto projects @pnicolli -- Added `LinkMore` component and link more in `HeroImageLeft` block. @giuliaghisini -- In the search block, allow editors to specify the sort on criteria. - @tiberiuichim -- Added `.storybook` setup in the Volto `app` generator. Volto projects generated from this scafolding are now ready to run Storybook for the project and develop addons (in `src/addons` folder). -- Style checkboxes @nileshgulia1 -- Allow loading .less files also from a Volto project's `src` folder. @tiberiuichim -- Add catalan translation @bloodbare @sneridagh -- Updated Volto production sites list @giuliaghisini -- Japanese translation updated @terapyon -- German translations updated @tisto -- Updated italian translation @pnicolli -- Updated Brazilian Portuguese translations @ericof - -### Bugfix - -- Fix `SelectWidget` vocabulary load on second component mount @avoinea #2655 -- Fix `/edit` and `/add` `nonContentRoutes` to fix `isCmsUi` fn @giuliaghisini -- Register the dev api proxy after the express middleware @tiberiuichim -- Fix on form errors in block editor, not changing to metadata tab @sneridagh -- Fix SSR on `/edit` with dev proxy @tiberiuichim -- Fix logout action, removing the `__ac` cookie as well, if present. @sneridagh -- Do not show lead image block when the content type does not have the behavior enabled @sneridagh -- Missing default messages from JSON EN language file @sneridagh -- Show correct fieldname and not internal field id in Toast error messages on Add/Edit forms @jackahl -- `sitemap.xml.gz` obeys Plone Search settings @erral -- Get `blocks` and `blocks_layout` defaults from existing behavior when enabling TTW editable DX Layout @avoinea -- Yet another attempt at fixing devproxy. Split the devproxy into a separate devproxy verbose @tiberiuichim -- Add spinner on sharing View Button @iRohitSingh -- Fixed `SelectWidget`: when there was a selected value, the selection was lost when the tab was changed. @giuliaghisini -- Bugfixes to search block. By default search block, when empty, makes a simple - query to the nav root, to list all content. Fix reading search text from URL. - Implement a simple compression of URL. Don't count searched text as filter. - Fix an edge case with showSearchInput in schema. Rename title to Section - Title in facet column settings. Avoid double calls to querystring endpoint. - @tiberiuichim -- Use correct shade of black in Plone logo @sneridagh -- Fix loading of cookie on SSR for certain requests, revert slight change in how they are loaded introduced in alpha 16 @sneridagh -- Prevent `ua-parser-js` security breach. See: https://github.com/advisories/GHSA-pjwm-rvh2-c87w @thet -- Fix storybook errors in the connected components, api is undefined. Using now a mock of the store instead of the whole thing @sneridagh -- CSS fix on `QueryWidget` to prevent line jumping for clear button when the multi selection widget has multiple items @kreafox -- Fix disable mode of `QuerystringWidget` when all criteria are deleted @kreafox -- Fix reset pagination in searchblock when changing facet filters @tiberiuichim -- Fix the selection of Maps Block @iRohitSingh -- `UniversalLink`: handle direct download for content-type File if user is not logged. @giuliaghisini -- Fixed `ObjectBrowserWidget` when is multiple or `maximumSelectionSize` is not set @giuliaghisini -- Fix full-width image overlaps the drag handle @iRohitSingh -- Fix move item to top of the folder when clicking on move to top action button @iRohitSingh -- Fix `downloadableObjects` default value @giuliaghisini -- Folder contents table header and breadcrumbs dropdown now appear only from the bottom, fixing an issue where the breadcrumb dropdown content was clipped by the header area @ichim-david -- Folder contents sort dropdown is now also simple as the other dropdowns - ensuring we have the same behavior between adjecent dropdown @ichim-david -- Fix documention on block extensions, replace `render` with `template` to match Listing block @tiberiuichim -- Fix `isInternalURL` when `settings.internalApiPath` is empty @tiberiuichim -- Fix external link not supported by Navigation component #2853. @ericof -- Get Add/Edit schema contextually #2852 @ericof -- Fix regression in actions vocabularies calls because the change to use contextual schemas @sneridagh -- Include block schema enhancers (main block schema enhancer + variation schema enhancer) when calculating block default data @tiberiuichim -- Fixed object browser selected items number. @giuliaghisini -- Fix action vocabularies call avoiding regex look behind @nzambello -- Use subrequest in hero block to not lost locking token. @cekk -- Always add lang attr in html @nzambello -- Fix time widget position on 24h format @nzambello -- QuerystringWidget more resilient on old schemas @nzambello -- In search block, read SearchableText search param, to use it as search text input @tiberiuichim -- Fix missing translation in link content type @iRohitSingh -- Fixed drag-and-drop list placeholder issues @reebalazs -- Update demo address @ksuess -- Update list of trainings documentation @ksuess -- Scroll to window top only when the location pathname changes, no longer take the window location search parameters into account. The search page and the listing block already use custom logic for their "scroll into view" behaviors. @tiberiuichim -- Add missing layout view for `document_view` @MarcoCouto -- Add missing `App.jsx` full paths @jimbiscuit -- Fix z-index value of hamburger-wrapper on mobile resolutions overlapping the sidebar @ichim-david -- Fix UniversalLink handling of remote URLs from Link @nzambello - -### Internal - -- Upgrade to react 17.0.2 @nzambello -- Update to latest `plone.restapi` (8.16.2) @sneridagh -- Upgrade to `@plone/scripts` 1.0.3 @sneridagh -- Upgrade caniuse-lite 1.0.30001286 @tiberiuichim -- fix:correctly checkout plone.volto in buildout @nileshgulia1 -- Add line in upgrade guide about `getVocabulary` API change @tiberiuichim -- Add new Volto websites in production @nzambello -- Remove Pastanaga logos from Toolbar @sneridagh -- Add `omelette` to the local Plone backend build @sneridagh -- Optimize npm package by adding `docs/` `cypress/` and `tests/` to .npmignore @avoinea -- Use released `@plone/scripts`, since the builds are broken if it's a local package @sneridagh -- Use `plone.volto` instead of `kitconcept.volto` @tisto -- Silence customization errors, they are now behind a `debug` library namespace @sneridagh -- Add development dependency on `use-trace-update`, useful for performance debugging @tiberiuichim -- Improved developer documentation. Proof read several chapters, most importantly the upgrade guide @ichim-david -- 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 -- Add locales to existing block variations @sneridagh -- Add RawMaterial website in Volto production sites @nzambello -- Removing the hardcoded default block type from text block @iRohitSingh -- updated Volto sites list @giuliaghisini -- Cleanup dangling virtualenv files that should not be committed @pnicolli -- Remove bundlesize @tisto -- Upgrade stylelint to v14 (vscode-stylelint requires it now) @sneridagh -- Add several more stories for Storybook @tiberiuichim -- Add 2 new Volto websites by Eau de web for EEA @tiberiuichim -- Fix references to old configuration style in apiExpanders documentation @tiberiuichim -- Add `applySchemaDefaults`, in addition to `applyBlockDefaults`, to allow reuse in object widgets and other advanced scenarios @tiberiuichim -- Fix select family widgets stories in storybook @sneridagh -- Remove getNavigation from `Login.jsx` @iRohitSingh -- Allow listing block to be used in non-content pages (when used in a slot it - shouldn't crash on add/edit pages) @tiberiuichim -- Fix typo "toolbalWidth" @iRohitSingh -- Update all requirements and the reasoning behind them in builds @sneridagh -- Update Plone version in api backend to 5.2.6. Update README and cleanup @fredvd -- Document CI changelog verifier failure details that mislead contributors @rpatterson - -## 14.0.0-alpha.43 (2021-12-20) - -### Breaking - -- 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 - -### Feature - -- 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 - -- Fix z-index value of hamburger-wrapper on mobile resolutions overlapping the sidebar @ichim-david -- Fix UniversalLink handling of remote URLs from Link @nzambello -- Add missing `App.jsx` full paths @jimbiscuit - -### Internal - -- Upgrade to react 17.0.2 @nzambello -- Upgrade caniuse-lite 1.0.30001286 @tiberiuichim -- fix:correctly checkout plone.volto in buildout @nileshgulia1 -- Add line in upgrade guide about `getVocabulary` API change @tiberiuichim -- Add new Volto websites in production @nzambello -- Remove Pastanaga logos from Toolbar @sneridagh - -## 14.0.0-alpha.42 (2021-12-13) - -### Breaking - -- Removed pagination in vocabularies widgets (SelectWidget, ArrayWidget, TokenWidget) and introduced subrequest to vocabulary action. @giuliaghisini - -### Feature - -- 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 - -### Bugfix - -- Add missing layout view for document_view @MarcoCouto - -## 14.0.0-alpha.41 (2021-12-13) - -### Feature - -- Add catalan translation @bloodbare @sneridagh -- Added `.storybook` setup in the Volto `app` generator. Volto projects - generated from this scafolding are now ready to run Storybook for the project - and develop addons (in `src/addons` folder). -- Add new listing block option "fullobjects" per variation @ksuess -- Style checkboxes @nileshgulia1 -- Allow loading .less files also from a Volto project's `src` folder. @tiberiuichim -- Allow loading .less files also from a Volto project's `src` folder. @tiberiuichim - -### Bugfix - -- Udate demo address @ksuess -- Update list of trainings documentation @ksuess -- Scroll to window top only when the location pathname changes, no longer take the window location search parameters into account. The search page and the listing block already use custom logic for their "scroll into view" behaviors. @tiberiuichim - -### Internal - -- Update to plone.restapi 8.16.2 (revert missing_value PR) @sneridagh -- Update all requirements and the reasoning behind them in builds @sneridagh -- Update Plone version in api backend to 5.2.6. Update README and cleanup @fredvd -- Various local development build improvements @rpatterson -- Document CI changelog verifier failure details that mislead contributors -- Document CI changelog verifier failure details that mislead contributors @rpatterson -- Updated italian translation @pnicolli - -## 14.0.0-alpha.40 (2021-12-01) - -### Bugfix - -- In search block, read SearchableText search param, to use it as search text input - @tiberiuichim -- Fix missing translation in link content type @iRohitSingh -- Fixed drag-and-drop list placeholder issues @reebalazs - -## 14.0.0-alpha.39 (2021-11-30) - -### Bugfix - -- QuerystringWidget more resilient on old schemas @nzambello - -## 14.0.0-alpha.38 (2021-11-30) - -### Bugfix - -- Use subrequest in hero block to not lost locking token. @cekk -- Always add lang attr in html @nzambello -- Fix time widget position on 24h format @nzambello - -### Internal - -- Remove getNavigation from Login.jsx @iRohitSingh -- Allow listing block to be used in non-content pages (when used in a slot it - shouldn't crash on add/edit pages) @tiberiuichim -- Fix typo "toolbalWidth" @iRohitSingh - -## 14.0.0-alpha.37 (2021-11-26) - -### Bugfix - -- Fixed object browser selected items number. @giuliaghisini -- Fix action vocabularies call avoiding regex look behind @nzambello - -### Internal - -- Fix select family widgets stories in storybook @sneridagh - -## 14.0.0-alpha.36 (2021-11-25) - -### Bugfix - -- Fix regression in actions vocabularies calls because the change to use contextual schemas @sneridagh -- Include block schema enhancers (main block schema enhancer + variation schema enhancer) when calculating block default data @tiberiuichim - -### Internal - -- Fix references to old configuration style in apiExpanders documentation @tiberiuichim -- Add `applySchemaDefaults`, in addition to `applyBlockDefaults`, to allow reuse in object widgets and other advanced scenarios @tiberiuichim - -## 14.0.0-alpha.35 (2021-11-24) - -### Bugfix - -- Fix `isInternalURL` when `settings.internalApiPath` is empty @tiberiuichim -- Fix external link not supported by Navigation component #2853. @ericof -- Get Add/Edit schema contextually #2852 @ericof - -### Internal - -- Upgrade p.restapi to 8.15.2 @sneridagh - -## 14.0.0-alpha.34 (2021-11-20) - -### Feature - -- 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 - -## 14.0.0-alpha.33 (2021-11-20) - -### Bugfix - -- Fix downloadableObjects default value @giuliaghisini -- Folder contents table header and breadcrumbs dropdown now appear only from the - bottom, fixing an issue where the breadcrumb dropdown content was clipped - by the header area @ichim-david -- Folder contents sort dropdown is now also simple as the other dropdowns - ensuring we have the same behavior between adjecent dropdown @ichim-david -- Fix documention on block extensions, replace `render` with `template` to match Listing block @tiberiuichim - -### Internal - -- Upgrade stylelint to v14 (vscode-stylelint requires it now) @sneridagh -- Add several more stories for Storybook @tiberiuichim -- Add 2 new Volto websites by Eau de web for EEA @tiberiuichim - -## 14.0.0-alpha.32 (2021-11-09) - -### Breaking - -- Listing block no longer use `fullobjects` to retrieve backend data. It uses the catalog data instead. @plone/volto-team - -### Internal - -- Updated i18n link into the README file @macagua -- Updated Spanish translations @macagua -- Remove bundlesize @tisto -- Upgrade plone.restapi from 8.12.1 -> 8.13.0 @tisto - -## 14.0.0-alpha.31 (2021-11-07) - -### Feature - -- Added LinkMore component and link more in HeroImageLeft block. @giuliaghisini - -### Bugfix - -- Fix the selection of Maps Block @iRohitSingh -- UniversalLink: handle direct download for content-type File if user is not logged. @giuliaghisini -- Fixed ObjectBrowserWidget when is multiple or maximumSelectionSize is not set @giuliaghisini -- Fix full-width image overlaps the drag handle @iRohitSingh -- Fix move item to top of the folder when clicking on move to top action button @iRohitSingh - -### Internal - -- Removing the hardcoded default block type from text block @iRohitSingh -- updated Volto sites list @giuliaghisini -- Cleanup dangling virtualenv files that should not be committed @pnicolli -- Improve italian translation @pnicolli - -## 14.0.0-alpha.30 (2021-11-07) - -### Feature - -- Support typescript usage in Volto sites @pnicolli - -## 14.0.0-alpha.29 (2021-11-06) - -### Bugfix - -- Fix reset pagination in searchblock when changing facet filters @tiberiuichim - -## 14.0.0-alpha.28 (2021-11-03) - -### Feature - -- Defaults are observed in block data if `InlineForm` or `BlockDataForm` are used. @sneridagh @tiberiuichim - -## 14.0.0-alpha.27 (2021-11-02) - -### Breaking - -- Use title instead of id as a source of translation in "Variation" field in block enhancers @sneridagh - -## 14.0.0-alpha.26 (2021-11-01) - -### 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 - -## 14.0.0-alpha.25 (2021-11-01) - -### Feature - -- FormFieldWrapper accepts now strings and elements for description @nzambello -- Image block: - - When uploading an image or selecting that from the object browser, Image block will set an empty string as alternative text @nzambello - - Adds a description to the alt-tag with w3c explaination @nzambello - -### Bugfix - -- Fix disable mode of `QuerystringWidget` when all criteria are deleted @kreafox - -### Internal - -- Add RawMaterial website in Volto production sites @nzambello - -## 14.0.0-alpha.24 (2021-10-29) - -### Feature - -- Support Node 16 @timo - -### Bugfix - -- Prevent ua-parser-js security breach. See: https://github.com/advisories/GHSA-pjwm-rvh2-c87w @thet -- Fix storybook errors in the connected components, api is undefined. Using now a mock of the store instead of the whole thing @sneridagh -- CSS fix on `QueryWidget` to prevent line jumping for clear button when the multi selection widget has multiple items @kreafox - -## 14.0.0-alpha.23 (2021-10-21) - -### Feature - -- Enable to be able to use the internal proxy in production as well @sneridagh - -### Bugfix - -- Fix loading of cookie on SSR for certain requests, revert slight change in how they are loaded introduced in alpha 16 @sneridagh - -## 14.0.0-alpha.22 (2021-10-20) - -### Breaking - -- Improve mobile navigation menu with a nicer interaction and a fixed overlay with a drawer (customizable via CSSTransitionGroup) animation @sneridagh - -### Internal - -- Add locales to existing block variations @sneridagh - -## 14.0.0-alpha.21 (2021-10-17) - -### Feature - -- In the search block, allow editors to specify the sort on criteria. - @tiberiuichim -- Updated Volto production sites list @giuliaghisini - -### Bugfix - -- Bugfixes to search block. By default search block, when empty, makes a simple - query to the nav root, to list all content. Fix reading search text from URL. - Implement a simple compression of URL. Don't count searched text as filter. - Fix an edge case with showSearchInput in schema. Rename title to Section - Title in facet column settings. Avoid double calls to querystring endpoint. - @tiberiuichim -- Use correct shade of black in Plone logo @sneridagh - -## 14.0.0-alpha.20 (2021-10-15) - -### Breaking - -- Revisited, rethought and refactored Seamless mode @sneridagh - For more information, please read the deploying guide - https://6.docs.plone.org/volto/deploying/seamless-mode.html - - and the upgrade guide - https://6.docs.plone.org/volto/upgrade-guide/index.html - -### Bugfix - -- Fixed SelectWidget: when there was a selected value, the selection was lost when the tab was changed. @giuliaghisini - -## 14.0.0-alpha.19 (2021-10-15) - -### Feature - -- Make VocabularyTermsWidget orderable @ksuess -- Get widget by tagged values @ksuess - -## 14.0.0-alpha.18 (2021-10-11) - -### Internal - -- Re-release last release, since it does not show on NPM @sneridagh - -## 14.0.0-alpha.17 (2021-10-11) - -### Breaking - -- Fix logout action using the backend @logout endpoint, effectively removing the `__ac` cookie. It is recommended to upgrade to the latest p.restapi version to take full advantage of this feature @sneridagh - -### Bugfix - -- Add spinner on sharing View Button @iRohitSingh - -## 14.0.0-alpha.16 (2021-10-10) - -### Bugfix - -- Yet another attempt at fixing devproxy. Split the devproxy into a separate - express middleware. Introduce the `DEBUG_HPM` env var to make the devproxy - verbose @tiberiuichim - -## 14.0.0-alpha.15 (2021-10-10) - -### Breaking - -- Adjusted main `Logo` component styling @sneridagh - -For more information, please read the upgrade guide -https://6.docs.plone.org/volto/upgrade-guide/index.html - -### Feature - -- Add `volto-guillotina` addon to core @sneridagh - -### Internal - -- 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 -- Fix "make start-frontend" @tisto -- Update all the tests infrastructure for the new `volto-guillotina` addon @sneridagh - -## 14.0.0-alpha.14 (2021-10-01) - -### Bugfix - -- Get `blocks` and `blocks_layout` defaults from existing behavior when enabling TTW editable DX Layout @avoinea - -### Internal - -- Add development dependency on use-trace-update, useful for performance debugging @tiberiuichim -- Upgrade to `@plone/scripts` 1.0.3 @sneridagh - -## 14.0.0-alpha.13 (2021-09-30) - -### Feature - -- Add the new search block @tiberiuichim @kreafox @sneridagh - -## 14.0.0-alpha.12 (2021-09-29) - -### Bugfix - -- Show correct fieldname and not internal field id in Toast error messages on Add/Edit forms @jackahl -- sitemap.xml.gz obeys Plone Search settings @erral - -### Internal - -- Use plone.volto instead of kitconcept.volto @tisto -- Silence customization errors, they are now behind a `debug` library namespace @sneridagh -- Remove recently introduced `RAZZLE_I18NDEBUGMODE` in favor of a `debug` library namespace @sneridagh - -## 14.0.0-alpha.11 (2021-09-25) - -### Internal - -- Use released @plone/scripts, since the builds are broken if it's a local package @sneridagh - -## 14.0.0-alpha.10 (2021-09-25) - -### Breaking - -- New i18n infrastructure in the new `@plone/scripts` package @sneridagh -- Removed `src/i18n.js` in favor of the above change @sneridagh - -### Feature - -- Add RAZZLE_I18NDEBUGMODE env var and corresponding i18nDebugMode config setting to enable/disable react-intl error messages. @sneridagh - -### Bugfix - -- Missing default messages from JSON EN language file @sneridagh - -## 14.0.0-alpha.9 (2021-09-21) - -### Breaking - -- 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 - -### Bugfix - -- Do not show lead image block when the content type does not have the behavior enabled @sneridagh - -## 14.0.0-alpha.8 (2021-09-20) - -### Bugfix - -- Fix logout action, removing the `__ac` cookie as well, if present. @sneridagh - -## 14.0.0-alpha.7 (2021-09-20) - -### Feature - -- Japanese translation updated @terapyon -- German translations updated @tisto - -## 14.0.0-alpha.6 (2021-09-20) - -### Bugfix - -- Fix SSR on /edit with dev proxy @tiberiuichim - -## 14.0.0-alpha.5 (2021-09-20) - -### Bugfix - -- Fix on form errors in block editor, not changing to metadata tab @sneridagh - -## 14.0.0-alpha.4 (2021-09-20) - -### Internal - -- Bring back the `cypress` folder from the npm ignore files, since the libs in there are required and helpful for projects, remove only the `tests` and `fixtures` @sneridagh - -## 14.0.0-alpha.3 (2021-09-20) - -### Bugfix - -- Fix /edit and /add nonContentRoutes to fix isCmsUi fn @giuliaghisini -- Register the dev api proxy after the express middleware @tiberiuichim - -### Internal - -- Update to latest p.restapi (8.9.1) @sneridagh -- Remove `workingcopy` from checkouts info for kitconcept.volto @sneridagh -- Remove built workingcopy fixture environment based on local, back to docker based one @sneridagh -- Add `omelette` to the local Plone backend build @sneridagh -- Optimize npm package by adding docs/ cypress/ and tests/ to .npmignore @avoinea - -## 14.0.0-alpha.2 (2021-09-14) - -### Internal - -- Revert: Detect when a user has logged in by means other than JWT, such as ZMI `Basic` - authentication or the classic HTML Plone `@login` view @rpatterson - -## 14.0.0-alpha.1 (2021-09-13) - -### Breaking - -- Detect when a user has logged in by means other than JWT, such as ZMI `Basic` - authentication or the classic HTML Plone `@login` view @rpatterson - -### Bugfix - -- Fix SelectWidget vocabulary load on second component mount @avoinea #2655 - -## 14.0.0-alpha.0 (2021-09-08) - -### 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://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 - -- Content locking support for Plone (plone.locking) @avoinea - -## 13.15.0 (2021-09-07) - -### Feature - -- Show item title and item type when hovering over item title and item type icon in folder content view @iFlameing -- Change the batch size of folder content @iFlameing -- Show loading indicator for listing view @iFlameing - -### Bugfix - -- Validate `required` touched-only fields in Form everywhere @nileshgulia1 - -### Internal - -- Add placeholder to WysiwygWidget @nzambello -- Update italian translations @nzambello -- Get SchemaWidget field factories from backend @avoinea - -## 13.14.0 (2021-09-02) - -### Feature - -- Refactor users and groups controlpanel @nileshgulia1 - -## 13.13.0 (2021-09-01) - -### Feature - -- Show version in history view @iFlameing -- Contents shows also array indexes @nzambello - -### Bugfix - -- Fix SearchWidget required `pathname` @avoinea #2645 -- Fix for Contents tag modal @nzambello -- Cut/Copy blocks: fixed cut/copy unselected blocks. @giuliaghisini -- Properly style QueryWidget when used standalone, outside of QuerystringWidget @kreafox -- Add location.search as criteria in `ScrollToTop` component @kreafox -- Scroll to top only if the location pathname changes @kreafox - -### Internal - -- 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 -- Array and token widget available as named widget @nzambello - -## 13.12.0 (2021-08-20) - -### Feature - -- Multilingual routing was added for sitemap, search, contact-form, change-password, register and password-reset @ionlizarazu -- Opening the search input in the object browser, it will get the focus @nzambello - -### Bugfix - -- Fix ObjectBrowserNav items key @nzambello -- Fix ObjectBrowserNav aria label: id => title @nzambello -- Fix missing code in `ArrayWidget` from refactored `SelectWidget` @sneridagh - -## 13.11.0 (2021-08-18) - -### Feature - -- Add select utils `normalizerValue`, add state to the basic select field forcing it to be fully controlled @sneridagh - -### Bugfix - -- Improve consistency of `TokenWidget`'s use of the choice labels as "values" instead of internal uids assigned by `react-select`. @tiberiuichim -- Solve glitch in async loading options in `AsyncSelect` components @sneridagh - -### Internal - -- Add tests for `Select` component, document the use cases propely @sneridagh -- Upgrade `AsyncSelect` to a version compatible with `react-select` v4 @sneridagh -- Upgrade to latest `react-select` @sneridagh - -## 13.10.0 (2021-08-18) - -### Feature - -- Increase clickable area of right-arrow in objectBrowser @iFlameing -- Prevent form submit when clicking on BlockChooserButton @giuliaghisini -- Make selectedItems Filter work in Contents folder @nileshgulia1 - -### Bugfix - -- Fix SearchWidget search by path @giuliaghisini - -## 13.9.0 (2021-08-18) - -### Feature - -- Removed unnecessary set-cookies for the removal of the authentication cookie when the user is not logged in @mamico -- Add additional classnames for the field wrappers and the fieldsets in forms, this helps to be more addressable in CSS if required @sneridagh - -### Bugfix - -- Add title/tooltip on Toolbar buttons @avoinea #1384 -- Slight CSS fix on `ObjectWidget` for supporting long add element button messages @sneridagh -- Fix the babel view cancel button redirect @iFlameing -- Show toast error when trying to delete item and it's not permitted @danielamormocea - -## 13.8.3 (2021-08-16) - -### Bugfix - -- Prevent form submit when clicking on BlockChooserButton @giuliaghisini -- Add missing `publicURL` to the list of `window.env` serialized variables coming from the hosts configuration to complete the support for seamless mode @sneridagh - -## 13.8.2 (2021-07-20) - -### Bugfix - -- Improve `URLWidget` component, so it uses `flattenToURL` for the value @sneridagh - -## 13.8.1 (2021-07-16) - -### Bugfix - -- Missing prop `properties` passed down required for #2579 to work properly @sneridagh - -## 13.8.0 (2021-07-14) - -### Feature - -- A new component was added, `BlockChooserButton`, it encapsulate the logic of show/hiding the `BlockChooser` @tiberiuichim -- Overload `required` property for blocks config, it supports a function as value taken `properties` (current object data) and `block` (the block being evaluated in `BlockChooser`). The purpose is to enable more control over the available blocks in the Blocks chooser. @sneridagh - -### Bugfix - -- Add fallback to the "image" field in Image Gallery if the listingPreviewImageField defined in the project is not available on an object @jackahl - -## 13.7.0 (2021-07-12) - -### Feature - -- VocabularyTermsWidget option with translations for config.settings.supportedLanguages @ksuess - -### Bugfix - -- Fix InlineForm's understanding of missing default values @rexalex -- Guard in `isInternalURL` to catch non-string values @sneridagh - -### Internal - -- Update `browserlist` DB @sneridagh -- Install `luxon` explicitly to fix `rrule` package flickering deps (yarn problem) @sneridagh -- Add a11y cypress test for table block @ThomasKindermann -- Add Cypress test for Link content type @tisto -- Upgrade plone.restapi to 8.4.1 in the dev buildout @tisto - -## 13.6.0 (2021-07-03) - -### Feature - -- Add VocabularyTermsWidget and map to field with widget attribute set to 'vocabularyterms'. @ksuess - -### Bugfix - -- added "Complementary" landmark-role to skiplink-container for a11y @ThomasKindermann -- changed breadcrumb link text-color slightly for a11y color contrast @ThomasKindermann -- changed table headline text color to black for a11y @ThomasKindermann - -### Internal - -- Updated Brazilian Portuguese translations @ericof - -## 13.5.0 (2021-06-30) - -### Feature - -- Add og tags for social sharing @giuliaghisini @nzambello -- Add interface for plone seo extensions to use values added by them as metadata @jackahl - -### Internal - -- Upgrade to Storybook 6.3, refresh deps version for babel @sneridagh - -## 13.4.0 (2021-06-29) - -### Feature - -- Working copy support for Plone (plone.app.iterate) @sneridagh - -## 13.3.1 (2021-06-29) - -### Internal - -- Remove locales .json files pushed again by mistake, now they are no longer needed to be in the repo, since they are generated at runtime, and included in the released versions @sneridagh - -## 13.3.0 (2021-06-29) - -### Feature - -- Allowing user to paste url in search box in objectBrowser @iFlameing -- Allowing user to click on the breadcrumbs of objectBrowser @iFlameing -- `Navigation` and `Breadcrumbs` are `apiExpanders` aware and run the action depending on them @sneridagh - -### Bugfix - -- Fixed docs for config.settings.externalRoutes @giuliaghisini -- Fix `Pluggable` in the use case that a `Plug` is empty @sneridagh -- Fix `Login` component navigation for `INavigationRoot` structures @sneridagh -- Hyphenation block chooser labels (no html changes) @ksuess - -### Internal - -- Bumps prismjs from 1.23.0 to 1.24.0. @timo - -## 13.2.2 (2021-06-18) - -### Bugfix - -- Avoid debugging error in toolbar @tiberiuichim -- Fix the bug related to specific versioning view @iFlameing -- Fix blocks-listing Cypress test @giuliaghisini -- Fix the translation of header in babel view @iFlameing -- Fix German translations for leadimage and listing block @timo -- Show toast success message when adding a new local role @iFlameing -- Bump postcss from 7.0.29 to 7.0.36 @timo -- Complete Spanish translation @erral -- Complete German translation @timo - -## 13.2.1 (2021-06-14) - -### Bugfix - -- Changed 'batch_size' attribute in 'b_size' in querystring widget. @giuliaghisini - -### Internal - -- Upgrade generator deps @sneridagh - -## 13.2.0 (2021-06-12) - -### Feature - -- Allow passing a schemaEnhancer to QuerystringWidget @tiberiuichim -- Add internal URL blacklist to avoid render custom routes in Volto @nzambello -- In listing blocks, scroll to start of listing block instead page start @giuliaghisini - -### Bugfix - -- Fix addBreaklinesInline when string ends with new line @giuliaghisini -- Changed 'batch_size' attribute in 'b_size' in querystring widget. @giuliaghisini -- Properly respect batching and result limits in listing block @tiberiuichim -- Changed 'batch_size' attribute in 'b_size' in querystring widget. @giuliaghisini -- Properly respect batching and result limits in listing block @tiberiuichim -- Improve folder_contents workflow state (#2017) @avoinea -- Making placeholder image of video block to take 100% width when it is right or left aligned @iFlameing -- Showing clear icon when title is too long in objectbrowser selected items in multiple mode @iFlameing -- Use querystring prop in ListingBody @giuliaghisini -- Set default value selected for variation in listing block @giuliaghisini - -### Internal - -- Add [Volta](https://volta.sh) support @nzambello -- Various minor `Makefile` cleanup @rpatterson -- Improve error handling in UniversalLink @nzambello - -## 13.1.2 (2021-05-26) - -### Internal - -- Make the `AddLinkForm` component generic, to allow reuse in volto-slate @tiberiuichim -- Adding hover effect on ObjectBrowserNav icon @iFlameing - -## 13.1.1 (2021-05-25) - -### Bugfix - -- Second try to fix images in dev mode when api path is present (e.g. using the Robot server in Cypress tests) @sneridagh - -## 13.1.0 (2021-05-24) - -### Feature - -- enabled ability to set 'extractScripts' for error pages @giuliaghisini - -### Bugfix - -- Modify Default and Summary templates to render the LinkMore @ionlizarazu -- Revert #2472, this broke normal development mode images @sneridagh - -## 13.0.2 (2021-05-22) - -### Bugfix - -- Apply the `schemaEnhancer` from the main block even if no variations are found @sneridagh - -### Internal - -## 13.0.1 (2021-05-18) - -### Bugfix - -- Backwards compatibility for existing listing blocks with templates @sneridagh - -## 13.0.0 (2021-05-18) - -### Breaking - -- Seamless mode by default in development. Added `Host` header support for production - deployments, so no `RAZZLE_API_PATH` is required in production builds anymore if the - header is present. Not an strictly breaking change, but it's a default behavior change - worth to notice on its own. No change required in your deployments if you suply - currently `RAZZLE_API_PATH` in build time. See documentation for more information. - @sneridagh -- Deprecate Node 10 since it's out of LTS since April 30th, 2021 @sneridagh -- Remove the "inverted" option in Table Block since it was useless with the current CSS - set. Better naming of options and labels in table block (English). Updating the i18n messages for the used translations is advisable, but not required. @iFlameing -- Get rid of the font icons in the control panels overview @sneridagh -- Refactored `src/components/manage/Widgets/QuerystringWidget` using `ObjectWidget` and schemas @sneridagh -- 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://6.docs.plone.org/volto/upgrade-guide/index.html - -### Feature - -- Compile i18n json locales only at build time on the fly and at release time @sneridagh -- Change login form fixing accessibility issues @nzambello - -### Bugfix - -- Fix the Listing block with criteria to render correctly on a non-multilingual homepage. @ionlizarazu -- Fix selection of previous block when deleting a block @tiberiuichim -- Disable `Select` components family to lazy load on SSR, since it's breaking and the fix is quite obscure. They are not valuable on SSR responses anyway. @sneridagh -- Fix leftover from the multilingual fix for composed language names @sneridagh @ericof -- Translate 'All' label in Contents view pagination. @giuliaghisini -- Replace `langmap` dependency with internal code that supports composite language names @sneridagh @ericof -- RenderBlocks: Blocks like the listing block need a path. @ksuess -- Normalize language to get the correct filename in lazy imports for composite language names @sneridagh @ericof -- Checkbox not using `null` as false @sneridagh -- Use params prop in api middleware @giuliaghisini -- Fix PORT env var handling, if you have set the PORT in build time, the setting was - removed back to defaults, now the build time setting is kept (unsetting in build time - and set it in runtime is now the recommended setup) @sneridagh -- Fix sort_order restapi call, works on action for existing listing blocks - and in ListingData saving correctly new ones @nzambello -- Fix `contextURL` in `ObjectBrowser` for special (add/edit) views using `getBaseUrl` @sneridagh - -### Internal - -- Full real zero configuration achievement by turning the stock default - `RAZZLE_PUBLIC_DIR` into a relative path, so we can enable truly movable builds - @sneridagh -- Upgrade Cypress to latest @sneridagh -- Remove surge since it's not used anymore @sneridagh -- Upgrade `react-redux` and friends @sneridagh -- Upgrade `yarnhook` and `yarn-deduplicate` @sneridagh -- Add Listing block test for root path @ionlizarazu -- Only log changes to po (`poToJson`) if running as a script @sneridagh -- Remove json locales from the repo to avoid merge conflicts @sneridagh -- All the `Select` components family in core are loaded through `Loadables` helper @sneridagh -- Updated Brazilian Portuguese translations @ericof -- Improve Github Actions names, separate the code analysis from the main core @sneridagh - -## 13.0.0-alpha.10 (2021-05-16) - -### Bugfix - -- Fix the Listing block with criteria to render correctly on a non-multilingual homepage. @ionlizarazu -- Fix selection of previous block when deleting a block @tiberiuichim - -### Internal - -- Upgrade Cypress to latest @sneridagh -- Remove surge since it's not used anymore @sneridagh -- Upgrade `react-redux` and friends @sneridagh -- Upgrade `yarnhook` and `yarn-deduplicate` @sneridagh -- Add Listing block test for root path @ionlizarazu -- Only log changes to po (`poToJson`) if running as a script @sneridagh - -## 13.0.0-alpha.9 (2021-05-13) - -### Feature - -- Compile i18n json locales only at build time on the fly and at release time @sneridagh - -### Internal - -- Remove json locales from the repo to avoid merge conflicts @sneridagh - -## 13.0.0-alpha.8 (2021-05-12) - -### Bugfix - -- Disable `Select` components family to lazy load on SSR, since it's breaking and the fix is quite obscure. They are not valuable on SSR responses anyway. @sneridagh - -### Internal - -- All the `Select` components family in core are loaded through `Loadables` helper @sneridagh - -## 13.0.0-alpha.7 (2021-05-11) - -### Bugfix - -- Fix leftover from the multilingual fix for composed language names @sneridagh @ericof - -### Internal - -- Updated Brazilian Portuguese translations @ericof - -## 13.0.0-alpha.6 (2021-05-11) - -### Bugfix - -- Translate 'All' label in Contents view pagination. @giuliaghisini -- Replace langmap dependency with internal code that supports composite language names @sneridagh @ericof - -## 13.0.0-alpha.5 (2021-05-10) - -### Bugfix - -- RenderBlocks: Blocks like the listing block need a path. @ksuess -- Normalize language to get the correct filename in lazy imports for composite language names @sneridagh @ericof - -### Internal - -- Updated Brazilian Portuguese translations @ericof - -## 13.0.0-alpha.4 (2021-05-07) - -### Breaking - -- Refactored `src/components/manage/Widgets/QuerystringWidget` using `ObjectWidget` and schemas @sneridagh -- 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://6.docs.plone.org/volto/upgrade-guide/index.html - -### Bugfix - -- Checkbox not using `null` as false @sneridagh - -## 13.0.0-alpha.3 (2021-05-06) - -### Bugfix - -- Use params prop in api middleware @giuliaghisini - -- Fix PORT env var handling, if you have set the PORT in build time, the setting was - removed back to defaults, now the build time setting is kept (unsetting in build time - and set it in runtime is now the recommended setup) @sneridagh - -## 13.0.0-alpha.2 (2021-05-05) - -### Bugfix - -- Fix sort_order restapi call, works on action for existing listing blocks - and in ListingData saving correctly new ones @nzambello - -### Internal - -- Updated Brazilian Portuguese translations @ericof - -## 13.0.0-alpha.1 (2021-05-03) - -### Internal - -- Full real zero configuration achievement by turning the stock default - `RAZZLE_PUBLIC_DIR` into a relative path, so we can enable truly movable builds - @sneridagh - -## 13.0.0-alpha.0 (2021-05-03) - -### Breaking - -- Seamless mode by default. Added `Host` header support for deployments, so no - `RAZZLE_API_PATH` is required in production builds anymore if the header is present. - Not an strictly breaking change, but it's a default behavior change worth to notice on - its own. No change required in your deployments if you suply currently - `RAZZLE_API_PATH` in build time. See documentation for more information. @sneridagh -- Deprecate Node 10 since it's out of LTS since April 30th, 2021 @sneridagh -- Remove the "inverted" option in Table Block since it was useless with the current CSS - set. Better naming of options and labels in table block (English). Updating the i18n messages for the used translations is advisable, but not required. @iFlameing -- 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://6.docs.plone.org/volto/upgrade-guide/index.html - -### Feature - -- Change login form fixing accessibility issues @nzambello - -### Internal - -- Improve Github Actions names, separate the code analysis from the main core @sneridagh - -## 12.14.0 (2021-05-03) - -### Feature - -- Provide api for block extensions. See `/blocks/extensions` in documentation @tiberiuichim - -### Bugfix - -- In BlockDataForm, always clone schema before applying enhancers @tiberiuichim -- In BlockDataForm, don't add the variations field multiple times @tiberiuichim - -## 12.13.0 (2021-04-30) - -### Feature - -- Making objectBrowserWidget context aware @iFlameing - -### Bugfix - -- Adding `flattenToAppURL` in Link component @iFlameing - -- Disable click event of the outside the engine click detection, since it leads to bad - behavior for custom and library elements that try to mount things attaching them in - the Body or outside the detected container @sneridagh - -## 12.12.0 (2021-04-29) - -### Feature - -- Translations german: Login/Register @ksuess - -### Bugfix - -- Fix image gallery in listing block for contained (non-query based) images @sneridagh - -## 12.11.0 (2021-04-28) - -### Feature - -- Implemented Babel view, to compare translated items in add and edit mode. @giuliaghisini -- as in Plone, hide controlpanel for users that are no 'Manager' or 'Site Administrator'. @giuliaghisini -- Improve the blocks engine by adding a detector for clicking outside in the `BlocksForm` @sneridagh -- Include a pluggable architecture for pluggable render-time insertions (similar to ) @tiberiuichim -- Add parseDateTime helper from DatetimeWidget to handle timezones @nzambello - -### Bugfix - -- Include selected block in multiselections @sneridagh -- Correct the selected values rendering at isMulti SelectWidget @ionlizarazu - -### Internal - -- Implement Github actions workflow to deploy the documentation to the Plone Foundation server @ericof -- Pin `immutable` to an updated version that does not produce continuous deprecation notices in console on every change @sneridagh -- Print console.error in SSR if not an ignored error code @nzambello -- Fetch addons with https using mrs-developer @nzambello -- Fix sitemap URL generation @nzambello - -## 12.10.1 (2021-04-14) - -### Bugfix - -- Better error handling code in SSR when an error occurs in the code @ksuess @sneridagh - -## 12.10.0 (2021-04-14) - -### Feature - -- Add support in FileWidget for raw file data in base64 (control panels, not really NamedFile fields) @sneridagh - -### Bugfix - -- ObjectListWidget: edit mode: expand last added item, not first of list. @ksuess -- Improve error handling in SSR when an error occurs in the code @sneridagh - -### Internal - -- Ignore files in addons when building i18n messages in the i18n script, since it's useless (they should be done in the addon itself) and lead to errors when parsing also internal `node_modules` and other utility files @sneridagh - -## 12.9.0 (2021-04-10) - -### Bugfix - -- Avoid double calling asyncPropsExtenders @ksuess @tiberiuichim - -### Internal - -- Fix server when ECONNRESET is received from the backend @sneridagh -- Remove all appearences of `UNSAFE_componentWillMount` since it loads also on the SSR calls too @sneridagh - -## 12.8.0 (2021-04-08) - -### Feature - -- Add configurable api expanders @csenger @nileshgulia1 @tiberiuichim @sneridagh -- In Text block, keep text selection on focus, and move focus to end of text if there's no selection @giuliaghisini - -### Bugfix - -- Fix `fieldset` instead of `fieldSet` in ObjectWidget component @sneridagh - -## 12.7.0 (2021-04-07) - -### Feature - -- Use `onInsertBlock` callback when adding new blocks if available, otherwise fallback to `onMutateBlock` refs #2330 @avoinea - -### Bugfix - -- fix universal link @nileshgulia1s -- fixed recurrence widget when weekly recurrence is selected and event start date is on sunday. @giuliaghisini -- Fix default value for checkbox widget @alexbueckig -- Fix for forms in content types, the fieldset was not being passed over to the field. This affected form generation ids and labels. @sneridagh -- Add a bit of a11y love to the `ObjectListWidget` @sneridagh -- fix universal link when no item content obj passed @nileshgulia1 - -### Internal - -- Add Blocks helpers docs and tests @avoinea - -## 12.6.1 (2021-04-06) - -### Bugfix - -- Remove duplicated wrapper on block edit form @sneridagh -- Fix small catched up issues in tests @sneridagh - -## 12.6.0 (2021-04-05) - -### Feature - -- Add ObjectWidget and ObjectListWidget @sneridagh -- Add `BlockForm` component, variations and schemaExtender aware @sneridagh -- Improvements to the `InlineForm` @sneridagh - -### Bugfix - -- Remove InlineForm default focus on first input @avoinea - -### Internal - -- Add Storybook to the main docs (https://6.docs.plone.org/storybook/) build @sneridagh - -## 12.5.0 (2021-03-31) - -### Feature - -- New setting, `config.settings.showTags` to be able to configure tags visibility on default View @avoinea - -### Bugfix - -### Internal - -- Add toPublicURL helper @nzambello -- Don't show empty groups in BlockChooser @tiberiuichim -- Fix Text Block placeholder regression refs #2322 @avoinea - -### Internal - -- BlocksForm and RenderBlocks now allow a `blocksConfig` configuration object as a prop @tiberiuichim -- Updated italian translations @nzambello - -## 12.4.2 (2021-03-29) - -### Bugfix - -- Re-add formTitle, formDescription, metadata to BlocksForm @avoinea - -## 12.4.1 (2021-03-29) - -### Bugfix - -- Fixed InlineForm boolean false value @razvanMiu -- Fix warning message in console, move open/close detection to the aside itself @sneridagh -- Revert SidebarPortal min-height @avoinea -- Add proper proptype in `SidebarPopup` @sneridagh - -### Internal - -- Update plone/volto Docker image to use latest yo generator and support ADDONS env @avoinea -- Add `docker-compose.yml` to the repo for quick demoing @sneridagh -- Fixed babel config when loading addons (in testing mode) @sneridagh - -## 12.4.0 (2021-03-25) - -### Feature - -- Improved comments @rexalex @avoinea -- Added SidebarPopup component for extra sidebar handling @avoinea -- Use SidebarPopup component in place of CSS transition sidebar @nileshgulia1 - -### Bugfix - -- Fixed multiSelected propType and BlocksForm multiSelected.includes @avoinea -- Fixed italian translations for block `Maps` @giuliaghisini -- Fixed SidebarPortal min-height @avoinea -- Fixed CheckboxWidget state @razvanMiu - -### Internal - -- Upgrade API to Plone 5.2.4 and p.restapi 7.1.0 @sneridagh -- Reorganization of the Cypress tests, now they live in `cypress/tests` @sneridagh -- Splitted Cypress tests into `core` tests and `guillotina` ones for better overall handling @sneridagh - -### Docs - -- Update internal proxy docs @nzambello - -## 12.3.0 (2021-03-18) - -### Feature - -- Improve `ObjectBrowserWidget` adding a manual input field and allow external URLs. Add feature to paste internal URLs and convert them to selected objects. Added the `allowExternals` prop in order to allow this behavior (opt-in). - -### Bugfix - -- Fix storybook initial config registry setup @sneridagh -- Search page now follows Plone's ISearchSchema settings @tiberiuichim -- Improve `ContextNavigation` component, adding the level you are in each iteration @sneridagh - -### Internal - -- Add testing add-on for enable special testing use cases and configuration options @sneridagh -- Add `RAZZLE_TESTING_ADDONS` environment variable for adding addons for testing purposes @sneridagh -- Add "Humboldt Labor" to show cases. -- Updated "Volto in Production" list @alecghica - -### Docs - -- Explicitly mention `src/config` in the "Internal proxy to API" documentation @pigeonflight - -## 12.2.0 (2021-03-03) - -### Feature - -- Adds skiplinks @nzambello -- Fix some semantic tags as nav @nzambello -- Allow addons to specify their own dependencies in their package.json `addons` key, just like the regular Volto projects. This means that it's no longer required to list all possible addons in the Volto project and they can be bootstrapped as being part of a dependency @tiberiuichim -- insert a dimmer with the loading message in the form when the status changes in the content folder. @martina.bustacchini - -### Bugfix - -- Enable draftjs links to open in target blank if is external url. @giuliaghisini - -### Internal - -- Use correct status code for static files error handling @nzambello -- Remove dangling `.replaces(...` for the apiPath and use flattenToAppURL instead @sneridagh - -## 12.1.2 (2021-02-28) - -### Bugfix - -- Fix addon reducers registration @tiberiuichim - -## 12.1.1 (2021-02-26) - -### Bugfix - -- Import asyncConnected actions directly from actions module, the resolution order is different in projects @tiberiuichim @avoinea - -## 12.1.0 (2021-02-24) - -**This is a brown bag release and should not be used, upgrade to Volto 12.1.1 instead.** - -### Feature - -- A new setting, `config.settings.storeExtenders` which allows customization of used Redux middleware @tiberiuichim -- Introduce `config.settings.asyncPropsExtenders` which allows customizing, per route, the `asyncConnected` actions @tiberiuichim @sneridagh - -### Bugfix - -- Adapt to BlocksForm in Blocks Engine @nileshgulia1 -- a11y improvements in `ObjectBrowser` and `BlockChooser` @sneridagh -- Fix UniversalLink for download link. @giuliaghisini - -### Internal - -- Fork redux-connect code in `src/helpers/AsyncConnect`, to allow mixing in config-based asyncConnects. Provide a webpack alias that overloads the redux-connect imports. @tiberiuichim - -### Docs - -- Update wording @svx - -## 12.0.0 (2021-02-20) - -### Breaking - -- Introduction of the new Volto Configuration Registry @sneridagh @tiberiuichim - For more information about this breaking change: https://6.docs.plone.org/volto/upgrade-guide/index.html#upgrading-to-volto-12-x-x - -### Feature - -- New breadcrumbs `INavigationRoot` aware for the _Home_ icon. This allows inner subsites navigation and better support for multilingual sites. @sneridagh - -### Internal - -- Upgrade plone.restapi to 7.0.0 and Plone to 5.2.3 @sneridagh - -## 12.0.0-alpha.0 (2021-02-17) - -### Breaking - -- Introduction of the new Volto Configuration Registry @sneridagh @tiberiuichim - 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) - -### Feature - -- Add `preloadLazyLibs` and `settings.lazyBundles` to allow preloading bundles of lazy libraries @tiberiuichim @silviubogan -- Added onChangeFormData prop to Form component @giuliaghisini -- Internationalization story for add-ons @sneridagh -- robots.txt from plone as fallback (if /public/robots.txt not exists and .env VOLTO_ROBOTSTXT variable not exists.) @giuliaghisini -- UniversalLink and ConditionalLink accepts also an item to link to. If item is of @type Link, a direct link to remote url is generated if user is not logged. @giuliaghisini - -### Bugfix - -- temporarly removed linkDetectionPlugin for draftjs (for some conflicts with AnchorPlugin) @giuliaghisini -- German translation: aria-label of '/contents' button : "Inhalte" not "Inhaltsverzeichnis" @ksuess -- fix view links and others styles of entities on editing Text Block. @giuliaghisini -- Make sidebar-collapsed visible on small mobile. @giuliaghisini -- Fix regresion on the imagesizes styling due to the removal of the id in 11 @sneridagh - -### Internal - -- Update docs: configuration of routes and addonRoutes @ksuess - -## 11.0.0 (2021-01-29) - -### Breaking - -- [circular deps] Move `AlignBlock` component to its rightful place @sneridagh -- Removing id from FormFieldWrapper @iFlameing -- Change default Listing Template to include only Text and renamed the old default Template to Summary Template @jackahl - -### Feature - -- Add `ContextNavigation` component, it can fetch the `@contextnavigation` plone.restapi - endpoint and display a navigation portlet, similar to Plone's classic - navigation portlet. -- added linkDetectionPlugin plugin to draftjs to automatically create links for urls and mails when editing text. @giuliaghisini -- An initial Storybook setup. Start it with `yarn storybook`. Feel free to contribute more stories! @sneridagh -- Add storybook Wrapper utility component. Add ContactForm initial story @tiberiuichim -- make and load configurable reducers in the client `window.__data`, decreasing the html size @nileshgulia1 @tiberiuichim -- Custom group component for selectStyling @nileshgulia1 -- Add new components: RenderBlocks, BlocksForm, DragDropList and EditBlockWrapper @tiberiuichim -- Add `noValueOption` prop to `SelectWidget` so you can opt-out from the "no-value" option so the choices are a closed list @sneridagh -- Provide `injectLazyLibs()` wrapper and `settings.loadables` config to deal with loadable libraries @tiberiuichim - -### Bugfix - -- Better handling of a condition in the new breadcrumbs @sneridagh - -### Internal - -- Upgrade react-select to 4.0.2 @sneridagh -- Upgrade react ecosystem to 13.14.0 @sneridagh -- Add shouldComponentUpdate to blocks @nileshgulia1 -- Update old entry in upgrade guide @tiberiuichim -- Add `@testing-library/cypress` as a dep @sneridagh -- Fix an internal link in documentation @tiberiuichim - -## 10.10.0 (2021-01-22) - -### Feature - -- Simple optional critical-CSS inclusion feature (without the actual building of - the critical CSS) @silviubogan @tiberiuichim @nileshgulia1 -- added support for allowedBlocks and showRestricted for BlockChooser in Form @giuliaghisini -- added objectBrowser to UrlWidget, and attached UrlWidget to remoteUrl field of ContentType Link @giuliaghisini -- managed tel link in UrlWidget and draftjs @giuliaghisini -- added support for allowedBlocks and showRestricted for BlockChooser in Form @giuliaghisini -- Improvements in InlineForm @nileshgulia1 -- Improved form validation. Tested required fields when field is array or richtext @giuliaghisini - -### Bugfix - -- Fix 'All' button batch size in Contents @nzambello -- Fixed field type for 'from' field in ContactForm @giuliaghisini -- handle SelectWidget null value and isMulti(#1915) &(1878) @nileshgulia1 -- Fix typo in ita locales @nzambello -- Wrap objectBrowserWidget with FormFieldWrapper @nileshgulia1 -- Added preventDefault and stopPropagation for toolbar buttons of Table block. @giuliaghisini -- Fix `Contents` breadcrumbs for multilingual sites @sneridagh - -### Internal - -- Add support for `nav_title` in breadcrumbs and navigation @sneridagh -- Add `settings.serverConfig` in the settings object of `~/config`. Add another module, `config/server.js` which is conditionally imported if `__SERVER__`. This module will host settings that are only relevant to the server. Being conditionally imported means that the code is safe to require server-only nodejs packages. @tiberiuichim -- Update browserlist and caniuse-lite @sneridagh -- Document deprecation of `@plone/create-volto-app` @sneridagh @nileshgulia1 -- Adding classname in TextWidget and ObjectBrowserBody so that we can target those element in tests. @iFlameing -- Add support for `nav_title` in breadcrumbs and navigation @sneridagh - -## 10.9.2 (2021-01-15) - -### Bugfix - -- Make a cypress test more resilient to platform differences @tiberiuichim -- Fix regression introduced by improve CSS in the inner toolbar for the image block to support narrower width (like for using it inside grid blocks) @sneridagh -- Avoid a bug in cypress tests caused by multi-block copy/paste @tiberiuichim - -### Internal - -- i18n for a literal in the table block @sneridagh - -## 10.9.1 (2021-01-14) - -### Bugfix - -- Fix regression introduced by improve CSS in the inner toolbar for the image block to support narrower width (like for using it inside grid blocks) @sneridagh - -## 10.9.0 (2021-01-14) - -### Feature - -- Enhance `BlockChooser` by adding support for `allowedBlocks` and `showRestricted` @avoinea @sneridagh - -### Bugfix - -- Better handling of @@images pipeline errors @tiberiuichim -- Fix `More` menu when using with Plone 4 backend / history action is undefined (#2120) @avoinea -- Fix `/sharing` page when using with Guillotina (#2122) @avoinea -- Improve CSS in the inner toolbar for the image block to support narrower width (like for using it inside grid blocks) @sneridagh - -### Internal - -- Move express middleware routes (sitemap, download, images and robotstxt) out of server.jsx into their own `express-middleware/*.js` modules. All express middleware now has access to the redux store, api middleware and an errorHandler, available under `req.app.locals` @tiberiuichim - -## 10.8.0 (2021-01-11) - -### Feature - -- Add proper icons to the table block @sneridagh - -### Internal - -- Add `packages` directory to the `modulePathIgnorePatterns` for the jest tests @sneridagh -- Add `packages` directory in npmignore @sneridagh - -## 10.7.0 (2021-01-05) - -### Feature - -- Lazy load image in blocks Image and HeroImage @mamico - -### Bugfix - -- Fix redirection for Link objects. @cekk -- Fix import order in server.jsx. @cekk @tiberiuichim -- Make sentry config more resilient to edge cases (SPA, storybook) @sneridagh -- Handle errors on file and image download (#2098) @cekk -- Remove test dependant on the year in `Copyright` footer section @sneridagh -- Increase maxResponseSize for superagent calls. Now is 500mb (#2098) @cekk - -### Internal - -- Translations german: Unauthorized, Login/Register @ksuess -- Removing id from FormFieldWrapper @iFlameing - -## 10.6.1 (2020-12-21) - -### Bugfix - -- Better API helper end request handling, since the existing one was causing problems and rendered the SSR server unusable in case of the request was rejected @sneridagh - -### Internal - -- Add a paragraph on dealing with CORS errors in Deploying doc page @tiberiuichim -- Remove useless RobotFramework related packages, keep only the minimum required ones @sneridagh -- Updated italian translations @nzambello - -## 10.6.0 (2020-12-18) - -### Feature - -- Allow setting a custom robots.txt from environment with the `VOLTO_ROBOTSTXT` environment variable @tiberiuichim - -### Bugfix - -- Replace `__SERVER__` occurrence from table `Edit` component @sneridagh - -## 10.5.0 (2020-12-17) - -### Feature - -- Adding `All` button to folder content @iFlameing - -### Bugfix - -- Fix "is client" check for SidebarPortal @tiberiuichim @sneridagh - -## 10.4.3 (2020-12-15) - -### Internal - -- Bring back `App` to `components/index.js` for now, since it's breaking the projects - where it gets referenced from `routes.js`. @sneridagh - -## 10.4.2 (2020-12-15) - -**This is a brown bag release and should not be used, upgrade to Volto 10.4.3 instead.** - -### Bugfix - -- Fix numeric widget console warnings regarding flex styling refs #2059 @ichim-david -- Fix numeric widget crash once we click inside it refs #2059 @ichim-david - -### Internal - -- Fix some key points to improve the circular imports problem @sneridagh - - - `App` and `View` components are meant to be used only by Volto internals, so it's no - point into having them exported in `components/index.js` that facilitated a path for - circular imports. - - `withObjectBrowser` and friends also are prone to facilitate a path for having - circular imports, so we are using there only absolute imports. - - All these changes are non-breaking and non-intrusive. - -## 10.4.1 (2020-12-12) - -### Bugfix - -- Make sure that prism is loaded before rendering HTML block @tiberiuichim - -## 10.4.0 (2020-12-11) - -### Feature - -- Add ability to filter the attributes that are saved in the ObjectBrowserWidget @sneridagh -- Add `object_browser` as widget @sneridagh - -### Bugfix - -- Adding video thumbnail for the .mp4 extension @iFlameing. - -### Internal - -- Added new in productions sites to README @terapyon - -## 10.3.0 (2020-12-04) - -### Feature - -- added search depth in listing and updated it locales @giuliaghisini -- Add emailSend action @nzambello -- lazy load react-dropzone @nileshgulia1 - -### Bugfix - -- Fix addons loader name generation on Windows @tiberiuichim -- For python3.9 compatibility, install wheel package in build-backend targets @tiberiuichim - -### Internal - -- Tweak Cypress command `waitForResourceToLoad` to timeout after 50 tries. @tiberiuichim - -## 10.2.0 (2020-12-04) - -### Feature - -- Generate language file of added missing German translations by @tisto. @ksuess - -### Bugfix - -- Fix regression in the `getContent` action with the expandable missing @sneridagh - -## 10.1.0 (2020-11-30) - -### Feature - -- Add missing German translations @tisto - -## 10.0.0 (2020-11-30) - -### Feature - -- Provide operations on multiple-selected blocks: delete, cut/copy and paste. You can trigger the "multiselected blocks" by holding the shift key and clicking on another block. You can add/remove blocks to the selection with the Control key. Holding Control when you click on the Paste button doesn't clear the clipboard, so you can paste multiple times. The blocks clipboard uses the browser's local storage to synchronize between tabs. @tiberiuichim -- Allow reducers to be persisted using localstorage @tiberiuichim - -### Breaking - -- Removal of the Razzle patch that was introduced in 9.0.0 @sneridagh - 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 - -- Fix link to login in the Unauthorised component @sneridagh - -### Internal - -- Add details on how to run Cypress integration tests @tiberiuichim -- Upgrade `@testing-library/react` to 11.2.2. Add `jest-environment-jsdom-sixteen as upgraded jsdom implementation @tiberiuichim -- Split some small prismjs related files (used in HTML block) in separate chunks @tiberiuichim -- Remove dangling analyzer plugin @sneridagh -- Support for Guillotina 6 @bloodbare @sneridagh -- Update Cypress to version 5.6.0 @sneridagh -- Terse `react-intl` errors in console during development turning them into warnings @sneridagh - -## 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://6.docs.plone.org/volto/upgrade-guide/index.html for more information. - -### Feature - -- Remove the Razzle patch for the local, "inline" Volto Razzle plugins @tiberiuichim @sneridagh - -### Bugfix - -- Move missplaced `appExtras` into settings @sneridagh - -### Internal - -- Make filewidget label more consistent @tisto - -## 9.1.0 (2020-11-20) - -### Feature - -- Extend the internal proxy capabilities, now the target is overridable and SSL aware @sneridagh -- Added new environment variables for the internal proxy `RAZZLE_PROXY_REWRITE_TARGET` and `RAZZLE_PROXY_REWRITE_TARGET` @sneridagh -- Enhance `AppExtras` component to make it pluggable through the - `config.settings.appExtras`. These are router-path filtered components that - are rendered inside the `AppExtras` component @tiberiuichim - -### Bugfix - -- Fix Sentry tags and extra via settings.sentryOptions @avoinea -- Fix `yarn analyze` command by packing our own version of - webpack-bundle-analyzer integration. It has a few changes to the old default - configuration. There is an alternative way of triggering the bundle analyzer, - with the `OFFLINE_BUNDLE_ANALYZE=true` env variable, which avoids starting - the HTTP bundle analyzer server. Also, it always saves a report html file. - @tiberiuichim - -### Internal - -- Improve developer documentation. Add several new chapters @tiberiuichim - -## 9.0.0 (2020-11-15) - -### Breaking - -- Upgrade Razzle to 3.3.7 @tiberiuichim @sneridagh - - Razzle 3.3.7 prepares the transition to the upcoming Razzle 4 so it improves and - unifies the extensibility story at the cost of change the signature of the - `razzle.config.js` and how plugins are declared. It also enables by default the new - _React Fast Refresh_ feature implemented by the React community, which improves the - refresh of the code while in development. - -- Babel plugins housekeeping - - Deprecated proposals: - - - @babel/plugin-proposal-function-bind - - @babel/plugin-proposal-do-expressions - - @babel/plugin-proposal-logical-assignment-operators - - @babel/plugin-proposal-pipeline-operator - - @babel/plugin-proposal-function-sent - -For a complete list of actions to follow, please read the upgrade guide -https://6.docs.plone.org/volto/upgrade-guide/index.html - -### Feature - -- Add `webpack-relative-resolver` plugin. For addons and Volto, it normalizes local relative imports to package-rooted imports. An import such as `import Something from './Something'` would be rerouted internally as `import Something from '@collective/someaddon/Something'`. By doing so we get easier customization of addons, as they don't have to be so strict with their import and exports @tiberiuichim -- Posibility to configure Sentry via `settings.sentryOptions` configuration key @avoinea -- Catch `console.error` by default with Sentry @avoinea -- Refactor CT icons helper: add getContentIcons @nzambello - -### Bugfix - -- Properly return 404, 401 and 403 on SSR, when appropriate @tiberiuichim -- Fix Guillotina PATCH by adding the `@static_behaviors` field inconditionally @sneridagh - -### Internal - -## 8.10.1 (2020-11-13) - -### Bugfix - -- Fix leaking input CSS in the link widget in draftjs @sneridagh - -### Internal - -- Move Guillotina CI job to GH actions @sneridagh - -## 8.10.0 (2020-11-12) - -### Feature - -- Adding show all button in UsersControlpanel @iFlameing -- Now you can prettify the html code in HTML block @iFlameing -- Adding preview image placeholder in Video Block @iFlameing - -### Bugfix - -- Fix error object in clipboard reducer @iFlameing -- Making QuerystringWidget more resilient by handeling null value @iFlameing -- Fixing bug related to initiation of table block with previous table block data @iFlameing -- enabled no-folderish CT to be translated @giuliaghisini - -### Internal - -- Changing checkbox widget of exclude-nav to select widget @iFlameing - -## 8.9.2 (2020-11-06) - -### Bugfix - -- Revert type-in detection in draftjs link widget, as that leads to a regression @sneridagh -- Fix and refactoring FileWidget @iFlameing - -## 8.9.1 (2020-11-06) - -### Bugfix - -- Fix SSR rendering in table blocks @sneridagh - -## 8.9.0 (2020-11-05) - -### Feature - -- Added Dropzone in FileWidget @iFlameing -- Making inline link toolbar, location aware in content browser @iFlameing. -- Detect if the link typed or pasted in the link widget of the text block is internal @sneridagh - -## 8.8.1 (2020-11-04) - -### Bugfix - -- Improve misleading translations deleted message @sneridagh -- Fixing overlap of labels with each other in select widget @iFlameing -- Throw error in crashReporter; also log sentry errors in server @tiberiuichim - -### Internal - -- Split razzle svg and sentry loaders to separate files @tiberiuichim -- prevent form without blocks. Form always have at least the default block. @giuliaghisini -- Fix default target for links in text blocks @giuliaghisini - -### Internal - -## 8.8.0 (2020-11-02) - -### 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://github.com/nodejs/release#release-schedule @sneridagh - -## 8.7.1 (2020-10-29) - -### Bugfix - -- Added loading icon when doing actions in folder-contents @giuliaghisini -- Fix German translation "from" -> "E-Mail" in contact form @tisto - -## 8.7.0 (2020-10-27) - -### Feature - -- Manage translations view @sneridagh - -### Internal - -- Update docs build and include pygments support for jsx @sneridagh - -## 8.6.0 (2020-10-25) - -### Feature - -- Added placeholder background color same as selected one @iFlameing -- Showing notification when user sort the folder-content @iFlameing -- Render full language name (e.g. "English") instead of 2 character language code in language selector, matching Plone default behavior. @mikejmets - -### Bugfix - -- A pathname like /policy/edit does not show the Unauthorized or Forbidden component when not logged in, ref #1936. @silviubogan -- Fixes secondary views in toolbar @iFlameing @sneridagh -- Fixing overlay expansion during link assign from objectbrowser in edit mode @iFlameing - -### Internal - -- Added new in productions sites to README @wkbkhard -- Writing test for the lisiting block location relative criteria @iFlameing -- Add `UniversalLink` to handle internal/external/download links @nzambello - -## 8.5.4 (2020-10-23) - -### Breaking - -### Feature - -### Bugfix - -- Fixing bug for link when inseting break lines in list tag for view mode @iFlameing - -## 8.5.3 (2020-10-22) - -### Bugfix - -- Removed timezone initialization for DatetimeWidget, ref #1923. @razvanMiu - -## 8.5.2 (2020-10-21) - -### Bugfix - -- Showing error notification when user try to paste disallowed content type. @iFlameing - -### Internal - -- Added environment parameter `RAZZLE_BIND_ADDRESS` to be able to bind server to localhost or other specific IPs instead of 0.0.0.0 @achimwilde - -## 8.5.1 (2020-10-21) - -### Bugfix - -- Fix sharing for when users has dots on them @sneridagh - -## 8.5.0 (2020-10-20) - -### Bugfix - -- Japanese translation updated @terapyon - -## 8.5.0-alpha.2 (2020-10-20) - -### Bugfix - -- Update German translation @ksuess - -### Internal - -- Fix runtimeConfig relative vs absolute import @avoinea - -## 8.5.1-alpha.0 (2020-10-19) - -### Feature - -- Adding softlinebreak in list tag @iFlameing - -### Bugfix - -- Errors catched by the default error handler are sent to sentry @zotya -- Fixed a problem what occured when RAZZLE*SENTRY_DSN was missing but the other RAZZLE_SENTRY*\* variables were set @zotya - -### Internal - -- Fix sentry docs markdown format @avoinea - -## 8.5.0-alpha.0 (2020-10-14) - -### Feature - -- Sentry integration @zotya -- All the environment variables defined at runtime that have the `RAZZLE_` prefix, are now available in the browser under window.env @zotya - -## 8.4.0 (2020-10-14) - -### Feature - -- Add `Style`, a wrapper component that applies float and width classes to wrapped content (typically blocks) @tiberiuichim -- Add `AlignWidget`, a widget that wraps the `AlignBlock` helper @tiberiuichim - -### Bugfix - -- Folder contents view: Save additional columns and updated order of columns @ksuess -- Fixed edit link in draft-js when link is selected from word-end to word-start @giuliaghisini -- Revert PR No. 1820 to fix linebreaks on inline links in draftJS @steffenri - -### Internal - -- Keep `@babel/core` in Volto core in sync with `babel-preset-razzle` it fixes #1897 @sneridagh - -## 8.3.0 (2020-10-12) - -### Feature - -- Adding droppable placeholder for Image Block @iFlameing - -### Bugfix - -- Test if content exists in ListingBody, for addon Dropdownmenu @giuliaghisini - -## 8.2.6 (2020-10-12) - -### Bugfix - -- Fix break-line in view mode @iFlameing - -## 8.2.5 (2020-10-08) - -### Bugfix - -- Fixing the bleed out of the modal for long filename @iFlameing - -## 8.2.4 (2020-10-08) - -### Bugfix - -- Fixing table block edit @iFlameing - -## 8.2.3 (2020-10-07) - -### Bugfix - -- Use Plone `I18N_LANGUAGE` cookie instead of `language` @cekk - -## 8.2.2 (2020-10-06) - -### Bugfix - -- Upgrade react-dropzone from 5.1.0 to 11.1.0 @nileshgulia1 -- Update German translations @tisto - -## 8.2.1 (2020-10-06) - -### Bugfix - -- Querystingsearch action now uses correct relative path, if specified. Fixes #1861 @jackahl -- Fixing ObjectBrowser search input reload @iFlameing -- Fix broken current folder by default in content browser for image links, solves #1860 @sneridagh - -## 8.2.0 (2020-09-27) - -### Feature - -- Add Basque translation @erral - -### Bugfix - -- Added prop resettable to DatetimeWidget @damiDevRT -- Removed the ability to reset the datepicker in the recurrence widget to prevent the uncontrolled creation of recurrences @damiDevRT -- Fix regression in setting selected sidebar tab by blocks @tiberiuichim - -## 8.1.1 (2020-09-27) - -### Bugfix - -- Japanese translation updated @terapyon - -## 8.1.0 (2020-09-22) - -### Breaking - -### Feature - -- Create link in Draftjs using Objectbrowser @giuliaghisini - -### Bugfix - -- Allow select widget to reset when the incoming props change. The react-select widget has its own internal state, so if you initialise the widget without choices, then populate the choices, it wouldn't properly show the default value @tiberiuichim - -### Internal - -- Fix console warning in ToHTML @iFlameing - -## 8.0.1 (2020-09-22) - -### Bugfix - -- Fix word overflow from html-block @iFlameing -- Fix Cypress test for image upload @zotya - -### Internal - -- Improve developer experience, don't logout on hot-reload @tiberiuichim -- Cleanup eslint in razzle.config.js @tiberiuichim - -## 8.0.0 (2020-09-18) - -### Breaking - -- Change dummy-addons-loader.js fixture name to `jest-addons-loader.js`, to match existing `jest-svgsystem-transform.js` @tiberiuichim - -### Feature - -- Added Schema Editor within Dexterity Content-Types Controlpanel @rexalex @avoinea #1517 -- Added Blocks Layout Editor within Dexterity Content-Types Controlpanel @avoinea #1517 -- Added missing components for Email and Url widgets #1246 @rexalex -- Use content title instead of image id in alt tag @nileshgulia1 - -### Bugfix - -- Fix the broken profile view in Toolbar @iFlameing - -### Internal - -- Hide block chooser button using React logic instead of CSS. This makes it easier to support nested blocks @tiberiuichim - -- Wrap addon configuration loaders in a wrapper to check that they return back config @tiberiuichim - -## 7.15.0 (2020-09-15) - -### Feature - -- Added missing components for Email and Url widgets #1246 @rexalex -- Show backend validation errors on corresponding fields #1246 @rexalex -- Validation implemented for add user/group @rexalex -- Show Username when Firstname attr is missing in UsersControlPanelUser @iFlameing - -### Bugfix - -- When dealing with authentication token expiration set to 0, auto-refresh token in one hour instead of logging out use @tiberiuichim -- Fixed front-end field validation #1246 @rexalex -- Fixed date only widget rendering #1246 @rexalex -- Fix errors with SelectWidget when removing the only element @rexalex - -## 7.14.2 (2020-09-10) - -### Bugfix - -- Hyphenate sidebar labels @ksuess -- Update German translations @tisto - -## 7.14.1 (2020-09-09) - -### Bugfix - -- Fix customization mechanism where customization paths end with `/` @tiberiuichim - -## 7.14.0 (2020-09-08) - -### Feature - -- Render form with vertical tabs, setting the property `verticalFormTabs` in config.js @giuliaghisini - -### Bugfix - -- Imported locales by razzle and fixed import locale @giuliaghisini -- Fix console warning due to uncontrolled selectWidget component @nileshgulia1 - -## 7.13.0 (2020-09-07) - -### Feature - -- Add NumberWidget, an input widget for numbers @tiberiuichim - -### Bugfix - -- Fixing the Image size settings in sidebar when Image alignment changes @iFlameing - -## 7.12.1 (2020-09-04) - -### Bugfix - -- Fix checkbox widget styles @nzambello - -## 7.12.0 (2020-09-04) - -### Feature - -- Allow Volto projects to customize (via webpack resolve aliases) addons. Allow addons to customize Volto and other addons. Allow Volto projects to customize Volto in a `src/customizations/volto` folder, for better organization of the customizations folder. @tiberiuichim @sneridagh - -## 7.11.3 (2020-08-28) - -### Bugfix - -- On image upload in a block, don't overwrite the global `state.content.data` with new image data @tiberiuichim @silviubogan - -### Internal - -- Add a `subrequest` option to the `createContent` action @tiberiuichim @silviubogan - -## 7.11.2 (2020-08-28) - -### Bugfix - -- Fix bug introduced in 7.9.0, properly return a list of results when dealing with batched api requests @tiberiuichim -- In folder contents batch upload, use a subrequest to avoid breaking the global `content.data` state @tiberiuichim -- Fix `null` response issue when passing custom `Accept:` headers to actions #1771 @avoinea -- Removed all artifacts from translations @steffenri -- Increase z-index of `block-add-button` @steffenri - -## 7.11.1 (2020-08-27) - -### Breaking - -### Feature - -### Bugfix - -- Update German translations @tisto - -### Internal - -## 7.11.0 (2020-08-27) - -### Feature - -- Add sort option to search @iFlameing - -### Bugfix - -- Turn autocomplete off for the search input field @timo - -## 7.10.0 (2020-08-26) - -### Feature - -- Added toast notifications for form errors @nzambello @avoinea -- Added italian translations and translated array, token and select widget. @giuliaghisini - -## 7.9.2 (2020-08-26) - -### Bugfix - -- Open content browser sidebar on parent object when editing an existing document. @iFlameing - -### Internal - -- Added developer-guidelines/redux documentation @tiberiuichim - -## 7.9.1 (2020-08-25) - -### Bugfix - -- Fix bug related to closing the More menu of Toolbar @iFlameing - -- Fix cosmetic issue, add links were not properly generated in Contents view not under the root. This didn't impact functionality as the content was properly created @tiberiuichim - -- Fix bug for text block with new line and styles applyed to all text. @giuliaghisini - -### Internal - -- Removed unused component `src/components/manage/Contents/ContentsToolbar.jsx` @tiberiuichim -- Add no-console eslint rule @tisto - -## 7.9.0 (2020-08-24) - -### Breaking - -### Feature - -- Adding support of pasting link of voltoCMS video link to video blocks @iFlameing -- Allow serial processing of API requests when `mode:'serial'` is passed in the action. @tiberiuichim -- Adding cypress test from image-gallery in edit mode @iFlameing - -### Bugfix - -- On mutating a block, don't create extra placeholder block if such block already exists @tiberiuichim -- Fixing broken file-preview placeholder for other file type than image @iFlameing - -### Internal - -- When passed an array of items (for example in batch upload content), the `createContent` action now serializes those requests @tiberiuichim - -## 7.8.3 (2020-08-21) - -### Bugfix - -- Change ImageGallery image scale from preview to large. @tisto -- Also use `settings.internalApiPath` in url helpers `isInternalURL`, `flattenToAppUrl` and `flattenHTMLToAppURL` @tiberiuichim -- Fix getBlocks helper when blocks_layout has no `items` (default PloneSite with no volto homepage) @avoinea - -### Internal - -- Docs: Review of "How to use and addon" @ksuess -- Addon: Hint for addon developers if function applying config is missing @ksuess - -## 7.8.2 (2020-08-18) - -### Bugfix - -- Include cypress folder in release @timo - -## 7.8.1 (2020-08-18) - -### Bugfix - -- Remove supposed fix to form.jsx again, as it apparently did not really fix anything but only broke stuff @jackahl - -## 7.8.0 (2020-08-18) - -### Breaking - -### Feature - -- Add cms-only theme that allows to completely remove semantic-ui from public facing views @pnicolli @nzambello - -### Internal - -## 7.7.2 (2020-08-18) - -### Bugfix - -- Fix bug showing wrong data in the edit view, that occured in some cases, when one would enter the edit view of a page from another page @jackahl - -### Internal - -- Remove "\$" from all examples in install docs and README @timo - -## 7.7.1 (2020-08-12) - -### Bugfix - -- Japanese translation updated @terapyon -- Bugfix Edit page through Contents list #1594 @terapyon @csenger - -### Internal - -- Bump serialize-javascript from 2.1.1 to 3.1.0 @timo -- Bump prismjs from 1.17.1 to 1.21.0 @timo -- Make Table Block Cypress test more reliable @timo -- Make listing template Cypress test more reliable @timo - -## 7.7.0 (2020-08-04) - -### Feature - -- Allow addons to provide less files @tiberiuichim -- Making Content browser aware of context @iFlameing - -### Bugfix - -- Fix click-select block on unknown block type @nileshgulia1 -- Fix Image Gallery Template in Listing Block crashing when no criteria are set (#1722) @jackahl - -## 7.6.0 (2020-07-31) - -### Feature - -- Added recurrence widget @giuliaghisini - -## 7.5.1 (2020-07-29) - -### Bugfix - -- Avoid React hydration complaining about mismatched server output in toolbar. In component rendering, replaced the use of `__CLIENT__` with a state-stored `isClient`, as that is more correct. @tiberiuichim - -## 7.5.0 (2020-07-29) - -### Feature - -- Used moment-timezone to set a specific server timezone as default for DatetimeWidget. @razvanMiu - -## 7.4.0 (2020-07-29) - -### Feature - -- Highlight the sidebar toggle button with a small flashing animation @silviubogan @tiberiuichim - -## 7.3.1 (2020-07-28) - -### Bugfix - -- Solved a browser console error in /contents view (#1695) @silviubogan -- Pagination icon fix @nileshgulia1 - -## 7.3.0 (2020-07-26) - -### Feature - -- Add Placeholder attribute to Textwidget and TextAreaWidget @iFlameing -- Make the default block type (currently draftjs text) configurable @tiberiuichim @silviubogan - -### Internal - -- Upgrade lodash dependency to 4.17.19 @tisto -- Add a new blocks helper method, `getBlocks`. It simplifies using `getBlocksFieldname` and `getBlocksLayoutFieldname` under a single method that returns ordered pairs of `[blockid, blockvalue]` @tiberiuichim - -## 7.2.1 (2020-07-16) - -### Internal - -- Upgrade to Cypress 4.10.0 @tisto -- Upgrade to cypress-file-upload 4.0.7 @iFlameing - -## 7.2.0 (2020-07-13) - -### Feature - -- 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 - -- Upgrade razzle to `^3.1.5`. @tiberiuichim - -## 7.1.0 (2020-07-09) - -### Feature - -- Addons can optionally include a `razzle.extend.js` file in their root. This module needs to follow the same rules as the `razzle.config.js`. They change the default Volto Razzle configuration, before it is passed to the Volto project @tiberiuichim @sneridagh - -### Bugfix - -- Managed hidden fields @giuliaghisini -- Fix bug in addon loading with namespaced packages @tiberiuichim -- Japanese translation updated @terapyon - -- Upgrade razzle to `^3.1.5`. @tiberiuichim - -## 7.0.1 (2020-07-07) - -### Bugfix - -- Adding absolute url in ObjectBrowser for image type @iFlameing - -## 7.0.0 (2020-07-06) - -### Breaking - -- Fix filename of strickthrough.svg to strikethrough.svg @tiberiuichim - -### Feature - -- Addons configuration loading. You can now declare addons in the addons key of - package.json and they'll be automatically loaded. @tiberiuichim @sneridagh - -## 6.5.0 (2020-07-03) - -### Feature - -- Added default Export for the QuerystringWidget for the ListingBlock @steffenri - -### Bugfix - -- Fix text overflow in pastanaga-menu header if title is too long. @giuliaghisini -- Fixing bug to correctly assign classes to image sizes in View @steffenri -- Center aligned Images are now displayed like they are center aligned in the View @steffenri -- Fix datepicker z-index @giuliaghisini - -### Internal - -- Upgrade insecure packages `http-proxy`, `http-proxy-middleware` and `handlebars` @tiberiuichim - -## 6.4.1 (2020-07-01) - -### Breaking - -### Feature - -- Allow JSON API calls to made to third-party servers @tiberiuichim - -### Bugfix - -- Fix styling and use of csss classes in `InlineForm.jsx` @tiberiuichim - -- Fixing bug for Image Preview on upload @iFlameing - -### Internal - -- Fix formatting of `src/server.jsx` @tiberiuichim - -## 6.4.0 (2020-06-29) - -### Feature - -- Translated workflow state in contents @nzambello -- Added item type as a tooltip in contents @nzambello -- Added Italian translations and translated array, token and select widget. @giuliaghisini -- Added uploading image preview in FileWidget @iFlameing -- Allow custom express middleware declared with `settings.expressMiddleware`. See [Custom Express middleware](https://6.docs.plone.org/volto/recipes/express.html) @tiberiuichim - -### Bugfix - -- Fix the toolbar dropdown to add content types if isMultilingual is enabled - but a type is not marked as translatable. @csenger -- Usage of Contettype label in Add component. @giuliaghisini - -### Internal - -- Update upgrade-guide to for `addonRoutes` and `addonReducers` @jackahl - -## 6.3.0 (2020-06-22) - -### Feature - -- Added internationalization for French language @bsuttor #1588 -- use of maximumSelectionSize from plone in ObjectBrowserWidget. @giuliaghisini -- Added selectableTypes in ObjectBrowserWidget @giuliaghisini - -### Bugfix - -- Added export for ObjectBrowserWidget in component/index.js @giuliaghisini -- Fixed duplicated items in SelectWidget and ArrayWidget @giuliaghisini -- Update German translation @timo -- Removed broken preview image in ContentsUploadModal if uploaded item is not an image. @giuliaghisini -- Localized content upload modal last modified date @nzambello -- Fix overflow in folder contents with long titles @nzambello -- Fixed object browser widget when a selected items is deleted. Plone.restapi returns a null object. @giuliaghisini -- Fixed error on adding new item if parent item is not translated when multilingual is set @giuliaghisini -- Added translations for select in querystring widget @nzambello - -## 6.2.0 (2020-06-14) - -### Feature - -- Added database information component in ControlPanels @iFlameing - -### Internal - -- Add yarn-deduplicate. @timo - -## 6.1.0 (2020-06-12) - -### Feature - -- Include `config.addonRoutes` in router configuration. This allows addons to - override route children defined for the `App` component. -- Added param 'wrapped' for widgets, to use widgets without form wrappers. @giuliaghisini -- Added internationalization for Romanian language @alecghica #1521 -- Support loading additional reducers from the `config.addonReducers` key, - to allow addons to provide their own reducers @tiberiuichim -- Add a no brainer image sizing option, using scales. This will be vastly improved when - we adopt srcsets. @sneridagh - -### Bugfix - -- Removed a regex check in default view, we already have that check implemented in `toHTML.jsx` L173s @nileshgulia1 -- UX and UI improvements to `DateTimeWidget` @sneridagh -- Fix an UTC handling for edge cases in `DateTimeWidget` @sneridagh -- Do not store the server information of the image block in the block @sneridagh -- expose `blocks` and `blocks_layout` only editing content types @nileshgulia1 -- Small fix for `TextAreaWidget` and max_lenght @sneridagh - -## 6.0.0 (2020-05-18) - -### Breaking - -- Removed support for CSS modules, since Razzle 3.1.x do not support them @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 - cleaned up in next major versions, so if for some reason you have customized the - styling of your blocks in edit mode relying in the old structure, you might want to - review and adapt them @sneridagh - -### Feature - -- Added `react-beautiful-dnd` in core for edit form @iFlameing - -### Bugfix - -- Improve `isInternalURL` helper to match also anchors @sneridagh -- Fix local build when no RAZZLE_API_PATH is set @sneridagh -- Fix `WysiwygWidget` redraft HTML conversion when creating an empty paragraph force a `
` on it @sneridagh - -### Internal - -- Update to Razzle 3.1.2 @sneridagh -- Update to React 16.13.1 @sneridagh -- Removal of unused (and deprecated) `@babel/preset-stage-0` @sneridagh -- Update `react-router` @sneridagh -- Update `react-redux` and friends @sneridagh -- Update `connected-react-router` @sneridagh -- Update low hanging fruits deps @sneridagh -- Update style/less loaders and friends @sneridagh -- Update stylelint and friends @sneridagh -- Update prettier @sneridagh -- Update eslint plugins @sneridagh -- Update `cypress-axe`, `detectbrowser`, `lint-staged` and `release-it` @sneridagh - -## 5.10.0 (2020-05-16) - -### Feature - -- Refactor createContent command to accept a single json object @iFlameing -- enable hyperlinks in comments when intelligent text is enabled for comments @jackahl -- Added InlineForm, a generic form implementation that can be used to edit, among others, block data. @tiberiuichim - -### Internal - -- Make available some internal artifacts (Router, Redux Store and Settings) to the Cypress acceptance tests, add docs @sneridagh -- Added a cypress test for the comment @iFlameing -- Add a cypress function to set registry entries @jackahl - -## 5.9.1 (2020-05-15) - -### Bugfix - -- Fix Bug in Form Component, that lead to site crash when transmitting a comment @jackahl #1475 -- Fix for the long lasted issue when creating links in newly created text blocks not showing as links until you save @avoinea - -### Internal - -- add a cypress function to set registry entries @jackahl - -## 5.9.0 (2020-05-12) - -### Feature - -- Implemented a new ObjectBrowserWidget @giuliaghisini -- Add system information in controlpanel @iFlameing #1457 -- Added Dexterity Types Controlpanel @avoinea #1285 -- Remember sort order of folder contents view. @ksuess - -### Bugfix - -- Fix new lines inside blockquotes are not rendered @iFlameing #1249 -- Fix blockquote style render error: unique key @iFlameing #1097 -- Added Dexterity control panel Cypress tests @iFlameing - -## 5.8.0 (2020-05-11) - -### Feature - -- Adding Image Gallery template in Listing view @iFlameing - -## 5.7.1 (2020-05-08) - -### Bugfix - -- Fix translation locator lookup in `CreateTranslation` component and remove the no longer needed store reducer @sneridagh - -## 5.7.0 (2020-05-08) - -### Feature - -- Enable `@querystringresults` action to use the new context aware query feature @sneridagh - -## 5.6.1 (2020-05-08) - -### Bugfix - -- REALLY load the current object language on SSR, instead of relying on the cookie @sneridagh - -### Internal - -- Pin some api devs (ZCatalog and p.namedfile improvements) @sneridagh - -## 5.6.0 (2020-05-06) - -### Feature - -- Load the current object language on SSR, instead of relying on the cookie @sneridagh - -### Bugfix - -- Correct the `defaultLanguage` intend in `react-intl-redux` configuration @sneridagh - -### Internal - -- Add default `src` alias for addons detecting if there is a released or a mrs-developer one @sneridagh - -## 5.5.0 (2020-05-06) - -### Feature - -- Added label expired if expiration date is smaller that current date #1413 @iFlameing -- Added word limit widget @iFlameing -- Addons control panel @esteele @iFlameing - -### Internal - -- Cypress test for Table Block @steffenri @iFlameing -- Cypress tests upgraded for Image, Hero and HTML Block @steffenri @iFlameing -- Added cypress test for sort method in folder content #1035 @iFlameing - -## 5.4.0 (2020-05-04) - -### Feature - -- Add babel and externals support in Webpack for add-on infrastructure @sneridagh -- Forward the images and files cache headers in Volto SSR passthrough @sneridagh - -### Bugfix - -- Fix handling of external links in ToHTML config @nzambello -- Remove the title field from right dropdown in folder content view - -### Internal - -- Periodical upgrade of `browserlist` lib @sneridagh - -## 5.3.0 (2020-04-29) - -### Feature - -- Add general @navigation endpoint depth setting @sneridagh - -### Bugfix - -- Fix `` `lang` attribute @sneridagh - -## 5.2.1 (2020-04-27) - -### Internal - -- Remove console log in workflow asyncConnect :( @sneridagh - -## 5.2.0 (2020-04-27) - -### Feature - -- Improvement of API requests error handling @sneridagh -- Unauthorized on folder contents if no proper credentials @sneridagh - -### Bugfix - -- Improve German translations for folder contents view @timo -- Make label of checkboxwidget clickable @pbauer #1414 -- Show new added user in user control panel @iFlameing #1271 -- Support multi selection in roles and groups and polish add user #1372 -- Listing block: removed message 'No results found' only in view mode on public site, in editMode is still present. @giuliaghisini - -### Internal - -- Add crossorigin to the preload resources tags while in development @sneridagh -- Permissions in contents and Edit @sneridagh -- Fix the error on content Edit no credentials now shows `Unauthorized` @sneridagh -- Improve console server output showing info @sneridagh - -## 5.1.0 (2020-04-23) - -### Breaking - -### Feature - -- Full screen right sidebar @rexalex #1345 -- Enable internal API proxy for not to rely on CORS on development @sneridagh -- Added Print CSS @iFlameing #1289 -- Added error handling for Add and Edit forms #1392 @nzambello - -### Bugfix - -- Japanese translation @terapyon -- Fix `ArrayWidget` to support multiselect schema `schema.List`/`schema.Set`-> `schema.Choice` hardcoded (not using vocabularies) combination @sneridagh -- Remove Back button from control panels, since it's redundant @sneridagh -- Show past dates in date time widget calendar @nzambello - -### Internal - -- Translated labels in Eventi View @nzambello -- Improve i18n script, so shadowed components are not overriding their original translations. For the record, any override of i18n messages, should be done somewhere else (eg. config object) @sneridagh - -## 5.0.1 (2020-04-16) - -### Bugfix - -- Show new added user in user control panel @iFlameing #1271 -- Fixes for contact form @nzambello - -## 5.0.0 (2020-04-12) - -### Breaking - -- Added basic lazy loading dependencies and boilerplate @sneridagh -- Change component to where page title is set to `View.jsx`, remove all `Helmet` calls from inner views @jackahl - -### Feature - -- Added date time widget @nzambello -- Add meta description tags and meta generator @sneridagh -- Add lang property in `html` tag depending on the site/content language @sneridagh -- Add `App.jsx` component insertion point @sneridagh -- Lazy load `EventView.jsx`, splitting out all its big dependencies (Luxon) along with it @sneridagh -- Lazy load `pretty` library, used in the HTML block @sneridagh -- Lazy load `Raven` library @sneridagh -- Lazy load `React Select` library @sneridagh - -### Bugfix - -- Show save/cancel on control panels @avoinea #850 -- Fix listing "show more" link rendering conditions @nzambello - -### Internal - -- Make Jest only looks up in `src` folder @sneridagh -- Re-arrange `components/index.js` @sneridagh -- Added a patch for Razzle Jest config generator to include `modulePathIgnorePatterns` option @sneridagh -- Fix Travis random no sound card found error @sneridagh -- docs: add release documentation @tisto - -## 4.6.0 (2020-04-06) - -### Feature - -- pagination on site search results @giuliaghisini - -### Bugfix - -- Fix use case for non-multilingual setups and on projects on lang loading @sneridagh - -### Internal - -- Typo in German translations @steffenri -- Complete more Italian translations @nzambello - -## 4.5.0 (2020-04-06) - -### Feature - -- /sitemap to view sitemap based on @navigation with depth 4 @giuliaghisini - -### Bugfix - -- Fix ArrayWidget to support static supermodel vocabulary @datakurre -- Bring back the OutdatedBrowser component, it got removed in a bad merge :( @sneridagh - -### Internal - -- Improve the i18n script, only write the pot file if it's really different @sneridagh - -## 4.4.0 (2020-04-03) - -### Feature - -- /contents (folder content view) is sortable @ksuess -- Updated the (folder content icons to Pastanaga Icons) @iFlameing - -### Bugfix - -- Fix conversion from DraftJS to HTML using redraft for atomic entities (IMAGE) @sneridagh - -## 4.3.0 (2020-04-01) - -### Feature - -- Added recursive workflow changes @robgietema - -### Bugfix - -- Fixed ssr link view @robgietema - -## 4.2.0 (2020-03-31) - -### Feature - -- Add Multilingual Support @sneridagh - -## 4.1.2 (2020-03-30) - -### Bugfix - -- Fix typo for Japanese translation @terapyon -- Fix refresh of the `Breadcrumbs` and `Navigation` components on calling `/login` and `/logout` @sneridagh -- Fix refresh of the `Navigation` component on calling `/login` and `/logout` @sneridagh -- Adjust implementation of the download link behavior for files @sneridagh -- Fix Maps block to use maps-inner instead of video-inner class @timo -- Add div with class "table-of-contents" to ToC block @timo - -### Internal - -- Upgrade critical Plone 5.2.1 deps in api folder @sneridagh -- Improve Cypress Video Block tests @sneridagh @timo -- Run `yarn i18n` on any JSX change @sneridagh -- Add link mailto Cypress test @timo -- Added design guidelines manifesto @sneridagh - -## 4.1.1 (2020-03-18) - -### Bugfix - -- Fix for #1267 - Link inside text for content-type without blocks breaks the site @sneridagh -- Japanese translation @terapyon -- Fix production mode for newly created `__DEVELOPMENT__` global @sneridagh - -### Internal - -- Upgrade to Cypress 4 @timo - -## 4.1.0 (2020-03-13) - -### Feature - -- Add `flattenHTMLToAppURL` helper method for remove api url from TinyMCE generated HTML @cekk -- Add development mode global @sneridagh - -### Bugfix - -- Improve the UX of the listing block when queries are running @sneridagh -- Added table of content cypress test @steffenri - -## 4.0.1 (2020-03-09) - -### Bugfix - -- Fixes #1262 - SSR support for "undetected" browsers -- Japanese translation @terapyon -- Site settings styling fixed in the Controlpanel -- Increase ObjectBrowser limit per folder to 1000, partially fixes #1259 @sneridagh -- Deprecate `utils.less` as it's a leftover and it collides with some use cases depending on the viewport, see: #1265 - -### Internal - -- Use kitconcept.volto as integration package @sneridagh - -## 4.0.0 (2020-03-01) - -### Feature - -Summary of the most important features in this final release. For more detailed information -refer to all of them in https://github.com/plone/volto/releases - -- Improved Pastanaga Editor -- New Pastanaga Editor sidebar -- New mobile first toolbar -- Developing blocks experience simplified -- New Object Browser -- Listing, TOC, Lead Image blocks -- Improved existing blocks (Image, Video, Maps) -- New blocks chooser and future proof blocks definitions -- Definition of default Blocks per content type -- Body classes like the Plone ones hinting content types, section and current view -- New message system -- React hooks support -- Several internal libraries updated, including Redux, Router ones that support hooks as well -- New locales (es, it, ja, pt, pt_BR) - -### Bugfixes - -- Tons of bug fixes - -## 4.0.0-alpha.43 (2020-03-01) - -### Changes - -- Fixes #982 - History compare/diff @avoinea -- Responsive header @ksuess - - Anontools (login, register) wrapping under long navigation. - - Breaking change: Hamburger menu also on tablet. - - Mobile: compact display of anontools and search. - -## 4.0.0-alpha.42 (2020-02-26) - -### Changes - -- Revert "Fix Scrolling Functionality if there are many columns in table" since it has non desired secondary effects in the table block and other tables @sneridagh - -## 4.0.0-alpha.41 (2020-02-26) - -### Changes - -- Fixes for the `ListingView` (Issue #1188, Listing View) @wkbkhard -- Fix date widgets on QueryString widget on listings and in the widget @sneridagh -- Update German translation @tisto -- i18n in toolbar and folder contents view @ksuess - -## 4.0.0-alpha.40 (2020-02-24) - -### Added - -- Add pagination support to listing blocks @sneridagh - -### Changes - -- Fix Video and Maps blocks hydration quirks on view mode @sneridagh -- Deleted Empty Select Component @aryamanpuri -- Fix `RichText` Widget on normal forms @sneridagh -- Fix Guillotina tests @bloodbare -- Fix problem with not wrapped element in `Provider` store in `WysiwygWidget` component - due that now, the links are wrapped with a connected component @sneridagh - -## 4.0.0-alpha.39 (2020-02-18) - -### Added - -- Add permission check to edit form @sneridagh - -### Changes - -- Fix and improve Error in SSR @sneridagh -- Fix `LinkAnchorPlugin` press Enter key inside blocks with draftJS widgets @sneridagh - -### Internal - -- Replace all relative paths to `@plone/volto` absolute paths to ensure you can override all the resources via component shadowing @sneridagh - -## 4.0.0-alpha.38 (2020-02-18) - -### Internal - -- Update to use ESLint 6 @timo - -## 4.0.0-alpha.37 (2020-02-18) - -### Added - -- Chose template for listing block @giuliaghisini -- Event type view @nileshgulia1 @pnicolli -- Add ability to define the starting blocks per content type @sneridagh -- Reference widget: show item title and path in search and hover items selected @giuliaghisini - -### Changes - -- Fix the "jump" on the blocks editor on focusing blocks @sneridagh -- Include link and size info to the full size image in `ImageView` view component @sneridagh -- In the Display menu, only show views that are implemented @pnicolli -- Hide Blocks fields in Layout fieldset in Add/Edit forms @pnicolli -- Updated italian translations @nzambello -- Fallback for non existing layout views registered in `constants/Layouts` when selected in the widget @sneridagh -- Fix select widget for array inline choices fields and `z-index` problem @sneridagh -- Improve UX of the edit block Image component @sneridagh -- Fix on creating a new block, it should show the sidebar block properties (#1167) @sneridagh -- Send only the changed fields on PATCH (edit content) operations @sneridagh -- Japanese translation @terapyon - -### Internal - -- 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 - -## 4.0.0-alpha.36 (2020-02-03) - -### Changes - -- Fix unable to login from /logout page (#1147) @sneridagh -- Fix sitemap.xml by increasing the batch size @robgietema -- Browser detect feature, adding a deprecation message for ancient browsers in the `App` component @sneridagh -- Adding fallback in the edit form, in case the blocks related fields are empty, so we are sure that the edit form shows at least the default blocks @sneridagh -- Fix shift return in tables @robgietema - -## 4.0.0-alpha.35 (2020-01-31) - -### Changes - -- Fix CSS when multiselection widgets have multiple items, then provoke a line jump @sneridagh -- added new italian translations, added italian to available languages, translated some static string -- updated italian translations -- Fix listing block sidebar focus @sneridagh -- Fix getBaseUrl helper method to not match inner occurrences of nonContentRoutes @sneridagh - -## 4.0.0-alpha.34 (2020-01-26) - -### Changes - -- Fix token expiration/renewer timer, this fixes #674 @sneridagh - -## 4.0.0-alpha.33 (2020-01-26) - -### Changes - -- Updated Maps block to the sidebar and image block look and feel @sneridagh -- Update video block to the sidebar and get the image block look and feel @sneridagh - -### Internal - -- Fix and update to latest husky and lint-staged @sneridagh -- Fix for i18n to use defaultMessages instead to default to the id @sneridagh -- Update `babel-plugin-react-intl` to latest @sneridagh - -## 4.0.0-alpha.32 (2020-01-24) - -### Added - -- Lead image behavior block @sneridagh sponsored by `CMSCOM.jp` @terapyon - -### Changes - -- Make login component honors the returnUrl prop if called from any pathname @sneridagh - -### Internal - -- Try to improve the realibility of the Cypress tests, reorganize commands @sneridagh -- Upgrade to Plone 5.2.1, add `Products.PloneHotfix20200121` @sneridagh -- Force global use of `browserslist` package to get rid of message on build @sneridagh - -## 4.0.0-alpha.31 (2020-01-22) - -### Changes - -- fix `SelectWidget`, when there is a vocabulary and no choices @sneridagh - -## 4.0.0-alpha.30 (2020-01-22) - -### Added - -- Added listing block @pnicolli @rodfersou @sneridagh @giuliaghisini - -### Changes - -- fix bug in TokenWidget and ArrayWidget when removing all elements. @giuliaghisini -- fix listing block customization @giuliaghisini -- fix Querystring widgets failing to render if the `MultipleSelectionWidget` field applied is not included in the site vocabulary returned by `@querystring`. This applies to `Subject` field when the tag value is not there any more. @sneridagh -- fix QueryString widget on creation when query is empty, fixed broken when editing after too @sneridagh - -## 4.0.0-alpha.29 (2020-01-18) - -### Changes - -- Remove dangling reference to external data in Image block not used anymore, causing confusion and lead to dead (and wrong) code @sneridagh -- Remove last remains of the append secondary actions, remove Image block toolbar. Update i18n, fix small issues in Image block @sneridagh - -## 4.0.0-alpha.28 (2020-01-17) - -### Changes - -- Fix ToC anchor links in Firefox @robgietema - -## 4.0.0-alpha.27 (2020-01-17) - -### Changes - -- Fix removing links in blocks @robgietema - -## 4.0.0-alpha.26 (2020-01-15) - -### Added - -- German translation updated @timo - -## 4.0.0-alpha.25 (2020-01-14) - -### Added - -- German translation for TOC @timo - -## 4.0.0-alpha.24 (2020-01-14) - -### Added - -- Added customStyleMap param to Editor of draftjs @giuliaghisini -- Added Table of Contents block @robgietema - -## 4.0.0-alpha.23 (2020-01-14) - -### Added - -- Support for indexable blocks (requires plone.restapi 6.1.0) @timo -- Set alt tag of image when selecting image in image block @robgietema - -### Changes - -- Avoid console warnings in AddLinkForm.jsx @tiberiuichim -- More cleaning the body classname from the current displayname view @sneridagh -- Make it possible to paste links, lists, b and i Elements into text-blocks - @jackahl -- added option to include mp4 files from a remote source in video Block @steffenri @jackahl -- Make it possible to paste links, lists, b and i Elements into text-blocks @jackahl - -## 4.0.0-alpha.22 (2020-01-04) - -### Changes - -- Disable all styling when copying text from another source (e.g. MS Word) into a text block @jackahl -- Avoid console warnings in QuerystringWidget @tiberiuichim -- Fix body classname based on the current content type @sneridagh - -## 4.0.0-alpha.21 (2020-01-02) - -### Changes - -- Fix failing test on Footer due to year change in Copyright notice @sneridagh - -## 4.0.0-alpha.20 (2020-01-02) - -### Added - -- Added translations to Portuguese @emansije - -### Changes - -- Fix wysiwyg widget help tag, for styling consistency @tiberiuichim -- Added more i18n improvements @macagua -- Disable submit button on save, to avoid multiple content creation @tiberiuichim -- Fix focus on sidebar @robgietema - -### Internal - -- Upgrade version pin for lxml, for compatibility with Python3.8 -- Bump handlebars from 4.1.2 to 4.3.0 @timo - -## 4.0.0-alpha.19 (2019-12-20) - -### Added - -- Implementation of `Portuguese (BR)` translation @LeuAlmeida -- Added translations to spanish @macagua -- Added AlbumView @wkbktill @alexbueckig - -### Changes - -- empty text blocks are shown as `
` in the view. -- Fix double fetch due to asyncConnect being executed in browser too @robgietema @sneridagh - -## 4.0.0-alpha.18 (2019-12-12) - -### Added - -- Added CTRL+ENTER feature in text blocks by default. It creates a newline inside the same text chunk (`

`) @sneridagh -- Automatically switch sidebar on block change @robgietema -- Japanese translation @terapyon - -### Changes - -- Remove "documentDescription" class in table block @sverbois -- Added possibility to work with vimeo-videos instead of youtube-videos in the video block @wkbkhard -- Fixed Issue 1021: typing in a "wrong" URL leads to error @wkbkhard -- General toolbar more and personal tools menu CSS fixes @sneridagh -- Fix bug that lead to crashing the view when deleting the last row of a table -- Fix Select widget bug if the field has already the options in the `choices` schema, do not trigger the vocabulary request @sneridagh - -### Internal - -- Updated to react-select v3 @robdayz -- Fix file and link redirect views @robgietema -- Restrict moment.js locales to available languages @tisto @robgietema -- Fix history view @robgietema - -## 4.0.0-alpha.17 (2019-12-03) - -### Internal - -- Revert eslint upgrade, because of problems with the react-app preset typescript settings @sneridagh - -## 4.0.0-alpha.16 (2019-12-02) - -### Changes - -- Fix small CSS issues in Blocks @sneridagh - -### Internal - -- Pin Guillotina docker image @sneridagh -- Forked `react-helmet` since it seems unmaintained. Now it's a Named import in helpers. @sneridagh -- Update internal dependencies, fix "unmet peer dependencies" console logs by adding the peer dependencies to the local dependencies @sneridagh -- Update some dependencies, including: react-router, eslint engine and plugins/config and others @sneridagh -- Lodash improvements for decrease bundle size @sneridagh - -## 4.0.0-alpha.15 (2019-11-27) - -### Internal - -- Export the resetContent action @pnicolli -- Fix toolbar collapsed color @sneridagh -- Minor CSS fixes @sneridagh -- Remove @testing-library/cypress dep, as it breaks builds if the internal cypress release is different than the one in this package @sneridagh - -## 4.0.0-alpha.14 (2019-11-24) - -### Internal - -- Proper config for stylelint-prettier integration, add husky integration and scripts for stylelint, review stylelint rules @sneridagh - -## 4.0.0-alpha.13 (2019-11-23) - -### Internal - -- Upgrade autoprefixer, remove deprecated `browsers` option, move to `browserlist` in `package.json` @sneridagh -- Upgrade react and react-dom to 16.12.0 @pnicolli -- Upgrade Cypress to 3.6.1 @timo - -## 4.0.0-alpha.12 (2019-11-13) - -### Changes - -- Add loading animation for save and edit buttons in toolbar @pgrunewald -- Move Body class depending on content type to `App` component in order to make it available everywhere @sneridagh -- Add root class name to `Tags` component @sneridagh - -## 4.0.0-alpha.11 (2019-11-08) - -### Added - -- Improved `ObjectBrowser` API to allow arbitrary field names and a custom `onSelectItem` @sneridagh - -### Changes - -- Fix icon in `TextWidget` @sneridagh -- Improve documentation for `Icon` @jackahl -- Fix ability to develop Volto itself (as and addon with a mrs.developer checkout) inside a Volto project @sneridagh - -### Internal - -- Add internationalization section to docs @pgrunewald - -### Internal - -- Set Cypress viewport width to 1280px @timo - -## 4.0.0-alpha.10 (2019-10-31) - -### Added - -- Add Node 12 support @timo - -### Changes - -- Removed wrapper `p` tag from image block in edit mode for better layout purposes @sneridagh -- Make SelectWidget more robust @robgietema -- Add image to listing view @robgietema -- Fix `SchemaWidget` @robgietema -- Move styles import to a separate file @pnicolli -- Fix crash when user enters only whitespace in required fields @JeffersonBledsoe -- Fix the _real_ focus thief in new tiles @sneridagh - -### Internal - -- Report port number on startup @fredvd -- Retry Cypress tests two times before failing @timo -- Add waitForResourceToLoad to Cypress @timo -- Add use cases to README @timo -- Re-enabled Guillotina tests @sneridagh -- Remove Docker build from tests @sneridagh -- Removed Enzyme @pnicolli -- Added testing-library (react and cypress) @pnicolli -- Tiles -> Blocks renaming @sneridagh - -## 4.0.0-alpha.9 (2019-10-09) - -### Changes - -- Rename `blockID` to `id` for view block components, to unify naming in edit-view @sneridagh -- Change the order of the widget decider algorithm to `choices` is chosen before the vocabularies one @sneridagh -- Remove old messages container since it's not used anymore @sneridagh -- Improve the Pastanaga Editor block wrapper container layout, deprecating the hack `.ui.wrapper > *` @sneridagh -- Fix `ArrayWidget` and amend users control panel arrays instantiations @sneridagh - -## 4.0.0-alpha.8 (2019-10-05) - -### Added - -- Upgrade react-intl to latest version @sneridagh - -### Changes - -- Fix `DefaultView.jsx` warning on missing key @sneridagh - -### Internal - -- Enable run yarn install on git checkout and git pull in husky @sneridagh -- Disable Cypress blocks tests @sneridagh -- Remove dockerized unit tests @timo -- Add Cypress link test for text blocks @timo - -## 4.0.0-alpha.7 (2019-10-02) - -### Added - -- Add CSS class names to block chooser @timo -- Add Cypress tests for blocks @timo @rodrigo @jakahl - -### Changes - -- Fix page jump on edit route @sneridagh -- Fixes to users and groups controlpanel i18n strings @nileshgulia1 - -### Internal - -- Change the general naming of the documentation to `developer` documentation @sneridagh -- Add `blockID` prop to block tiles render view, this is handy for some blocks use cases @sneridagh -- Fix flaky Cypress test @sneridagh - -## 4.0.0-alpha.6 (2019-09-30) - -### Added - -- Transfer focus management and keyboard navigation to the tiles engine @sneridagh - -### Changes - -- Slight amendment to Blocks chooser styling @sneridagh -- The default view for content types `DocumentView.jsx` has been renamed to a more appropiate `DefaultView.jsx` @sneridagh - -### Internal - -- Add complete husky config @sneridagh -- Add `COC.md` file @timo - -## 4.0.0-alpha.5 (2019-09-28) - -### Added - -- Default body classes were enhanced to accept path and content type based ones as in Plone @sneridagh - -### Changes - -- Fix for checkboxes when setting `false` values, this fixes #888 @sneridagh - -## 4.0.0-alpha.4 (2019-09-27) - -### Added - -- Added Users and Groups Controlpanel @nileshgulia1 @csenger @jackahl - -### Changes - -- Move the Tile Edit wrapper one level up to the tiles engine, so we can simplify how edit tiles are made @sneridagh -- Rename Metadata and Properties in sidebar to Document and Block @jackahl -- Add some German Translations @steffenri, @jackahl - -### Internal - -- Fix cypress test for file Upload @jackahl -- Dependencies upgrades (router, redux) @sneridagh -- Enhance Cypress createContent keyword to create files and images @timo -- Fix docs build locally @sneridagh - -## 4.0.0-alpha.3 (2019-09-22) - -### Added - -- New tiles chooser @sneridagh - -### Internal - -- Fail eslint check on any warnings @timo -- Add i18n check on Travis @timo - -## 4.0.0-alpha.2 (2019-09-19) - -### Changes - -- Fix parameter handling in Search view to avoid limiting search results with empty parameters #845 @csenger -- Fix SearchTags handling of keyword vocabulary for anonymous users @csenger -- Fix hero tile being next to a left or right aligned image @jackahl -- Fix toolbar elements showing depending on user permissions @sneridagh - -## 4.0.0-alpha.1 (2019-09-17) - -### Changes - -- Fix test failure for `VersionOverview` component in master after release process @sneridagh -- Improve usability of login form @sneridagh -- Fix creation of image objects from image tile by adding the id as well @sneridagh -- Remove description tile from the default tiles on new content @sneridagh - -### Internal - -- Update release-it to fix some deprecation messages @sneridagh - -## 4.0.0-alpha.0 (2019-09-13) - -### Added - -- Show images in Rich Text editor @rodfersou @sneridagh -- Full Pastanaga Toolbabr implementation @sneridagh -- Internal API path for containers @bloodbare -- Add toast component @sneridagh -- Add sidebar support for components @sneridagh -- Add Volto version number in control panel @nzambello -- Remove Mosaic component @tisto -- Added toast component in actions @nzambello -- Added translations to italian @nzambello -- Add table tile @robgietema -- Add image sidebar @sneridagh @gomez -- Add delete file button to file Widget @jackahl -- Add link redirect view @robgietema -- Add proper unique id to all fields, based on the fieldset and field name @sneridagh -- Add QueryString widget @robgietema @sneridagh - -### Changes - -- Add a delay when filtering content in folder contents so it doesn't overload backend @vangheem -- Small UX/UI fixes @sneridagh -- Fix query string search in subjects vocab field @gomez -- Removed the delete button from the title tile @pnicolli -- Rewrite sidebar @robgietma @sneridagh -- Added SidebarPortal component for easier sidebar handling @pnicolli -- Fixed tiles outline in Pastanaga editor @pnicolli -- Fix typos @balavec -- Fix warnings for boolean fields @miziodel -- Fix dropdown styling @robgietema -- Update connected-react-router and fix instantiation of the wrapper component - to fix the sync problems with the router and the store @sneridagh -- Fix link popup in case you dismiss it without setting anything @sneridagh -- Export history in start-client.jsx for being able to import it from the project for trackers (Matomo, etc) @csenger -- Workflow change awareness on toolbar @robgietema -- Fix reordering in folder contents view and problems with previous windowing settings leaked to current one. @robgietema -- Fix remove link entity of only a part it only removes that part, not the whole entity @robgietema -- Add proper placeholder to the add link feature in the editor @sneridagh -- Fix bulk workflow change in contents view @sneridagh -- Fix regresion on uploading image to root @sneridagh -- Fix hero tile on view if image is missing @sneridagh -- Fix link to contextual contents in toolbar @sneridagh -- Add automatically the wildcard for the `SearchableText` on the @search action @sneridagh - -### Internal - -- Upgrade lodash to 4.17.15 @tisto -- Fix console errors on tests @sneridagh -- Add development mode for kitkoncept.voltodemo to /api plonebacked @fredvd -- Cleanup map dispatch to props @robgietema -- Fix linting warnings @robgietema -- Remove decorators @robgietema -- Pin mem to 4.0.0 @tisto -- Add razzle-plugin-bundle-analyzer @tisto -- Add bundlewatch @tisto -- Add bundlesize @tisto -- Update base buildout @sneridagh - -## 3.1.0 (2019-06-14) - -### Added - -- Upgrade to react-redux 7.1. It includes the new official hooks for Redux. @sneridagh -- Make Login Route accessible from anywhere in path url @nileshgulia1 - -### Changes - -- Fix basic tiles classes @rodfersou -- Fix video alignment @sneridagh - -### Internal - -- Upgrade handlebars to 4.1.2 @timo -- Upgrade js-yaml to 3.13.3 @timo -- Upgrade Plone api folder to 5.2rc3 @sneridagh -- Fixes for image/file fields widgets for Guillotina @sneridagh -- Fixes for Cypress Guillotina tests @sneridagh - -## 3.0.4 (2019-05-30) - -### Changes - -### Internal - -- Add cypress a11y tests. @timo -- Fix order of arguments when sending the contact form @csenger -- Fix @babel/core import on i18n script @sneridagh - -## 3.0.3 (2019-05-13) - -### Internal - -- Use eslint-config-react-app instead of airbnb + custom config for linting @timo -- More eslint fixes for avoiding parsing errors on decorators @sneridagh -- Add 'prettier' command to check if there are any missing prettier fixes @timo -- Run 'prettier' on Travis and fail the build if there are missing prettier fixes @timo -- Add 'prettier:fix' command to fix all missing prettier fixes at once @timo -- Run 'prettier:fix' once and commit all fixes @timo -- Fix the most important violations reported with the new config @sneridagh - -## 3.0.2 (2019-05-10) - -### Changes - -- Re-add babel-eslint because of the decorators @sneridagh -- Upgrade eslint-config-airbnb @sneridagh - -## 3.0.1 (2019-05-10) - -### Changes - -- Small fix for a missplacement of the hooks plugin in .eslintrc @sneridagh - -## 3.0.0 (2019-05-10) - -### Added - -- Upgrade to Razzle 3 @sneridagh -- contact-form view @cekk -- Add cypress setup for both Plone and Guillotina @sneridagh -- Update SelectWidget and ArrayWidget and related vocabularies actions/reducers - for the breaking changes in plone.restapi 4.0.0 @davisagli @sneridagh -- Expose request on the promise returned by the api helper @csenger - -### Changes - -- Several dependencies upgraded @sneridagh -- Fix image of Hero Tile for images in private containers @sneridagh -- Remove enforcement of JSdocs in Volto ESlint rules @sneridagh -- Remove RobotFramework tests in favor of the cypress ones @sneridagh -- Updated docs to highlight some code changes @pigeonflight - -## 2.1.3 (2019-04-17) - -### Changes - -- Update api folder to Plone 5.2 and Python3, update the whole story @sneridagh - -## 2.1.2 (2019-04-16) - -### Changes - -- Fixed issue where it was not possible to click into the title tile above the - small red bar at the beginning of the line in some browsers. @jackahl -- Docs content editing. @esteele -- Fix the folder_contents view component bby preventing the SearchableText be - empty if you haven't typed anything in the filter fields yet. This is caused - by the new ZCatalog in Zope 4. @sneridagh - -## 2.1.1 (2019-04-04) - -### Changes - -- Improved search action, now it supports passing directly the arrayed values - and it converts it to Plone's query syntax @sneridagh - -- Added depth argument to the navigation action, to match the @navigation - endpoint feature @sneridagh - -## 2.1.0 (2019-04-02) - -### Added - -- Added specific `onMutateTile` for solely use of the Text tile when it mutates - to another type of tile. This prevents onChangeTile do one thing that it was - not designed lifting responsibilities from it. @sneridagh -- Added `detached` mode for the text tile so it will be able to render outside - the Volto editor without all the tile mutation machinery and the keyboard - handlers. @sneridagh - -### Changes - -- Small improvements to the internal tile api @sneridagh -- Fix for tiles having dialog box `ENTER` key captured by global tile onKeyDown - handler, then creating a tile instead of the intended behavior. @sneridagh -- Fix small CSS and import issues @sneridagh -- Fix Invalid Redraft object warning on console @sneridagh - -## 2.0.0 (2019-03-25) - -### Added - -- Tiles refactor, move keyboard listeners and Trash icon to Tiles HOC - @sneridagh -- Fix tiles navigation via cursors on all available tiles @sneridagh -- Fix UX on HTML tile when navigating via cursors @sneridagh -- Add ability to add new text tile via `Enter` key @sneridagh -- Add create new text tile at the bottom on adding tiles @sneridagh -- Improve general UX on tiles creation and focusing on creation @sneridagh - -## 1.10.0 (2019-03-25) - -### Added - -- Fix npm package generation @sneridagh - -## 1.9.0 (2019-03-25) - -### Added - -- Upgraded to React 16.8 (the one with hooks) @sneridagh -- Upgraded to the recent (at last) released react-redux 7.0beta.0, this release - solves the performance issues with the new React context and leave them ready - for the upcoming useRedux hook. This release supports the latest React 16.8. - @sneridagh -- Upgraded to the latest Router and react-router-config and other required - upgrades. @sneridagh -- Upgraded to latest redux-connect @sneridagh -- Upgraded to latest razzle @sneridagh - -## 1.8.3 (2019-03-21) - -### Changes - -- Several CSS fixes @sneridagh -- Add several icons @sneridagh - -## 1.8.2 (2019-03-21) - -### Changes - -- Improve README @svx @fredvd -- Pretty Pastanaga UI .overrides stylesheets @sneridagh - -## 1.8.1 (2019-03-19) - -### Changes - -- Fix hero tile View styling, add definitive icon @sneridagh -- Fix the trash icon on the tiles that was displaced by other change @sneridagh - -## 1.8.0 (2019-03-15) - -### Added - -- Hero Tile @nileshgulia1 @sneridagh - -### Changes - -## 1.7.0 (2019-03-03) - -### Added - -- Add image-zooming functionality @nileshgulia1 - -### Changes - -- Fix image float/left right on image tile @timo - -## 1.6.1 (2019-03-01) - -### Changes - -- Fix a regression on the add tile button alignment @sneridagh - -## 1.6.0 (2019-03-01) - -### Added - -- Set image width in Volto editor to 50% for images that float left/right @timo -- Ability to navigate through the existing tiles with the cursors. @sneridagh -- HTML Tile for Volto Editor with preview and code prettifier - @ajayns @nileshgulia1 @sneridagh -- Add error log in the SSR console @sneridagh -- Add SSR helper to get resources (images/files) from the server using the API - headers. This fixes the missing images on non published resources while editing @sneridagh -- Fix not valid `

` tag nested in a `

` tag error on tiles and wysiwyg - field @sneridagh - -### Changes - -- Clean .variables files from Pastanaga theme since they are already applied by - the theming engine from the default theme. @sneridagh -- Fix edit forms with richtext fields coming from SSR @sneridagh - -## 1.5.2 (2019-02-20) - -### Changes - -- Fix external images on Image Tile render @sneridagh -- Several fixes reagarding correctness of markup @sneridagh -- Issue with dangerouslySetInnerHTML RichText fields on first SSR load - apparently fixed (due to the above fix) :) @sneridagh - -## 1.5.1 (2019-02-19) - -### Changes - -- Fix build for projects created with `create-volto-app` @sneridagh -- Fix link view @nileshgulia1 - -## 1.5.0 (2019-02-19) - -### Added - -- Add Google Maps tile @nileshgulia1 -- Add support for extending Semantic UI Styling using the semantic theme engine - by adding an `extras` file that can bring into the engine new styles coming - from third party libs or custom styling code for the local theme. Being this - applied after semantic default styling, it's the last one in the styling - cascade easing the develop of new themes. @sneridagh - -### Changes - -- Prevent Volto hit the @types endpoint (via its action, getTypes()) if the - user is not authenticated, since it's useless and always returns a 401 - @sneridagh -- Improved readme @sneridagh -- New logo for the Pastanaga Theme referring to Volto and fix header @sneridagh -- Disable SocialSharing component by default @sneridagh -- Fix login tab index for username autofocus and password after tab @sneridagh -- Fix hamburgers menu @sneridagh -- Fix CSS sourcemaps by make postcss stage to accept other stages sourcemaps - @sneridagh -- Add IE11 fixes by pinning some packages, added documentation in `docs` about - it and how to deal with it. However, compatibility is _NOT_ guaranteed in - future Volto releases @sneridagh -- Fix Header scroll in Firefox in case that there are lot of items in the nav - @sneridagh -- Add supported browsers in README @sneridagh -- Default tile position to center for all the existing tiles @sneridagh - -## 1.4.0 (2019-02-15) - -### Added - -- Add the ability to detect the edit Plone Site hack for show the tiles editor - on Plone site edit @sneridagh - -### Changes - -- Bring back the stylelint default configs for IDEs @sneridagh -- Improve ESlint resolvers for special paths (@plone/volto and ~), so IDEs do - not complain any more with no-unresolved active @sneridagh -- Fix the floating image problem in the Volto Editor @sneridagh - -## 1.3.0 (2019-02-13) - -### Added - -- Improve the definitions of the view/edit tiles components for better - extensibility. This might be a BREAKING change if you have already used the - old way to extend/add more tiles, please update to the new one @sneridagh - -### Changes - -- Fix Travis unit testing false green @sneridagh -- Fix bad Proptype for location in ScrollToTop component @sneridagh - -## 1.2.1 (2019-02-04) - -### Changes - -- Bring back the scroll to top on every route change feature @sneridagh -- Loosen node version, allow LTS (v8 and v10) @sneridagh - -## 1.2.0 (2019-01-22) - -### Added - -- be able to specify custom headers in actions @vangheem -- fix icons used in contents @vangheem -- be able to work with mr.developer @vangheem -- add alias `@plone/volto-original` and `@package` webpack aliases @vangheem -- add `errorViews` configuration @vangheem - -### Changes - -- Upgrade to Node 10.14.2 @nileshgulia1 - -## 1.1.0 (2018-12-24) - -### Changes - -- Fix edit on root @robgietema -- Fix sharing @robgietema -- Fix error on token renew @robgietema -- Fix layout fieldname @bloodbare -- First field in a form will get the focus @robgietema -- Fix download file links @mikejmets -- Fix HMR missbehaving on both server and client @sneridagh -- Upgrade to Node 8.14.0 @timo -- Relaxed node runtime constraints @sneridagh -- Update to latest LESS and Semantic UI version @sneridagh - -## Added - -- Add .gitattributes file to avoid most Changelog merge conflicts @pnicolli -- Buildout for Python 3 @pbauer -- Websockets support @robgietema -- Subrequests to search and get content actions @robgietema -- Add logos @sneridagh @albertcasado - -## 1.0.0 (2018-10-31) - -### Added - -- Training documentation link @robgietema - -## 0.9.5 (2018-10-24) - -### Changes - -- Fix API*PATH variable using RAZZLE* prefix instead @sneridagh -- Fix FUOC (flash of unstyled content) in production mode @sneridagh -- Fix missing buttons on RichText tiles @sneridagh -- Fix original external `overrides.css` position in the cascade was applied in - the wrong order in site.overrides in Pastanaga theme @sneridagh -- Fatten widget config @robgietema - -## 0.9.4 (2018-10-10) - -### Changes - -- Fix tags layout @robgietema @jaroel -- Fix imports of views, widgets and tiles @robgietema @jaroel - -## 0.9.3 (2018-10-10) - -### Changes - -- Fix logo import path @robgietema @jaroel - -## 0.9.2 (2018-10-10) - -### Added - -- Automatic customization imports for images @robgietema @jaroel - -## 0.9.1 (2018-10-10) - -### Added - -- Automatic customization imports @robgietema @jaroel - -## 0.9.0 (2018-10-04) - -### Changes - -- Renamed package to Volto @robgietema - -## 0.8.3 (2018-10-03) - -### Changes - -- Fix i18n script for dependency @robgietema - -## 0.8.2 (2018-10-03) - -### Changes - -- Move all dev dependencies to dependencies @robgietema - -## 0.8.1 (2018-10-03) - -### Changes - -- Fix compiling when used as a library @robgietema -- Fix buildout security issue @robgietema - -## 0.8.0 (2018-10-03) - -### Added - -- Move the webpack config to Razzle @sneridagh @robgietema -- Upgrade React to 16.5 @tisto -- Upgrade React to 16.4.2 to fix a server-side vulnerability @tisto -- Support for base url @bloodbare - -### Changes - -- Merged Guillotina and Plone robot tests @bloodbare -- Don't reset total and batching on pending search @robgietema - -## 0.7.0 (2018-07-31) - -### Added - -- Add Pastanaga Icon System @sneridagh -- Support for nested schemas @robgietema -- New block on return in editor @robgietema -- Added 404 page on page not found @robgietema -- Custom tiles support @sneridagh -- Add full register/password reset views @sneridagh -- Make the list block types configurable @robgietema -- Add all missing German translations @tisto -- Add helper `BodyClass` for appending classes to the `body` tag from View components @sneridagh -- Add Tiles support for Guillotina CMS @bloodbare @sneridagh @robgietema - -### Changes - -- Pastanaga Editor look and feel improvements and polishment @sneridagh @albertcasado -- Refactor configuration of routes, views and widgets for extensibility @sneridagh @davilima6 -- Fix view name class in body element @sneridagh @davilima6 -- Refactor actions @robgietema -- Store text tile data in json @robgietema -- Fixed tile add menu @robgietema -- Change to use root import on all config calls @sneridagh -- Fix CSS on tile image view @sneridagh -- Fix broken CSS on alignments left/right @sneridagh -- Tile DE literals translations @sneridagh -- Pass location as prop to child views in main View component in case we require it in some views @sneridagh -- Fix computed displayName from add-display-name Babel plugin for connected components @sneridagh - -## 0.6.0 (2018-07-14) - -### Added - -- Schema widget @robgietema -- User actions and reducers @robgietema -- Group actions and reducers @robgietema -- Roles actions and reducers @robgietema -- Move combineReducers to the store creation level. This will ease the extensibility of them in Plone-React apps. @sneridagh -- Upgrade node to 8.11.2 @sneridagh -- Basic user listing in users controlpanel @robgietema -- Add missing FileWidget import @sneridagh -- Option to delete tiles @robgietema -- Option to add tiles @robgietema -- Image tiles in editor @robgietema -- Align images in editor @robgietema -- Video tiles in editor @robgietema -- Video tiles in editor @robgietema -- Sitemap.xml.gz view @robgietema -- Upload image indicator @robgietema -- Video tile view @robgietema -- Option to reset image @robgietema -- Drag and drop to reorder tiles @robgietema -- Enhanced DraftJS AnchorLink Plugin @robgietema @sneridagh -- Added the configuration required in Webpack config to load CSS modules in the project, required by DraftJS AnchorLink plugin @sneridagh - -### Changes - -- Styled wysiwyg widget @robgietema -- Switch from accordion to tabs in forms @robgietema -- Upgrade to Node 8.11.1 @tisto -- Replace ExtractionTextCSSPlugin with the new mini-css-extract-plugin, adapt universal-webpack config @sneridagh -- Removed flow @robgietema -- Fix eslint prettier config @robgietema -- Refactor actions and reducers to match restapi docs naming @robgietema -- Fix site root api calls @robgietema -- Change visual editor to use the new tiles api @robgietema -- Fix bug with wrong order input @robgietema -- Fix several problems in the DraftJS AnchorLink plugin @sneridagh -- Replace DraftJS Toolbar plugin H1/H2 buttons for H2/H3 ones @sneridagh -- Sync i18n translations @sneridagh -- Fix CSS .input class scope intrusion on the project introduced by the AnchorLink plugin fork @sneridagh -- Improve search reducer by adding the batching property in the search store. -- Upgrade to Node 8.11.3 @sneridagh - -## 0.5.0 (2018-03-23) - -### Added - -- Pastanaga theme package @jaroel, @robgietema -- Registry based controlpanels @robgietema -- Component documentation @robgietema -- Component documentation examples @VaysseB -- Folder listing view @cekk -- Prettier docs for SCA @nileshgulia1 -- Comments, email notification and vocabularies reducers @robgietema -- Pastanaga theme @robgietema -- Pastanaga manage views @robgietema -- Pastanaga theme views @robgietema -- Callout styling to draftjs @robgietema -- Image, file and news item view @robgietema -- Social sharing @robgietema -- Commenting @robgietema -- Tags @robgietema -- Renew login token when almost expired @robgietema -- Cctions reducers @robgietema -- Error reporting with Sentry support on client (default ErrorBoundary), server and Redux middleware @sneridagh -- Tiles reducers @robgietema -- Context aware toolbar @robgietema -- Hamburger menu navigation on mobile @sneridagh -- Editor prototype @robgietema -- Support for null values when reseting a field value @sneridagh - -### Changes - -- Update plone api versions / bootstrap process @thet -- Fix textwidget proptypes @cekk -- Remove phantomjs @tulikavijay -- Upgrade to node 8 @robgietema -- Switched to draft js plugins editor @robgietema -- Fix paragraph styling in draftjs @robgietema -- Fixed summary and tabular views @robgietema -- Upgrade to React 16 @sneridagh -- Upgrade to Webpack 4 @sneridagh -- Review chunks policy. Keep it in sync with Webpack 4 policy with entrypoint bundles @sneridagh -- Merged block styling to inline toolbar @robgietema -- Actions aware toolbar @sneridagh -- Fix permissions on the toolbar display menu @sneridagh - -## 0.4.0 (2017-05-03) - -### Added - -- Adding tiles @robgietema -- Handle different tiles @robgietema -- Resizing of tiles @robgietema -- Deletion of tiles @robgietema -- Drag and drop of tiles @robgietema -- Basic mosaic grid rendering @robgietema -- Form validation @robgietema -- Notification messages @robgietema - -### Changes - -- Updated to new history api @robgietema -- Deselect on click outside grid @robgietema - -## 0.3.0 (2017-04-29) - -### Added - -- Personal information @robgietema -- Change password @robgietema -- Password widget @robgietema -- I18n support and translations @robgietema -- Personal preferences @robgietema -- Rename action @robgietema - -### Changed - -- Fixed favicon @robgietema - -## 0.2.0 (2017-04-27) - -### Added - -- Batch state in folder contents @robgietema -- Batch properties in folder contents @robgietema -- Batch tags in folder contents @robgietema -- Batch rename in folder contents @robgietema -- Diff view @robgietema -- Add revert to version @robgietema -- Create view revision page @robgietema -- Create history list view @robgietema -- Sorting of items in folder contents @robgietema -- Upload files in folder contents @robgietema -- Ordering of columns in folder contents @robgietema -- Ordering of items in folder contents @robgietema -- Pagination in folder contents @robgietema -- Delete in folder contents @robgietema - -### Changed - -- Only show add and contents in the toolbar when folderish @robgietema -- Diff on words not chars @robgietema - -## 0.1.0 (2017-04-20) - -### Added - -- Folder contents @robgietema -- Sharing menu and view @robgietema -- Display menu @robgietema -- Semantic UI integration @robgietema -- Basic Mosaic setup @robgietema -- Basic Server Side Rendering @robgietema -- Search view @robgietema -- Actions menu @robgietema -- Workflow menu @robgietema -- Add menu @robgietema -- Add and edit forms including widgets @robgietema -- Basic components (navigation, toolbar, breadcrumbs etc) @robgietema -- Authentication including login / logout @robgietema -- Setup build environment @robgietema - -### Changed - -- Fixed passing intl to the schemaExtender in the ObjectListWidget component. @1bsilver diff --git a/COMMITLINT.md b/COMMITLINT.md deleted file mode 100644 index a4a79c240c..0000000000 --- a/COMMITLINT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Volto Commit Messages - -Volto uses the (conventional commit specification)[https://www.conventionalcommits.org/en/v1.0.0/#specification] for consistent commit messages. - -All commit messages should have the following form: - -``` -: -``` - -## Fix - -A fix (PATCH in semantic versioning) looks like this: - -``` -fix: correct minor typos in code -``` - -## Feature - -A new feature (MINOR in semantic versioning) looks like this: - -``` -feat: add catalan language -``` - -## Breaking Change - -Breaking changes can be indicated by either appending a "!" to the type: - -``` -refactor!: drop support for Node 6 -``` - -Or adding "BREAKING CHANGE" to the commit message body text: - -``` -refactor!: drop support for Node 6 - -BREAKING CHANGE: refactor to use JavaScript features not available in Node 6. -``` - -## Available Types - -In addition to "fix" and "feat" the following types are allowed: -build:, chore:, ci:, docs:, style:, refactor:, perf:, test: - -Install commitlint: - -``` -npm install --save-dev @commitlint/{config-conventional,cli} -``` - -or via yarn: - -``` -yarn add @commitlint/{config-conventional,cli} -``` - -Create a commitlint.config.js file: - -``` -echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js -``` - -Add husky to package.json: - -``` -{ - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - } -} -``` diff --git a/Makefile b/Makefile index ca85430928..179130e6c6 100644 --- a/Makefile +++ b/Makefile @@ -11,25 +11,14 @@ MAKEFLAGS+=--warn-undefined-variables MAKEFLAGS+=--no-builtin-rules # Project settings - -INSTANCE_PORT=8080 -DOCKER_IMAGE=plone/server-dev:6.0.6 -DOCKER_IMAGE_ACCEPTANCE=plone/server-acceptance:6.0.6 -KGS=plone.restapi==8.42.0 -NODEBIN = ./node_modules/.bin -SCRIPTSPACKAGE = ./packages/scripts - -# Plone 5 legacy -DOCKER_IMAGE5=plone/plone-backend:5.2.12 -KGS5=plone.restapi==8.42.0 plone.volto==4.0.8 plone.rest==3.0.0 -TESTING_ADDONS=plone.app.robotframework==2.0.0 plone.app.testing==7.0.0 +include variables.mk # Sphinx variables # You can set these variables from the command line. SPHINXOPTS ?= # Internal variables. -SPHINXBUILD = $(realpath bin/sphinx-build) -SPHINXAUTOBUILD = $(realpath bin/sphinx-autobuild) +SPHINXBUILD = "$(realpath bin/sphinx-build)" +SPHINXAUTOBUILD = "$(realpath bin/sphinx-autobuild)" DOCS_DIR = ./docs/source/ BUILDDIR = ../_build/ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(SPHINXOPTS) . @@ -37,10 +26,10 @@ VALEFILES := $(shell find $(DOCS_DIR) -type f -name "*.md" -print) # Recipe snippets for reuse -CHECKOUT_BASENAME=$(shell basename $(shell realpath ./)) +CHECKOUT_BASENAME="$(shell basename $(shell realpath ./))" CHECKOUT_BRANCH=$(shell git branch --show-current) CHECKOUT_TMP=../$(CHECKOUT_BASENAME).tmp -CHECKOUT_TMP_ABS=$(shell realpath $(CHECKOUT_TMP)) +CHECKOUT_TMP_ABS="$(shell realpath $(CHECKOUT_TMP))" # We like colors # From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects @@ -69,15 +58,14 @@ start: .PHONY: start-frontend start-frontend: - yarn start + pnpm start .PHONY: start-backend start-backend: ## Start Plone Backend $(MAKE) -C "./api/" start -.PHONY: release -release: - ./node_modules/.bin/release-it +# TODO: Review release commands for all packages +# Use TurboRepo .PHONY: build build: @@ -86,17 +74,12 @@ build: .PHONY: build-frontend build-frontend: - yarn && RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn build + $(MAKE) -C "./packages/volto/" build-frontend .PHONY: build-backend build-backend: ## Build Plone 5.2 $(MAKE) -C "./api/" build -.PHONY: dist -dist: - yarn - yarn build - .PHONY: test test: $(MAKE) -C "./api/" test @@ -104,12 +87,19 @@ test: bin/python: python3 -m venv . || virtualenv --clear --python=python3 . bin/python -m pip install --upgrade pip + @echo "Python environment created." bin/pip install -r requirements-docs.txt + @echo "Requirements installed." .PHONY: clean clean: $(MAKE) -C "./api/" clean - rm -rf node_modules + find ./packages -name node_modules -exec rm -rf {} \; + +.PHONY: setup +setup: + # Setup ESlint for VSCode + node packages/scripts/vscodesettings.js ##### Documentation @@ -119,54 +109,68 @@ docs-clean: ## Clean current and legacy docs build directories, and Python virt rm -rf docs/_build cd $(DOCS_DIR) && rm -rf $(BUILDDIR)/ +.PHONY: docs-news +docs-news: ## Create or update the symlink from docs to volto package + ln -snf ../../packages/volto/news docs/source/news && echo "Symlink to Volto news created or updated."; + .PHONY: docs-html -docs-html: bin/python ## Build html +docs-html: bin/python docs-news ## Build html cd $(DOCS_DIR) && $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." .PHONY: docs-livehtml -docs-livehtml: bin/python ## Rebuild Sphinx documentation on changes, with live-reload in the browser +docs-livehtml: bin/python docs-news ## Rebuild Sphinx documentation on changes, with live-reload in the browser cd "$(DOCS_DIR)" && ${SPHINXAUTOBUILD} \ --ignore "*.swp" \ -b html . "$(BUILDDIR)/html" $(SPHINXOPTS) .PHONY: docs-linkcheck -docs-linkcheck: bin/python ## Run linkcheck +docs-linkcheck: bin/python docs-news ## Run linkcheck cd $(DOCS_DIR) && $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/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=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/ ." +docs-linkcheckbroken: bin/python docs-news ## 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=always | GREP_COLORS='0;31' grep -vi "https://github.com/plone/volto/issues/" --color=always && if test $$? -eq 0; then exit 1; fi || test $$? -ne 0 .PHONY: docs-vale -docs-vale: ## Run Vale style, grammar, and spell checks - vale sync - vale --no-wrap $(VALEFILES) +docs-vale: bin/python docs-news ## Install (once) and run Vale style, grammar, and spell checks + bin/vale sync + bin/vale --no-wrap $(VALEFILES) @echo @echo "Vale is finished; look for any errors in the above output." .PHONY: netlify netlify: - pip install -r requirements-docs.txt - cd $(DOCS_DIR) && sphinx-build -b html $(ALLSPHINXOPTS) ../$(BUILDDIR)/html + pnpm build:registry + (cd packages/volto && pnpm build-storybook -o ../../_build/html/storybook) + pwd && pip install -r requirements-docs.txt + cd $(DOCS_DIR) && pwd && sphinx-build -b html $(ALLSPHINXOPTS) ../$(BUILDDIR)/html .PHONY: docs-test docs-test: docs-clean docs-linkcheckbroken docs-vale ## Clean docs build, then run linkcheckbroken, vale +##### Build + .PHONY: storybook-build storybook-build: - yarn build-storybook -o docs/_build/storybook + pnpm build:registry + (cd packages/volto && pnpm build-storybook -o ../../docs/_build/html/storybook) .PHONY: patches patches: - /bin/bash patches/patchit.sh > /dev/null 2>&1 ||true + (cd packages/volto && /bin/bash patches/patchit.sh > /dev/null 2>&1 ||true) + +.PHONY: cypress-install +cypress-install: + $(NODEBIN)/cypress install + +.PHONY: build-deps +build-deps: + if [ ! -d $$(pwd)/registry/dist ]; then (pnpm build:deps); fi ##### Release @@ -174,12 +178,29 @@ patches: corepackagebump: node $(SCRIPTSPACKAGE)/corepackagebump.js packages/volto-slate $(VERSION) +.PHONY: copyreleasenotestodocs +copyreleasenotestodocs: + cp CHANGELOG.md docs/source/release-notes/index.md + git add docs/source/release-notes/index.md + ##### Docker containers .PHONY: start-backend-docker start-backend-docker: docker run -it --rm --name=backend -p 8080:8080 -e SITE=Plone -e ADDONS='$(KGS)' $(DOCKER_IMAGE) +.PHONY: start-backend-docker-detached +start-backend-docker-detached: + docker run -d --rm --name=backend -p 8080:8080 -e SITE=Plone -e ADDONS='$(KGS)' $(DOCKER_IMAGE) + +.PHONY: stop-backend-docker-detached +stop-backend-docker-detached: + docker kill backend + +.PHONY: start-backend-docker-no-cors +start-backend-docker-no-cors: + docker run -it --rm --name=backend -p 8080:8080 -e SITE=Plone -e ADDONS='$(KGS)' -e CORS_=true $(DOCKER_IMAGE) + .PHONY: start-frontend-docker start-frontend-docker: docker run -it --rm --name=volto --link backend -p 3000:3000 -e RAZZLE_INTERNAL_API_PATH=http://backend:8080/Plone -e RAZZLE_DEV_PROXY_API_PATH=http://backend:8080/Plone plone/plone-frontend:latest @@ -188,159 +209,156 @@ start-frontend-docker: start-backend-docker-guillotina: docker-compose -f g-api/docker-compose.yml up -d -##### Acceptance tests (Cypress) - -.PHONY: start-test -start-test: ## Start Test - @echo "$(GREEN)==> Start Test$(RESET)" - yarn cypress:open - -.PHONY: start-test-all -start-test-all: ## Start Test - @echo "$(GREEN)==> Start Test$(RESET)" - yarn ci:cypress:run - -.PHONY: start-test-frontend -start-test-frontend: ## Start Test Volto Frontend - @echo "$(GREEN)==> Start Test Volto Frontend$(RESET)" - 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) - $(MAKE) -C "./api/" start-test - .PHONY: stop-backend-docker-guillotina stop-backend-docker-guillotina: docker-compose -f g-api/docker-compose.yml down - -.PHONY: test-acceptance-server-old -test-acceptance-server-old: - $(MAKE) -C "./api/" test-acceptance-server-old - +##### Acceptance tests (Cypress) ######### Dev mode Acceptance tests .PHONY: start-test-acceptance-frontend-dev -start-test-acceptance-frontend-dev: ## Start the Core Acceptance Frontend Fixture in dev mode - RAZZLE_API_PATH=http://127.0.0.1:55001/plone yarn start +start-test-acceptance-frontend-dev: build-deps ## Start the Core Acceptance Frontend Fixture in dev mode + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-dev ######### 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 -p 55001:55001 $(DOCKER_IMAGE_ACCEPTANCE) + docker run -it --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://127.0.0.1:55001/plone yarn build && yarn start:prod +start-test-acceptance-frontend: build-deps ## Start the Core Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend .PHONY: test-acceptance test-acceptance: ## Start Core Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress open + $(MAKE) -C "./packages/volto/" test-acceptance .PHONY: test-acceptance-headless test-acceptance-headless: ## Start Core Cypress Acceptance Tests in headless mode - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress run --config specPattern='cypress/tests/core/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-headless .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://127.0.0.1:55001/plone "make start-test-acceptance-frontend" http://127.0.0.1:3000 "make test-acceptance-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance ######### Seamless Core Acceptance tests .PHONY: start-test-acceptance-frontend-seamless -start-test-acceptance-frontend-seamless: ## Start the Seamless Core Acceptance Frontend Fixture - yarn build && yarn start:prod +start-test-acceptance-frontend-seamless: build-deps ## Start the Seamless Core Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-seamless .PHONY: test-acceptance-seamless test-acceptance-seamless: ## Start Seamless Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress open --config baseUrl='http://localhost' + $(MAKE) -C "./packages/volto/" test-acceptance-seamless .PHONY: start-test-acceptance-webserver-seamless start-test-acceptance-webserver-seamless: ## Start the seamless webserver - cd cypress/docker && docker-compose -f seamless.yml up + $(MAKE) -C "./packages/volto/" start-test-acceptance-webserver-seamless .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://127.0.0.1:55001/plone "make start-test-acceptance-frontend-seamless" http://127.0.0.1:3000 "make test-acceptance-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance-seamless ######### 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://127.0.0.1:55001/plone yarn build && yarn start:prod +start-test-acceptance-frontend-project: build-deps ## Start the Project Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-project ######### 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 -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) + docker run -it --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://127.0.0.1:55001/plone yarn build && yarn start:prod +start-test-acceptance-frontend-coresandbox: build-deps ## Start the CoreSandbox Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-coresandbox .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 +start-test-acceptance-frontend-coresandbox-dev: build-deps ## Start the CoreSandbox Acceptance Frontend Fixture in dev mode + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-coresandbox-dev .PHONY: test-acceptance-coresandbox test-acceptance-coresandbox: ## Start CoreSandbox Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress open --config specPattern='cypress/tests/coresandbox/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-coresandbox .PHONY: test-acceptance-coresandbox-headless test-acceptance-coresandbox-headless: ## Start CoreSandbox Cypress Acceptance Tests in headless mode - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress run --config specPattern='cypress/tests/coresandbox/**/*.{js,jsx,ts,tsx}/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-coresandbox-headless .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://127.0.0.1:55001/plone "make start-test-acceptance-frontend-coresandbox" http://127.0.0.1:3000 "make test-acceptance-coresandbox-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance-coresandbox ######### 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 -p 55001:55001 -e APPLY_PROFILES=plone.app.contenttypes:plone-content,plone.restapi:default,plone.volto:multilingual $(DOCKER_IMAGE_ACCEPTANCE) + docker run -it --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://127.0.0.1:55001/plone yarn build && yarn start:prod +start-test-acceptance-frontend-multilingual: build-deps ## Start the Multilingual Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-multilingual .PHONY: test-acceptance-multilingual test-acceptance-multilingual: ## Start Multilingual Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress open --config specPattern='cypress/tests/multilingual/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-multilingual .PHONY: test-acceptance-multilingual-headless test-acceptance-multilingual-headless: ## Start Multilingual Cypress Acceptance Tests in headless mode - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress run --config specPattern='cypress/tests/multilingual/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-multilingual-headless .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://127.0.0.1:55001/plone "make start-test-acceptance-frontend-multilingual" http://127.0.0.1:3000 "make test-acceptance-multilingual-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance-multilingual + +######### Seamless Multilingual Acceptance tests + +.PHONY: start-test-acceptance-server-seamless-multilingual test-acceptance-server-seamless-multilingual +start-test-acceptance-server-seamless-multilingual test-acceptance-server-seamless-multilingual: ## Start Seamless Multilingual Acceptance Server Multilingual Fixture (docker container) + docker run -it --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-seamless-multilingual +start-test-acceptance-frontend-seamless-multilingual: build-deps ## Start the Seamless Multilingual Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-seamless-multilingual + +.PHONY: test-acceptance-seamless-multilingual +test-acceptance-seamless-multilingual: ## Start Seamless Multilingual Cypress Acceptance Tests + $(MAKE) -C "./packages/volto/" test-acceptance-seamless-multilingual + +.PHONY: test-acceptance-seamless-multilingual-headless +test-acceptance-seamless-multilingual-headless: ## Start Seamless Multilingual Cypress Acceptance Tests in headless mode + $(MAKE) -C "./packages/volto/" test-acceptance-seamless-multilingual-headless + +.PHONY: full-test-acceptance-seamless-multilingual +full-test-acceptance-seamless-multilingual: ## Runs Seamless Multilingual Full Acceptance Testing in headless mode + $(MAKE) -C "./packages/volto/" full-test-acceptance-seamless-multilingual ######### 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 -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) + docker run -it --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://127.0.0.1:55001/plone yarn build && yarn start:prod +start-test-acceptance-frontend-workingcopy: build-deps ## Start the WorkingCopy Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-workingcopy .PHONY: test-acceptance-workingcopy test-acceptance-workingcopy: ## Start WorkingCopy Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress open --config specPattern='cypress/tests/workingCopy/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-workingcopy .PHONY: test-acceptance-workingcopy-headless test-acceptance-workingcopy-headless: ## Start WorkingCopy Cypress Acceptance Tests in headless mode - NODE_ENV=production CYPRESS_API=plone $(NODEBIN)/cypress run --config specPattern='cypress/tests/workingCopy/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-workingcopy-headless .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://127.0.0.1:55001/plone "make start-test-acceptance-frontend-workingcopy" http://127.0.0.1:3000 "make test-acceptance-workingcopy-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance-workingcopy ######### Guillotina Acceptance tests @@ -349,23 +367,33 @@ start-test-acceptance-server-guillotina: ## Start Guillotina Test Acceptance Ser docker-compose -f g-api/docker-compose.yml up > /dev/null .PHONY: start-test-acceptance-frontend-guillotina -start-test-acceptance-frontend-guillotina: ## Start the Guillotina Acceptance Frontend Fixture - ADDONS=volto-guillotina RAZZLE_API_PATH=http://127.0.0.1:8081/db/web RAZZLE_LEGACY_TRAVERSE=true yarn build && yarn start:prod +start-test-acceptance-frontend-guillotina: build-deps ## Start the Guillotina Acceptance Frontend Fixture + $(MAKE) -C "./packages/volto/" start-test-acceptance-frontend-guillotina .PHONY: test-acceptance-guillotina test-acceptance-guillotina: ## Start the Guillotina Cypress Acceptance Tests - NODE_ENV=production CYPRESS_API=guillotina $(NODEBIN)/cypress open --config specPattern='cypress/tests/guillotina/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-guillotina .PHONY: test-acceptance-guillotina-headless test-acceptance-guillotina-headless: ## Start the Guillotina Cypress Acceptance Tests in headless mode - NODE_ENV=production CYPRESS_API=guillotina $(NODEBIN)/cypress run --config specPattern='cypress/tests/guillotina/**/*.{js,jsx,ts,tsx}' + $(MAKE) -C "./packages/volto/" test-acceptance-guillotina-headless .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://127.0.0.1:8081 "make start-test-acceptance-frontend-guillotina" http://127.0.0.1:3000 "make test-acceptance-guillotina-headless" + $(MAKE) -C "./packages/volto/" full-test-acceptance-guillotina ######### Plone 5 Acceptance tests .PHONY: start-test-acceptance-server-5 start-test-acceptance-server-5: ## Start Test Acceptance Server Main Fixture Plone 5 (docker container) - docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS5) $(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_IMAGE5) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + docker run -it --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS5) $(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_IMAGE5) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + +######### @plone/client + +.PHONY: start-test-acceptance-server-detached +start-test-acceptance-server-detached: ## Start Test Acceptance Server Main Fixture (docker container) in a detached (daemon) mode + docker run -d --name plone-client-acceptance-server -i --rm -p 55001:55001 $(DOCKER_IMAGE_ACCEPTANCE) + +.PHONY: stop-test-acceptance-server-detached +stop-test-acceptance-server-detached: ## Stop Test Acceptance Server Main Fixture (docker container) in a detached (daemon) mode + docker kill plone-client-acceptance-server diff --git a/PACKAGES.md b/PACKAGES.md new file mode 100644 index 0000000000..4baa88756f --- /dev/null +++ b/PACKAGES.md @@ -0,0 +1,82 @@ +# Plone frontend packages + +This document describes the packages that come with Volto, the default frontend for Plone 6. + + +## `@plone/types` + +Plone types is a special development package. +It contains the Plone typings for TypeScript. +It's considered a core package, and it's the only package that the other core packages can rely on as +a `devDependency` in your project configuration. + +This package contains `.d.ts` typing definitions, curated by hand. +Due to the nature of this package, it does not need bundling. +It's published "as is", so you can import the type definitions from anywhere in your code. + + +## Core packages + +- `@plone/registry` +- `@plone/client` +- `@plone/components` + + +### Rules + +Core packages must not depend on any other `@plone/*` package, with only one exception, `@plone/types`. +They must be published and bundled in a traditional (transpiled) way. +The bundle of these packages must work on both CommonJS and ECMAScript Module (ESM) environments. + +## Feature packages + +- `@plone/contents` + + +## Utility packages + +- `@plone/blocks` +- `@plone/helpers` +- `@plone/drivers` +- `@plone/rsc` + + +### Rules + +Utility packages can depend on core packages and other utility packages. +They must be published in a traditional way, bundled. +This bundle must work on both CommonJS and ESM environments. + + +## Development utility packages + +These are packages that are not bundled, and they are used in conjunction with Volto core or Volto projects. +They contain utilities that are useful for the development of a Volto project. +Some of them are released: + +- `@plone/scripts` +- `@plone/generator-volto` + +Some of them are used by the build, and separated in packages for convenience. + +- `tsconfig` +- `parcel-optimizer-react-client` + + +## Volto add-ons packages + +These Volto add-ons are packages used by Volto core. +They are always loaded, so they are also called "core packages". +The Volto add-ons are not transpiled or bundled. +They are supposed to be used and built along with a Volto project build. + +- `@plone/volto-slate` + + +## Volto testing add-on packages + +These packages are used when testing Volto core. +They contain fixtures that configure features or components that the vanilla Volto core does not have by default. +Once their fixtures are loaded, they can be tested, for example, in acceptance tests. + +- `@plone/volto-coresandbox` diff --git a/README.md b/README.md index 9ac6dc757f..a5bc0876ba 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Volto +# Volto - the default Plone 6 frontend Volto logo png Volto logo png @@ -8,22 +8,21 @@ [![Acceptance Tests](https://github.com/plone/volto/actions/workflows/acceptance.yml/badge.svg)](https://github.com/plone/volto/actions/workflows/acceptance.yml) [![Build Status Docs](https://github.com/plone/volto/actions/workflows/docs.yml/badge.svg)](https://github.com/plone/volto/actions) + ## Introduction -[Volto](https://github.com/plone/volto) is a ReactJS-based frontend for the [Plone](https://plone.org) Content Management System. It will become the default UI for the upcoming Plone 6 release. +[Volto](https://github.com/plone/volto) is a ReactJS-based frontend for the [Plone](https://plone.org) Content Management System. +It is the default frontend starting with the Plone 6 release. [Plone](https://plone.org) is a CMS built on Python with more than 20 years of history and experience. -Plone has very interesting features that appeal to developers and users alike, -such as customizable content types, hierarchical URL object traversing and a -sophisticated content workflow powered by a granular permissions model. This -allows you to build anything from simple websites to enterprise-grade -intranets. +Plone has features that appeal to developers and users alike, such as an intuitive editing interface, customizable content types, hierarchical organization, and a sophisticated permissions model. +This allows you to build anything from simple websites to enterprise-grade intranets. Volto exposes all these features and communicates with Plone via its [REST API](https://github.com/plone/plone.restapi). -Volto has the ability of being easily extensible, themeable, and customizable. -It features the Pastanaga editor, a modern block-based content layout editor. It is extensible and customizable, so you can adapt the default blocks provided to match your requirements, or build new ones to cover them. +Volto features the Pastanaga editor, a modern block-based content layout editor. +It is extensible and customizable, so you can adapt the provided default blocks to meet your requirements, or build new ones. Volto is extensible using add-ons. You can build your own or choose from the community released ones: @@ -31,297 +30,50 @@ You can build your own or choose from the community released ones: - [Volto Add-ons in NPM](https://www.npmjs.com/search?q=keywords%3Avolto-addon%2Cvolto) - [Volto Awesome](https://github.com/collective/awesome-volto) -## Demo - -You can try a Volto online demo in [https://6.demo.plone.org/](https://6.demo.plone.org/) - -### Try the demo locally - -If you want to give Volto a quick try and you have [Docker](https://www.docker.com/get-started) installed in your computer, bootstrap the demo using `docker-compose`: - -```shell -git clone https://github.com/plone/volto.git -cd volto -docker-compose up -``` - -Go to [http://localhost:3000](http://localhost:3000) in your browser. - -## Quick Start - -First get all the requirements installed on your system. - -### Prerequisites - -- [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) - -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 | 3.8-3.11 | 16.0 | - -### Create a Volto project using the generator - -Create a new Volto project by using the `@plone/generator-volto` utility. - -It will bootstrap a Volto project in a folder of your choice with all the required -boilerplate to start customizing your Volto site. - -``` -npm install -g yo @plone/generator-volto -yo @plone/volto -``` -follow the prompts questions, provide `myvoltoproject` as project name then, when it finishes: - -``` -cd myvoltoproject -``` - -### Bootstrap the Plone API backend - -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.5 -``` - -or as an alternative if you have experience with Plone and you have all the -dependencies installed on your system, you can use the supplied convenience buildout in the -`api` folder by issuing the command: - -```shell -make build-backend -``` - -#### Recommended Plone version - -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.10). -#### KGS (known good set of versions) for backend packages - -On Plone 6, we recommend using the known good set (KGS) of package versions that are specified in the Plone release. - -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.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.32.6 plone.volto==4.0.3 plone.rest==2.0.0" -e PROFILES="plone.volto:default-homepage" plone/plone-backend -``` - -### Start Volto +## Demo -```shell -yarn start -``` +You can try a Volto online demo at [https://demo.plone.org/](https://demo.plone.org/). -### Browsing -Go to [http://localhost:3000](http://localhost:3000) in your browser. +## Create a Volto project -## Volto in Production +To start a new project using Volto, follow the [Plone installation documentation](https://6.docs.plone.org/install/create-project.html). -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 bakery 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) -- [Energy Climate Union portal for Europe](https://climate-energy.eea.europa.eu/) (Thematic website focusing on European strides towards mitigating climate change, developed by [Eau de Web](https://www.eaudeweb.ro), 2020) -- [Talke Carrer Website](https://karriere.talke.com/) (Carrer website for [Talke](https://www.talke.com), one of the leading a chemical and petrochemical logistics companies in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2020) -- [Stradanove](http://www.stradanove.it/) (Website of the Department of Youth Policies of the Municipality of Modena, developed by [RedTurtle](https://redturtle.it), 2020) -- [VisitModena](https://www.visitmodena.it/) (Tourist website of the Municipality of Modena, developed by [RedTurtle](https://redturtle.it), 2020) -- [Study guide at University of Jyväskylä](https://studyguide.jyu.fi/2020/) (Static website where [Volto is used as a headless CMS for authoring additional content](https://tech.blog.jyu.fi/2020/06/plone-volto-hasura-gatsbyjs-mashup/), 2020) -- [Nuova Voce Ecologista](https://nuovavoceecologista.it) (Website of Nuova Voce Ecologista, an Italian green Party, 2020) -- [BISE](https://biodiversity.europa.eu) (Biodiversity Information System for Europe, developed by [Eau de Web](https://www.eaudeweb.ro), 2019) -- [MEDICE Webseite](https://medice.com/de-de) (Website for MEDICE Arzneimittel Pütter GmbH & Co. KG), developed by [Werkbank GmbH](https://werkbank.de/), 2020) -- [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 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) -- [Comune di Cantagallo](https://www.comune.cantagallo.po.it/) (Website of the Municipality of Cantagallo. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Comune di Vernio](https://www.comune.vernio.po.it/) (Website of the Municipality of Vernio. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Unione dei Comuni della Val Bisenzio](https://www.bisenzio.it/) (Website of the Municipality union of Val Bisenzio. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Comune di Vaiano](https://www.comune.vaiano.po.it/) (Website of the Municipality of Vaiano. Developed by [RedTurtle](https://redturtle.it), 2021) -- [ASP Area Nord](https://www.aspareanord.it/) (Website of the Public company of personal services of the Modena municipalities in the north area. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Comune di San Possidonio](https://www.comune.sanpossidonio.mo.it/) (Website of the Municipality of San Possidonio. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Comune di Mirandola](https://comune.mirandola.mo.it/) (Website of the Municipality of Mirandola. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Comune di Medolla](http://www.comune.medolla.mo.it/) (Website of the Municipality of Medolla. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Camera di Commercio dell'Umbria](https://www.umbria.camcom.it) (Website Chamber of Commerce of Umbria. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Biblioteche Pianura Est](https://bibest.it) (Website of the Associated libraries of eastern plain. Developed by [RedTurtle](https://redturtle.it), 2021) -- [Camera di Commercio di Reggio Emilia](https://www.re.camcom.gov.it/) (Website Chamber of Commerce of Reggio Emilia. Developed by [RedTurtle](https://redturtle.it), 2021) -- [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 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! ## Documentation -You can find the latest (in-progress) documentation in [https://6.docs.plone.org/](https://6.docs.plone.org/volto/index.html) - -## Training - -On the [Plone Training website](https://training.plone.org), you'll find Volto-dedicated training materials, plus other JavaScript-centered trainings. - -- [Mastering Plone 6 Development](https://training.plone.org/mastering-plone/) - The comprehensive training on Plone 6 with best practice tips for developers and integrators. -- [Volto Hands-On](https://training.plone.org/voltohandson/index.html) -- [Volto Add-ons Development](https://training.plone.org/voltoaddons/index.html) -- [Effective Volto](https://training.plone.org/effective-volto/index.html) -- [Plone Deployment](https://training.plone.org/plone-deployment/index.html) -- [Volto](https://2022.training.plone.org/volto/index.html) (archived) -- [JavaScript For Plone Developers](https://2022.training.plone.org/javascript/index.html) (archived) - -## Talks - -### Plone Conference Ferrara 2019 - -[Víctor Fernández de Alba - Plone Beyond 2020: Jump into Volto today!](https://www.youtube.com/watch?v=8QrGOgXo1Js&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=16&t=0s) - -[Rob Gietema - How to create your own Volto site!](https://www.youtube.com/watch?v=3QLN8tsjjf4&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=11&t=0s) +You can find the latest documentation at [https://6.docs.plone.org/](https://6.docs.plone.org/volto/index.html). -[Timo Stollenwerk - On the Road - Plone 6 and Beyond](https://www.youtube.com/watch?v=suXVdfYV2kA&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=14&t=0s) +For links to trainings and videos, see [Other learning resources](https://6.docs.plone.org/volto/tutorials/index.html). -[Rodrigo Ferreira de Souza - Data migration to Plone 5.2 and Volto](https://www.youtube.com/watch?v=kb9SEsnllqE&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=49&t=0s) -[Nicola Zambello - A Volto story: building a website by prototyping](https://www.youtube.com/watch?v=xtxJURICkWc&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=17&t=0s) +## Supported Plone, Python, and Plone REST API versions -[Luca Pisani - Plone and React.js: An interview to Volto](https://www.youtube.com/watch?v=JZFUOG843no&list=PLGN9BI-OAQkQD9HliElIk9pe-8O_Y6S04&index=26&t=0s) +See [Plone, Python, and Plone REST API compatibility](https://6.docs.plone.org/volto/contributing/version-policy.html#version-policy-plone-python-and-plone-rest-api-compatibility) -### Plone Conference Tokyo 2018 +See the [Plone Release Schedule](https://plone.org/download/release-schedule) for details of maintenance and support. -[Rob Gietema - Volto](https://2018.ploneconf.org/talks/plone-react) -[Rob Gietema / Víctor Fernández de Alba - Volto Extensibility Story](https://2018.ploneconf.org/talks/plone-react-extensibility-story) +## Supported Node.js versions -[Víctor Fernández de Alba - Theming Volto](https://2018.ploneconf.org/talks/theming-plone-react) +See [Node.js version policy](https://6.docs.plone.org/volto/contributing/version-policy.html#version-policy-plone-python-and-plone-rest-api-compatibility). -[Timo Stollenwerk / Víctor Fernández de Alba / Ramon Navarro - Volto Case Studies](https://2018.ploneconf.org/talks/plone-react-case-studies-when-stability-and-security-meet-speed-and-a-modern-user-interface) -[Timo Stollenwerk - Reinventing Plone, Roadmap to the Modern Web](https://2018.ploneconf.org/talks/reinventing-plone-roadmap-to-the-modern-web) +## Supported browsers -## Node Support +See [Supported browsers](https://6.docs.plone.org/volto/contributing/version-policy.html#version-policy-supported-browsers). -- Node 18: Supported since Volto 17 -- Node 16: Supported since Volto 14 -- 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 +## Contributing -Volto works well with any modern (evergreen) browser, including their mobile -flavors: Chrome, Firefox, Safari, Edge. +To contribute to the Volto project by writing code, documentation, translations, and so on, please read [Contributing to Plone](https://6.docs.plone.org/contributing/index.html) and [Contributing to Volto](https://6.docs.plone.org/volto/contributing/index.html). -We do not guarantee that deprecated browsers (e.g., Internet Explorer 11) are supported by Volto. Although proven possible, it's too great an effort to maintain. It is left to the integrator to provide support for it. +For newcomers to Volto, Plone, or open source software, you must read and follow [First-time contributors](https://6.docs.plone.org/contributing/first-time.html). -## Upgrades +Since December 2023, this repository has a monorepo structure. +Volto itself is treated as a library and you can find it in the `packages/volto` folder. -You can find the upgrade guide here: https://6.docs.plone.org/volto/upgrade-guide/index.html - -## Volto Development - -For Volto development you need all the requirements already mentioned on the -[Quick Start](#quick-start) section. - -### Checkout the Volto repository - -```shell -git clone https://github.com/plone/volto.git -``` - -### Install dependencies - -```shell -yarn -``` - -### Install Plone backend - -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.5 -``` - -or using the convenience makefile command: - -```shell -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://6.docs.plone.org/install/index.html). - -```shell -make build-backend -``` - -### Run frontend - -Either using a Docker command: - -```shell -docker run -it --rm --name=volto --link backend -p 3000:3000 -e RAZZLE_INTERNAL_API_PATH=http://backend:8080/Plone -e RAZZLE_DEV_PROXY_API_PATH=http://backend:8080/Plone plone/plone-frontend:latest -``` - -or using the convenience makefile command: - -```shell -make start-frontend-docker -``` - -or from the local repository code: - -```shell -yarn && yarn start -``` - -### Browsing - -Browse to [http://localhost:3000](http://localhost:3000) in your browser. - -### Testing - -```shell -yarn test -``` - -## Acceptance testing - -Here you can find a guide on how acceptance testing is done in Volto: - -https://6.docs.plone.org/volto/developer-guidelines/acceptance-tests.html - -## Translations - -If you would like contribute to translate Volto into several languages, please, read the [Internationalization (i18n) guide](https://6.docs.plone.org/volto/recipes/i18n.html). ## Contributors @@ -329,40 +81,90 @@ If you would like contribute to translate Volto into several languages, please, -## Alternative backends - -Volto also supports other APIs like [Guillotina](https://guillotina.io/), a -Python resource management system, inspired by Plone and using the same basic -concepts like traversal, content types, and permissions model. - -Last but not least, it also supports a [Volto Node.js-based backend reference](https://github.com/plone/volto-reference-backend) API implementation that -demos how other systems could also use Volto to display and create content -through it. - -### Run a Guillotina backend - -*Disclaimer:* Guillotina doesn't support the full API/features that Plone provides. Contributors are welcome. - -```shell -docker-compose -f g-api/docker-compose.yml up -d -``` - -or using the convenience makefile command: - -```shell -make start-backend-docker-guillotina -``` - -### Running the acceptance tests with Guillotina backend - -If you want to use Guillotina as a backend to run the tests you should run: - -```shell -yarn ci:start-api-plone-guillotina -``` ## License -MIT License. Copyrights hold the [Plone Foundation](https://plone.org/foundation). +MIT License. Copyrights held by the [Plone Foundation](https://plone.org/foundation). See [LICENSE.md](LICENSE.md) for details. + + +## Volto in production + +Volto has been actively developed since 2017. +It has been used in production since 2018 on numerous websites. + +The authoritative source of the list of Volto websites in production is maintained at [Awesome Volto](https://github.com/collective/awesome-volto#websites-built-with-volto). + +The Plone Marketing Team copy-pastes its content on a quarterly basis into [They use Plone 6](https://plone.org/why-plone/they-use-plone/they-use-plone-6). + +To ensure your website gets the greatest exposure, add it both to [Awesome Volto](https://github.com/collective/awesome-volto#websites-built-with-volto) and this README. + +- [ASP Area Nord](https://www.aspareanord.it/) (Website of the Public company of personal services of the Modena municipalities in the north area. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Baccanale Imola](https://www.baccanaleimola.it) (Baccanale is a food fair that happens every year in Imola, Italy. Developed by [RedTurtle](https://www.redturtle.it), 2020) +- [Biblioteche Pianura Est](https://bibest.it/it) (Website of the Associated libraries of eastern plain. Developed by [RedTurtle](https://www.redturtle.it/), 2021) +- [BISE](https://biodiversity.europa.eu) (Biodiversity Information System for Europe, developed by [Eau de Web](https://eaudeweb.ro/), 2019) +- [Camera di Commercio dell'Umbria](https://www.umbria.camcom.it) (Website Chamber of Commerce of Umbria. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Camera di Commercio di Reggio Emilia](https://www.emilia.camcom.it) (Website Chamber of Commerce of Reggio Emilia. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Camposanto](https://www.comune.camposanto.mo.it/) (Website of the Municipality of Camposanto. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Cantagallo](https://www.comune.cantagallo.po.it/) (Website of the Municipality of Cantagallo. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Medolla](https://www.comune.medolla.mo.it/) (Website of the Municipality of Medolla. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Mirandola](https://www.comune.mirandola.mo.it/) (Website of the Municipality of Mirandola. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Modena](https://www.comune.modena.it/) (Website of the Municipality of Modena. Developed by [RedTurtle](https://www.redturtle.it), 2020) +- [Comune di San Possidonio](https://www.comune.sanpossidonio.mo.it/) (Website of the Municipality of San Possidonio. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Vaiano](https://www.comune.vaiano.po.it/) (Website of the Municipality of Vaiano. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Comune di Vernio](https://www.comune.vernio.po.it/) (Website of the Municipality of Vernio. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [Debabarreneko mankomunitatea](https://debabarrena.eus/eu) (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/eu) (Website of the municipality of Deba, developed by [CodeSyntax](https://www.codesyntax.com/en), 2022) +- [EEA-IMSv4](https://www.eea.europa.eu/en/analysis/indicators) (EEA Indicator Management System v4. Developed by [Eau de web](https://eaudeweb.ro) for the European Environmental Agency, 2021) +- [Energy Climate Union portal for Europe](https://climate-energy.eea.europa.eu/) (Thematic website focusing on European strides towards mitigating climate change, developed by [Eau de Web](https://eaudeweb.ro/), 2020) +- [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://www.hu-berlin.de/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://eaudeweb.ro/), 2019) +- [Forschungszentrum Jülich](https://www.fz-juelich.de/de) (Website for Forschungzentrum Jülich, which is one of the largest research institutions in Europe, developed by [kitconcept GmbH](https://kitconcept.com), 2022) +- [German Aerospace Center (DLR)](https://www.dlr.de/de) (The German Aerospace Center (DLR) is the Federal Republic of Germany's research center for aeronautics. With more than 10.000 employees and a yearly budget of more than 1 billion euros, it is one of the largest research institutions in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2023) +- [Helmholtz-Institut Erlangen-Nürnberg für Erneuerbare Energien (HI-ERN)](https://www.hi-ern.de/de) (Website for HI ERN, a research institution for renewable energies, developed by [kitconcept GmbH](https://kitconcept.com), 2022) +- [Humboldt Labor](https://www.humboldtforum.org/de/programm/dauerangebot/ausstellung/nach-der-natur-14144/) (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) +- [ILPO](https://ilpo.jyu.fi/) (the registration portal of continuous learning at the University of Jyväskylä. Developed by University of Jyväskylä, 2022) +- [Industrial Emissions portal for Europe](https://industry.eea.europa.eu) (Thematic website focusing on European industrial emissions, developed by [Eau de Web](https://eaudeweb.ro/), 2020) +- [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) +- [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) +- [Leibniz Institute for Science and Mathematics Education (IPN)](https://www.leibniz-ipn.de/de) (Website of the IPN, a research institute dedicated to issues related to learning and teaching of science, mathematics and computer science in and outside of schools, developed by [Starzel](https://www.starzel.de), 2023) +- [MEDICE Webseite](https://medice.com/de-de) (Website for MEDICE Arzneimittel Pütter GmbH & Co. KG), developed by [Werkbank GmbH](https://werkbank.de/), 2020) +- [Nuova Voce Ecologista](https://nuovavoceecologista.it) (Website of Nuova Voce Ecologista, an Italian green Party, 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) +- [ResOU](https://resou.osaka-u.ac.jp/ja) (ResOU is introducing official researched releases by the University of Osaka, Japan. Developed by [CMScom](https://www.cmscom.jp), 2020) +- [Stradanove](https://www.stradanove.it/) (Website of the Department of Youth Policies of the Municipality of Modena, developed by [RedTurtle](https://www.redturtle.it), 2020) +- [Study guide at University of Jyväskylä](https://studyguide.jyu.fi/2020/en/) (Static website where [Volto is used as a headless CMS for authoring additional content](https://tech.blog.jyu.fi/2020/06/plone-volto-hasura-gatsbyjs-mashup/), 2020) +- [Talke Carrer Website](https://karriere.talke.com/) (Carrer website for [Talke](https://www.talke.com), one of the leading a chemical and petrochemical logistics companies in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2020) +- [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) +- [Unione dei Comuni della Val Bisenzio](https://www.bisenzio.it/) (Website of the Municipality union of Val Bisenzio. Developed by [RedTurtle](https://www.redturtle.it), 2021) +- [VHS Ehrenamtsportal](https://vhs-ehrenamtsportal.de) (Website to help volunteers that help refugees for the [German Adult Education Association](https://www.volkshochschule.de/), developed by [kitconcept GmbH](https://kitconcept.com), 2018) +- [VisitModena](https://www.visitmodena.it/it) (Tourist website of the Municipality of Modena, developed by [RedTurtle](https://www.redturtle.it), 2020) +- [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) +- [Zeelandia](https://www.zeelandia.de/) (Corporate website for one of the leading bakery ingredients manufacturers in Germany, developed by [kitconcept GmbH](https://kitconcept.com), 2019) + + +### Open-source websites built with Volto + +The following websites have been built with Volto. +You can find their complete source code by following their links. +Please note that complex websites are built on top of Volto add-ons, and most of the time they're just an empty shell for the add-ons. +You should check the dependencies in their `package.json` for more details. + +- [Forest Information System for Europe](https://github.com/eea/fise-frontend) - Volto project for [Forest Information System for Europe website](https://forest.eea.europa.eu) +- [Freshwater Information System for Europe](https://github.com/eea/freshwater-frontend) - Volto project for [Freshwater Information System for Europe website](https://water.europa.eu/freshwater) +- [European Industrial Emissions Portal](https://github.com/eea/industry-frontend ) - Volto project for [European Industrial Emissions Portal website](https://industry.eea.europa.eu) +- [Biodiversity Information System for Europe](https://github.com/eea/bise-frontend) - Volto project for [Biodiversity Information System for Europe website](https://biodiversity.europa.eu) +- [Sustainability transitions, EEA-Eionet platform](https://github.com/eea/sustainability-frontend) - Volto project for [Sustainability transitions, EEA-Eionet platform website](https://sustainability.eionet.europa.eu) +- [EEA Indicator Management System](https://github.com/eea/ims-frontend) - Volto project for [EEA Indicator Management System site](https://www.eea.europa.eu/en/analysis/indicators) +- [Climate and energy in the EU](https://github.com/eea/climate-energy-frontend) - Volto project for [Climate and energy in the EU website](https://climate-energy.eea.europa.eu) +- [volto-bise](https://github.com/eea/volto-bise) - A Volto project packaged as an addon. It provides Theming using a razzle.extend.js provided alias. +- [design-volto-theme](https://github.com/RedTurtle/design-volto-theme) Volto theme for Italian Public Administration +- [2021.ploneconf.org](https://github.com/plone/ploneconf.org/tree/2021) - Volto project for [Plone Conference 2021 site](https://2021.ploneconf.org) +- [2022.ploneconf.org](https://github.com/plone/ploneconf.org/tree/2022) - Volto project for [Plone Conference 2022 site](https://2022.ploneconf.org) +- [2023.ploneconf.org](https://github.com/plone/ploneconf.org/tree/2023) - Volto project for [Plone Conference 2023 site](https://2023.ploneconf.org) +- [plone.org.br](https://github.com/plonegovbr/plone.org.br) - Volto project for the [Brazilian Plone Community](https://plone.org.br) +- [nsw-design-system-plone6-kit](https://github.com/pretagov/nsw-design-system-plone6-kit) - NSW Design System Plone 6 Kit Volto project for [NSW.gov.au sites](https://digitalnsw.pretagov.com.au/) +- [volto-centraalmuseum-theme](https://github.com/intk/volto-centraalmuseum-theme) - Volto project for the [Centraal Museum & Rietveld](https://www.centraalmuseum.nl/nl) made for [INTK](https://www.intk.com/en). +- [volto-rietveldschroderhuis-theme](https://github.com/intk/volto-rietveldschroderhuis-theme) - Volto project for the [Rietveld Schröder House](https://www.rietveldschroderhuis.nl/en) made for [INTK](https://www.intk.com/en). +- [volto-zeeuwsmuseum-theme](https://github.com/intk/volto-zeeuwsmuseum-theme) - Volto project for the [Zeeuws Museum](https://www.zeeuwsmuseum.nl/en) made for [INTK](https://www.intk.com/en). diff --git a/RELEASING.md b/RELEASING.md index 6e5b7cbd04..55a6def6e7 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -6,18 +6,18 @@ To ease the release process, we use the utility [`release-it`](https://www.npmjs To start a release, you must fulfill the following requirements: -- Have permission to push to `master` branch +- Have permission to push to `main` 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 +### Permission to push to `main` 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`. +The release process involves pushing directly to the `main` branch. +Volto's `main` 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 `main`. ### Permission to release Volto to npm registry diff --git a/ROADMAP.md b/ROADMAP.md deleted file mode 100644 index b95821dc72..0000000000 --- a/ROADMAP.md +++ /dev/null @@ -1,30 +0,0 @@ -# Roadmap - -## Volto 14 (Plone 6 alpha) - -- [x] Add locking support (requires plone.restapi 8.9.0 or 7.4.0) @avoinea -- [x] Add search block @tiberiuichim @kreafox @sneridagh -- [x] New seamless mode (see https://docs.voltocms.com/deploying/seamless-mode/ for details) @sneridagh -- [x] New mobile navigation menu @sneridagh -- [x] Add Plone logo @ericof @sneridagh -- [x] Deprecate the old configuration system (see https://docs.voltocms.com/upgrade-guide/#volto-configuration-registry for details) @sneridagh -- [x] New i18n infrastructure in the new @plone/scripts package @sneridagh -- [x] Support Node 16 @tisto - -Check the Volto 14 upgrade guide for breaking changes: https://docs.voltocms.com/upgrade-guide/#upgrading-to-volto-14xx - -## Volto 15 (Plone 6 beta) - -- [ ] Switch from DraftJS to Slate as default editor: https://github.com/plone/volto/issues/2167 - -## Volto 16+ (nice to have, no blockers) - -- [ ] Control Panel Overhaul: https://github.com/plone/volto/issues/29 -- [ ] Content Rules: https://github.com/plone/volto/issues/10 -- [ ] Form Builder: https://github.com/plone/volto/issues/739 -- [ ] Grid Block -- [ ] Teaser Block - -## Plone 6 - -- Plone 6 final will ship with the current final Volto version that is around at that time diff --git a/SECURITY.md b/SECURITY.md index c25158310e..2e8e5876c7 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,14 +1,8 @@ -# Security Policy +# Security policy -## Supported Versions +Volto supports only the latest major version of Plone with security updates. +See https://plone.org/security/update-policy. -Volto is currently under very active development. Therefore we only support the latest major version with security updates. +## Reporting a vulnerability -| Version | Supported | -| ------- | ------------------ | -| 7.x.x | :white_check_mark: | -| < 7.0 | :x: | - -## Reporting a Vulnerability - -If you found a possible vulnerability please contact the Plone security team under security@plone.org. +If you found a possible vulnerability, please contact the Plone security team at security@plone.org. diff --git a/__tests__/addon-registry-volto.test.js b/__tests__/addon-registry-volto.test.js deleted file mode 100644 index 1f6c6a7cff..0000000000 --- a/__tests__/addon-registry-volto.test.js +++ /dev/null @@ -1,11 +0,0 @@ -const path = require('path'); -const AddonConfigurationRegistry = require('../addon-registry'); - -describe('AddonConfigurationRegistry - Volto', () => { - it('works in Volto', () => { - const base = path.join(__dirname, '..'); - const reg = new AddonConfigurationRegistry(base); - expect(reg.projectRootPath).toStrictEqual(base); - expect(reg.addonNames).toStrictEqual(['@plone/volto-slate']); - }); -}); diff --git a/addon-registry.js b/addon-registry.js deleted file mode 100644 index b502977ee8..0000000000 --- a/addon-registry.js +++ /dev/null @@ -1,589 +0,0 @@ -/* eslint no-console: 0 */ -const glob = require('glob').sync; -const path = require('path'); -const fs = require('fs'); -const debug = require('debug')('shadowing'); -const { map } = require('lodash'); -const { DepGraph } = require('dependency-graph'); - -function getPackageBasePath(base) { - while (!fs.existsSync(`${base}/package.json`)) { - base = path.join(base, '../'); - } - return path.resolve(base); -} - -function fromEntries(pairs) { - const res = {}; - pairs.forEach((p) => { - res[p[0]] = p[1]; - }); - return res; -} - -function buildDependencyGraph(addons, extractDependency) { - // getAddonsLoaderChain - const graph = new DepGraph({ circular: true }); - graph.addNode('@root'); - - const seen = ['@root']; - const stack = [['@root', addons]]; - - while (stack.length > 0) { - const [pkgName, addons] = stack.shift(); - if (!graph.hasNode(pkgName)) { - graph.addNode(pkgName, []); - } - - if (!seen.includes(pkgName)) { - stack.push([pkgName, extractDependency(pkgName)]); - seen.push(pkgName); - } - - addons.forEach((loaderString) => { - const [name, extra] = loaderString.split(':'); - if (!graph.hasNode(name)) { - graph.addNode(name, []); - } - - const data = graph.getNodeData(name) || []; - if (extra) { - extra.split(',').forEach((funcName) => { - if (!data.includes(funcName)) data.push(funcName); - }); - } - graph.setNodeData(name, data); - - graph.addDependency(pkgName, name); - - if (!seen.includes(name)) { - stack.push([name, extractDependency(name)]); - } - }); - } - - return graph; -} - -/** - * Given an addons loader string, it generates an addons loader string with - * a resolved chain of dependencies - */ -function getAddonsLoaderChain(graph) { - return graph.dependenciesOf('@root').map((name) => { - const extras = graph.getNodeData(name) || [].join(','); - return extras.length ? `${name}:${extras}` : name; - }); -} - -/** - * A registry to discover and publish information about the structure of Volto - * projects and their addons. - * - * The registry builds information about both addons and other development - * packages, structured as an object with the following information: - * - * - name - * - isPublishedPackage (just for info, to distinguish addons from other Javascript development packages) - * - modulePath (the path that would be resolved from Javascript package name) - * - packageJson (the path to the addon's package.json file) - * - extraConfigLoaders (names for extra functions to be loaded from the addon - * for configuration purposes) - * - razzleExtender (the path to the addon's razzle.extend.js path, to allow - * addons to customize the webpack configuration) - * - */ -class AddonConfigurationRegistry { - constructor(projectRootPath) { - const packageJson = (this.packageJson = require(path.join( - projectRootPath, - 'package.json', - ))); - // Loads the dynamic config, if any - if (fs.existsSync(path.join(projectRootPath, 'volto.config.js'))) { - this.voltoConfigJS = require(path.join( - projectRootPath, - 'volto.config.js', - )); - } else { - this.voltoConfigJS = []; - } - - this.projectRootPath = projectRootPath; - this.voltoPath = - packageJson.name === '@plone/volto' - ? `${projectRootPath}` - : `${projectRootPath}/node_modules/@plone/volto`; - - this.packagesFolderAddons = - packageJson.name === '@plone/volto' - ? packageJson.packagesFolderAddons || {} - : require(`${getPackageBasePath(this.voltoPath)}/package.json`) - .packagesFolderAddons || {}; - - this.resultantMergedAddons = [ - ...(packageJson.addons || []), - ...(this.voltoConfigJS.addons || []), - ]; - - this.addonNames = this.resultantMergedAddons.map((s) => s.split(':')[0]); - this.packages = {}; - this.customizations = new Map(); - - // Theme from a package.json key, from volto.config.js or from an ENV VAR - // Programatically via volto.config.js wins or the ENV VAR if present - this.theme = - packageJson.theme || this.voltoConfigJS.theme || process.env.THEME; - - this.initDevelopmentPackages(); - this.initPublishedPackages(); - this.initAddonsFromEnvVar(); - - this.dependencyGraph = buildDependencyGraph( - [ - ...(Object.keys(this.packagesFolderAddons).map( - (key) => this.packagesFolderAddons[key].package, - ) || []), - ...this.resultantMergedAddons, - ...(process.env.ADDONS ? process.env.ADDONS.split(';') : []), - ], - (name) => { - this.initPublishedPackage(name); - return this.packages[name].addons || []; - }, - ); - - this.initAddonExtenders(); - } - - /** - * Use tsconfig.json or jsconfig.json to get paths for "development" packages/addons - * (coming from mrs.developer.json) - * Not all of these packages have to be Volto addons. - */ - initDevelopmentPackages() { - let configFile; - if (fs.existsSync(`${this.projectRootPath}/tsconfig.json`)) - configFile = `${this.projectRootPath}/tsconfig.json`; - else if (fs.existsSync(`${this.projectRootPath}/jsconfig.json`)) - configFile = `${this.projectRootPath}/jsconfig.json`; - - if (configFile) { - const jsConfig = require(configFile).compilerOptions; - const pathsConfig = jsConfig.paths; - - Object.keys(pathsConfig).forEach((name) => { - const packagePath = `${this.projectRootPath}/${jsConfig.baseUrl}/${pathsConfig[name][0]}`; - const packageJsonPath = `${getPackageBasePath( - packagePath, - )}/package.json`; - const innerAddons = require(packageJsonPath).addons || []; - const innerAddonsNormalized = innerAddons.map((s) => s.split(':')[0]); - if ( - this.addonNames.includes(name) && - innerAddonsNormalized.length > 0 - ) { - innerAddonsNormalized.forEach((name) => { - if (!this.addonNames.includes(name)) this.addonNames.push(name); - }); - } - const pkg = { - modulePath: packagePath, - packageJson: packageJsonPath, - version: require(packageJsonPath).version, - isPublishedPackage: false, - isRegisteredAddon: this.addonNames.includes(name), - name, - addons: require(packageJsonPath).addons || [], - }; - - this.packages[name] = Object.assign(this.packages[name] || {}, pkg); - }); - } - this.initPackagesFolder(); - } - - initPackagesFolder() { - const registerPackageFolder = (packageFolderName, packageInfo) => { - const packageName = packageInfo.package; - if (this.packages[packageName]) return; - - const packagePath = path.normalize( - `${this.voltoPath}/packages/${packageFolderName}/src`, - ); - const packageJsonPath = path.normalize( - `${this.voltoPath}/packages/${packageFolderName}/package.json`, - ); - - // some tests set the root in a location that doesn't have the packages - if (!fs.existsSync(packagePath)) return; - - this.packages[packageName] = { - modulePath: packagePath, - packageJson: packageJsonPath, - version: require(packageJsonPath).version, - isPublishedPackage: false, - isRegisteredAddon: false, - name: packageName, - addons: [], - }; - this.addonNames.push(packageName); - }; - - Object.keys(this.packagesFolderAddons).forEach((packageFolderName) => { - registerPackageFolder( - packageFolderName, - this.packagesFolderAddons[packageFolderName], - ); - }); - } - - /** - * Add path to the "src" of npm-released packages. These packages can - * release their source code in src, or transpile. The "main" of their - * package.json needs to point to the module that exports `applyConfig` as - * default. - */ - initPublishedPackages() { - this.addonNames.forEach(this.initPublishedPackage.bind(this)); - } - - initPublishedPackage(name) { - if (!Object.keys(this.packages).includes(name)) { - const resolved = require.resolve(name, { paths: [this.projectRootPath] }); - const basePath = getPackageBasePath(resolved); - const packageJson = path.join(basePath, 'package.json'); - const pkg = require(packageJson); - const main = pkg.main || 'src/index.js'; - const modulePath = path.dirname(require.resolve(`${basePath}/${main}`)); - const innerAddons = pkg.addons || []; - const innerAddonsNormalized = innerAddons.map((s) => s.split(':')[0]); - if (this.addonNames.includes(name) && innerAddonsNormalized.length > 0) { - innerAddonsNormalized.forEach((name) => { - if (!this.addonNames.includes(name)) this.addonNames.push(name); - }); - } - this.packages[name] = { - name, - version: pkg.version, - isPublishedPackage: true, - isRegisteredAddon: this.addonNames.includes(name), - modulePath, - packageJson, - addons: pkg.addons || [], - }; - } - } - - initAddonsFromEnvVar() { - if (process.env.ADDONS) { - process.env.ADDONS.split(';').forEach( - this.initAddonFromEnvVar.bind(this), - ); - } - } - - initAddonFromEnvVar(name) { - // First lookup in the packages folder, local to the root (either vanilla Volto or project) - const normalizedAddonName = name.split(':')[0]; - const testingPackagePath = `${this.projectRootPath}/packages/${normalizedAddonName}/src`; - if (fs.existsSync(testingPackagePath)) { - const basePath = getPackageBasePath(testingPackagePath); - const packageJson = path.join(basePath, 'package.json'); - - if (!this.addonNames.includes(normalizedAddonName)) - this.addonNames.push(normalizedAddonName); - const pkg = { - modulePath: testingPackagePath, - version: require(packageJson).version, - packageJson: packageJson, - isPublishedPackage: false, - isRegisteredAddon: this.addonNames.includes(name), - name: normalizedAddonName, - addons: require(packageJson).addons || [], - }; - - this.packages[normalizedAddonName] = Object.assign( - this.packages[normalizedAddonName] || {}, - pkg, - ); - } else { - // Fallback in case the addon is released (not in packages folder nor in development, but in node_modules) - const normalizedAddonName = name.split(':')[0]; - this.initPublishedPackage(normalizedAddonName); - } - } - - /** - * 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 - */ - 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; - } - }); - } - - /** - * Returns the addon records, respects order from package.json:addons - */ - getAddons() { - return this.dependencyGraph - .dependenciesOf('@root') - .map((name) => this.packages[name]); - } - - getAddonExtenders() { - return this.getAddons() - .map((o) => o.razzleExtender) - .filter((e) => e); - } - - getEslintExtenders() { - return this.getAddons() - .map((o) => o.eslintExtender) - .filter((e) => e); - } - - getCustomThemeAddons() { - const customThemeAddonsInfo = { - variables: [], - main: [], - }; - - this.getAddonDependencies().forEach((addon) => { - const normalizedAddonName = addon.split(':')[0]; - // We have two possible insertion points, variables and main - - const customThemeVariables = `${this.packages[normalizedAddonName].modulePath}/theme/_variables.scss`; - const customThemeMain = `${this.packages[normalizedAddonName].modulePath}/theme/_main.scss`; - if ( - fs.existsSync(customThemeVariables) && - normalizedAddonName !== this.theme - ) { - customThemeAddonsInfo.variables.push(normalizedAddonName); - } - if ( - fs.existsSync(customThemeMain) && - normalizedAddonName !== this.theme - ) { - customThemeAddonsInfo.main.push(normalizedAddonName); - } - }); - - return customThemeAddonsInfo; - } - - /** - * Returns a mapping name:diskpath to be uses in webpack's resolve aliases - */ - getResolveAliases() { - const pairs = [ - ...Object.keys(this.packages).map((o) => [ - o, - this.packages[o].modulePath, - ]), - ]; - - return fromEntries(pairs); - } - - /** - * Retrieves a mapping (to be used in resolve aliases) of module name to - * filestype paths, to be used as customization paths. - * - * There are two styles of customizations: "classic style" and "addons style" - * - * In the classic style, the customization folders are only used to customize - * Volto itself, so inside it we'll find a mirror of the Volto project - * structure. - * - * In the "addons style" customization folder, we allow customization of - * addons along with Volto customization, so we need separate folders. By - * convention, we use a folder called "volto" inside customizations folder - * and separate folder for each addon, identified by its addon (package) name. - */ - getCustomizationPaths(packageJson, rootPath) { - const aliases = {}; - let { customizationPaths } = packageJson; - if (!customizationPaths) { - customizationPaths = ['src/customizations']; - } - customizationPaths.forEach((customizationPath) => { - customizationPath = customizationPath.endsWith('/') - ? customizationPath.slice(0, customizationPath.length - 1) - : customizationPath; - const base = path.join(rootPath, customizationPath); - const reg = []; - - // All registered addon packages (in tsconfig.json/jsconfig.json and package.json:addons) - // can be customized - Object.values(this.packages).forEach((addon) => { - const { name, modulePath } = addon; - if (fs.existsSync(path.join(base, name))) { - reg.push({ - customPath: path.join(base, name), - sourcePath: modulePath, - name, - }); - } - }); - - // allow customization of modules in the `@root` namespace from addons, - // by creating a folder called `@root`. - const rootBase = path.join(base, '@root'); - if (fs.existsSync(rootBase)) - reg.push({ - customPath: rootBase, - sourcePath: `${this.projectRootPath}/src`, - name: '@root', - }); - - reg.push( - fs.existsSync(path.join(base, 'volto')) - ? { - // new style (addons) customizations - customPath: path.join(base, 'volto'), - sourcePath: `${this.voltoPath}/src/`, - name: '@plone/volto', - } - : { - // old style, customizations directly in folder - customPath: base, - sourcePath: `${this.voltoPath}/src/`, - name: '@plone/volto', - }, - ); - - reg.forEach(({ customPath, name, sourcePath }) => { - map( - glob(`${customPath}/**/*.*(svg|png|jpg|jpeg|gif|ico|less|js|jsx)`), - (filename) => { - const targetPath = filename.replace(customPath, sourcePath); - if (fs.existsSync(targetPath)) { - aliases[ - filename.replace(customPath, name).replace(/\.(js|jsx)$/, '') - ] = path.resolve(filename); - } else { - debug( - `The file ${filename} doesn't exist in the ${name} (${targetPath}), unable to customize.`, - ); - } - }, - ); - }); - }); - - return aliases; - } - - getProjectCustomizationPaths() { - return this.getCustomizationPaths(this.packageJson, this.projectRootPath); - } - - /** - * Allow addons to customize Volto and other addons. - * - * We follow the same logic for overriding as the main `package.json:addons`. - * First declared addon gets overridden by subsequent declared addons. That - * means: customization in volto-addonA will potentially be rewritten by - * customizations in volto-addonB if the declaration in package.json is like: - * `addons:volto-addonA,volto-addonB` - */ - getAddonCustomizationPaths() { - let aliases = {}; - this.getAddons().forEach((addon) => { - aliases = { - ...aliases, - ...this.getCustomizationPaths( - require(addon.packageJson), - getPackageBasePath(addon.modulePath), - ), - }; - }); - return aliases; - } - - /** - * Allow packages from addons set in env vars to customize Volto and other addons. - * - * Same as the above one, but specific for Volto addons coming from env vars - */ - getAddonsFromEnvVarCustomizationPaths() { - let aliases = {}; - if (process.env.ADDONS) { - process.env.ADDONS.split(';').forEach((addon) => { - const normalizedAddonName = addon.split(':')[0]; - const testingPackagePath = `${this.projectRootPath}/packages/${normalizedAddonName}/src`; - if (fs.existsSync(testingPackagePath)) { - const basePath = getPackageBasePath(testingPackagePath); - const packageJson = path.join(basePath, 'package.json'); - aliases = { - ...aliases, - ...this.getCustomizationPaths(require(packageJson), basePath), - }; - } - }); - - return aliases; - } else { - return []; - } - } - - /** - * Returns an agregated, dependency-resolved list of addon loader strings - */ - getAddonDependencies() { - return getAddonsLoaderChain(this.dependencyGraph); - } - - getDotDependencyGraph() { - const seen = new Set(); - let out = `digraph { - layout="fdp" - beautify=true - sep="+10" - splines=curved - - "@root" [color = red fillcolor=yellow style=filled] -`; - let queue = ['@root']; - let name; - - while (queue.length > 0) { - name = queue.pop(); - - const deps = this.dependencyGraph.directDependenciesOf(name); - for (let i = 0; i < deps.length; i++) { - const dep = deps[i]; - - if (!seen.has(dep)) { - seen.add(dep); - queue.push(dep); - } - out += ` "${name}" -> "${dep}"\n`; - } - } - out += '}'; - return out; - } -} - -module.exports = AddonConfigurationRegistry; -module.exports.getAddonsLoaderChain = getAddonsLoaderChain; -module.exports.buildDependencyGraph = buildDependencyGraph; diff --git a/api/buildout.cfg b/api/buildout.cfg index e11b411802..823c5ae050 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.6/versions.cfg + http://dist.plone.org/release/6.0.10.1/versions.cfg version-constraints.cfg versions.cfg parts = instance plonesite site-packages test robot-server @@ -16,8 +16,9 @@ show-picked-versions = true [sources] plone.volto = git https://github.com/plone/plone.volto.git branch=main -plone.rest = git git@github.com:plone/plone.rest.git branch=master -plone.restapi = git https://github.com/plone/plone.restapi.git pushurl=git@github.com:plone/plone.restapi.git branch=master +plone.rest = git git@github.com:plone/plone.rest.git branch=main +plone.restapi = git https://github.com/plone/plone.restapi.git pushurl=git@github.com:plone/plone.restapi.git branch=main +plone.app.linkintegrity = git https://github.com/plone/plone.app.linkintegrity.git pushurl=git@github.com:plone/plone.app.linkintegrity.git branch=master [instance] recipe = plone.recipe.zope2instance diff --git a/api/versions.cfg b/api/versions.cfg index f24f7e7966..f91119d3db 100644 --- a/api/versions.cfg +++ b/api/versions.cfg @@ -3,3 +3,6 @@ # Added by buildout at 2021-12-15 17:25:36.097866 collective.folderishtypes = 3.0.0 collective.recipe.plonesite = 1.12.0 + +# without this volto is not building locally +pyyaml = 5.3.1 diff --git a/apps/nextjs/.eslintrc.js b/apps/nextjs/.eslintrc.js new file mode 100644 index 0000000000..d0e37670c7 --- /dev/null +++ b/apps/nextjs/.eslintrc.js @@ -0,0 +1,10 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: 'next/core-web-vitals', + ignorePatterns: ['.next/**', 'dist/**', 'node_modules/**'], + settings: { + next: { + rootDir: 'apps/nextjs/', + }, + }, +}; diff --git a/apps/nextjs/.gitignore b/apps/nextjs/.gitignore new file mode 100644 index 0000000000..e5671ba458 --- /dev/null +++ b/apps/nextjs/.gitignore @@ -0,0 +1,47 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# yarn 3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Addons +src/lib/* diff --git a/apps/nextjs/.prettierignore b/apps/nextjs/.prettierignore new file mode 100644 index 0000000000..fc1ff10317 --- /dev/null +++ b/apps/nextjs/.prettierignore @@ -0,0 +1 @@ +src/lib diff --git a/apps/nextjs/.prettierrc b/apps/nextjs/.prettierrc new file mode 100644 index 0000000000..6e778b4fb9 --- /dev/null +++ b/apps/nextjs/.prettierrc @@ -0,0 +1,4 @@ +{ + "trailingComma": "all", + "singleQuote": true +} diff --git a/apps/nextjs/LICENSE b/apps/nextjs/LICENSE new file mode 100644 index 0000000000..c0af2b1b65 --- /dev/null +++ b/apps/nextjs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Plone Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/apps/nextjs/Makefile b/apps/nextjs/Makefile new file mode 100644 index 0000000000..f60d23fdf0 --- /dev/null +++ b/apps/nextjs/Makefile @@ -0,0 +1,50 @@ + +# Add the following 'help' target to your Makefile +# And add help text after each target name starting with '\#\#' +.PHONY: help +help: ## This help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: clean +clean: ## Clean installation + @echo "Clean installation" + rm -Rf node_modules .yarn/cache cache omelette build + +.PHONY: build +build: install ## Build the frontend + @echo "Build Frontend" + yarn build + +.PHONY: start +start: ## Start Frontend + yarn start + +.PHONY: format-prettier +format-prettier: ## Format Code with Prettier + yarn run prettier:fix + +.PHONY: format-stylelint +format-stylelint: ## Format Code with Stylelint + yarn run stylelint:fix + +.PHONY: format-lint +format-lint: ## Format Code with Lint + yarn run lint:fix + +.PHONY: format +format: format-prettier format-lint format-stylelint ## Format the codebase according to our standards + +.PHONY: install +install: ## Install the frontend + @echo "Install frontend" + $(MAKE) preinstall + yarn -v + 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) + if [ ! -f $$(pwd)/jsconfig.json ]; then npx -p mrs-developer missdev --output=lib --fetch-https; fi diff --git a/apps/nextjs/README.md b/apps/nextjs/README.md new file mode 100644 index 0000000000..687905853e --- /dev/null +++ b/apps/nextjs/README.md @@ -0,0 +1,113 @@ +# Plone on Next.js + +This is a proof of concept of a [Next.js](https://nextjs.org) app, using the app router and the `@plone/client` and `@plone/components` library. This is intended to serve as both a playground for the development of both packages and as demo of Plone using Next.js. + +## Development + +To start, from the root of the monorepo: + +```shell +pnpm install +pnpm build:deps && pnpm build:components +pnpm --filter plone-nextjs run dev +``` + +Then start the Plone backend: + +```shell +make start-backend-docker +``` + +## Deployment at Vercel + + +We introduce an environment variable `API_SERVER_URL`. +You need to create this environment variable in the Vercel deployment's control panel, specifying the URL where your backend API server is deployed, and the route where the API is located, as shown. + +```shell +API_SERVER_URL=https://my-server-DNS-name.tld/api +``` + +### Application rewrite configuragtion + +To avoid issues with CORS and maintain the server counterpart private, our Next.js app should have a rewrite, configured as follows: + +```jsx +const nextConfig = { + // Rewrite to the backend to avoid CORS + async rewrites() { + const apiServerURL = + process.env.API_SERVER_URL || + 'http://localhost:8080/Plone/%2B%2Bapi%2B%2B'; + + return [ + { + source: '/\\+\\+api\\+\\+/:slug*', + destination: + `${apiServerURL}/VirtualHostBase/https/${process.env.NEXT_PUBLIC_VERCEL_URL}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot/:slug*`, + }, + ]; + }, +}; +``` + +Plone Client uses the `++api++` prefix as default, so we should create a redirect in our app pointing to the API server, but using Plone's traditional virtual host management configuration. + +Next.js rewrites are picky on the `destination` field, because its rewrite library does not support URLs with regular expression operators. +Therefore, we can't use the usual `++api++` route for the rewrite. +This will allow us to infer the current server URL—even in deployed branches and pull requests—without touching the rewrite rules. +We will fallback to configure a `api` route in our reverse proxy of choice. + +### Plone backend + +You have to deploy the Plone backend elsewhere, since Vercel is serverless oriented. +We need to set up the rewrite rule in Next.js's `rewrite` feature as shown in the previous section. + +We will fallback to configure an `api` route in our reverse proxy of choice. + +For example, if we use `traefik`: + +```yaml + ## VHM rewrite /api/ (Plone Next.js) + - "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.regex=^/api($$|/.*)" + ## We remove the incoming /api and just use the path + - "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.replacement=$$1" + + ## /api router + - traefik.http.routers.rt-backend-api.rule=Host(`my_server_DNS_name`) && PathPrefix(`/api`) + - traefik.http.routers.rt-backend-api.entrypoints=https + - traefik.http.routers.rt-backend-api.tls=true + - traefik.http.routers.rt-backend-api.service=svc-backend + - traefik.http.routers.rt-backend-api.middlewares=gzip,mw-backend-vhm-api +``` + +## About this app + +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting started + +First, run the development server: + +```bash +pnpm dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/pages/building-your-application/deploying) for more details. diff --git a/apps/nextjs/next.config.js b/apps/nextjs/next.config.js new file mode 100644 index 0000000000..ae8d5d1813 --- /dev/null +++ b/apps/nextjs/next.config.js @@ -0,0 +1,49 @@ +const path = require('path'); + +/** @type {import('next').NextConfig} */ +const nextConfig = { + // sassOptions: { + // includePaths: [path.join(__dirname, 'src/lib/components/src/styles')], + // }, + + // webpack(config) { + // config.resolve.alias = { + // ...config.resolve.alias, + // '../fonts': path.resolve(__dirname, 'src/lib/components/src/fonts'), + // }; + + // return config; + // }, + + // Rewrite to the backend to avoid CORS + async rewrites() { + let apiServerURL, vhmRewriteRule; + if (process.env.API_SERVER_URL) { + apiServerURL = process.env.API_SERVER_URL; + vhmRewriteRule = `/VirtualHostBase/https/${process.env.NEXT_PUBLIC_VERCEL_URL}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot`; + } else if ( + process.env.API_SERVER_URL && + !process.env.NEXT_PUBLIC_VERCEL_URL + ) { + throw new Error( + 'API_SERVER_URL set and NEXT_PUBLIC_VERCEL_URL not present.', + ); + } else { + apiServerURL = 'http://localhost:8080'; + vhmRewriteRule = + '/VirtualHostBase/http/localhost%3A3000/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot'; + } + + return [ + { + source: '/\\+\\+api\\+\\+/:slug*', + destination: + // 'https://static.197.123.88.23.clients.your-server.de/api/:slug*', + // `${apiServerURL}/:slug*`, + `${apiServerURL}${vhmRewriteRule}/:slug*`, + }, + ]; + }, +}; + +module.exports = nextConfig; diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json new file mode 100644 index 0000000000..6e29f5f31e --- /dev/null +++ b/apps/nextjs/package.json @@ -0,0 +1,31 @@ +{ + "name": "plone-nextjs", + "version": "1.0.0-alpha", + "private": true, + "scripts": { + "dev": "next dev", + "check-ts": "tsc --project tsconfig.json", + "build": "next build", + "start:prod": "next start", + "lint": "next lint" + }, + "dependencies": { + "@plone/client": "workspace: *", + "@plone/components": "workspace: *", + "@tanstack/react-query": "^5.24.6", + "@tanstack/react-query-devtools": "^5.24.6", + "next": "14.1.1", + "react": "^18", + "react-aria-components": "^1.1.1", + "react-dom": "^18" + }, + "devDependencies": { + "@types/node": "^20", + "@types/react": "^18", + "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.1.1", + "mrs-developer": "^2.1.1", + "typescript": "5.2.2" + } +} diff --git a/apps/nextjs/public/next.svg b/apps/nextjs/public/next.svg new file mode 100644 index 0000000000..5174b28c56 --- /dev/null +++ b/apps/nextjs/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/nextjs/public/vercel.svg b/apps/nextjs/public/vercel.svg new file mode 100644 index 0000000000..d2f8422273 --- /dev/null +++ b/apps/nextjs/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/nextjs/src/app/Providers.tsx b/apps/nextjs/src/app/Providers.tsx new file mode 100644 index 0000000000..324bce7a2f --- /dev/null +++ b/apps/nextjs/src/app/Providers.tsx @@ -0,0 +1,55 @@ +'use client'; +import React from 'react'; +import { useRouter } from 'next/navigation'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { PloneClientProvider } from '@plone/client/provider'; +import PloneClient from '@plone/client'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { RouterProvider } from 'react-aria-components'; +import { FlattenToAppURLProvider } from '@plone/components'; +import { flattenToAppURL } from './utils'; +import config from './config'; + +const Providers: React.FC<{ + children?: React.ReactNode; +}> = ({ children }) => { + // Creating the clients at the file root level makes the cache shared + // between all requests and means _all_ data gets passed to _all_ users. + // Besides being bad for performance, this also leaks any sensitive data. + // We use this pattern to ensure that every client gets its own clients + const [queryClient] = React.useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, + }, + }, + }), + ); + + const [ploneClient] = React.useState(() => + PloneClient.initialize({ + apiPath: config.settings.apiPath, + }), + ); + + let router = useRouter(); + + return ( + + + + + {children} + + + + + + ); +}; + +export default Providers; diff --git a/apps/nextjs/src/app/[...slug]/page.tsx b/apps/nextjs/src/app/[...slug]/page.tsx new file mode 100644 index 0000000000..bfd9dccfd2 --- /dev/null +++ b/apps/nextjs/src/app/[...slug]/page.tsx @@ -0,0 +1,3 @@ +import Main from '../main'; + +export default Main; diff --git a/apps/nextjs/src/app/config.ts b/apps/nextjs/src/app/config.ts new file mode 100644 index 0000000000..47bad754da --- /dev/null +++ b/apps/nextjs/src/app/config.ts @@ -0,0 +1,12 @@ +const settings = { + apiPath: process.env.NEXT_PUBLIC_VERCEL_URL + ? // Vercel does not prepend the schema to the NEXT_PUBLIC_VERCEL_URL automatic env var + `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` + : 'http://localhost:3000', +}; + +const config = { + settings, +}; + +export default config; diff --git a/apps/nextjs/src/app/content.tsx b/apps/nextjs/src/app/content.tsx new file mode 100644 index 0000000000..c2c6ad2235 --- /dev/null +++ b/apps/nextjs/src/app/content.tsx @@ -0,0 +1,49 @@ +'use client'; + +import { useQuery } from '@tanstack/react-query'; +import { usePathname } from 'next/navigation'; +import Link from 'next/link'; +import { flattenToAppURL } from './utils'; +import { usePloneClient } from '@plone/client/provider'; +import { Breadcrumbs } from '@plone/components'; +import '@plone/components/dist/basic.css'; + +export default function Content() { + const { getContentQuery } = usePloneClient(); + const pathname = usePathname(); + const { data, isLoading } = useQuery(getContentQuery({ path: pathname })); + + if (data) { + return ( +

+

{data.title}

+ {/* */} + +
    + {data?.['@components']?.navigation?.items?.map((item) => ( +
  • + + {flattenToAppURL(item['@id'])} + +
  • + ))} +
+
+
{JSON.stringify(data, null, 2)}
+
+
+ ); + } + + return ''; +} diff --git a/apps/nextjs/src/app/favicon.ico b/apps/nextjs/src/app/favicon.ico new file mode 100644 index 0000000000..718d6fea48 Binary files /dev/null and b/apps/nextjs/src/app/favicon.ico differ diff --git a/apps/nextjs/src/app/getQueryClient.tsx b/apps/nextjs/src/app/getQueryClient.tsx new file mode 100644 index 0000000000..6489c92efa --- /dev/null +++ b/apps/nextjs/src/app/getQueryClient.tsx @@ -0,0 +1,15 @@ +import { QueryClient } from '@tanstack/react-query'; +import { cache } from 'react'; + +const getQueryClient = cache( + () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + }, + }, + }), +); + +export default getQueryClient; diff --git a/apps/nextjs/src/app/layout.tsx b/apps/nextjs/src/app/layout.tsx new file mode 100644 index 0000000000..3c118fb9fa --- /dev/null +++ b/apps/nextjs/src/app/layout.tsx @@ -0,0 +1,24 @@ +import type { Metadata } from 'next'; +import { Inter } from 'next/font/google'; +import Providers from './Providers'; + +const inter = Inter({ subsets: ['latin'] }); + +export const metadata: Metadata = { + title: 'NextJS-powered Plone', + description: '', +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {children} + + + ); +} diff --git a/apps/nextjs/src/app/main.tsx b/apps/nextjs/src/app/main.tsx new file mode 100644 index 0000000000..f0d5c302a3 --- /dev/null +++ b/apps/nextjs/src/app/main.tsx @@ -0,0 +1,32 @@ +import ploneClient from '@plone/client'; +import { dehydrate, HydrationBoundary } from '@tanstack/react-query'; +import { headers } from 'next/headers'; +import getQueryClient from './getQueryClient'; +import Content from './content'; +import config from './config'; + +const cli = ploneClient.initialize({ + apiPath: config.settings.apiPath, +}); + +const expand = ['breadcrumbs', 'navigation']; + +export default async function Main() { + const { getContentQuery } = cli; + const queryClient = getQueryClient(); + const headersList = headers(); + const path = headersList.get('x-pathname') || '/'; + console.log(`Visiting: ${path}`); + await queryClient.prefetchQuery(getContentQuery({ path, expand })); + const dehydratedState = dehydrate(queryClient); + + return ( + +
+ apiPath in main RSC: {cli.config.apiPath} +
the content path in main RSC: {path} + +
+
+ ); +} diff --git a/apps/nextjs/src/app/page.tsx b/apps/nextjs/src/app/page.tsx new file mode 100644 index 0000000000..9a28e1dd09 --- /dev/null +++ b/apps/nextjs/src/app/page.tsx @@ -0,0 +1,3 @@ +import Main from './main'; + +export default Main; diff --git a/apps/nextjs/src/app/utils.ts b/apps/nextjs/src/app/utils.ts new file mode 100644 index 0000000000..2f8aab3cec --- /dev/null +++ b/apps/nextjs/src/app/utils.ts @@ -0,0 +1,13 @@ +import config from './config'; + +/** + * Flatten to app server URL - Given a URL if it starts with the API server URL + * this method flattens it (removes) the server part + * TODO: Update it when implementing non-root based app location (on a + * directory other than /, eg. /myapp) + * @method flattenToAppURL + */ +export function flattenToAppURL(url: string | undefined) { + const { settings } = config; + return (url && url.replace(settings.apiPath, '')) || '/'; +} diff --git a/apps/nextjs/src/middleware.ts b/apps/nextjs/src/middleware.ts new file mode 100644 index 0000000000..59c2d7b5d4 --- /dev/null +++ b/apps/nextjs/src/middleware.ts @@ -0,0 +1,22 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +export function middleware(request: NextRequest) { + // Clone the request headers and set a new header `x-hello-from-middleware1` + const requestHeaders = new Headers(request.headers); + // console.log(request.nextUrl.pathname); + // requestHeaders.set('x-hello-from-middleware1', 'hello'); + + // You can also set request headers in NextResponse.rewrite + const response = NextResponse.next({ + request: { + // New request headers + headers: requestHeaders, + }, + }); + + // Set a new response header `x-pathname` and set the pathname on it + // This is required because you can't get the current path from an RSC + response.headers.set('x-pathname', request.nextUrl.pathname); + return response; +} diff --git a/apps/nextjs/tsconfig.json b/apps/nextjs/tsconfig.json new file mode 100644 index 0000000000..33bcb0c4f4 --- /dev/null +++ b/apps/nextjs/tsconfig.json @@ -0,0 +1,38 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ] + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "**/*.js", + "**/*.jx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules", + ] +} diff --git a/.editorconfig b/apps/plone/.editorconfig similarity index 100% rename from .editorconfig rename to apps/plone/.editorconfig diff --git a/apps/plone/.eslintrc.js b/apps/plone/.eslintrc.js new file mode 100644 index 0000000000..6148e2e62f --- /dev/null +++ b/apps/plone/.eslintrc.js @@ -0,0 +1,63 @@ +const fs = require('fs'); +const projectRootPath = __dirname; +const AddonConfigurationRegistry = require('@plone/registry/src/addon-registry'); + +let voltoPath = './node_modules/@plone/volto'; + +let configFile; +if (fs.existsSync(`${projectRootPath}/tsconfig.json`)) + configFile = `${projectRootPath}/tsconfig.json`; +else if (fs.existsSync(`${projectRootPath}/jsconfig.json`)) + configFile = `${projectRootPath}/jsconfig.json`; + +if (configFile) { + const jsConfig = require(configFile).compilerOptions; + const pathsConfig = jsConfig.paths; + if (pathsConfig['@plone/volto']) + voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`; +} + +const reg = new AddonConfigurationRegistry(__dirname); + +// Extends ESlint configuration for adding the aliases to `src` directories in Volto addons +const addonAliases = Object.keys(reg.packages).map((o) => [ + o, + reg.packages[o].modulePath, +]); + +const addonExtenders = reg.getEslintExtenders().map((m) => require(m)); + +const defaultConfig = { + extends: `${voltoPath}/.eslintrc`, + ignorePatterns: [ + // '.storybook/**/*', + 'src/addons/**/node_modules', + 'src/addons/**/cypress', + 'src/addons/**/build', + '!src/addons/volto-volto-project', + ], + settings: { + 'import/resolver': { + alias: { + map: [ + ['@plone/volto', '@plone/volto/src'], + ['@plone/volto-slate', '@plone/volto-slate/src'], + ...addonAliases, + ['@root', `${__dirname}/src`], + ['~', `${__dirname}/src`], + ], + extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], + }, + 'babel-plugin-root-import': { + rootPathSuffix: 'src', + }, + }, + }, +}; + +const config = addonExtenders.reduce( + (acc, extender) => extender.modify(acc), + defaultConfig, +); + +module.exports = config; diff --git a/apps/plone/.gitignore b/apps/plone/.gitignore new file mode 100644 index 0000000000..8dd6203312 --- /dev/null +++ b/apps/plone/.gitignore @@ -0,0 +1,96 @@ +.vscode/ +logs +*.log +npm-debug.log* +.DS_Store + +coverage + +# Node +node_modules +coverage +jsdoc +webpack-assets.json +webpack-stats.json +npm-debug.log +dist +junit.xml +eslint.xml +yarn-error.log +build + +# Other +.DS_Store +.idea +lighthouse-report.html +.vscode/ +.#* +*~ + +# Python +/api/.installed.cfg +/api/.mr.developer.cfg +/api/bin/ +/api/develop-eggs/ +/api/eggs/ +/api/include/ +/api/lib/ +/api/lib64/ +/api/notebook/env/ +/api/parts/ +/api/share/python-wheels/ +/api/src/ +/api/var/ +/api/venv/ +/bin/ +/lib/ +.Python +include +pip-selfcheck.json +pyvenv.cfg +share + +# locales +locales/*.json + +# Tests +/tests/bin +/tests/develop-eggs +/tests/parts +/tests/.installed.cfg +*.pyc +geckodriver.log +log.html +output.xml +report.html +selenium-screenshot-*.png +/selenium/ +cypress/videos/ +cypress/screenshots + +# Local environment setup +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# generic +data +omelette + +# build +public/critical.css +src/addons/* +/cache + +# yarn 3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +!src/addons/volto-volto-project \ No newline at end of file diff --git a/apps/plone/.prettierignore b/apps/plone/.prettierignore new file mode 100644 index 0000000000..84cca9725b --- /dev/null +++ b/apps/plone/.prettierignore @@ -0,0 +1,3 @@ +src/**/CHANGELOG.md +src/**/README.md +!src/addons/volto-volto-project \ No newline at end of file diff --git a/apps/plone/.storybook/main.js b/apps/plone/.storybook/main.js new file mode 100644 index 0000000000..0455b194c9 --- /dev/null +++ b/apps/plone/.storybook/main.js @@ -0,0 +1,177 @@ +const webpack = require('webpack'); +const fs = require('fs'); +const path = require('path'); + +const projectRootPath = path.resolve('.'); +const lessPlugin = require('@plone/volto/webpack-plugins/webpack-less-plugin'); +const scssPlugin = require('razzle-plugin-scss'); + +const createConfig = require('../node_modules/razzle/config/createConfigAsync.js'); +const razzleConfig = require(path.join(projectRootPath, 'razzle.config.js')); + +const SVGLOADER = { + test: /icons\/.*\.svg$/, + use: [ + { + loader: 'svg-loader', + }, + { + loader: 'svgo-loader', + options: { + plugins: [ + { + name: 'preset-default', + params: { + overrides: { + convertPathData: false, + removeViewBox: false, + }, + }, + }, + 'removeTitle', + 'removeUselessStrokeAndFill', + ], + }, + }, + ], +}; + +const defaultRazzleOptions = { + verbose: false, + debug: {}, + buildType: 'iso', + cssPrefix: 'static/css', + jsPrefix: 'static/js', + enableSourceMaps: true, + enableReactRefresh: true, + enableTargetBabelrc: false, + enableBabelCache: true, + forceRuntimeEnvVars: [], + mediaPrefix: 'static/media', + staticCssInDev: false, + emitOnErrors: false, + disableWebpackbar: false, + browserslist: [ + '>1%', + 'last 4 versions', + 'Firefox ESR', + 'not ie 11', + 'not dead', + ], +}; + +module.exports = { + core: { + builder: 'webpack5', + }, + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + // '@storybook/preset-scss', + ], + 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, + ); + const AddonConfigurationRegistry = require('@plone/volto/addon-registry'); + + const registry = new AddonConfigurationRegistry(projectRootPath); + + config = lessPlugin({ registry }).modifyWebpackConfig({ + env: { target: 'web', dev: 'dev' }, + webpackConfig: config, + webpackObject: webpack, + options: {}, + }); + + config = scssPlugin.modifyWebpackConfig({ + env: { target: 'web', dev: 'dev' }, + webpackConfig: config, + webpackObject: webpack, + options: { razzleOptions: {} }, + }); + + // Put the SVG loader on top and prevent the asset/resource rule + // from processing the app's SVGs + config.module.rules.unshift(SVGLOADER); + 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 }, + fallback: { ...config.resolve.fallback, zlib: false }, + }, + }; + + // 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) => + // 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)); + + const addonExtenders = registry.getAddonExtenders().map((m) => require(m)); + + const extendedConfig = addonExtenders.reduce( + (acc, extender) => + extender.modify(acc, { target: 'web', dev: 'dev' }, config), + resultConfig, + ); + + // Note: we don't actually support razzle plugins, which are also a feature + // of the razzle.extend.js addons file. Those features are probably + // provided in a different manner by Storybook plugins (for example scss + // loaders). + + return extendedConfig; + }, + babel: async (options) => { + return { + ...options, + plugins: [ + ...options.plugins, + [ + './node_modules/babel-plugin-root-import/build/index.js', + { + rootPathSuffix: './src', + }, + ], + ], + // any extra options you want to set + }; + }, +}; diff --git a/.storybook/manager.js b/apps/plone/.storybook/manager.js similarity index 100% rename from .storybook/manager.js rename to apps/plone/.storybook/manager.js diff --git a/apps/plone/.storybook/preview.js b/apps/plone/.storybook/preview.js new file mode 100644 index 0000000000..bcbfccb212 --- /dev/null +++ b/apps/plone/.storybook/preview.js @@ -0,0 +1,28 @@ +import '@plone/volto/config'; // This is the bootstrap for the global config - client side +import React from 'react'; +import { StaticRouter } from 'react-router-dom'; +import { IntlProvider } from 'react-intl'; +// eslint-disable-next-line import/no-unresolved +import enMessages from '@root/../locales/en.json'; + +import '@root/theme'; + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; + +export const decorators = [ + (Story) => ( + + + + + + ), +]; diff --git a/apps/plone/Makefile b/apps/plone/Makefile new file mode 100644 index 0000000000..4a5a606c1f --- /dev/null +++ b/apps/plone/Makefile @@ -0,0 +1,106 @@ +### Defensive settings for make: +# https://tech.davis-hansson.com/p/make/ +SHELL:=bash +.ONESHELL: +.SHELLFLAGS:=-eu -o pipefail -c +.SILENT: +.DELETE_ON_ERROR: +MAKEFLAGS+=--warn-undefined-variables +MAKEFLAGS+=--no-builtin-rules + +# Update the versions depending on your project requirements | Last Updated 2023-03-02 +DOCKER_IMAGE=plone/server-dev:6.0.6 +DOCKER_IMAGE_ACCEPTANCE=plone/server-acceptance:6.0.6 +KGS= +NODEBIN = ./node_modules/.bin + +# Plone 5 legacy +DOCKER_IMAGE5=plone/plone-backend:5.2.12 +KGS5=plone.restapi==8.43.3 plone.volto==4.1.0 plone.rest==3.0.1 +TESTING_ADDONS=plone.app.robotframework==2.0.0 plone.app.testing==7.0.0 + +# Project settings + +DIR=$(shell basename $$(pwd)) + +# Recipe snippets for reuse + +# We like colors +# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects +RED=`tput setaf 1` +GREEN=`tput setaf 2` +RESET=`tput sgr0` +YELLOW=`tput setaf 3` + + +# Top-level targets +.PHONY: all +all: project + +.PHONY: help +help: ## Show this help. + @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" + +.PHONY: start-backend-docker +start-backend-docker: ## Starts a Docker-based backend + @echo "$(GREEN)==> Start Docker-based Plone Backend$(RESET)" + docker run -it --rm --name=backend -p 8080:8080 -e SITE=Plone -e ADDONS='$(KGS)' $(DOCKER_IMAGE) + +.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) + if [ -f $$(pwd)/jsconfig.json ]; then npx -p mrs-developer missdev --config=jsconfig.json --output=addons --fetch-https; fi + if [ ! -f $$(pwd)/jsconfig.json ]; then npx -p mrs-developer missdev --output=addons --fetch-https; fi + +.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 + +.PHONY: start-test-acceptance-server start-test-backend +start-test-acceptance-server start-test-backend : ## Start Test Plone Backend + @echo "$(GREEN)==> Start Test Plone Backend$(RESET)" + docker run -i --rm -p 55001:55001 $(DOCKER_IMAGE_ACCEPTANCE) + ## KGS in case you need a Plone 5.2 series (comment/remove above line): + # docker run -i --rm -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(KGS5) $(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_IMAGE5) ./bin/robot-server plone.app.robotframework.testing.VOLTO_ROBOT_TESTING + +.PHONY: start-test-acceptance-frontend +start-test-acceptance-frontend: ## Start the Acceptance Frontend Fixture + 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 + $(NODEBIN)/cypress open + +.PHONY: test-acceptance-headless +test-acceptance-headless: ## Start Core Cypress Acceptance Tests in headless mode + $(NODEBIN)/cypress run + +.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://127.0.0.1:55001/plone "make start-test-acceptance-frontend" http://127.0.0.1:3000 "make test-acceptance-headless" + +.PHONY: test-acceptance +test-acceptance-addon: ## Start Core Cypress Acceptance Tests for an addon + $(NODEBIN)/cypress open -P $(ADDONPATH) + +.PHONY: test-acceptance-headless +test-acceptance-addon-headless: ## Start Core Cypress Acceptance Tests for an addon in headless mode + $(NODEBIN)/cypress run -P $(ADDONPATH) + +.PHONY: full-test-acceptance-addon +full-test-acceptance-addon: ## Runs Core Full Acceptance Testing for an addon in headless mode + $(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-addon-headless" diff --git a/apps/plone/README.md b/apps/plone/README.md new file mode 100644 index 0000000000..da034e8ad3 --- /dev/null +++ b/apps/plone/README.md @@ -0,0 +1,81 @@ +# README.md + +This README guides you for development with Volto and Plone. + + +## Documentation + +[Volto Hands-On](https://training.plone.org/voltohandson/index.html) is a training on how to create your own website. + + +## Quick Start + +Below is a list of useful commands. + +### `make install` + +Installs and checks out the `mrs-developer` directives (`make develop`), creates a shortcut to the Volto source code (`omelette` folder), then triggers the install of the frontend environment. + + +### `yarn start` + +Runs the project in development mode. +You can view your application at `http://localhost:3000`. + +The page will reload if you make edits. + + +### `yarn build` + +Builds the app for production to the `build` folder. + +The build is minified and the filenames include the hashes. +Your app is ready to be deployed! + + +### `yarn start:prod` + +Runs the compiled app in production. + +You can view your application at `http://localhost:3000`. + + +### `yarn test` + +Runs the test watcher (Jest) in an interactive mode. +By default, runs tests related to files changed since the last commit. + + +### `yarn i18n` + +Runs the test i18n runner, which extracts all the translation strings and generates the needed files. + +### mrs-developer + +[mrs-developer](https://github.com/collective/mrs-developer) is a great tool for developing multiple packages at the same time. + +mrs-developer should work with this project by running the configured shortcut script: + +```bash +make develop +``` + +Volto's latest Razzle configuration will honor your `tsconfig.json` or `jsconfig.json` file for any customizations. + +In case you don't want (or can't) install mrs-developer globally, you can install it in this project by running: + +```bash +yarn add -W mrs-developer +``` + + +## Acceptance tests + +To run the project acceptance tests while developing using Cypress as the test runner, there are some `Makefile` commands in place in the repository root. + +Run them in order: + +- `start-test-acceptance-server`: Start the server fixture in Docker (previous build required). +- `start-test-acceptance-frontend`: Start the Core Acceptance Frontend Fixture in development mode. +- `test-acceptance`: Start the Core Cypress Acceptance Tests in development mode. +- `full-test-acceptance`: Start the entire suite (backend + frontend + headless tests) using Cypress Acceptance Tests in headless (CI) mode. diff --git a/apps/plone/babel.config.js b/apps/plone/babel.config.js new file mode 100644 index 0000000000..a900a7555e --- /dev/null +++ b/apps/plone/babel.config.js @@ -0,0 +1 @@ +module.exports = require('@plone/volto/babel'); diff --git a/packages/generator-volto/generators/addon/templates/cypress.config.js b/apps/plone/cypress.config.js similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress.config.js rename to apps/plone/cypress.config.js diff --git a/news/.gitkeep b/apps/plone/cypress/.gitkeep similarity index 100% rename from news/.gitkeep rename to apps/plone/cypress/.gitkeep diff --git a/cypress/fixtures/broccoli.jpg b/apps/plone/cypress/fixtures/broccoli.jpg similarity index 100% rename from cypress/fixtures/broccoli.jpg rename to apps/plone/cypress/fixtures/broccoli.jpg diff --git a/packages/generator-volto/generators/addon/templates/cypress/fixtures/example.json b/apps/plone/cypress/fixtures/example.json similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/fixtures/example.json rename to apps/plone/cypress/fixtures/example.json diff --git a/packages/generator-volto/generators/addon/templates/cypress/fixtures/file.pdf b/apps/plone/cypress/fixtures/file.pdf similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/fixtures/file.pdf rename to apps/plone/cypress/fixtures/file.pdf diff --git a/cypress/fixtures/halfdome2022.jpg b/apps/plone/cypress/fixtures/halfdome2022.jpg similarity index 100% rename from cypress/fixtures/halfdome2022.jpg rename to apps/plone/cypress/fixtures/halfdome2022.jpg diff --git a/cypress/fixtures/image.png b/apps/plone/cypress/fixtures/image.png similarity index 100% rename from cypress/fixtures/image.png rename to apps/plone/cypress/fixtures/image.png diff --git a/packages/generator-volto/generators/addon/templates/cypress/plugins/index.js b/apps/plone/cypress/plugins/index.js similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/plugins/index.js rename to apps/plone/cypress/plugins/index.js diff --git a/packages/generator-volto/generators/addon/templates/cypress/support/commands.js b/apps/plone/cypress/support/commands.js similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/support/commands.js rename to apps/plone/cypress/support/commands.js diff --git a/packages/generator-volto/generators/addon/templates/cypress/support/e2e.js b/apps/plone/cypress/support/e2e.js similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/support/e2e.js rename to apps/plone/cypress/support/e2e.js diff --git a/apps/plone/cypress/support/reset-fixture.js b/apps/plone/cypress/support/reset-fixture.js new file mode 100644 index 0000000000..4e2b4372d5 --- /dev/null +++ b/apps/plone/cypress/support/reset-fixture.js @@ -0,0 +1,43 @@ +function setup() { + const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + cy.request({ + method: 'POST', + url: `${api_url}/RobotRemote`, + headers: { Accept: 'text/xml', 'content-type': 'text/xml' }, + body: 'run_keywordremote_zodb_setupplone.app.robotframework.testing.PLONE_ROBOT_TESTING', + }).then(() => cy.log('Setting up API fixture')); +} + +function teardown() { + const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + cy.request({ + method: 'POST', + url: `${api_url}/RobotRemote`, + headers: { Accept: 'text/xml', 'content-type': 'text/xml' }, + body: 'run_keywordremote_zodb_teardownplone.app.robotframework.testing.PLONE_ROBOT_TESTING', + }).then(() => cy.log('Tearing down API fixture')); +} + +function main() { + const command = process.argv[2]; + switch (command) { + case 'setup': + setup(); + break; + case 'teardown': + teardown(); + break; + default: + setup(); + } +} + +// This is the equivalent of `if __name__ == '__main__'` in Python :) +if (require.main === module) { + main(); +} + +module.exports = { + setup, + teardown, +}; diff --git a/packages/generator-volto/generators/addon/templates/cypress/.gitkeep b/apps/plone/cypress/tests/.gitkeep similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/.gitkeep rename to apps/plone/cypress/tests/.gitkeep diff --git a/apps/plone/locales/de/LC_MESSAGES/volto.po b/apps/plone/locales/de/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..49d2e20662 --- /dev/null +++ b/apps/plone/locales/de/LC_MESSAGES/volto.po @@ -0,0 +1,20 @@ +# Translation of volto.pot to German +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2016-10-22 16:41-0500\n" +"Last-Translator: German \n" +"Language: de\n" +"Language-Team: German \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Language-Code: de\n" +"Language-Name: Deutsch\n" +"Preferred-Encodings: utf-8 latin1\n" +"X-Is-Fallback-For: de-at de-li de-lu de-ch de-de\n" + + diff --git a/apps/plone/locales/en/LC_MESSAGES/volto.po b/apps/plone/locales/en/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..12b9a47628 --- /dev/null +++ b/apps/plone/locales/en/LC_MESSAGES/volto.po @@ -0,0 +1,14 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language: \n" +"Language-Team: \n" +"Content-Type: \n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + + diff --git a/apps/plone/locales/es/LC_MESSAGES/volto.po b/apps/plone/locales/es/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..784b64fb17 --- /dev/null +++ b/apps/plone/locales/es/LC_MESSAGES/volto.po @@ -0,0 +1,21 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-12-03 03:20-0400\n" +"PO-Revision-Date: 2019-12-12 06:07-0400\n" +"Last-Translator: Leonardo J. Caballero G. \n" +"Language: es\n" +"Language-Team: ES \n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"X-Generator: Virtaal 0.7.1\n" +"Language-Code: es\n" +"Language-Name: Español\n" +"Preferred-Encodings: utf-8\n" +"Domain: volto\n" +"X-Is-Fallback-For: es-ar es-bo es-cl es-co es-cr es-do es-ec es-es es-sv es-gt es-hn es-mx es-ni es-pa es-py es-pe es-pr es-us es-uy es-ve\n" + + diff --git a/apps/plone/locales/eu/LC_MESSAGES/volto.po b/apps/plone/locales/eu/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..984adca72e --- /dev/null +++ b/apps/plone/locales/eu/LC_MESSAGES/volto.po @@ -0,0 +1,19 @@ +# Translation of volto.pot to EU +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2016-10-22 16:41-0500\n" +"Last-Translator: Plone i18n \n" +"Language: eu\n" +"Language-Team: Plone i18n \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Language-Code: eu\n" +"Language-Name: eu\n" +"Preferred-Encodings: utf-8 latin1\n" + + diff --git a/apps/plone/locales/fr/LC_MESSAGES/volto.po b/apps/plone/locales/fr/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..f6050e4530 --- /dev/null +++ b/apps/plone/locales/fr/LC_MESSAGES/volto.po @@ -0,0 +1,20 @@ +# Translation of volto.pot to French +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2016-10-22 16:41-0500\n" +"Last-Translator: Benoît Suttor \n" +"Language: fr\n" +"Language-Team: French \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Language-Code: fr\n" +"Language-Name: French\n" +"Preferred-Encodings: utf-8 latin1\n" +"X-Is-Fallback-For: fr-be fr-ca fr-lu fr-mc fr-ch fr-fr\n" + + diff --git a/apps/plone/locales/it/LC_MESSAGES/volto.po b/apps/plone/locales/it/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..12b9a47628 --- /dev/null +++ b/apps/plone/locales/it/LC_MESSAGES/volto.po @@ -0,0 +1,14 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language: \n" +"Language-Team: \n" +"Content-Type: \n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + + diff --git a/apps/plone/locales/ja/LC_MESSAGES/volto.po b/apps/plone/locales/ja/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..a543785fbf --- /dev/null +++ b/apps/plone/locales/ja/LC_MESSAGES/volto.po @@ -0,0 +1,19 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2019-11-15 12:06+0900\n" +"Last-Translator: Manabu TERADA \n" +"Language: ja\n" +"Language-Team: Plone Japanese Team \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Language-Code: ja\n" +"Language-Name: Japanese\n" +"Preferred-Encodings: utf-8\n" +"X-Is-Fallback-For: ja-jp\n" + + diff --git a/apps/plone/locales/nl/LC_MESSAGES/volto.po b/apps/plone/locales/nl/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..a9816b4cea --- /dev/null +++ b/apps/plone/locales/nl/LC_MESSAGES/volto.po @@ -0,0 +1,18 @@ +msgid "" +msgstr "" +"Project-Id-Version: PlonenPOT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: \n" +"PO-Revision-Date: 2017-02-28 08:52+0100\n" +"Last-Translator: Dutch \n" +"Language: nl\n" +"Language-Team: Dutch \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Language-Code: nl\n" +"Language-Name: Nederlands\n" +"Preferred-Encodings: utf-8\n" + + diff --git a/apps/plone/locales/pt/LC_MESSAGES/volto.po b/apps/plone/locales/pt/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..3713b40e7d --- /dev/null +++ b/apps/plone/locales/pt/LC_MESSAGES/volto.po @@ -0,0 +1,19 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-12-17T20:38:19.520Z\n" +"PO-Revision-Date: \n" +"Last-Translator: Emanuel de Jesus , 2019\n" +"Language: pt\n" +"Language-Team: Portuguese (https://www.transifex.com/plone/teams/14552/pt/)\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Domain: volto\n" +"Language-Code: pt\n" +"Language-Name: Portuguese\n" +"Preferred-Encodings: utf-8\n" + + diff --git a/apps/plone/locales/pt_BR/LC_MESSAGES/volto.po b/apps/plone/locales/pt_BR/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..d788679fdc --- /dev/null +++ b/apps/plone/locales/pt_BR/LC_MESSAGES/volto.po @@ -0,0 +1,18 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2017-02-28 08:52+0100\n" +"Last-Translator: Léu Almeida \n" +"Language: pt-BR\n" +"Language-Team: Plone i18n \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Language-Code: pt-br\n" +"Language-Name: Português do Brasil\n" +"Preferred-Encodings: utf-8\n" + + diff --git a/apps/plone/locales/ro/LC_MESSAGES/volto.po b/apps/plone/locales/ro/LC_MESSAGES/volto.po new file mode 100644 index 0000000000..42c60f4d17 --- /dev/null +++ b/apps/plone/locales/ro/LC_MESSAGES/volto.po @@ -0,0 +1,18 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-04-27T19:30:59.079Z\n" +"PO-Revision-Date: 2016-10-22 16:41-0500\n" +"Last-Translator: Plone i18n \n" +"Language: ro\n" +"Language-Team: Plone i18n \n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"MIME-Version: 1.0\n" +"Language-Code: ro\n" +"Language-Name: Romanian\n" +"Preferred-Encodings: utf-8 latin1\n" + + diff --git a/apps/plone/locales/volto.pot b/apps/plone/locales/volto.pot new file mode 100644 index 0000000000..430c431165 --- /dev/null +++ b/apps/plone/locales/volto.pot @@ -0,0 +1,16 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"POT-Creation-Date: 2018-10-03T09:01:24.737Z\n" +"Last-Translator: Plone i18n \n" +"Language-Team: Plone i18n \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Preferred-Encodings: utf-8\n" +"Domain: volto\n" + + diff --git a/apps/plone/mrs.developer.json b/apps/plone/mrs.developer.json new file mode 100644 index 0000000000..502bb075b9 --- /dev/null +++ b/apps/plone/mrs.developer.json @@ -0,0 +1,5 @@ +{ + "volto-volto-project": { + "local": "addons/volto-volto-project/src" + } +} \ No newline at end of file diff --git a/apps/plone/package.json b/apps/plone/package.json new file mode 100644 index 0000000000..0fa1eae05c --- /dev/null +++ b/apps/plone/package.json @@ -0,0 +1,355 @@ +{ + "name": "plone", + "description": "Plone CMS Volto frontend project", + "license": "MIT", + "version": "1.0.0", + "scripts": { + "start": "razzle start", + "build": "razzle build --noninteractive", + "lint": "./node_modules/eslint/bin/eslint.js --max-warnings=0 'src/**/*.{js,jsx,ts,tsx}'", + "lint:fix": "./node_modules/eslint/bin/eslint.js --fix 'src/**/*.{js,jsx,ts,tsx}'", + "lint:ci": "./node_modules/eslint/bin/eslint.js --max-warnings=0 -f checkstyle 'src/**/*.{js,jsx,ts,tsx}' > eslint.xml", + "prettier": "./node_modules/.bin/prettier --single-quote --check 'src/**/*.{js,jsx,ts,tsx,css,scss}'", + "prettier:fix": "./node_modules/.bin/prettier --single-quote --write 'src/**/*.{js,jsx,ts,tsx,css,scss}'", + "prettier:ci": "./node_modules/.bin/prettier --single-quote --check 'src/**/*.{js,jsx,ts,tsx,css,scss}'", + "stylelint": "stylelint 'theme/**/*.{css,scss,less}' 'src/**/*.{css,scss,less}'", + "stylelint:overrides": "stylelint 'theme/**/*.overrides' 'src/**/*.overrides'", + "stylelint:fix": "yarn stylelint --fix && yarn stylelint:overrides --fix", + "test": "razzle test --passWithNoTests", + "typecheck": "tsc --project tsconfig.json --noEmit", + "cypress:open": "make test-acceptance", + "cypress:run": "test-acceptance-headless", + "start:prod": "NODE_ENV=production node build/server.js", + "i18n": "rm -rf build/messages && NODE_ENV=production i18n", + "storybook": "start-storybook -p 6006", + "build-storybook": "build-storybook" + }, + "workspaces": [ + "src/addons/volto-volto-project" + ], + "addons": [ + "volto-volto-project" + ], + "jest": { + "modulePathIgnorePatterns": [ + "api" + ], + "transform": { + "^.+\\.js(x)?$": "babel-jest", + "^.+\\.(png)$": "jest-file", + "^.+\\.(jpg)$": "jest-file", + "^.+\\.(svg)$": "./node_modules/@plone/volto/jest-svgsystem-transform.js" + }, + "transformIgnorePatterns": [ + "/node_modules/(?!@plone/volto).+\\.js$" + ], + "moduleNameMapper": { + "@plone/volto/cypress/(.*)$": "/node_modules/@plone/volto/cypress/$1", + "@plone/volto/addon-registry": "/node_modules/@plone/volto/addon-registry", + "@plone/volto/webpack-plugins/webpack-less-plugin": "/node_modules/@plone/volto/webpack-plugins/webpack-less-plugin", + "@plone/volto/babel": "/node_modules/@plone/volto/babel", + "@plone/volto/(.*)$": "/node_modules/@plone/volto/src/$1", + "@plone/volto-slate/(.*)$": "/node_modules/@plone/volto/packages/volto-slate/src/$1", + "load-volto-addons": "/node_modules/@plone/volto/jest-addons-loader.js", + "@package/(.*)$": "/src/$1", + "@root/(.*)$": "/src/$1", + "~/(.*)$": "/src/$1", + "\\.(css|less|scss|sass)$": "identity-obj-proxy" + }, + "coverageThreshold": { + "global": { + "branches": 10, + "functions": 10, + "lines": 10, + "statements": 10 + } + }, + "setupFiles": [ + "@plone/volto/test-setup-globals.js", + "@plone/volto/test-setup-config.js" + ], + "globals": { + "__DEV__": true + } + }, + "prettier": { + "trailingComma": "all", + "singleQuote": true, + "overrides": [ + { + "files": "*.overrides", + "options": { + "parser": "less" + } + } + ] + }, + "stylelint": { + "extends": [ + "stylelint-config-idiomatic-order" + ], + "plugins": [ + "stylelint-prettier" + ], + "overrides": [ + { + "files": [ + "**/*.less" + ], + "customSyntax": "postcss-less" + }, + { + "files": [ + "**/*.overrides" + ], + "customSyntax": "postcss-less" + }, + { + "files": [ + "**/*.scss" + ], + "customSyntax": "postcss-scss" + } + ], + "rules": { + "prettier/prettier": true, + "rule-empty-line-before": [ + "always-multi-line", + { + "except": [ + "first-nested" + ], + "ignore": [ + "after-comment" + ] + } + ] + }, + "ignoreFiles": "theme/themes/default/**/*.overrides" + }, + "browserslist": [ + ">1%", + "last 4 versions", + "Firefox ESR", + "not ie 11", + "not dead" + ], + "engines": { + "node": "^16 || ^18 || ^20" + }, + "dependencies": { + "@loadable/component": "5.14.1", + "@loadable/server": "5.14.0", + "@plone/registry": "workspace:*", + "@plone/scripts": "workspace:*", + "@plone/volto": "workspace:*", + "@plone/volto-slate": "workspace:*", + "@redux-devtools/extension": "^3.3.0", + "classnames": "2.2.6", + "connected-react-router": "6.8.0", + "debug": "4.3.2", + "decorate-component-with-props": "1.2.1", + "dependency-graph": "0.10.0", + "detect-browser": "5.1.0", + "diff": "3.5.0", + "express": "4.17.3", + "filesize": "6", + "github-slugger": "1.4.0", + "history": "4.10.1", + "hoist-non-react-statics": "3.3.2", + "http-proxy-middleware": "2.0.1", + "image-extensions": "1.1.0", + "immutable": "3", + "is-hotkey": "0.2.0", + "is-url": "1.2.4", + "jotai": "2.0.3", + "jwt-decode": "2.2.0", + "linkify-it": "3.0.2", + "locale": "0.1.0", + "lodash": "4.17.21", + "lodash-move": "1.1.1", + "moment": "2.29.4", + "object-assign": "4.1.1", + "prepend-http": "2", + "pretty-bytes": "5.3.0", + "prismjs": "1.27.0", + "process": "^0.11.10", + "promise-file-reader": "1.0.2", + "prop-types": "15.7.2", + "query-string": "7.1.0", + "rc-time-picker": "3.7.3", + "react": "18.2.0", + "react-anchor-link-smooth-scroll": "1.0.12", + "react-animate-height": "2.0.17", + "react-beautiful-dnd": "13.0.0", + "react-cookie": "4.1.1", + "react-dates": "21.5.1", + "react-detect-click-outside": "1.1.1", + "react-dnd": "5.0.0", + "react-dnd-html5-backend": "5.0.1", + "react-dom": "18.2.0", + "react-dropzone": "11.1.0", + "react-fast-compare": "2.0.4", + "react-image-gallery": "1.2.7", + "react-intersection-observer": "9.1.0", + "react-intl": "3.8.0", + "react-intl-redux": "2.3.0", + "react-medium-image-zoom": "3.0.15", + "react-popper": "^2.3.0", + "react-redux": "8.1.2", + "react-router": "5.2.0", + "react-router-config": "5.1.1", + "react-router-dom": "5.2.0", + "react-router-hash-link": "2.4.3", + "react-select": "4.3.1", + "react-select-async-paginate": "0.5.3", + "react-share": "2.3.1", + "react-side-effect": "2.1.2", + "react-simple-code-editor": "0.7.1", + "react-sortable-hoc": "2.0.0", + "react-test-renderer": "18.2.0", + "react-toastify": "5.5.0", + "react-transition-group": "4.4.5", + "react-virtualized": "9.22.3", + "redux": "4.2.1", + "redux-actions": "3.0.0", + "redux-connect": "10.0.0", + "redux-localstorage-simple": "2.5.1", + "redux-mock-store": "1.5.4", + "redux-thunk": "2.4.2", + "rrule": "2.7.1", + "semantic-ui-less": "2.4.1", + "semantic-ui-react": "2.1.5", + "serialize-javascript": "3.1.0", + "slate": "0.100.0", + "slate-hyperscript": "0.100.0", + "slate-react": "0.98.4", + "superagent": "3.8.2", + "tlds": "1.203.1", + "undoo": "0.5.0", + "universal-cookie": "4.0.4", + "universal-cookie-express": "4.0.3", + "url": "^0.11.3", + "use-deep-compare-effect": "1.8.1", + "uuid": "^8.3.2", + "volto-volto-project": "workspace:*" + }, + "devDependencies": { + "@babel/core": "^7.0.0", + "@babel/eslint-parser": "7.22.15", + "@babel/plugin-proposal-export-default-from": "7.18.10", + "@babel/plugin-proposal-export-namespace-from": "7.18.9", + "@babel/plugin-proposal-json-strings": "7.18.6", + "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6", + "@babel/plugin-proposal-throw-expressions": "7.18.6", + "@babel/plugin-syntax-export-namespace-from": "7.8.3", + "@babel/runtime": "7.20.6", + "@babel/types": "7.20.5", + "@jest/globals": "^29.7.0", + "@loadable/babel-plugin": "5.13.2", + "@loadable/webpack-plugin": "5.15.2", + "@plone/scripts": "workspace:*", + "@plone/types": "workspace:*", + "@plone/volto-coresandbox": "workspace:*", + "@sinonjs/fake-timers": "^6.0.1", + "@storybook/addon-actions": "^6.5.15", + "@storybook/addon-controls": "6.5.15", + "@storybook/addon-docs": "^6.5.15", + "@storybook/addon-essentials": "^6.5.15", + "@storybook/addon-links": "^6.5.15", + "@storybook/builder-webpack5": "^6.5.15", + "@storybook/manager-webpack5": "^6.5.15", + "@storybook/react": "^6.5.15", + "@testing-library/cypress": "10.0.1", + "@testing-library/jest-dom": "6.4.2", + "@testing-library/react": "14.2.0", + "@testing-library/react-hooks": "8.0.1", + "@types/jest": "^29.5.8", + "@types/lodash": "^4.14.201", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/react-router-dom": "^5.3.3", + "@types/react-test-renderer": "18.0.7", + "@types/uuid": "^9.0.2", + "@typescript-eslint/eslint-plugin": "7.1.1", + "@typescript-eslint/parser": "7.1.1", + "autoprefixer": "10.4.8", + "axe-core": "4.4.2", + "babel-loader": "9.1.0", + "babel-plugin-add-module-exports": "0.2.1", + "babel-plugin-lodash": "3.3.4", + "babel-plugin-react-intl": "5.1.17", + "babel-plugin-root-import": "6.1.0", + "babel-preset-razzle": "4.2.18", + "bundlewatch": "0.3.3", + "circular-dependency-plugin": "5.2.2", + "css-loader": "5.2.7", + "cypress": "13.6.6", + "cypress-axe": "1.5.0", + "cypress-file-upload": "5.0.8", + "deep-freeze": "0.0.1", + "eslint": "8.49.0", + "eslint-config-prettier": "9.1.0", + "eslint-config-react-app": "7.0.1", + "eslint-import-resolver-alias": "1.1.2", + "eslint-import-resolver-babel-plugin-root-import": "1.1.1", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-prettier": "5.1.3", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-react-hooks": "4.6.0", + "full-icu": "1.4.0", + "glob": "7.1.6", + "html-webpack-plugin": "5.5.0", + "identity-obj-proxy": "3.0.0", + "jest": "26.6.3", + "jest-environment-jsdom": "^26", + "jest-file": "1.0.0", + "jest-junit": "8.0.0", + "jsdom": "^16.7.0", + "jsonwebtoken": "9.0.0", + "less": "3.11.1", + "less-loader": "11.1.0", + "lodash-webpack-plugin": "0.11.6", + "mini-css-extract-plugin": "2.7.2", + "moment-locales-webpack-plugin": "1.2.0", + "mrs-developer": "^2.1.1", + "postcss": "8.4.31", + "postcss-flexbugs-fixes": "5.0.2", + "postcss-less": "6.0.0", + "postcss-load-config": "3.1.4", + "postcss-loader": "7.0.2", + "postcss-overrides": "3.1.4", + "postcss-scss": "4.0.6", + "prettier": "3.2.5", + "razzle": "4.2.18", + "razzle-dev-utils": "4.2.18", + "razzle-plugin-scss": "4.2.18", + "react-docgen-typescript-plugin": "^1.0.5", + "react-error-overlay": "6.0.9", + "react-is": "^18.2.0", + "release-it": "^17.1.1", + "semver": "^7.5.4", + "start-server-and-test": "1.14.0", + "style-loader": "3.3.1", + "stylelint": "16.2.1", + "stylelint-config-idiomatic-order": "10.0.0", + "stylelint-prettier": "5.0.0", + "svg-loader": "0.0.2", + "svgo-loader": "3.0.3", + "terser-webpack-plugin": "5.3.6", + "tmp": "0.2.1", + "ts-jest": "^26.4.2", + "ts-loader": "9.4.4", + "tsconfig": "*", + "typescript": "5.2.2", + "use-trace-update": "1.3.2", + "wait-on": "6.0.0", + "webpack": "5.76.1", + "webpack-bundle-analyzer": "4.10.1", + "webpack-dev-server": "4.11.1", + "webpack-node-externals": "3.0.0", + "why": "0.6.2" + }, + "theme": "volto-volto-project" +} \ No newline at end of file diff --git a/patches/patchit.sh b/apps/plone/patches/patchit.sh similarity index 100% rename from patches/patchit.sh rename to apps/plone/patches/patchit.sh diff --git a/apps/plone/patches/razzle-jest.patch b/apps/plone/patches/razzle-jest.patch new file mode 100644 index 0000000000..5b822cf57f --- /dev/null +++ b/apps/plone/patches/razzle-jest.patch @@ -0,0 +1,10 @@ +--- node_modules/razzle/config/createJestConfig.js 2020-05-09 19:48:07.276871617 +0200 ++++ patched.js 2020-05-09 19:50:07.049471664 +0200 +@@ -60,6 +60,7 @@ + 'moduleDirectories', + 'moduleFileExtensions', + 'moduleNameMapper', ++ 'modulePathIgnorePatterns', + 'modulePaths', + 'snapshotSerializers', + 'setupFiles', diff --git a/public/android-chrome-192x192.png b/apps/plone/public/android-chrome-192x192.png similarity index 100% rename from public/android-chrome-192x192.png rename to apps/plone/public/android-chrome-192x192.png diff --git a/public/android-chrome-512x512.png b/apps/plone/public/android-chrome-512x512.png similarity index 100% rename from public/android-chrome-512x512.png rename to apps/plone/public/android-chrome-512x512.png diff --git a/public/apple-touch-icon.png b/apps/plone/public/apple-touch-icon.png similarity index 100% rename from public/apple-touch-icon.png rename to apps/plone/public/apple-touch-icon.png diff --git a/public/favicon-16x16.png b/apps/plone/public/favicon-16x16.png similarity index 100% rename from public/favicon-16x16.png rename to apps/plone/public/favicon-16x16.png diff --git a/public/favicon-32x32.png b/apps/plone/public/favicon-32x32.png similarity index 100% rename from public/favicon-32x32.png rename to apps/plone/public/favicon-32x32.png diff --git a/public/favicon.ico b/apps/plone/public/favicon.ico similarity index 100% rename from public/favicon.ico rename to apps/plone/public/favicon.ico diff --git a/public/icon.svg b/apps/plone/public/icon.svg similarity index 100% rename from public/icon.svg rename to apps/plone/public/icon.svg diff --git a/public/index.html.spa b/apps/plone/public/index.html.spa similarity index 100% rename from public/index.html.spa rename to apps/plone/public/index.html.spa diff --git a/public/robots.txt b/apps/plone/public/robots.txt similarity index 100% rename from public/robots.txt rename to apps/plone/public/robots.txt diff --git a/public/site.webmanifest b/apps/plone/public/site.webmanifest similarity index 100% rename from public/site.webmanifest rename to apps/plone/public/site.webmanifest diff --git a/apps/plone/razzle.config.js b/apps/plone/razzle.config.js new file mode 100644 index 0000000000..6bab4ae583 --- /dev/null +++ b/apps/plone/razzle.config.js @@ -0,0 +1,44 @@ +/** + * Replace with custom razzle config when needed. + * @module razzle.config + */ +const fs = require('fs'); + +let voltoPath = './node_modules/@plone/volto'; + +let configFile; +if (fs.existsSync(`${this.projectRootPath}/tsconfig.json`)) + configFile = `${this.projectRootPath}/tsconfig.json`; +else if (fs.existsSync(`${this.projectRootPath}/jsconfig.json`)) + configFile = `${this.projectRootPath}/jsconfig.json`; + +if (configFile) { + const jsConfig = require(configFile).compilerOptions; + const pathsConfig = jsConfig.paths; + if (pathsConfig['@plone/volto']) + voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`; +} + +const defaultVoltoRazzleConfig = require(`${voltoPath}/razzle.config`); +const { modifyWebpackConfig } = defaultVoltoRazzleConfig; + +const customModifyWebpackConfig = ({ + env: { target, dev }, + webpackConfig, + webpackObject, + options, +}) => { + const config = modifyWebpackConfig({ + env: { target, dev }, + webpackConfig, + webpackObject, + options, + }); + // add custom code here.. + return config; +}; + +module.exports = { + ...defaultVoltoRazzleConfig, + modifyWebpackConfig: customModifyWebpackConfig, +}; diff --git a/apps/plone/src/addons/volto-volto-project/.github/workflows/acceptance.yml b/apps/plone/src/addons/volto-volto-project/.github/workflows/acceptance.yml new file mode 100644 index 0000000000..51d072e448 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/.github/workflows/acceptance.yml @@ -0,0 +1,52 @@ +name: Acceptance tests +on: [push] + +env: + ADDON_NAME: "volto-volto-project" + ADDON_PATH: "volto-volto-project" + VOLTO_VERSION: "17.0.0" + +jobs: + + acceptance: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Install Cypress + run: | + cd acceptance + yarn + + - name: "Cypress: Acceptance tests" + uses: cypress-io/github-action@v6 + env: + BABEL_ENV: production + CYPRESS_RETRIES: 2 + with: + parallel: false + browser: chrome + working-directory: acceptance + spec: cypress/tests/*.js + install: false + start: | + docker compose -f ci.yml --profile prod up + wait-on: 'npx wait-on --httpTimeout 20000 http-get://localhost:55001/plone http://localhost:3000' + + # Upload Cypress screenshots + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: cypress-screenshots-acceptance + path: acceptance/cypress/screenshots + + # Upload Cypress videos + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: cypress-videos-acceptance + path: acceptance/cypress/videos diff --git a/apps/plone/src/addons/volto-volto-project/.github/workflows/changelog.yml b/apps/plone/src/addons/volto-volto-project/.github/workflows/changelog.yml new file mode 100644 index 0000000000..113171e7e5 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/.github/workflows/changelog.yml @@ -0,0 +1,43 @@ +name: Changelog check +on: + pull_request: + types: [assigned, opened, synchronize, reopened, labeled, unlabeled] + branches: + - main + +env: + node-version: 18.x + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + # Fetch all history + fetch-depth: '0' + + - name: Install pipx + run: pip install towncrier + + # node setup + - name: Use Node.js ${{ env.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ env.node-version }} + cache: 'yarn' + + # node install + - name: Install dependencies + run: yarn + + - 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 main + towncrier check --compare-with origin/main + env: + BASE_BRANCH: ${{ github.base_ref }} + if: github.event_name == 'pull_request' diff --git a/apps/plone/src/addons/volto-volto-project/.github/workflows/code.yml b/apps/plone/src/addons/volto-volto-project/.github/workflows/code.yml new file mode 100644 index 0000000000..a7eeb58513 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/.github/workflows/code.yml @@ -0,0 +1,15 @@ +name: Code analysis checks +on: [push] +jobs: + codeanalysis: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + + steps: + - name: Main checkout + uses: actions/checkout@v3 + + - name: Linting + run: make lint diff --git a/apps/plone/src/addons/volto-volto-project/.github/workflows/unit.yml b/apps/plone/src/addons/volto-volto-project/.github/workflows/unit.yml new file mode 100644 index 0000000000..8dbb3de936 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/.github/workflows/unit.yml @@ -0,0 +1,15 @@ +name: Unit Tests +on: [push] +jobs: + unit: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [18.x] + + steps: + - name: Main checkout + uses: actions/checkout@v3 + + - name: Unit tests + run: make test-ci diff --git a/apps/plone/src/addons/volto-volto-project/.gitignore b/apps/plone/src/addons/volto-volto-project/.gitignore new file mode 100644 index 0000000000..f11144ebfb --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/.gitignore @@ -0,0 +1,27 @@ +.vscode/ +.history +logs +*.log +npm-debug.log* +.DS_Store +*.swp +yarn-error.log + +node_modules +build +dist +.env.local +.env.development.local +.env.test.local +.env.production.local + +.changelog.draft + +# yarn 3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/apps/plone/src/addons/volto-volto-project/CHANGELOG.md b/apps/plone/src/addons/volto-volto-project/CHANGELOG.md new file mode 100644 index 0000000000..413fb920e1 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/CHANGELOG.md @@ -0,0 +1,9 @@ +# Release Notes + + + + diff --git a/apps/plone/src/addons/volto-volto-project/Makefile b/apps/plone/src/addons/volto-volto-project/Makefile new file mode 100644 index 0000000000..c13a5ffc57 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/Makefile @@ -0,0 +1,151 @@ +# Yeoman Volto App development + +### Defensive settings for make: +# https://tech.davis-hansson.com/p/make/ +SHELL:=bash +.ONESHELL: +.SHELLFLAGS:=-eu -o pipefail -c +.SILENT: +.DELETE_ON_ERROR: +MAKEFLAGS+=--warn-undefined-variables +MAKEFLAGS+=--no-builtin-rules + +CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +# Recipe snippets for reuse + +# We like colors +# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects +RED=`tput setaf 1` +GREEN=`tput setaf 2` +RESET=`tput sgr0` +YELLOW=`tput setaf 3` + +PLONE_VERSION=6 +VOLTO_VERSION=17.0.0 + +ADDON_NAME='volto-volto-project' +ADDON_PATH='volto-volto-project' +COMPOSE_FILE=dockerfiles/docker-compose.yml +ACCEPTANCE_COMPOSE=acceptance/docker-compose.yml +CMD=CURRENT_DIR=${CURRENT_DIR} ADDON_NAME=${ADDON_NAME} ADDON_PATH=${ADDON_PATH} VOLTO_VERSION=${VOLTO_VERSION} PLONE_VERSION=${PLONE_VERSION} docker compose +DOCKER_COMPOSE=${CMD} -p ${ADDON_PATH} -f ${COMPOSE_FILE} +DEV_COMPOSE=COMPOSE_PROFILES=dev ${DOCKER_COMPOSE} +LIVE_COMPOSE=COMPOSE_PROFILES=dev ${DOCKER_COMPOSE} +ACCEPTANCE=${CMD} -p ${ADDON_PATH}-acceptance -f ${ACCEPTANCE_COMPOSE} + +.PHONY: build-backend +build-backend: ## Build + @echo "$(GREEN)==> Build Backend Container $(RESET)" + ${DEV_COMPOSE} build backend + +.PHONY: start-backend +start-backend: ## Starts Docker backend + @echo "$(GREEN)==> Start Docker-based Plone Backend $(RESET)" + ${DEV_COMPOSE} up backend -d + +.PHONY: stop-backend +stop-backend: ## Stop Docker backend + @echo "$(GREEN)==> Stop Docker-based Plone Backend $(RESET)" + ${DEV_COMPOSE} stop backend + +.PHONY: build-live +build-live: ## Build Addon live + @echo "$(GREEN)==> Build Addon development container $(RESET)" + ${LIVE_COMPOSE} build addon-live + +.PHONY: build-addon +build-addon: ## Build Addon dev + @echo "$(GREEN)==> Build Addon development container $(RESET)" + ${DEV_COMPOSE} build addon-dev + +.PHONY: start-dev +start-dev: ## Starts Dev container + @echo "$(GREEN)==> Start Addon Development container $(RESET)" + ${DEV_COMPOSE} up addon-dev + +.PHONY: dev +dev: ## Develop the addon + @echo "$(GREEN)==> Start Development Environment $(RESET)" + make build-backend + make start-backend + make build-addon + make start-dev + +.PHONY: help +help: ## Show this help. + @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" + +## Setup the local environment +.PHONY: install +install: ## Install the local environment, Cypress, build acceptance containers + yarn + make install-acceptance + +# Dev Helpers +.PHONY: i18n +i18n: ## Sync i18n + @echo "$(YELLOW)==> Do not forget to setup the local environment (make install) $(RESET)" + yarn i18n + +.PHONY: format +format: ## Format codebase + ${DEV_COMPOSE} run --rm addon-dev lint:fix + ${DEV_COMPOSE} run --rm addon-dev prettier:fix + ${DEV_COMPOSE} run --rm addon-dev stylelint:fix + +.PHONY: lint +lint: ## Lint Codebase + ${DEV_COMPOSE} run --rm addon-dev lint + ${DEV_COMPOSE} run --rm addon-dev prettier + ${DEV_COMPOSE} run --rm addon-dev stylelint --allow-empty-input + +.PHONY: test +test: ## Run unit tests + ${DEV_COMPOSE} run --rm addon-dev test --watchAll + +.PHONY: test-ci +test-ci: ## Run unit tests in CI + ${DEV_COMPOSE} run -e CI=1 addon-dev test + +## Acceptance +.PHONY: install-acceptance +install-acceptance: ## Install Cypress, build acceptance containers + (cd acceptance && yarn) + ${ACCEPTANCE} --profile dev --profile prod build + +.PHONY: start-test-acceptance-server +start-test-acceptance-server: ## Start acceptance server (for use it in while developing) + ${ACCEPTANCE} --profile dev up + +.PHONY: start-test-acceptance-server-prod +start-test-acceptance-server-prod: ## Start acceptance server in prod (used by CI) + ${ACCEPTANCE} --profile prod up -d + +.PHONY: test-acceptance +test-acceptance: ## Start Cypress (for use it while developing) + (cd acceptance && ./node_modules/.bin/cypress open) + +.PHONY: test-acceptance-headless +test-acceptance-headless: ## Run cypress tests in CI + (cd acceptance && ./node_modules/.bin/cypress run) + +.PHONY: stop-test-acceptance-server +stop-test-acceptance-server: ## Stop acceptance server (for use it while finished developing) + ${ACCEPTANCE} --profile dev down + +.PHONY: status-test-acceptance-server +status-test-acceptance-server: ## Status of Acceptance Server (for use it while developing) + ${ACCEPTANCE} ps + +.PHONY: debug-frontend +debug-frontend: ## Run bash in the Frontend container (for debug infrastructure purposes) + ${DEV_COMPOSE} run --entrypoint bash addon-dev + +.PHONY: pull-backend-image +pull-backend-image: ## Pulls and updates the backend image (for use it while developing) + docker pull ghcr.io/voltovolto-project:latest + +.PHONY: release +release: ## Release a version of the add-on + yarn release diff --git a/apps/plone/src/addons/volto-volto-project/README.md b/apps/plone/src/addons/volto-volto-project/README.md new file mode 100644 index 0000000000..df94efe809 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/README.md @@ -0,0 +1,135 @@ +# volto-volto-project + +You can develop an add-on in isolation using the boilerplate provided by the add-on generator. +The project is configured with the current add-on installed and ready to work with. +This is useful to bootstrap an isolated environment that can be used to quickly develop the add-on or for demo purposes. +It's also useful when testing an add-on in a CI environment. + +This process is similar to when you develop a Plone backend add-on in Python, then embed a ready to use Plone build (using buildout or pip) to develop and test the package. + +The Dockerized approach performs all these actions in a custom built Docker environment: + +1. generates a vanilla project using the official Volto Yo Generator (`@plone/generator-volto`) +2. configures it to use the add-on with the name stated in the `package.json` +3. links the root of the add-on inside the created project + +After that you can use the inner Dockerized project, and run any standard Volto command for linting, acceptance test, or unit tests using Makefile commands provided for your convenience. + + +## Set up the environment + +Run once: + +```shell +make dev +``` + +This will build and launch the backend and frontend containers. +There's no need to build them again after the first time, unless something has changed from the container setup. + +To make your IDE play well with this setup, you must run `yarn` once to install the required packages: + +```shell +yarn +``` + + +## Development + +This section describes various Makefile commands to ease development. + + +### Build the containers manually + +```shell +make build-backend +make build-addon +``` + + +### Run the containers + +```shell +make start-dev +``` + +This will start both the frontend and backend containers. + + +### Stop backend (Docker) + +After developing, you should stop the running backend. + +```shell +make stop-backend +``` + + +### Linting + +```shell +make lint +``` + + +### Formatting + +```shell +make format +``` + + +### i18n + +```shell +make i18n +``` + + +### Unit tests + +```shell +make test +``` + + +### Acceptance tests + +First install requirements to run acceptance tests with the following command. +Run it only once. + +```shell +make install-acceptance +``` + +The frontend runs in development mode to allow development while writing. +To start the servers: + +```shell +make start-test-acceptance-server +``` + +To run Cypress tests after you finish development: + +```shell +make test-acceptance +``` + +Shut down the backend server after you complete development with tests. + +```shell +make stop-test-acceptance-server +``` + + +## Release + +```shell +make release +``` + +To release a release candidate (rc) version: + +```shell +make release-rc +``` diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/ci.yml b/apps/plone/src/addons/volto-volto-project/acceptance/ci.yml new file mode 100644 index 0000000000..b0c643462a --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/ci.yml @@ -0,0 +1,29 @@ +version: "3" + +services: + + addon-acceptance: + build: + context: ../ + dockerfile: ./dockerfiles/Dockerfile + args: + ADDON_NAME: "${ADDON_NAME}" + ADDON_PATH: "${ADDON_PATH}" + VOLTO_VERSION: ${VOLTO_VERSION:-17} + environment: + RAZZLE_INTERNAL_API_PATH: http://backend-acceptance:55001/plone + RAZZLE_API_PATH: http://localhost:55001/plone + ports: + - 3000:3000 + depends_on: + - backend-acceptance + profiles: + - prod + + backend-acceptance: + image: plone/server-acceptance:${PLONE_VERSION:-6} + ports: + - 55001:55001 + profiles: + - dev + - prod diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress.config.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress.config.js new file mode 100644 index 0000000000..d841d7ab7c --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress.config.js @@ -0,0 +1,9 @@ +const { defineConfig } = require('cypress'); + +module.exports = defineConfig({ + viewportWidth: 1280, + e2e: { + baseUrl: 'http://localhost:3000', + specPattern: 'cypress/tests/*.cy.{js,jsx}', + }, +}); diff --git a/packages/generator-volto/generators/addon/templates/cypress/fixtures/broccoli.jpg b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/broccoli.jpg similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/fixtures/broccoli.jpg rename to apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/broccoli.jpg diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/example.json b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/example.json new file mode 100644 index 0000000000..02e4254378 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/file.pdf b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/file.pdf new file mode 100644 index 0000000000..ef9c798194 Binary files /dev/null and b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/file.pdf differ diff --git a/packages/generator-volto/generators/addon/templates/cypress/fixtures/halfdome2022.jpg b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/halfdome2022.jpg similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/fixtures/halfdome2022.jpg rename to apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/halfdome2022.jpg diff --git a/packages/generator-volto/generators/addon/templates/cypress/fixtures/image.png b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/image.png similarity index 100% rename from packages/generator-volto/generators/addon/templates/cypress/fixtures/image.png rename to apps/plone/src/addons/volto-volto-project/acceptance/cypress/fixtures/image.png diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/plugins/index.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/plugins/index.js new file mode 100644 index 0000000000..dffed2532f --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +}; diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/commands.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/commands.js new file mode 100644 index 0000000000..44a5000326 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/commands.js @@ -0,0 +1 @@ +import '@plone/volto-testing/cypress/support/commands'; diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/e2e.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/e2e.js new file mode 100644 index 0000000000..48912f7f19 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/e2e.js @@ -0,0 +1,14 @@ +import 'cypress-axe'; +import 'cypress-file-upload'; +import './commands'; +import { setup, teardown } from './reset-fixture'; + +beforeEach(function () { + cy.log('Setting up API fixture'); + setup(); +}); + +afterEach(function () { + cy.log('Tearing down API fixture'); + teardown(); +}); diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/reset-fixture.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/reset-fixture.js new file mode 100644 index 0000000000..4e2b4372d5 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/reset-fixture.js @@ -0,0 +1,43 @@ +function setup() { + const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + cy.request({ + method: 'POST', + url: `${api_url}/RobotRemote`, + headers: { Accept: 'text/xml', 'content-type': 'text/xml' }, + body: 'run_keywordremote_zodb_setupplone.app.robotframework.testing.PLONE_ROBOT_TESTING', + }).then(() => cy.log('Setting up API fixture')); +} + +function teardown() { + const api_url = Cypress.env('API_PATH') || 'http://localhost:55001/plone'; + cy.request({ + method: 'POST', + url: `${api_url}/RobotRemote`, + headers: { Accept: 'text/xml', 'content-type': 'text/xml' }, + body: 'run_keywordremote_zodb_teardownplone.app.robotframework.testing.PLONE_ROBOT_TESTING', + }).then(() => cy.log('Tearing down API fixture')); +} + +function main() { + const command = process.argv[2]; + switch (command) { + case 'setup': + setup(); + break; + case 'teardown': + teardown(); + break; + default: + setup(); + } +} + +// This is the equivalent of `if __name__ == '__main__'` in Python :) +if (require.main === module) { + main(); +} + +module.exports = { + setup, + teardown, +}; diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/slate.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/slate.js new file mode 100644 index 0000000000..8ed5b53ab2 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/support/slate.js @@ -0,0 +1,14 @@ +export const createSlateBlock = () => { + cy.get('.ui.basic.icon.button.block-add-button').first().click(); + cy.get('.blocks-chooser .title').contains('Text').click(); + cy.get('.ui.basic.icon.button.slate').contains('Text').click(); + return getSelectedSlateEditor(); +}; + +export const getSelectedSlateEditor = () => { + return cy.get('.slate-editor.selected [contenteditable=true]').click(); +}; + +export const getSlateEditorAndType = (selector, type) => { + return cy.get(selector).focus().click().wait(1000).type(type).wait(1000); +}; diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/cypress/tests/basic.cy.js b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/tests/basic.cy.js new file mode 100644 index 0000000000..2f55da049a --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/cypress/tests/basic.cy.js @@ -0,0 +1,71 @@ +import { + getSlateEditorAndType, + getSelectedSlateEditor, +} from '../support/slate'; + +context('Basic Acceptance Tests', () => { + describe('Text Block Tests', () => { + beforeEach(() => { + cy.intercept('GET', `/**/*?expand*`).as('content'); + cy.intercept('GET', '/**/Document').as('schema'); + + // given a logged in editor and a page in edit mode + cy.autologin(); + cy.createContent({ + contentType: 'Document', + contentId: 'document', + contentTitle: 'Document', + }); + cy.visit('/'); + cy.wait('@content'); + }); + + it('As editor I can add a page with a text block', function () { + // when I add a page with a text block + cy.get('#toolbar-add').click(); + cy.get('#toolbar-add-document').click(); + cy.get('.documentFirstHeading') + .type('My Page') + .get('.documentFirstHeading') + .contains('My Page'); + + getSlateEditorAndType( + '.block .slate-editor [contenteditable=true]', + 'This is the text', + ); + + getSelectedSlateEditor().contains('This is the text'); + cy.get('#toolbar-save').click(); + cy.wait('@content'); + cy.url().should('eq', Cypress.config().baseUrl + '/my-page'); + }); + + it('As editor I can add a link to a text block', function () { + cy.navigate('/document/edit'); + cy.wait('@schema'); + + cy.get('.block.inner.title .documentFirstHeading'); + + cy.log('when I create a link'); + + cy.getSlateEditorAndType( + 'Colorless green ideas sleep furiously.', + ).setSlateSelection('furiously'); + cy.clickSlateButton('Add link'); + cy.get('.slate-toolbar .link-form-container input').type( + 'https://google.com{enter}', + ); + + cy.get('#toolbar-save', { timeout: 10000 }).click(); + cy.wait('@content'); + + cy.log('then the page view should contain a link'); + + cy.get('.container p').contains('Colorless green ideas sleep furiously.'); + cy.get('.container p a') + .should('have.text', 'furiously') + .and('have.attr', 'href') + .and('include', 'https://google.com'); + }); + }); +}); diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/docker-compose.yml b/apps/plone/src/addons/volto-volto-project/acceptance/docker-compose.yml new file mode 100644 index 0000000000..0af8d4a15f --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/docker-compose.yml @@ -0,0 +1,53 @@ +version: "3" + +services: + + addon-dev: + build: + context: ../ + dockerfile: ./dockerfiles/Dockerfile.acceptance + args: + ADDON_NAME: "${ADDON_NAME}" + ADDON_PATH: "${ADDON_PATH}" + VOLTO_VERSION: ${VOLTO_VERSION:-17} + volumes: + - ${CURRENT_DIR}:/app/src/addons/${ADDON_PATH}/ + environment: + RAZZLE_INTERNAL_API_PATH: http://backend-acceptance:55001/plone + RAZZLE_API_PATH: http://localhost:55001/plone + HOST: 0.0.0.0 + ports: + - 3000:3000 + - 3001:3001 + tty: true + depends_on: + - backend-acceptance + profiles: + - dev + + addon-acceptance: + build: + context: ../ + dockerfile: ./dockerfiles/Dockerfile + args: + ADDON_NAME: "${ADDON_NAME}" + ADDON_PATH: "${ADDON_PATH}" + VOLTO_VERSION: ${VOLTO_VERSION:-17} + environment: + RAZZLE_INTERNAL_API_PATH: http://backend-acceptance:55001/plone + RAZZLE_API_PATH: http://localhost:55001/plone + HOST: 0.0.0.0 + ports: + - 3000:3000 + depends_on: + - backend-acceptance + profiles: + - prod + + backend-acceptance: + image: plone/server-acceptance:${PLONE_VERSION:-6} + ports: + - 55001:55001 + profiles: + - dev + - prod diff --git a/apps/plone/src/addons/volto-volto-project/acceptance/package.json b/apps/plone/src/addons/volto-volto-project/acceptance/package.json new file mode 100644 index 0000000000..c11c8e33cb --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/acceptance/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@plone/volto-testing": "^4.0.0" + } +} diff --git a/apps/plone/src/addons/volto-volto-project/babel.config.js b/apps/plone/src/addons/volto-volto-project/babel.config.js new file mode 100644 index 0000000000..51bd52b5df --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/babel.config.js @@ -0,0 +1,17 @@ +module.exports = function (api) { + api.cache(true); + const presets = ['razzle']; + const plugins = [ + [ + 'react-intl', // React Intl extractor, required for the whole i18n infrastructure to work + { + messagesDir: './build/messages/', + }, + ], + ]; + + return { + plugins, + presets, + }; +}; diff --git a/apps/plone/src/addons/volto-volto-project/dockerfiles/Dockerfile b/apps/plone/src/addons/volto-volto-project/dockerfiles/Dockerfile new file mode 100644 index 0000000000..c413663a7f --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/dockerfiles/Dockerfile @@ -0,0 +1,27 @@ +# syntax=docker/dockerfile:1 +ARG VOLTO_VERSION +FROM plone/frontend-builder:${VOLTO_VERSION} as builder + +ARG ADDON_NAME +ARG ADDON_PATH + +# Copy addon code +COPY --chown=node:node ./ /app/src/addons/${ADDON_PATH}/ + +# Install +RUN </node_modules/@plone/volto/cypress', + '@plone/volto/babel': '/node_modules/@plone/volto/babel', + '@plone/volto/(.*)$': '/node_modules/@plone/volto/src/$1', + '@package/(.*)$': '/src/$1', + '@root/(.*)$': '/src/$1', + '~/(.*)$': '/src/$1', + 'load-volto-addons': + '/node_modules/@plone/volto/jest-addons-loader.js', + '\\.(css|less|scss|sass)$': 'identity-obj-proxy', + }, + transform: { + '^.+\\.js(x)?$': 'babel-jest', + '^.+\\.(png)$': 'jest-file', + '^.+\\.(jpg)$': 'jest-file', + '^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js', + }, + coverageThreshold: { + global: { + branches: 5, + functions: 5, + lines: 5, + statements: 5, + }, + }, +}; diff --git a/apps/plone/src/addons/volto-volto-project/locales/volto.pot b/apps/plone/src/addons/volto-volto-project/locales/volto.pot new file mode 100644 index 0000000000..1b22bc00e9 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/locales/volto.pot @@ -0,0 +1,14 @@ +msgid "" +msgstr "" +"Project-Id-Version: Plone\n" +"POT-Creation-Date: 2021-01-29T12:34:47.097Z\n" +"Last-Translator: Plone i18n \n" +"Language-Team: Plone i18n \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Language-Code: en\n" +"Language-Name: English\n" +"Preferred-Encodings: utf-8\n" +"Domain: volto\n" diff --git a/apps/plone/src/addons/volto-volto-project/package.json b/apps/plone/src/addons/volto-volto-project/package.json new file mode 100644 index 0000000000..7aefb7b746 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/package.json @@ -0,0 +1,44 @@ +{ + "name": "volto-volto-project", + "version": "0.1.0", + "description": "volto-volto-project: Volto add-on", + "main": "src/index.ts", + "license": "MIT", + "keywords": [ + "volto-addon", + "volto", + "plone", + "react" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "i18n": "rm -rf build/messages && NODE_ENV=production i18n --addon", + "dry-release": "release-it --dry-run", + "release": "release-it", + "release-major-alpha": "release-it major --preRelease=alpha", + "release-alpha": "release-it --preRelease=alpha", + "release-rc": "release-it --preRelease=rc" + }, + "devDependencies": { + "@babel/eslint-parser": "7.22.15", + "@plone/scripts": "workspace:*", + "eslint": "8.49.0", + "eslint-config-prettier": "9.0.0", + "eslint-config-react-app": "7.0.1", + "eslint-plugin-flowtype": "8.0.3", + "eslint-plugin-import": "2.28.1", + "eslint-plugin-jsx-a11y": "6.7.1", + "eslint-plugin-prettier": "5.0.0", + "eslint-plugin-react": "7.33.2", + "eslint-plugin-react-hooks": "4.6.0", + "postcss-scss": "4.0.8", + "prettier": "3.0.3", + "release-it": "^16.1.5", + "stylelint": "15.10.3", + "stylelint-config-idiomatic-order": "9.0.0", + "stylelint-config-sass-guidelines": "10.0.0", + "stylelint-prettier": "4.0.2" + } +} diff --git a/apps/plone/src/addons/volto-volto-project/src/index.ts b/apps/plone/src/addons/volto-volto-project/src/index.ts new file mode 100644 index 0000000000..2681f2ee1d --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/src/index.ts @@ -0,0 +1,7 @@ +import type { ConfigData } from '@plone/registry'; + +const applyConfig = (config: ConfigData) => { + return config; +}; + +export default applyConfig; diff --git a/apps/plone/src/addons/volto-volto-project/src/theme/theme.config b/apps/plone/src/addons/volto-volto-project/src/theme/theme.config new file mode 100644 index 0000000000..5d3e8f2dd3 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/src/theme/theme.config @@ -0,0 +1,88 @@ +/******************************* + Theme Selection +*******************************/ + +/* To override a theme for an individual element specify theme name below */ + +/* Global */ +@site : 'pastanaga'; +@reset : 'pastanaga'; + +/* Elements */ +@button : 'pastanaga'; +@container : 'pastanaga'; +@divider : 'pastanaga'; +@flag : 'pastanaga'; +@header : 'pastanaga'; +@icon : 'pastanaga'; +@image : 'pastanaga'; +@input : 'pastanaga'; +@label : 'pastanaga'; +@list : 'pastanaga'; +@loader : 'pastanaga'; +@placeholder : 'pastanaga'; +@rail : 'pastanaga'; +@reveal : 'pastanaga'; +@segment : 'pastanaga'; +@step : 'pastanaga'; + +/* Collections */ +@breadcrumb : 'pastanaga'; +@form : 'pastanaga'; +@grid : 'pastanaga'; +@menu : 'pastanaga'; +@message : 'pastanaga'; +@table : 'pastanaga'; + +/* Modules */ +@accordion : 'pastanaga'; +@checkbox : 'pastanaga'; +@dimmer : 'pastanaga'; +@dropdown : 'pastanaga'; +@embed : 'pastanaga'; +@modal : 'pastanaga'; +@nag : 'pastanaga'; +@popup : 'pastanaga'; +@progress : 'pastanaga'; +@rating : 'pastanaga'; +@search : 'pastanaga'; +@shape : 'pastanaga'; +@sidebar : 'pastanaga'; +@sticky : 'pastanaga'; +@tab : 'pastanaga'; +@transition : 'pastanaga'; + +/* Views */ +@ad : 'pastanaga'; +@card : 'pastanaga'; +@comment : 'pastanaga'; +@feed : 'pastanaga'; +@item : 'pastanaga'; +@statistic : 'pastanaga'; + +/* Extras */ +@main : 'pastanaga'; +@custom : 'pastanaga'; + +/******************************* + Folders +*******************************/ + +/* Path to theme packages */ +@themesFolder : '~volto-themes'; + +/* Path to site override folder */ +@siteFolder : "volto-volto-project/theme"; + +/******************************* + Import Theme +*******************************/ + +@import (multiple) "~semantic-ui-less/theme.less"; +@fontPath : "~volto-themes/@{theme}/assets/fonts"; + +.loadAddonOverrides() { + @import (optional) "@{siteFolder}/@{addon}/@{addontype}s/@{addonelement}.overrides"; +} + +/* End Config */ diff --git a/apps/plone/src/addons/volto-volto-project/towncrier.toml b/apps/plone/src/addons/volto-volto-project/towncrier.toml new file mode 100644 index 0000000000..489f792262 --- /dev/null +++ b/apps/plone/src/addons/volto-volto-project/towncrier.toml @@ -0,0 +1,33 @@ +[tool.towncrier] +filename = "CHANGELOG.md" +directory = "news/" +title_format = "## {version} ({project_date})" +underlines = ["", "", ""] +template = "./node_modules/@plone/scripts/templates/towncrier_template.jinja" +start_string = "\n" +issue_format = "[#{issue}](https://github.com/voltovolto-project/pull/{issue})" + +[[tool.towncrier.type]] +directory = "breaking" +name = "Breaking" +showcontent = true + +[[tool.towncrier.type]] +directory = "feature" +name = "Feature" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bugfix" +showcontent = true + +[[tool.towncrier.type]] +directory = "internal" +name = "Internal" +showcontent = true + +[[tool.towncrier.type]] +directory = "documentation" +name = "Documentation" +showcontent = true diff --git a/apps/plone/src/client.js b/apps/plone/src/client.js new file mode 100644 index 0000000000..9be1247a3a --- /dev/null +++ b/apps/plone/src/client.js @@ -0,0 +1,7 @@ +import client from '@plone/volto/start-client'; + +client(); + +if (module.hot) { + module.hot.accept(); +} diff --git a/apps/plone/src/config.js b/apps/plone/src/config.js new file mode 100644 index 0000000000..9e0bea7532 --- /dev/null +++ b/apps/plone/src/config.js @@ -0,0 +1,18 @@ +/** Volto Project Configuration + * The recommended way for configuring a Volto project is using an add-on. + * The project should only be considered as boilerplate, and all the code and + * configuration should happen and be placed in add-ons. + * + * Both configuring directly and placing code in a project is discouraged, and might be + * removed at some point from Volto. + * + * The local project is left for backwards compatibility for existing projects. + */ + +// [Internal] All the imports of modules required for the configuration *must* happen +// here BEFORE the following line +import '@plone/volto/config'; + +export default function applyConfig(config) { + return config; +} diff --git a/apps/plone/src/customizations/README.md b/apps/plone/src/customizations/README.md new file mode 100644 index 0000000000..29ccb1bcee --- /dev/null +++ b/apps/plone/src/customizations/README.md @@ -0,0 +1,6 @@ + +# Local customizations + +To override a file in the Volto package, add the directory structure and file to this folder. +For example, to override the `Logo.svg` file, add the directory structure `components/theme/Logo`, and add the file `Logo.svg` to it. +To apply your customizations, restart the server. diff --git a/apps/plone/src/index.js b/apps/plone/src/index.js new file mode 100644 index 0000000000..9ae184cc6b --- /dev/null +++ b/apps/plone/src/index.js @@ -0,0 +1,7 @@ +import start from '@plone/volto/start-server'; + +const reloadServer = start(); + +if (module.hot) { + reloadServer(); +} diff --git a/apps/plone/src/reducers/index.js b/apps/plone/src/reducers/index.js new file mode 100644 index 0000000000..520fa47c6d --- /dev/null +++ b/apps/plone/src/reducers/index.js @@ -0,0 +1,20 @@ +/** + * Root reducer. + * @module reducers/root + */ + +import defaultReducers from '@plone/volto/reducers'; + +/** + * Root reducer. + * @function + * @param {Object} state Current state. + * @param {Object} action Action to be handled. + * @returns {Object} New state. + */ +const reducers = { + ...defaultReducers, + // Add your reducers here +}; + +export default reducers; diff --git a/apps/plone/src/routes.js b/apps/plone/src/routes.js new file mode 100644 index 0000000000..d23ac9305d --- /dev/null +++ b/apps/plone/src/routes.js @@ -0,0 +1,26 @@ +/** + * Routes. + * @module routes + */ + +import { defaultRoutes } from '@plone/volto/routes'; +import config from '@plone/volto/registry'; + +/** + * Routes array. + * @array + * @returns {array} Routes. + */ +const routes = [ + { + path: '/', + component: config.getComponent('App').component, // Change this if you want a different component + routes: [ + // Add your routes here + ...(config.addonRoutes || []), + ...defaultRoutes, + ], + }, +]; + +export default routes; diff --git a/apps/plone/src/theme.js b/apps/plone/src/theme.js new file mode 100644 index 0000000000..41018009fb --- /dev/null +++ b/apps/plone/src/theme.js @@ -0,0 +1,2 @@ +import 'semantic-ui-less/semantic.less'; +import '@plone/volto/../theme/themes/pastanaga/extras/extras.less'; diff --git a/apps/plone/tsconfig.json b/apps/plone/tsconfig.json new file mode 100644 index 0000000000..a6ea060da5 --- /dev/null +++ b/apps/plone/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "commonjs", + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "paths": { + "@plone/volto/*": ["../node_modules/@plone/volto/src/*", "../node_modules/@plone/volto/types/*"] + }, + "baseUrl": "src" + }, + "include": ["src"], + "exclude": [ + "node_modules", + "build", + "public", + "coverage", + "src/**/*.test.{js,jsx,ts,tsx}", + "src/**/*.spec.{js,jsx,ts,tsx}", + "src/**/*.stories.{js,jsx,ts,tsx}" + ] +} diff --git a/apps/remix/.eslintrc.cjs b/apps/remix/.eslintrc.cjs new file mode 100644 index 0000000000..b4a6a65b4d --- /dev/null +++ b/apps/remix/.eslintrc.cjs @@ -0,0 +1,80 @@ +/** + * This is intended to be a basic starting point for linting in your app. + * It relies on recommended configs out of the box for simplicity, but you can + * and should modify this configuration to best suit your team's needs. + */ + +/** @type {import('eslint').Linter.Config} */ +module.exports = { + root: true, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + env: { + browser: true, + commonjs: true, + es6: true, + }, + + // Base config + extends: ['eslint:recommended'], + + overrides: [ + // React + { + files: ['**/*.{js,jsx,ts,tsx}'], + plugins: ['react', 'jsx-a11y'], + extends: [ + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + 'plugin:jsx-a11y/recommended', + ], + settings: { + react: { + version: 'detect', + }, + formComponents: ['Form'], + linkComponents: [ + { name: 'Link', linkAttribute: 'to' }, + { name: 'NavLink', linkAttribute: 'to' }, + ], + }, + }, + + // Typescript + { + files: ['**/*.{ts,tsx}'], + plugins: ['@typescript-eslint', 'import'], + parser: '@typescript-eslint/parser', + settings: { + 'import/internal-regex': '^~/', + 'import/resolver': { + node: { + extensions: ['.ts', '.tsx'], + }, + typescript: { + alwaysTryTypes: true, + }, + }, + }, + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:import/recommended', + 'plugin:import/typescript', + ], + }, + + // Node + { + files: ['.eslintrc.js'], + env: { + node: true, + }, + }, + ], +}; diff --git a/apps/remix/.gitignore b/apps/remix/.gitignore new file mode 100644 index 0000000000..3f7bf98da3 --- /dev/null +++ b/apps/remix/.gitignore @@ -0,0 +1,6 @@ +node_modules + +/.cache +/build +/public/build +.env diff --git a/apps/remix/README.md b/apps/remix/README.md new file mode 100644 index 0000000000..de9880b2f6 --- /dev/null +++ b/apps/remix/README.md @@ -0,0 +1,25 @@ +# Plone on Remix + +This is a proof of concept of a [Remix](https://remix.run) app, using the `@plone/client` and `@plone/components` libraries. +This is intended to serve as both a playground for the development of both packages and as a demo of Plone using Remix. + + +## Development + +To start, from the root of the monorepo: + +```shell +pnpm install +pnpm --filter plone-remix run dev +``` + +Then start the Plone backend: + +```shell +make start-backend-docker +``` + + +## About this app + +- [Remix Docs](https://remix.run/docs/en/main) diff --git a/apps/remix/app/config.ts b/apps/remix/app/config.ts new file mode 100644 index 0000000000..c2f3c47921 --- /dev/null +++ b/apps/remix/app/config.ts @@ -0,0 +1,9 @@ +const settings = { + apiPath: 'http://localhost:8080/Plone', +}; + +const config = { + settings, +}; + +export default config; diff --git a/apps/remix/app/entry.client.tsx b/apps/remix/app/entry.client.tsx new file mode 100644 index 0000000000..3f01ce18b1 --- /dev/null +++ b/apps/remix/app/entry.client.tsx @@ -0,0 +1,18 @@ +/** + * By default, Remix will handle hydrating your app on the client for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.client + */ + +import { RemixBrowser } from '@remix-run/react'; +import { startTransition, StrictMode } from 'react'; +import { hydrateRoot } from 'react-dom/client'; + +startTransition(() => { + hydrateRoot( + document, + + + , + ); +}); diff --git a/apps/remix/app/entry.server.tsx b/apps/remix/app/entry.server.tsx new file mode 100644 index 0000000000..648debcb2f --- /dev/null +++ b/apps/remix/app/entry.server.tsx @@ -0,0 +1,140 @@ +/** + * By default, Remix will handle generating the HTTP Response for you. + * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ + * For more information, see https://remix.run/file-conventions/entry.server + */ + +import { PassThrough } from 'node:stream'; + +import type { AppLoadContext, EntryContext } from '@remix-run/node'; +import { createReadableStreamFromReadable } from '@remix-run/node'; +import { RemixServer } from '@remix-run/react'; +import isbot from 'isbot'; +import { renderToPipeableStream } from 'react-dom/server'; + +const ABORT_DELAY = 5_000; + +export default function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, + // This is ignored so we can keep it in the template for visibility. Feel + // free to delete this parameter in your app if you're not using it! + // eslint-disable-next-line @typescript-eslint/no-unused-vars + loadContext: AppLoadContext, +) { + return isbot(request.headers.get('user-agent')) + ? handleBotRequest( + request, + responseStatusCode, + responseHeaders, + remixContext, + ) + : handleBrowserRequest( + request, + responseStatusCode, + responseHeaders, + remixContext, + ); +} + +function handleBotRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onAllReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set('Content-Type', 'text/html'); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }), + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + }, + ); + + setTimeout(abort, ABORT_DELAY); + }); +} + +function handleBrowserRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + remixContext: EntryContext, +) { + return new Promise((resolve, reject) => { + let shellRendered = false; + const { pipe, abort } = renderToPipeableStream( + , + { + onShellReady() { + shellRendered = true; + const body = new PassThrough(); + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set('Content-Type', 'text/html'); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }), + ); + + pipe(body); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + console.error(error); + } + }, + }, + ); + + setTimeout(abort, ABORT_DELAY); + }); +} diff --git a/apps/remix/app/root.tsx b/apps/remix/app/root.tsx new file mode 100644 index 0000000000..3a893ab269 --- /dev/null +++ b/apps/remix/app/root.tsx @@ -0,0 +1,62 @@ +import { cssBundleHref } from '@remix-run/css-bundle'; +import type { LinksFunction } from '@remix-run/node'; +import { + Links, + LiveReload, + Meta, + Outlet, + Scripts, + ScrollRestoration, +} from '@remix-run/react'; +import { useState } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { PloneClientProvider } from '@plone/client/provider'; +import PloneClient from '@plone/client'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; + +export const links: LinksFunction = () => [ + ...(cssBundleHref ? [{ rel: 'stylesheet', href: cssBundleHref }] : []), +]; + +export default function App() { + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, + }, + }, + }), + ); + + const [ploneClient] = useState(() => + PloneClient.initialize({ + apiPath: 'http://localhost:8080/Plone', + }), + ); + + return ( + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/remix/app/routes/_index.tsx b/apps/remix/app/routes/_index.tsx new file mode 100644 index 0000000000..f7784f545f --- /dev/null +++ b/apps/remix/app/routes/_index.tsx @@ -0,0 +1,62 @@ +import { + json, + type LoaderFunctionArgs, + type MetaFunction, +} from '@remix-run/node'; +import { + dehydrate, + QueryClient, + HydrationBoundary, + useQuery, +} from '@tanstack/react-query'; +import ploneClient from '@plone/client'; +import { flattenToAppURL } from '../utils'; +import { useLoaderData, useLocation } from '@remix-run/react'; +import { usePloneClient } from '@plone/client/provider'; + +export const meta: MetaFunction = () => { + return [ + { title: 'New Remix App' }, + { name: 'description', content: 'Welcome to Remix!' }, + ]; +}; + +const expand = ['breadcrumbs', 'navigation']; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export const loader = async ({ params, request }: LoaderFunctionArgs) => { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, + }, + }, + }); + const cli = ploneClient.initialize({ + apiPath: 'http://localhost:8080/Plone', + }); + const { getContentQuery } = cli; + + await queryClient.prefetchQuery( + getContentQuery({ path: flattenToAppURL(request.url), expand }), + ); + + return json({ dehydratedState: dehydrate(queryClient) }); +}; + +export default function Index() { + const { dehydratedState } = useLoaderData(); + const { getContentQuery } = usePloneClient(); + const pathname = useLocation().pathname; + const { data } = useQuery(getContentQuery({ path: pathname, expand })); + + return ( + +
+
{JSON.stringify(data, null, 2)}
+
+
+ ); +} diff --git a/apps/remix/app/utils.ts b/apps/remix/app/utils.ts new file mode 100644 index 0000000000..f6513198f8 --- /dev/null +++ b/apps/remix/app/utils.ts @@ -0,0 +1,17 @@ +import config from './config'; + +/** + * Flatten to app server URL - Given a URL if it starts with the API server URL + * this method flattens it (removes) the server part + * TODO: Update it when implementing non-root based app location (on a + * directory other than /, eg. /myapp) + * @method flattenToAppURL + */ +export function flattenToAppURL(url: string) { + const { settings } = config; + return ( + (url && + url.replace(settings.apiPath, '').replace('http://localhost:3000', '')) || + '/' + ); +} diff --git a/apps/remix/package.json b/apps/remix/package.json new file mode 100644 index 0000000000..2da2695bce --- /dev/null +++ b/apps/remix/package.json @@ -0,0 +1,41 @@ +{ + "name": "plone-remix", + "private": true, + "sideEffects": false, + "type": "module", + "scripts": { + "build": "remix build", + "dev": "remix dev --manual", + "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", + "start:prod": "remix-serve ./build/index.js", + "typecheck": "tsc" + }, + "dependencies": { + "@plone/client": "workspace: *", + "@remix-run/css-bundle": "^2.4.0", + "@remix-run/node": "^2.4.0", + "@remix-run/react": "^2.4.0", + "@remix-run/serve": "^2.4.0", + "@tanstack/react-query": "^5.24.6", + "@tanstack/react-query-devtools": "^5.24.6", + "isbot": "^3.6.8", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@remix-run/dev": "^2.4.0", + "@types/react": "^18.2.20", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.7.4", + "eslint": "^8.38.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "typescript": "^5.2.2" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/apps/remix/public/favicon.ico b/apps/remix/public/favicon.ico new file mode 100644 index 0000000000..8830cf6821 Binary files /dev/null and b/apps/remix/public/favicon.ico differ diff --git a/apps/remix/remix.config.js b/apps/remix/remix.config.js new file mode 100644 index 0000000000..812df9d051 --- /dev/null +++ b/apps/remix/remix.config.js @@ -0,0 +1,8 @@ +/** @type {import('@remix-run/dev').AppConfig} */ +export default { + ignoredRouteFiles: ['**/.*'], + // appDirectory: "app", + // assetsBuildDirectory: "public/build", + // publicPath: "/build/", + // serverBuildPath: "build/index.js", +}; diff --git a/apps/remix/remix.env.d.ts b/apps/remix/remix.env.d.ts new file mode 100644 index 0000000000..dcf8c45e1d --- /dev/null +++ b/apps/remix/remix.env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/apps/remix/tsconfig.json b/apps/remix/tsconfig.json new file mode 100644 index 0000000000..28cce918b8 --- /dev/null +++ b/apps/remix/tsconfig.json @@ -0,0 +1,22 @@ +{ + "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], + "compilerOptions": { + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "isolatedModules": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "target": "ES2022", + "strict": true, + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "~/*": ["./app/*"] + }, + + // Remix takes care of building everything in `remix build`. + "noEmit": true + } +} diff --git a/apps/vite-ssr/.gitignore b/apps/vite-ssr/.gitignore new file mode 100644 index 0000000000..d451ff16c1 --- /dev/null +++ b/apps/vite-ssr/.gitignore @@ -0,0 +1,5 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local diff --git a/apps/vite-ssr/.prettierignore b/apps/vite-ssr/.prettierignore new file mode 100644 index 0000000000..083bdb7c4c --- /dev/null +++ b/apps/vite-ssr/.prettierignore @@ -0,0 +1 @@ +src/routeTree.gen.ts diff --git a/apps/vite-ssr/README.md b/apps/vite-ssr/README.md new file mode 100644 index 0000000000..2894982c36 --- /dev/null +++ b/apps/vite-ssr/README.md @@ -0,0 +1,6 @@ +# Plone on Vite with SSR mode + +This is a proof of concept of a [Vite](https://vitejs.dev) build, using `@plone/client` and `@plone/components` libraries. +This is intended to serve as both a playground for the development of both packages and as a demo of Plone using Vite built with server side rendering (SSR). + +It also uses [TanStack Router](https://tanstack.com/router/latest/docs/framework/react/overview) for its routing library. diff --git a/apps/vite-ssr/index.html b/apps/vite-ssr/index.html new file mode 100644 index 0000000000..eecb058a61 --- /dev/null +++ b/apps/vite-ssr/index.html @@ -0,0 +1,12 @@ + + + + + + + + +
+ + + diff --git a/apps/vite-ssr/package.json b/apps/vite-ssr/package.json new file mode 100644 index 0000000000..353377b65e --- /dev/null +++ b/apps/vite-ssr/package.json @@ -0,0 +1,50 @@ +{ + "name": "plone-vite-ssr", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "node server", + "build": "npm run build:client && npm run build:server", + "build:client": "vite build --outDir dist/client", + "build:server": "vite build --ssr src/entry-server.tsx --outDir dist/server", + "start:prod": "NODE_ENV=production node server", + "debug": "node --inspect-brk server" + }, + "dependencies": { + "@plone/client": "workspace:*", + "@plone/components": "workspace:*", + "@plone/registry": "workspace:*", + "@plone/blocks": "workspace:*", + "@tanstack/react-query": "5.24.1", + "@tanstack/react-router": "^1.16.0", + "@tanstack/react-router-server": "^1.16.0", + "@tanstack/router-devtools": "^1.16.0", + "@tanstack/router-vite-plugin": "^1.16.1", + "axios": "^1.6.5", + "get-port": "^7.0.0", + "react": "^18.2.0", + "react-aria-components": "^1.1.1", + "react-dom": "^18.2.0", + "sirv": "^2.0.4" + }, + "devDependencies": { + "@babel/core": "^7.23.7", + "@babel/generator": "^7.23.6", + "@plone/types": "workspace:*", + "@rollup/plugin-babel": "^6.0.4", + "@tanstack/react-query-devtools": "^5.24.1", + "@types/express": "^4.17.21", + "@types/react": "^18.2.55", + "@types/react-dom": "^18.2.19", + "@vitejs/plugin-react": "^4", + "compression": "^1.7.4", + "express": "^4.18.2", + "isbot": "^4.3.0", + "node-fetch": "^3.3.2", + "serve-static": "^1.15.0", + "typescript": "^5.3.3", + "vite": "^5.1.4", + "vite-plugin-babel": "^1.2.0" + } +} diff --git a/apps/vite-ssr/server.js b/apps/vite-ssr/server.js new file mode 100644 index 0000000000..e5af2f9156 --- /dev/null +++ b/apps/vite-ssr/server.js @@ -0,0 +1,108 @@ +import fs from 'node:fs/promises'; +import express from 'express'; +import getPort, { portNumbers } from 'get-port'; +import dns from 'dns'; + +const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD; + +// If DNS returns both ipv4 and ipv6 addresses, prefer ipv4 + +export async function createServer( + root = process.cwd(), + isProd = process.env.NODE_ENV === 'production', + hmrPort, +) { + dns.setDefaultResultOrder('ipv4first'); + const app = express(); + + const prodIndexHtml = isProd + ? await fs.readFile('./dist/client/index.html', 'utf-8') + : ''; + + /** + * @type {import('vite').ViteDevServer} + */ + let vite; + if (!isProd) { + vite = await ( + await import('vite') + ).createServer({ + root, + logLevel: isTest ? 'error' : 'info', + server: { + middlewareMode: true, + watch: { + // During tests we edit the files too fast and sometimes chokidar + // misses change events, so enforce polling for consistency + usePolling: true, + interval: 100, + }, + hmr: { + port: hmrPort, + }, + }, + appType: 'custom', + }); + // use vite's connect instance as middleware + app.use(vite.middlewares); + } else { + const sirv = (await import('sirv')).default; + app.use((await import('compression')).default()); + app.use('/', sirv('./dist/client', { extensions: [] })); + } + + app.use('*', async (req, res) => { + try { + const url = req.originalUrl; + + if (url.includes('.')) { + console.warn(`${url} is not valid router path`); + res.status(404); + res.end(`${url} is not valid router path`); + return; + } + + // Extract the head from vite's index transformation hook + let viteHead = !isProd + ? await vite.transformIndexHtml( + url, + ``, + ) + : prodIndexHtml; + + viteHead = viteHead.substring( + viteHead.indexOf('') + 6, + viteHead.indexOf(''), + ); + + const entry = await (async () => { + if (!isProd) { + return vite.ssrLoadModule('/src/entry-server.tsx'); + } else { + return import('./dist/server/entry-server.js'); + } + })(); + + console.log('Rendering: ', url, '...'); + entry.render({ req, res, url, head: isProd ? viteHead : '' }); + } catch (e) { + !isProd && vite.ssrFixStacktrace(e); + console.log(e.stack); + res.status(500).end(e.stack); + } + }); + + return { app, vite }; +} + +if (!isTest) { + createServer().then(async ({ app }) => + app.listen( + await getPort({ port: portNumbers(3000, 3100) }), + '0.0.0.0', + () => { + console.log('Client Server: http://localhost:3000'); + }, + ), + ); +} diff --git a/apps/vite-ssr/src/config.ts b/apps/vite-ssr/src/config.ts new file mode 100644 index 0000000000..eb76dfdc36 --- /dev/null +++ b/apps/vite-ssr/src/config.ts @@ -0,0 +1,14 @@ +import config from '@plone/registry'; +import { slate } from '@plone/blocks'; +import { blocksConfig } from '@plone/blocks'; + +const settings = { + apiPath: 'http://localhost:8080/Plone', + slate, +}; + +config.set('settings', settings); + +config.set('blocks', { blocksConfig }); + +export default config; diff --git a/apps/vite-ssr/src/entry-client.tsx b/apps/vite-ssr/src/entry-client.tsx new file mode 100644 index 0000000000..e178ab84f1 --- /dev/null +++ b/apps/vite-ssr/src/entry-client.tsx @@ -0,0 +1,10 @@ +import ReactDOM from 'react-dom/client'; + +import { StartClient } from '@tanstack/react-router-server/client'; +import { createRouter } from './router'; + +import './config'; + +const router = createRouter(); + +ReactDOM.hydrateRoot(document, ); diff --git a/apps/vite-ssr/src/entry-server.tsx b/apps/vite-ssr/src/entry-server.tsx new file mode 100644 index 0000000000..f701a08446 --- /dev/null +++ b/apps/vite-ssr/src/entry-server.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import ReactDOMServer from 'react-dom/server'; +import { createMemoryHistory } from '@tanstack/react-router'; +import { ServerResponse } from 'http'; +import express from 'express'; +import { StartServer } from '@tanstack/react-router-server/server'; +import { createRouter } from './router'; +import './config'; + +// index.js +import './fetch-polyfill'; + +export async function render(opts: { + url: string; + head: string; + req: express.Request; + res: ServerResponse; +}) { + const router = createRouter(); + + const memoryHistory = createMemoryHistory({ + initialEntries: [opts.url], + }); + + // Update the history and context + router.update({ + history: memoryHistory, + context: { + ...router.options.context, + head: opts.head, + }, + }); + + // Since we're using renderToString, Wait for the router to finish loading + await router.load(); + + // Render the app + const appHtml = ReactDOMServer.renderToString( + , + ); + + opts.res.statusCode = 200; + opts.res.setHeader('Content-Type', 'text/html'); + opts.res.end(`${appHtml}`); +} diff --git a/apps/vite-ssr/src/fetch-polyfill.js b/apps/vite-ssr/src/fetch-polyfill.js new file mode 100644 index 0000000000..555ffcb254 --- /dev/null +++ b/apps/vite-ssr/src/fetch-polyfill.js @@ -0,0 +1,20 @@ +// fetch-polyfill.js +import fetch, { + Blob, + blobFrom, + blobFromSync, + File, + fileFrom, + fileFromSync, + FormData, + Headers, + Request, + Response, +} from 'node-fetch'; + +if (!globalThis.fetch) { + globalThis.fetch = fetch; + globalThis.Headers = Headers; + globalThis.Request = Request; + globalThis.Response = Response; +} diff --git a/apps/vite-ssr/src/routeTree.gen.ts b/apps/vite-ssr/src/routeTree.gen.ts new file mode 100644 index 0000000000..8106e66cba --- /dev/null +++ b/apps/vite-ssr/src/routeTree.gen.ts @@ -0,0 +1,62 @@ +/* prettier-ignore-start */ + +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file is auto-generated by TanStack Router + +// Import Routes + +import { Route as rootRoute } from './routes/__root'; +import { Route as ErrorImport } from './routes/error'; +import { Route as SplatImport } from './routes/$'; +import { Route as IndexImport } from './routes/index'; + +// Create/Update Routes + +const ErrorRoute = ErrorImport.update({ + path: '/error', + getParentRoute: () => rootRoute, +} as any); + +const SplatRoute = SplatImport.update({ + path: '/$', + getParentRoute: () => rootRoute, +} as any); + +const IndexRoute = IndexImport.update({ + path: '/', + getParentRoute: () => rootRoute, +} as any); + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + preLoaderRoute: typeof IndexImport; + parentRoute: typeof rootRoute; + }; + '/$': { + preLoaderRoute: typeof SplatImport; + parentRoute: typeof rootRoute; + }; + '/error': { + preLoaderRoute: typeof ErrorImport; + parentRoute: typeof rootRoute; + }; + } +} + +// Create and export the route tree + +export const routeTree = rootRoute.addChildren([ + IndexRoute, + SplatRoute, + ErrorRoute, +]); + +/* prettier-ignore-end */ diff --git a/apps/vite-ssr/src/router.tsx b/apps/vite-ssr/src/router.tsx new file mode 100644 index 0000000000..62d9a2ac4d --- /dev/null +++ b/apps/vite-ssr/src/router.tsx @@ -0,0 +1,64 @@ +import { + QueryClient, + QueryClientProvider, + dehydrate, + hydrate, +} from '@tanstack/react-query'; +import PloneClient from '@plone/client'; +import { createRouter as createReactRouter } from '@tanstack/react-router'; + +import { routeTree } from './routeTree.gen'; +import { PloneClientProvider } from '@plone/client/provider'; +import { FlattenToAppURLProvider } from '@plone/components'; +import { flattenToAppURL } from './utils'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 60 * 1000, + }, + }, +}); + +const ploneClient = PloneClient.initialize({ + apiPath: 'http://localhost:8080/Plone', +}); + +export function createRouter() { + return createReactRouter({ + routeTree, + context: { + head: '', + queryClient, + ploneClient, + }, + defaultPreload: 'intent', + dehydrate: () => { + return { + queryClientState: dehydrate(queryClient), + }; + }, + hydrate: (dehydrated) => { + hydrate(queryClient, dehydrated.queryClientState); + }, + Wrap: ({ children }: { children: any }) => { + return ( + + + + {children} + + + + ); + }, + }); +} + +declare module '@tanstack/react-router' { + interface Register { + router: ReturnType; + } +} diff --git a/apps/vite-ssr/src/routerContext.tsx b/apps/vite-ssr/src/routerContext.tsx new file mode 100644 index 0000000000..de5df3de21 --- /dev/null +++ b/apps/vite-ssr/src/routerContext.tsx @@ -0,0 +1,8 @@ +import { QueryClient } from '@tanstack/react-query'; +import PloneClient from '@plone/client'; + +export type RouterContext = { + head: string; + queryClient: QueryClient; + ploneClient: PloneClient; +}; diff --git a/apps/vite-ssr/src/routes/$.tsx b/apps/vite-ssr/src/routes/$.tsx new file mode 100644 index 0000000000..d9400c3809 --- /dev/null +++ b/apps/vite-ssr/src/routes/$.tsx @@ -0,0 +1,37 @@ +import { createFileRoute } from '@tanstack/react-router'; +import * as React from 'react'; +import { flattenToAppURL } from '../utils'; +import { useSuspenseQuery } from '@tanstack/react-query'; +import { usePloneClient } from '@plone/client/provider'; +import { Breadcrumbs } from '@plone/components'; + +const expand = ['breadcrumbs', 'navigation']; + +export const Route = createFileRoute('/$')({ + loader: ({ context: { queryClient, ploneClient }, location }) => { + const { getContentQuery } = ploneClient; + return queryClient.ensureQueryData( + getContentQuery({ path: flattenToAppURL(location.pathname), expand }), + ); + }, + component: SplatRouteComponent, +}); + +function SplatRouteComponent() { + const { _splat: path } = Route.useParams(); + const { getContentQuery } = usePloneClient(); + const { data } = useSuspenseQuery( + getContentQuery({ path: flattenToAppURL(`/${path}`), expand }), + ); + return ( +
+ + +

{data.title}

+
+ ); +} diff --git a/apps/vite-ssr/src/routes/__root.tsx b/apps/vite-ssr/src/routes/__root.tsx new file mode 100644 index 0000000000..f9438828bf --- /dev/null +++ b/apps/vite-ssr/src/routes/__root.tsx @@ -0,0 +1,67 @@ +import * as React from 'react'; +import { TanStackRouterDevtools } from '@tanstack/router-devtools'; +import { + Outlet, + createRootRouteWithContext, + useRouter, +} from '@tanstack/react-router'; +import { DehydrateRouter } from '@tanstack/react-router-server/client'; +import { RouterContext } from '../routerContext'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { RouterProvider } from 'react-aria-components'; + +import '@plone/components/dist/basic.css'; + +export const Route = createRootRouteWithContext()({ + component: RootComponent, +}); + +function RootComponent() { + const router = useRouter(); + + return ( + + {router.options.context.head ? ( + + ) : ( + + + + Plone on Vite SSR build + \ No newline at end of file diff --git a/packages/components/.storybook/preview.ts b/packages/components/.storybook/preview.ts new file mode 100644 index 0000000000..31493af9d1 --- /dev/null +++ b/packages/components/.storybook/preview.ts @@ -0,0 +1,14 @@ +import './storybook-base.css'; + +export const parameters = { + backgrounds: { + default: 'light', + }, + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; diff --git a/packages/components/.storybook/storybook-base.css b/packages/components/.storybook/storybook-base.css new file mode 100644 index 0000000000..ce1752cb8a --- /dev/null +++ b/packages/components/.storybook/storybook-base.css @@ -0,0 +1,15 @@ +/* Base styles */ +:root { + --basic-font-family: system-ui; + --basic-font-size: 16px; + background: var(--background-color); + font-family: var(--basic-font-family); + font-size: var(--basic-font-size); + line-height: 1.5; +} + +.sbdocs.sbdocs-content { + p { + font-size: 16px; + } +} diff --git a/packages/components/.storybook/theme.ts b/packages/components/.storybook/theme.ts new file mode 100644 index 0000000000..3262e1f700 --- /dev/null +++ b/packages/components/.storybook/theme.ts @@ -0,0 +1,10 @@ +import { create } from '@storybook/theming/create'; +import logo from './Logo.svg'; + +export default create({ + base: 'light', + brandTitle: '@plone/components StoryBook', + brandUrl: 'https://plone-components.netlify.app/', + brandImage: logo, + brandTarget: '_self', +}); diff --git a/packages/components/.stylelintrc b/packages/components/.stylelintrc new file mode 100644 index 0000000000..8ac62f8d0f --- /dev/null +++ b/packages/components/.stylelintrc @@ -0,0 +1,14 @@ +{ + "extends": ["stylelint-config-idiomatic-order"], + "plugins": ["stylelint-prettier"], + "overrides": [ + { + "files": ["**/*.scss"], + "customSyntax": "postcss-scss" + } + ], + "rules": { + "prettier/prettier": true, + "order/properties-alphabetical-order": null + } +} diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md new file mode 100644 index 0000000000..9197b93bd3 --- /dev/null +++ b/packages/components/CHANGELOG.md @@ -0,0 +1,176 @@ +# @plone/client Release Notes + + + + + +## 2.0.0-alpha.7 (2024-03-14) + +### Bugfix + +- Missing CSS in build for `Container` @sneridagh [#5849](https://github.com/plone/volto/issues/5849) + +### Internal + +- Cleanup deps @sneridagh [#5846](https://github.com/plone/volto/issues/5846) + +## 2.0.0-alpha.6 (2024-03-06) + +### Breaking + +- Refactor the `Container` component. + The inference for the `as` prop is complete. + Replace the internal `className` to be `q container` @sneridagh [#5848](https://github.com/plone/volto/issues/5848) + +## 2.0.0-alpha.5 (2024-03-05) + +### Bugfix + +- Fix some case inconsistencies in CSS declarations @sneridagh [#5824](https://github.com/plone/volto/issues/5824) + +## 2.0.0-alpha.4 (2024-03-02) + +### Bugfix + +- Remove `lodash` dependency. + Several packages upgrades and general cleanup. @sneridagh [#5822](https://github.com/plone/volto/issues/5822) +- Proxy the `PopoverContext` inside the `Select` component, to be able to override it from the outside @sneridagh [#5823](https://github.com/plone/volto/issues/5823) + +### Internal + +- Update dependencies @sneridagh [#5815](https://github.com/plone/volto/issues/5815) + +## 2.0.0-alpha.3 (2024-03-01) + +### Breaking + +- Use `pathname` instead of the full location as prop in `BlocksRenderer` @sneridagh [#5798](https://github.com/plone/volto/issues/5798) + +### Bugfix + +- Fix `lodash` imports for bundling @sneridagh [#5798](https://github.com/plone/volto/issues/5798) + +## 2.0.0-alpha.2 (2024-02-23) + +### Bugfix + +- Move basic general CSS rules to StoryBook so we don't spoil the build @sneridagh [#5791](https://github.com/plone/volto/issues/5791) + +### Internal + +- Improve StoryBook look and feel @sneridagh [#5791](https://github.com/plone/volto/issues/5791) + +## 2.0.0-alpha.1 (2024-02-18) + +### Bugfix + +- Add import path for bundled CSS @sneridagh [#5770](https://github.com/plone/volto/issues/5770) + +## 2.0.0-alpha.0 (2024-02-17) + +### Breaking + +- Move to only CSS-based approach + Removal of SCSS in favor of the above + New Basic components, based in React Aria Components + + @sneridagh [#5766](https://github.com/plone/volto/issues/5766) + +### Documentation + +- Build the `volto/components` Storybook only when its source files change. @stevepiercy [#5601](https://github.com/plone/volto/issues/5601) + +## 1.7.0 (2023-12-25) + +### Feature + +- Introduce support views - Add `RenderBlocks` view @sneridagh [#16](https://github.com/plone/volto/issues/16) +- Transfer `@plone/components` to the Volto monorepo @sneridagh [#5544](https://github.com/plone/volto/issues/5544) + +### Bugfix + +- Fixed some imports, build was failing @sneridagh [#5545](https://github.com/plone/volto/issues/5545) + +### Internal + +- ESlint general improvements @sneridagh [#5548](https://github.com/plone/volto/issues/5548) + +## 1.6.0 (2023-11-12) + +### Internal + +- Update Textarea with new FieldError component @sneridagh [#15](https://github.com/plone/components/issues/15) + +## 1.5.0 (2023-11-12) + +### Feature + +- Add Quanta icons as react components ready to use with the Icon component @sneridagh [#12](https://github.com/plone/components/issues/12) +- Basic `Select` component. + Introduce new FieldError component. + Other CSS fixes. @sneridagh [#14](https://github.com/plone/components/issues/14) + +### Internal + +- Update to `react-aria-components` RC. @sneridagh [#14](https://github.com/plone/components/issues/14) + +## 1.4.1 (2023-11-01) + +### Internal + +- Fixed wrong pointer to the new d.ts file @sneridagh [#0](https://github.com/plone/components/issues/0) + +## 1.4.0 (2023-11-01) + +### Feature + +- Add build process to the package, add the resultant build to the npm release @sneridagh [#11](https://github.com/plone/components/issues/11) + +### Internal + +- Update to latest @types/react @sneridagh [#10](https://github.com/plone/components/issues/10) + +## 1.3.0 (2023-10-31) + +### Feature + +- New component: `Link` + New provider: `FlattenToAppURLProvider` + Based on the `react-aria-components` `Link` component + It uses the new `FlattenToAppURLProvider` helper to flatten all the incoming URLs @sneridagh [#8](https://github.com/plone/components/issues/8) + +## 1.2.0 (2023-10-28) + +### Feature + +- New component: Icon + Styling for Breadcrumbs component. + Improve the Breadcrumbs component internally. @sneridagh [#7](https://github.com/plone/components/issues/7) + +## 1.1.0 (2023-10-24) + +### Feature + +- Breadcrumbs styling @sneridagh [#5](https://github.com/plone/components/issues/5) +- Color Palette @sneridagh + Stories cleanup @sneridagh [#6](https://github.com/plone/components/issues/6) + + +## 1.0.1 (2023-10-20) + +### Bugfix + +- Cleanup @sneridagh [#2](https://github.com/plone/components/issues/2) + + +## 1.0.0 (2023-10-20) + +### Feature + +- Initial release @sneridagh + Container component @sneridagh + Input component @sneridagh [#1](https://github.com/plone/components/issues/1) diff --git a/packages/components/LICENSE b/packages/components/LICENSE new file mode 100644 index 0000000000..c0af2b1b65 --- /dev/null +++ b/packages/components/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Plone Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/components/Makefile b/packages/components/Makefile new file mode 100644 index 0000000000..8393f631a1 --- /dev/null +++ b/packages/components/Makefile @@ -0,0 +1,30 @@ +SHELL := /bin/bash +CURRENT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + + +# We like colors +# From: https://coderwall.com/p/izxssa/colored-makefile-for-golang-projects +RED=`tput setaf 1` +GREEN=`tput setaf 2` +RESET=`tput sgr0` +YELLOW=`tput setaf 3` + +DOCKER_IMAGE=plone/plone-backend:6.0.1 +TESTING_ADDONS=plone.app.robotframework==2.0.0 plone.app.testing==7.0.0 + +.PHONY: all +all: build + +# Add the following 'help' target to your Makefile +# And add help text after each target name starting with '\#\#' +.PHONY: help +help: ## This help message + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: start-test-acceptance-server +start-test-acceptance-server: ## Start Test Acceptance Server Main Fixture (docker container) + docker run -i --rm -d -e ZSERVER_HOST=0.0.0.0 -e ZSERVER_PORT=55001 -p 55001:55001 -e ADDONS='$(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 + +.PHONY: build-storybook +build-storybook: ## Build Storybook + yarn && yarn build-storybook diff --git a/packages/components/README.md b/packages/components/README.md new file mode 100644 index 0000000000..af2f8c0589 --- /dev/null +++ b/packages/components/README.md @@ -0,0 +1,250 @@ +# @plone/components + +[![NPM](https://img.shields.io/npm/v/@plone/components.svg)](https://www.npmjs.com/package/@plone/components) +[![Build Status](https://github.com/plone/components/actions/workflows/code.yml/badge.svg)](https://github.com/plone/components/actions) +[![Build Status](https://github.com/plone/components/actions/workflows/unit.yml/badge.svg)](https://github.com/plone/components/actions) +[![Netlify Status](https://api.netlify.com/api/v1/badges/ff1f19ce-9b19-48f9-94a8-d533b53d4a9a/deploy-status)](https://app.netlify.com/sites/plone-components/deploys) + +This package contains ReactJS components for using Plone as a headless CMS. + +The purpose of this package is to provide an agnostic set of baseline components to build sites upon. + +## Storybook / Demo + +You can find the self-documented Storybook in: + +https://plone-components.netlify.app/ + +`@plone/components` is based on [React Aria Components](https://react-spectrum.adobe.com/react-aria/components.html), the documentation there applies also to all the components in this package. + +## Design decisions and assumptions + +This package provides a set of simple, ready to use components with the following features: + +- Agnostic (not tied to any known design system) +- Composable (they are ready to be the building blocks of other complex components) +- Theme-able (they can be themed, using both the provided basic theme as a baseline and custom CSS properties) +- Data-driven-less (they are dumb, presentational components) +- i18n-less (they do not provide i18n machinery or attached to any i18n framework or library) +- Built on a renowned headless CMS components library: [React Aria Components (RAC)](https://react-spectrum.adobe.com/react-aria/components.html) + +Since we are using RAC as the base, the styling of this package components are done via the [RAC styling options](https://react-spectrum.adobe.com/react-aria/styling.html). +See the `react-aria-components` section below for more information about RAC. +This package provides a simple and basic set of CSS rules to build upon. +Alternatively, you can bring your own styles, removing the basic styling or complementing it, and build on top of it. +You can even use RAC to use other CSS utility libraries, like TailwindCSS. + +## Styling + +This package provide a basic set of CSS rules. +You should add them to your project build to make the components properly styled. + +You can bring your own styles, but the CSS you provide should replace what the basic stylying does and style the bare components from scratch. + +You can use the CSS bundled for all components in a single file, or use the specific files for your components. +They are distributed along with the components code in the `dist` folder of the library. + +```js +import '@plone/components/dist/basic.css'; +``` + +or selectively: + +```js +import '@plone/components/src/styles/basic/TextField.css'; +``` + +## Theming + +You can use the basic styles as a baseline while building the theme of your site. +You can take advantage of them, as they are very thin and basic (almost vanilla CSS for the components). +Using them as a baseline will allow you to quickly build your theme around them. +`@plone/components` basic styles provide a simple, yet powerful, set of tokenized custom CSS properties that will help you customize your own styles on the top of the basic styling. +You can override them in your classes while maintaining them for others. + +### Quanta + +This package also features the Quanta components. +The Quanta theme is an example of it. +These components use the basic styling as a baseline, not only in styling, but also in the component side, reusing the CSS and custom CSS properties in it. + +Quanta is built upon the basic styles in an additive way. +The use of the Quanta CSS implies using it upon basic styling. +You could take Quanta as example to build your own layer of styles over basic styling for your theme. + +To use a theme built upon the basic styling, you need to import both the basic and the theme CSS, in this order: + +```js +import '@plone/components/dist/basic.css'; +import '@plone/components/dist/quanta.css'; +``` + +You have the option of doing it selectively per component, too: + +```js +import '@plone/components/src/styles/basic/TextField.css'; +import '@plone/components/src/styles/quanta/TextField.css'; +``` + +Take a look at the implementation of the Quanta components, using the basic ones as baseline in the `quanta` folders. + +Alternatively, as RAC allows, you can also drop your own basic set of styles. +You can take the basic styles as reference. +You can even remove the basic styling completely and bring your own CSS framework and push a new styling from scratch in there using the utilities of your choice, targeting the default RAC class names. +It's even possible to use TailwindCSS for styling the components in this package, using the RAC styling approach. + +## Components list + +### Basic + +- BlockToolbar +- Button +- Checkbox +- Container +- Dialog +- GridList +- Icon +- Link +- ListBox +- Menu +- Modal +- Popover +- Slider +- Table +- Tabs +- TagGroup +- ToggleButton +- Toolbar +- Tooltip + +### Forms + +- CheckboxField +- Form +- Meter +- NumberField +- SearchField +- Select +- TextAreaField +- TextField +- TimeField + +### Widgets + +- Calendar +- CheckboxField +- CheckboxGroup +- ComboBox +- DateField +- DatePicker +- DateRangePicker +- ProgressBar +- RadioGroup +- RangeCalendar +- Switch + +### Viewlets + +- Breadcrumbs + +### Views + +- DefaultBlockView +- RenderBlocks + +### Quanta + +- TextField +- TextAreaField +- Select + +## Quanta icons + +This package provides an implementation of the Quanta Icon set in React components. +They can be used directly in your components as: + +```tsx +import { ChevronupIcon, ChevrondownIcon, Button } from '@plone/components'; + +const MyComponent = (props) => ( + +) +``` + +## Helper providers + +### `flattenToAppURL` + +This provider allows you to pass down to your components a `flattenToAppURL` helper. +This helper can be different across platforms or frameworks, since the way to provide configuration can also be different. + +```tsx +import { FlattenToAppURLProvider } from '@plone/components'; +import { flattenToAppURL } from './utils'; + +const rootApp = ( + + {children} + +) +``` + +Then from your components: + +```tsx +import { useFlattenToAppURL } from '@plone/components'; +import { Link as RACLink } from 'react-aria-components'; + +const Link = (props: LinkProps, ref: ForwardedRef) => { + const { flattenToAppURL } = useFlattenToAppURL(); + const flattenedURL = flattenToAppURL(props.href); + + return ( + + {props.children} + + ); +}; +``` + +## Development + +This package follows a style guide (Storybook) driven development. +The components are developed in isolation, given their own Storybook stories. + +The components are expected to be data-driven-less. +They won't rely internally on any data retrieval facility or utilities (as in i18n). +They are expected to receive all the necessary data as props from the parent components. +In that regard, they should be "dumb" components that only take care of rendering. + +### Headless UI component library + +This package has the form of a headless UI component library. +A headless UI component library provides "white label" components that you can later style with your own styles. +It is not tied to any heavy, specific styling, nor to any CSS framework. +The vanilla CSS provided allows you to "drop-in" your own CSS framework, and build existing styling into the components. + +This post explains extensively its benefits: + +https://medium.com/@nirbenyair/headless-components-in-react-and-why-i-stopped-using-ui-libraries-a8208197c268 + +### `react-aria-components` + +`@plone/components` is based on Adobe's [`react-aria-components` library](https://react-spectrum.adobe.com/react-aria/react-aria-components.html). +React Aria Components is a library of unstyled components built on top of the React Aria library. +It provides a simpler way to build accessible components with custom styles, while offering the flexibility to drop down to hooks for even more customizability where needed. + +## Releases + +The release policy for this package follows a quick 1.0.0 release, as opposed to have an excessively long-lasting alpha/beta road to 1.0.0. +This is because the development of this package is expected to happen over the next few years. + +Breaking changes will be stated properly using semantic versioning. +However, an upgrade guide won't be supplied until the package is considered "ready for production". +The Volto Team will communicate this state properly when the moment comes. + +## PLIP #4352 + +This package is the result of the execution of the [Plone Improvement Proposal #4352](https://github.com/plone/volto/issues/4352). diff --git a/packages/components/netlify.toml b/packages/components/netlify.toml new file mode 100644 index 0000000000..dd96154375 --- /dev/null +++ b/packages/components/netlify.toml @@ -0,0 +1,2 @@ +[build] + ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ./src/" diff --git a/__tests__/fixtures/test-volto-project/addons/my-volto-config-addon/src/testaddon.js b/packages/components/news/.gitkeep similarity index 100% rename from __tests__/fixtures/test-volto-project/addons/my-volto-config-addon/src/testaddon.js rename to packages/components/news/.gitkeep diff --git a/packages/components/package.json b/packages/components/package.json new file mode 100644 index 0000000000..214f17e970 --- /dev/null +++ b/packages/components/package.json @@ -0,0 +1,140 @@ +{ + "name": "@plone/components", + "description": "ReactJS components for Plone", + "maintainers": [ + { + "name": "Plone Foundation", + "url": "http://plone.org" + } + ], + "license": "MIT", + "version": "2.0.0-alpha.7", + "repository": { + "type": "git", + "url": "http://github.com/plone/components.git" + }, + "bugs": { + "url": "https://github.com/plone/components/issues" + }, + "files": [ + "dist", + "src", + "README.md" + ], + "source": "./src/index.ts", + "main": "./dist/main.js", + "module": "./dist/module.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/module.mjs", + "require": "./dist/main.js" + }, + "./dist/*.css": "./dist/*.css", + "./src/*": "./src/*" + }, + "homepage": "https://plone.org", + "keywords": [ + "volto", + "plone", + "plone6", + "react", + "cms", + "components", + "quanta" + ], + "scripts": { + "build": "parcel build --no-cache && pnpm build:css", + "build:css": "pnpm build:basic && pnpm build:quanta", + "build:basic": "lightningcss --browserslist --bundle --sourcemap src/styles/basic/main.css -o basic.css && mv basic.css* dist/.", + "build:quanta": "lightningcss --browserslist --bundle --sourcemap src/styles/quanta/main.css -o quanta.css && mv quanta.css* dist/.", + "check-ts": "tsc --project tsconfig.json", + "test": "vitest --passWithNoTests", + "coverage": "vitest run --coverage --no-threads", + "lint": "pnpm eslint && pnpm prettier && pnpm stylelint", + "format": "pnpm eslint:fix && pnpm prettier:fix && pnpm stylelint:fix", + "eslint": "eslint 'src/**/*.{js,ts,tsx}' --quiet", + "eslint:fix": "eslint 'src/**/*.{js,ts,tsx}' --quiet --fix", + "prettier": "prettier --check 'src/**/*.{js,jsx,ts,tsx}'", + "prettier:fix": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'", + "stylelint": "stylelint 'src/**/*.{css,scss,less}'", + "stylelint:fix": "stylelint 'src/**/*.{css,scss,less}' --fix", + "dry-release": "release-it --dry-run", + "release": "release-it", + "release-major-alpha": "release-it major --preRelease=alpha", + "release-alpha": "release-it --preRelease=alpha", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "publishConfig": { + "access": "public" + }, + "browserslist": [ + ">0.5%", + "last 2 versions", + "not dead" + ], + "devDependencies": { + "@parcel/config-default": "^2.12.0", + "@parcel/core": "^2.12.0", + "@parcel/packager-ts": "^2.12.0", + "@parcel/transformer-js": "^2.12.0", + "@parcel/transformer-react-refresh-wrap": "^2.12.0", + "@parcel/transformer-typescript-types": "^2.12.0", + "@plone/types": "workspace: *", + "@react-types/shared": "^3.22.0", + "@storybook/addon-essentials": "^7.6.17", + "@storybook/addon-interactions": "^7.6.17", + "@storybook/addon-links": "^7.6.17", + "@storybook/blocks": "^7.6.17", + "@storybook/manager-api": "^7.6.17", + "@storybook/react": "^7.6.17", + "@storybook/react-vite": "^7.6.17", + "@storybook/testing-library": "^0.2.2", + "@storybook/theming": "^7.6.17", + "@testing-library/jest-dom": "6.4.2", + "@testing-library/react": "14.2.1", + "@types/jest-axe": "^3.5.7", + "@types/react": "^18", + "@types/react-dom": "^18", + "@typescript-eslint/eslint-plugin": "7.1.1", + "@typescript-eslint/parser": "7.1.1", + "@vitejs/plugin-react": "^4.1.0", + "@vitest/coverage-v8": "^1.3.1", + "browserslist": "^4.23.0", + "eslint": "^8.57.0", + "eslint-plugin-storybook": "^0.8.0", + "jest-axe": "^8.0.0", + "jsdom": "^22.1.0", + "lightningcss": "^1.24.0", + "lightningcss-cli": "^1.24.0", + "parcel": "^2.12.0", + "parcel-optimizer-react-client": "workspace:^", + "prettier": "3.2.5", + "release-it": "17.1.1", + "storybook": "^7.6.17", + "stylelint": "16.2.1", + "stylelint-config-idiomatic-order": "10.0.0", + "stylelint-prettier": "5.0.0", + "typescript": "5.2.2", + "vite": "^5.1.4", + "vitest": "^1.3.1", + "vitest-axe": "^0.1.0" + }, + "dependencies": { + "@react-aria/utils": "^3.22.0", + "@react-spectrum/utils": "^3.11.1", + "clsx": "^2.0.0", + "react-aria-components": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } +} diff --git a/packages/components/setupTesting.ts b/packages/components/setupTesting.ts new file mode 100644 index 0000000000..8bc87fa36e --- /dev/null +++ b/packages/components/setupTesting.ts @@ -0,0 +1,3 @@ +import '@testing-library/jest-dom'; +import { toHaveNoViolations } from 'jest-axe'; +expect.extend(toHaveNoViolations); diff --git a/packages/components/src/components/BlockToolbar/BlockToolbar.stories.tsx b/packages/components/src/components/BlockToolbar/BlockToolbar.stories.tsx new file mode 100644 index 0000000000..813366906f --- /dev/null +++ b/packages/components/src/components/BlockToolbar/BlockToolbar.stories.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { BlockToolbar } from './BlockToolbar'; +import { + Button, + Checkbox, + Group, + Separator, + Text, + ToggleButton, +} from 'react-aria-components'; +import { Menu, MenuItem } from '../Menu/Menu'; + +import { BoldIcon } from '../Icons/BoldIcon'; +import { ItalicIcon } from '../Icons/ItalicIcon'; +import { LinkIcon } from '../Icons/LinkIcon'; + +import type { Meta } from '@storybook/react'; +import { SettingsIcon } from '../Icons/SettingsIcon'; +import { RowbeforeIcon } from '../Icons/RowbeforeIcon'; +import { RowafterIcon } from '../Icons/RowafterIcon'; +import { MoreoptionsIcon } from '../Icons/MoreoptionsIcon'; +import { BinIcon } from '../Icons/BinIcon'; + +import '../../styles/basic/BlockToolbar.css'; + +const meta: Meta = { + component: BlockToolbar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +}; + +export default meta; + +export const Example = (args: any) => ( + + + + + + + + + + + + + + }> + + + Settings + + + + Insert block before + + + + Insert block after + + + + + Remove block + + + +); diff --git a/packages/components/src/components/BlockToolbar/BlockToolbar.tsx b/packages/components/src/components/BlockToolbar/BlockToolbar.tsx new file mode 100644 index 0000000000..62f1b47922 --- /dev/null +++ b/packages/components/src/components/BlockToolbar/BlockToolbar.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Toolbar as RACToolbar, ToolbarProps } from 'react-aria-components'; + +export function BlockToolbar(props: ToolbarProps) { + return ; +} diff --git a/packages/components/src/components/Breadcrumbs/Breadcrumb.stories.tsx b/packages/components/src/components/Breadcrumbs/Breadcrumb.stories.tsx new file mode 100644 index 0000000000..0f080c1c42 --- /dev/null +++ b/packages/components/src/components/Breadcrumbs/Breadcrumb.stories.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Breadcrumbs as BreadcrumbsComponent } from './Breadcrumbs'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Breadcrumbs.css'; + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Viewlets/Breadcrumbs', + component: BreadcrumbsComponent, + tags: ['autodocs'], + parameters: { + layout: 'centered', + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Default: Story = { + args: { + root: '/', + includeRoot: true, + items: [ + { '@id': '/folder', title: 'Folder' }, + { '@id': '/folder/page', title: 'Page' }, + ], + }, +}; + +export const NoRoot: Story = { + args: { + root: '/', + includeRoot: false, + items: [ + { '@id': '/folder', title: 'Folder' }, + { '@id': '/folder/page', title: 'Page' }, + ], + }, +}; diff --git a/packages/components/src/components/Breadcrumbs/Breadcrumbs.test.tsx b/packages/components/src/components/Breadcrumbs/Breadcrumbs.test.tsx new file mode 100644 index 0000000000..9092c7660b --- /dev/null +++ b/packages/components/src/components/Breadcrumbs/Breadcrumbs.test.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { axe, toHaveNoViolations } from 'jest-axe'; +import { Breadcrumbs } from './Breadcrumbs'; + +expect.extend(toHaveNoViolations); + +it('Breadcrumbs basic a11y test', async () => { + const { container } = render( + , + ); + + const results = await axe(container); + + expect(results).toHaveNoViolations(); +}); diff --git a/packages/components/src/components/Breadcrumbs/Breadcrumbs.tsx b/packages/components/src/components/Breadcrumbs/Breadcrumbs.tsx new file mode 100644 index 0000000000..c7f8f7dbd6 --- /dev/null +++ b/packages/components/src/components/Breadcrumbs/Breadcrumbs.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { + Breadcrumbs as RACBreadcrumbs, + Breadcrumb as RACBreadcrumb, +} from 'react-aria-components'; +import { Link } from '../Link/Link'; +import { HomeIcon } from './HomeIcon'; +import type { BreadcrumbsProps as RACBreadcrumbsProps } from 'react-aria-components'; + +type Breadcrumb = { + '@id': string; + title: string; +}; + +interface BreadcrumbsProps extends RACBreadcrumbsProps { + /** + * Current navigation root URL (flattened) + */ + root?: string; + /** + * Whether include the root item in the breadcrubs (based on the root prop) + */ + includeRoot?: boolean; +} + +/** + * Breadcrumbs display a hierarchy of links to the current page or resource in an application. + */ +export function Breadcrumbs({ + items, + root, + includeRoot, +}: BreadcrumbsProps) { + let itemsWithRoot: typeof items; + if (includeRoot) { + const rootItem: Breadcrumb = { + '@id': root || '/', + title: 'Home', + }; + itemsWithRoot = [rootItem, ...(items as Breadcrumb[])]; + } + + return ( + + ); +} diff --git a/packages/components/src/components/Breadcrumbs/HomeIcon.tsx b/packages/components/src/components/Breadcrumbs/HomeIcon.tsx new file mode 100644 index 0000000000..ce92d24e2e --- /dev/null +++ b/packages/components/src/components/Breadcrumbs/HomeIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const HomeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Button/Button.stories.tsx b/packages/components/src/components/Button/Button.stories.tsx new file mode 100644 index 0000000000..0c76f1801b --- /dev/null +++ b/packages/components/src/components/Button/Button.stories.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { Button } from './Button'; +import { Link } from '../Link/Link'; +import { Text } from 'react-aria-components'; +import { AddIcon } from '../Icons/AddIcon'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Button.css'; + +const meta = { + title: 'Components/Button', + component: Button, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + onPress: () => alert('Hello world!'), + }, +}; + +export const Disabled: Story = { + ...Default, + args: { + ...Default.args, + isDisabled: true, + }, +}; + +export const WithStyle: Story = { + render: (args: any) => ( + + ), + args: { + ...Default.args, + }, +}; + +export const Icon: Story = { + render: (args: any) => ( + + ), + args: { + ...Default.args, + }, +}; + +export const IconAndText: Story = { + render: (args: any) => ( + + ), + args: { + ...Default.args, + }, +}; + +export const AsLink: Story = { + render: (args: any) => ( + + Plone.org + + ), + args: { + ...Default.args, + }, +}; diff --git a/packages/components/src/components/Button/Button.tsx b/packages/components/src/components/Button/Button.tsx new file mode 100644 index 0000000000..b5f2ae1fa8 --- /dev/null +++ b/packages/components/src/components/Button/Button.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Button as RACButton, ButtonProps } from 'react-aria-components'; + +export function Button(props: ButtonProps) { + return ; +} diff --git a/packages/components/src/components/Calendar/Calendar.stories.tsx b/packages/components/src/components/Calendar/Calendar.stories.tsx new file mode 100644 index 0000000000..7449ae3dd3 --- /dev/null +++ b/packages/components/src/components/Calendar/Calendar.stories.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Calendar } from './Calendar'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Calendar.css'; + +const meta: Meta = { + title: 'Widgets/Calendar', + component: Calendar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , +}; diff --git a/packages/components/src/components/Calendar/Calendar.tsx b/packages/components/src/components/Calendar/Calendar.tsx new file mode 100644 index 0000000000..37f3b489c4 --- /dev/null +++ b/packages/components/src/components/Calendar/Calendar.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { + Button, + Calendar as RACCalendar, + CalendarCell, + CalendarGrid, + CalendarProps as RACCalendarProps, + DateValue, + Heading, + Text, +} from 'react-aria-components'; + +export interface CalendarProps + extends RACCalendarProps { + errorMessage?: string; +} + +export function Calendar({ + errorMessage, + ...props +}: CalendarProps) { + return ( + +
+ + + +
+ {(date) => } + {errorMessage && {errorMessage}} +
+ ); +} diff --git a/packages/components/src/components/Checkbox/Checkbox.stories.tsx b/packages/components/src/components/Checkbox/Checkbox.stories.tsx new file mode 100644 index 0000000000..fa26be0b8d --- /dev/null +++ b/packages/components/src/components/Checkbox/Checkbox.stories.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Checkbox } from './Checkbox'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Checkbox.css'; + +const meta = { + title: 'Components/Checkbox', + component: Checkbox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => Unsubscribe, +}; diff --git a/packages/components/src/components/Checkbox/Checkbox.tsx b/packages/components/src/components/Checkbox/Checkbox.tsx new file mode 100644 index 0000000000..a24407dd5b --- /dev/null +++ b/packages/components/src/components/Checkbox/Checkbox.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { + Checkbox as RACCheckbox, + CheckboxProps as RACCheckboxProps, +} from 'react-aria-components'; + +interface CheckboxProps extends RACCheckboxProps { + label?: string; +} + +export function Checkbox({ children, ...props }: CheckboxProps) { + return ( + + {({ isIndeterminate }) => ( + <> +
+ +
+ {props.label || children} + + )} +
+ ); +} diff --git a/packages/components/src/components/CheckboxField/CheckboxField.stories.tsx b/packages/components/src/components/CheckboxField/CheckboxField.stories.tsx new file mode 100644 index 0000000000..52d8e05085 --- /dev/null +++ b/packages/components/src/components/CheckboxField/CheckboxField.stories.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import { CheckboxField } from './CheckboxField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Forms/CheckboxField', + component: CheckboxField, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + // controlled value prop + value: { + control: { + disable: true, + }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Default: Story = { + args: { + name: 'empty', + label: 'field 1 title', + description: 'Optional help text', + }, +}; + +export const Required: Story = { + args: { + ...Default.args, + name: 'required', + isRequired: true, + }, +}; + +export const Filled: Story = { + args: { + ...Default.args, + name: 'field-filled', + label: 'Filled field title', + defaultSelected: true, + isRequired: true, + }, +}; + +export const Errored: Story = { + args: { + ...Default.args, + name: 'field-errored', + label: 'I accept the terms and conditions', + errorMessage: 'You should agree with the terms and conditions', + isInvalid: true, + isRequired: true, + }, +}; + +export const Disabled: Story = { + args: { + ...Default.args, + name: 'field-disabled', + label: 'Disabled field title', + isDisabled: true, + }, +}; diff --git a/packages/components/src/components/CheckboxField/CheckboxField.test.tsx b/packages/components/src/components/CheckboxField/CheckboxField.test.tsx new file mode 100644 index 0000000000..88956c677f --- /dev/null +++ b/packages/components/src/components/CheckboxField/CheckboxField.test.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { axe, toHaveNoViolations } from 'jest-axe'; +import { CheckboxField } from './CheckboxField'; + +expect.extend(toHaveNoViolations); + +it('CheckboxField basic a11y test', async () => { + const { container } = render( + , + ); + + const results = await axe(container); + + expect(results).toHaveNoViolations(); +}); diff --git a/packages/components/src/components/CheckboxField/CheckboxField.tsx b/packages/components/src/components/CheckboxField/CheckboxField.tsx new file mode 100644 index 0000000000..bbd083beee --- /dev/null +++ b/packages/components/src/components/CheckboxField/CheckboxField.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import type { CheckboxProps as RACCheckboxProps } from 'react-aria-components'; +import { Text } from 'react-aria-components'; +import { Checkbox } from '../Checkbox/Checkbox'; + +interface CheckboxProps extends RACCheckboxProps { + label?: string; + description?: string; + errorMessage?: string; +} + +export function CheckboxField({ + children, + errorMessage, + description, + ...props +}: CheckboxProps) { + return ( +
+ + {description && {description}} + {props.isInvalid && {errorMessage}} +
+ ); +} diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx new file mode 100644 index 0000000000..239ee9444c --- /dev/null +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Checkbox } from '../Checkbox/Checkbox'; +import { CheckboxGroup } from './CheckboxGroup'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/CheckboxGroup.css'; + +const meta = { + title: 'Widgets/CheckboxGroup', + component: CheckboxGroup, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Soccer + Baseball + Basketball + + ), + args: { + label: 'Favorite sports', + }, +}; diff --git a/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx new file mode 100644 index 0000000000..0c29059708 --- /dev/null +++ b/packages/components/src/components/CheckboxGroup/CheckboxGroup.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { + CheckboxGroup as RACCheckboxGroup, + CheckboxGroupProps as RACCheckboxGroupProps, + FieldError, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface CheckboxGroupProps + extends Omit { + children?: React.ReactNode; + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function CheckboxGroup({ + label, + description, + errorMessage, + children, + ...props +}: CheckboxGroupProps) { + return ( + + {label} + {children} + {description && {description}} + {errorMessage} + + ); +} diff --git a/packages/components/src/components/ComboBox/ComboBox.stories.tsx b/packages/components/src/components/ComboBox/ComboBox.stories.tsx new file mode 100644 index 0000000000..d016c58a81 --- /dev/null +++ b/packages/components/src/components/ComboBox/ComboBox.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { ComboBox, ComboBoxItem } from './ComboBox'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/ComboBox.css'; + +const meta = { + title: 'Widgets/ComboBox', + component: ComboBox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Chocolate + Mint + Strawberry + Vanilla + + ), + args: { + label: 'Ice cream flavor', + }, +}; diff --git a/packages/components/src/components/ComboBox/ComboBox.tsx b/packages/components/src/components/ComboBox/ComboBox.tsx new file mode 100644 index 0000000000..f3cc54422c --- /dev/null +++ b/packages/components/src/components/ComboBox/ComboBox.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { + Button, + ComboBox as RACComboBox, + ComboBoxProps as RACComboBoxProps, + FieldError, + Input, + Label, + ListBox, + ListBoxItem, + ListBoxItemProps, + Popover, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface ComboBoxProps + extends Omit, 'children'> { + label?: string; + description?: string | null; + errorMessage?: string | ((validation: ValidationResult) => string); + children: React.ReactNode | ((item: T) => React.ReactNode); +} + +export function ComboBox({ + label, + description, + errorMessage, + children, + ...props +}: ComboBoxProps) { + return ( + + +
+ + +
+ {description && {description}} + {errorMessage} + + {children} + +
+ ); +} + +export function ComboBoxItem(props: ListBoxItemProps) { + return ; +} diff --git a/packages/components/src/components/Container/Container.tsx b/packages/components/src/components/Container/Container.tsx new file mode 100644 index 0000000000..d291827690 --- /dev/null +++ b/packages/components/src/components/Container/Container.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import cx from 'clsx'; + +/** + * Props Types for the Container component. + * They are able to infer the props of the element type passed to the `as` prop. + */ +type ContainerProps = { + /** Primary content. */ + children: React.ReactNode; + /** An element type to render as (string or function). */ + as?: T; + /** Additional classes. */ + className?: string; + /** Layout size */ + layout?: boolean; + /** Narrow size. */ + narrow?: boolean; +} & React.ComponentPropsWithoutRef; + +export const Container = ( + props: ContainerProps, +) => { + const { + as: Component = 'div', + children, + className, + layout, + narrow, + ...rest + } = props; + const classes = cx('q', 'container', className, { layout, narrow }); + + return ( + + {children} + + ); +}; diff --git a/packages/components/src/components/DateField/DateField.stories.tsx b/packages/components/src/components/DateField/DateField.stories.tsx new file mode 100644 index 0000000000..352c34b650 --- /dev/null +++ b/packages/components/src/components/DateField/DateField.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { DateField } from './DateField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/DateField.css'; + +const meta: Meta = { + title: 'Widgets/DateField', + component: DateField, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Event date', + }, +}; diff --git a/packages/components/src/components/DateField/DateField.tsx b/packages/components/src/components/DateField/DateField.tsx new file mode 100644 index 0000000000..8f41e0a680 --- /dev/null +++ b/packages/components/src/components/DateField/DateField.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { + DateField as RACDateField, + DateFieldProps as RACDateFieldProps, + DateInput, + DateSegment, + DateValue, + FieldError, + Label, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface DateFieldProps + extends RACDateFieldProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function DateField({ + label, + description, + errorMessage, + ...props +}: DateFieldProps) { + return ( + + + {(segment) => } + {description && {description}} + {errorMessage} + + ); +} diff --git a/packages/components/src/components/DatePicker/DatePicker.stories.tsx b/packages/components/src/components/DatePicker/DatePicker.stories.tsx new file mode 100644 index 0000000000..247f79a2c0 --- /dev/null +++ b/packages/components/src/components/DatePicker/DatePicker.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { DatePicker } from './DatePicker'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/DatePicker.css'; + +const meta: Meta = { + title: 'Widgets/DatePicker', + component: DatePicker, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Event date', + }, +}; diff --git a/packages/components/src/components/DatePicker/DatePicker.tsx b/packages/components/src/components/DatePicker/DatePicker.tsx new file mode 100644 index 0000000000..b49bc7e493 --- /dev/null +++ b/packages/components/src/components/DatePicker/DatePicker.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { + Button, + Calendar, + CalendarCell, + CalendarGrid, + DateInput, + DatePicker as RACDatePicker, + DatePickerProps as RACDatePickerProps, + DateSegment, + DateValue, + Dialog, + FieldError, + Group, + Heading, + Label, + Popover, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface DatePickerProps + extends RACDatePickerProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function DatePicker({ + label, + description, + errorMessage, + ...props +}: DatePickerProps) { + return ( + + + + {(segment) => } + + + {description && {description}} + {errorMessage} + + + +
+ + + +
+ + {(date) => } + +
+
+
+
+ ); +} diff --git a/packages/components/src/components/DateRangePicker/DateRangePicker.stories.tsx b/packages/components/src/components/DateRangePicker/DateRangePicker.stories.tsx new file mode 100644 index 0000000000..a926072990 --- /dev/null +++ b/packages/components/src/components/DateRangePicker/DateRangePicker.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { DateRangePicker } from './DateRangePicker'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/DateRangePicker.css'; + +const meta: Meta = { + title: 'Widgets/DateRangePicker', + component: DateRangePicker, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Event date', + }, +}; diff --git a/packages/components/src/components/DateRangePicker/DateRangePicker.tsx b/packages/components/src/components/DateRangePicker/DateRangePicker.tsx new file mode 100644 index 0000000000..55b76c5fde --- /dev/null +++ b/packages/components/src/components/DateRangePicker/DateRangePicker.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { + Button, + CalendarCell, + CalendarGrid, + DateInput, + DateRangePicker as RACDateRangePicker, + DateRangePickerProps as RACDateRangePickerProps, + DateSegment, + DateValue, + Dialog, + FieldError, + Group, + Heading, + Label, + Popover, + RangeCalendar, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface DateRangePickerProps + extends RACDateRangePickerProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function DateRangePicker({ + label, + description, + errorMessage, + ...props +}: DateRangePickerProps) { + return ( + + + + + {(segment) => } + + + + {(segment) => } + + + + {description && {description}} + {errorMessage} + + + +
+ + + +
+ + {(date) => } + +
+
+
+
+ ); +} diff --git a/packages/components/src/components/Dialog/Dialog.stories.tsx b/packages/components/src/components/Dialog/Dialog.stories.tsx new file mode 100644 index 0000000000..8061cd1745 --- /dev/null +++ b/packages/components/src/components/Dialog/Dialog.stories.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { Dialog } from './Dialog'; +import { Button } from '../Button/Button'; +import { + DialogTrigger, + Heading, + Input, + Label, + Modal, + TextField, +} from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Dialog.css'; + +const meta = { + component: Dialog, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + + + + {({ close }) => ( +
+ Sign up + + + + + + + + + +
+ )} +
+
+
+ ), +}; diff --git a/packages/components/src/components/Dialog/Dialog.tsx b/packages/components/src/components/Dialog/Dialog.tsx new file mode 100644 index 0000000000..39de5afd8e --- /dev/null +++ b/packages/components/src/components/Dialog/Dialog.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Dialog as RACDialog, DialogProps } from 'react-aria-components'; + +export function Dialog(props: DialogProps) { + return ; +} diff --git a/packages/components/src/components/Form/Form.stories.tsx b/packages/components/src/components/Form/Form.stories.tsx new file mode 100644 index 0000000000..1e3215d15c --- /dev/null +++ b/packages/components/src/components/Form/Form.stories.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Form } from './Form'; +import { + Button, + FieldError, + Input, + Label, + TextField, +} from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Form.css'; + +const meta = { + title: 'Forms/Form', + component: Form, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( +
+ + + + + + +
+ ), + args: {}, +}; diff --git a/packages/components/src/components/Form/Form.tsx b/packages/components/src/components/Form/Form.tsx new file mode 100644 index 0000000000..f2f2e9b70a --- /dev/null +++ b/packages/components/src/components/Form/Form.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Form as RACForm, FormProps } from 'react-aria-components'; + +export function Form(props: FormProps) { + return ; +} diff --git a/packages/components/src/components/GridList/GridList.stories.tsx b/packages/components/src/components/GridList/GridList.stories.tsx new file mode 100644 index 0000000000..eb399bb648 --- /dev/null +++ b/packages/components/src/components/GridList/GridList.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { GridList, GridListItem } from './GridList'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/GridList.css'; + +const meta = { + component: GridList, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Chocolate + Mint + Strawberry + Vanilla + + ), + args: { + onAction: null, + selectionMode: 'multiple', + }, +}; diff --git a/packages/components/src/components/GridList/GridList.tsx b/packages/components/src/components/GridList/GridList.tsx new file mode 100644 index 0000000000..d195b71cfd --- /dev/null +++ b/packages/components/src/components/GridList/GridList.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { + Button, + GridList as RACGridList, + GridListItem as RACGridListItem, + GridListItemProps, + GridListProps, +} from 'react-aria-components'; + +import { Checkbox } from '../Checkbox/Checkbox'; + +export function GridList({ + children, + ...props +}: GridListProps) { + return {children}; +} + +export function GridListItem({ children, ...props }: GridListItemProps) { + let textValue = typeof children === 'string' ? children : undefined; + return ( + + {({ selectionMode, selectionBehavior, allowsDragging }) => ( + <> + {/* Add elements for drag and drop and selection. */} + {allowsDragging && } + {selectionMode === 'multiple' && selectionBehavior === 'toggle' && ( + + )} + {children} + + )} + + ); +} diff --git a/packages/components/src/components/Icon/Icon.stories.tsx b/packages/components/src/components/Icon/Icon.stories.tsx new file mode 100644 index 0000000000..cb2387c46c --- /dev/null +++ b/packages/components/src/components/Icon/Icon.stories.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { Icon } from './Icon'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/icons.css'; + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Components/Icon', + component: Icon, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], + argTypes: { + size: { + options: ['XS', 'S', 'M', 'L', 'XL', 'XXL'], + control: { type: 'radio' }, + }, + color: { + options: ['informative', 'negative', 'notice', 'positive'], + control: { type: 'radio' }, + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Default: Story = { + args: { + size: 'L', + children: ( + + + + ), + }, +}; diff --git a/packages/components/src/components/Icon/Icon.tsx b/packages/components/src/components/Icon/Icon.tsx new file mode 100644 index 0000000000..0056688024 --- /dev/null +++ b/packages/components/src/components/Icon/Icon.tsx @@ -0,0 +1,90 @@ +import React, { ReactElement } from 'react'; +import type { + AriaLabelingProps, + DOMProps, + IconColorValue, + StyleProps, +} from '@react-types/shared'; +import { + baseStyleProps, + StyleHandlers, + useSlotProps, + useStyleProps, +} from '@react-spectrum/utils'; +import { filterDOMProps } from '@react-aria/utils'; +import _clsx from 'clsx'; + +export interface IconProps extends DOMProps, AriaLabelingProps, StyleProps { + /** + * A screen reader only label for the Icon. + */ + 'aria-label'?: string; + /** + * The content to display. Should be an SVG. + */ + children: ReactElement; + /** + * Size of Icon (changes based on scale). + */ + size?: 'XXS' | 'XS' | 'S' | 'M' | 'L' | 'XL' | 'XXL'; + /** + * A slot to place the icon in. + * @default 'icon' + */ + slot?: string; + /** + * Indicates whether the element is exposed to an accessibility API. + */ + 'aria-hidden'?: boolean | 'false' | 'true'; + /** + * Color of the Icon. + */ + color?: IconColorValue; +} + +export type IconPropsWithoutChildren = Omit; + +function iconColorValue(value: IconColorValue) { + return `var(--quanta-color-icon-${value})`; +} + +const iconStyleProps: StyleHandlers = { + ...baseStyleProps, + color: ['color', iconColorValue], +}; + +/** + * Spectrum icons are clear, minimal, and consistent across platforms. They follow the focused and rational principles of the design system in both metaphor and style. + */ +export function Icon(props: IconProps) { + props = useSlotProps(props, 'icon'); + let { + children, + size, + 'aria-label': ariaLabel, + 'aria-hidden': ariaHidden, + ...otherProps + } = props; + let { styleProps } = useStyleProps(otherProps, iconStyleProps); + + if (!ariaHidden) { + ariaHidden = undefined; + } + + let iconSize = size ? size : 'M'; + + return React.cloneElement(children, { + ...filterDOMProps(otherProps), + ...styleProps, + focusable: 'false', + 'aria-label': ariaLabel, + 'aria-hidden': ariaLabel ? ariaHidden || undefined : true, + role: 'img', + className: _clsx( + 'q icon', + `icon--size${iconSize}`, + children.props.className, + styleProps.className, + ), + }); +} diff --git a/packages/components/src/components/Icons/AddIcon.tsx b/packages/components/src/components/Icons/AddIcon.tsx new file mode 100644 index 0000000000..d92406abf6 --- /dev/null +++ b/packages/components/src/components/Icons/AddIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AddIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/AligncenterIcon.tsx b/packages/components/src/components/Icons/AligncenterIcon.tsx new file mode 100644 index 0000000000..1cdd6cf80d --- /dev/null +++ b/packages/components/src/components/Icons/AligncenterIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AligncenterIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/AlignleftIcon.tsx b/packages/components/src/components/Icons/AlignleftIcon.tsx new file mode 100644 index 0000000000..65edf19261 --- /dev/null +++ b/packages/components/src/components/Icons/AlignleftIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AlignleftIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/AlignrightIcon.tsx b/packages/components/src/components/Icons/AlignrightIcon.tsx new file mode 100644 index 0000000000..6fe8aa0ce1 --- /dev/null +++ b/packages/components/src/components/Icons/AlignrightIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AlignrightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArchiveIcon.tsx b/packages/components/src/components/Icons/ArchiveIcon.tsx new file mode 100644 index 0000000000..282a5dab83 --- /dev/null +++ b/packages/components/src/components/Icons/ArchiveIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArchiveIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArrowdownIcon.tsx b/packages/components/src/components/Icons/ArrowdownIcon.tsx new file mode 100644 index 0000000000..275e236a9b --- /dev/null +++ b/packages/components/src/components/Icons/ArrowdownIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArrowdownIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArrowleftIcon.tsx b/packages/components/src/components/Icons/ArrowleftIcon.tsx new file mode 100644 index 0000000000..04676b026a --- /dev/null +++ b/packages/components/src/components/Icons/ArrowleftIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArrowleftIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArrowrightIcon.tsx b/packages/components/src/components/Icons/ArrowrightIcon.tsx new file mode 100644 index 0000000000..e7edf57858 --- /dev/null +++ b/packages/components/src/components/Icons/ArrowrightIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArrowrightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArrowtoprightIcon.tsx b/packages/components/src/components/Icons/ArrowtoprightIcon.tsx new file mode 100644 index 0000000000..8c8a551838 --- /dev/null +++ b/packages/components/src/components/Icons/ArrowtoprightIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArrowtoprightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ArrowupIcon.tsx b/packages/components/src/components/Icons/ArrowupIcon.tsx new file mode 100644 index 0000000000..3d60dc331e --- /dev/null +++ b/packages/components/src/components/Icons/ArrowupIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ArrowupIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/AttachmentIcon.tsx b/packages/components/src/components/Icons/AttachmentIcon.tsx new file mode 100644 index 0000000000..37e0943da5 --- /dev/null +++ b/packages/components/src/components/Icons/AttachmentIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AttachmentIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/AutomatedcontentIcon.tsx b/packages/components/src/components/Icons/AutomatedcontentIcon.tsx new file mode 100644 index 0000000000..c2fa0fba2a --- /dev/null +++ b/packages/components/src/components/Icons/AutomatedcontentIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const AutomatedcontentIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/BackgroundIcon.tsx b/packages/components/src/components/Icons/BackgroundIcon.tsx new file mode 100644 index 0000000000..b874142988 --- /dev/null +++ b/packages/components/src/components/Icons/BackgroundIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const BackgroundIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/BinIcon.tsx b/packages/components/src/components/Icons/BinIcon.tsx new file mode 100644 index 0000000000..24399b68f6 --- /dev/null +++ b/packages/components/src/components/Icons/BinIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const BinIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/BlindIcon.tsx b/packages/components/src/components/Icons/BlindIcon.tsx new file mode 100644 index 0000000000..d3bcaef960 --- /dev/null +++ b/packages/components/src/components/Icons/BlindIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const BlindIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/BoldIcon.tsx b/packages/components/src/components/Icons/BoldIcon.tsx new file mode 100644 index 0000000000..1f6f989a85 --- /dev/null +++ b/packages/components/src/components/Icons/BoldIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const BoldIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CalendarIcon.tsx b/packages/components/src/components/Icons/CalendarIcon.tsx new file mode 100644 index 0000000000..fc2d9f7072 --- /dev/null +++ b/packages/components/src/components/Icons/CalendarIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CalendarIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CheckboxIcon.tsx b/packages/components/src/components/Icons/CheckboxIcon.tsx new file mode 100644 index 0000000000..2f2323fc9b --- /dev/null +++ b/packages/components/src/components/Icons/CheckboxIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CheckboxIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ChevrondownIcon.tsx b/packages/components/src/components/Icons/ChevrondownIcon.tsx new file mode 100644 index 0000000000..4463ddb202 --- /dev/null +++ b/packages/components/src/components/Icons/ChevrondownIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ChevrondownIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ChevronleftIcon.tsx b/packages/components/src/components/Icons/ChevronleftIcon.tsx new file mode 100644 index 0000000000..4637b0c8d2 --- /dev/null +++ b/packages/components/src/components/Icons/ChevronleftIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ChevronleftIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ChevronrightIcon.tsx b/packages/components/src/components/Icons/ChevronrightIcon.tsx new file mode 100644 index 0000000000..5f51fdba82 --- /dev/null +++ b/packages/components/src/components/Icons/ChevronrightIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ChevronrightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ChevronupIcon.tsx b/packages/components/src/components/Icons/ChevronupIcon.tsx new file mode 100644 index 0000000000..0d55eaa278 --- /dev/null +++ b/packages/components/src/components/Icons/ChevronupIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ChevronupIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CloseIcon.tsx b/packages/components/src/components/Icons/CloseIcon.tsx new file mode 100644 index 0000000000..5c77e5af9a --- /dev/null +++ b/packages/components/src/components/Icons/CloseIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CloseIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CodeIcon.tsx b/packages/components/src/components/Icons/CodeIcon.tsx new file mode 100644 index 0000000000..5a4ce60d25 --- /dev/null +++ b/packages/components/src/components/Icons/CodeIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CodeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CollectionIcon.tsx b/packages/components/src/components/Icons/CollectionIcon.tsx new file mode 100644 index 0000000000..ebc218f204 --- /dev/null +++ b/packages/components/src/components/Icons/CollectionIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CollectionIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ColumnafterIcon.tsx b/packages/components/src/components/Icons/ColumnafterIcon.tsx new file mode 100644 index 0000000000..1e37f757e9 --- /dev/null +++ b/packages/components/src/components/Icons/ColumnafterIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ColumnafterIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ColumnbeforeIcon.tsx b/packages/components/src/components/Icons/ColumnbeforeIcon.tsx new file mode 100644 index 0000000000..fe8024efa7 --- /dev/null +++ b/packages/components/src/components/Icons/ColumnbeforeIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ColumnbeforeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ColumndeleteIcon.tsx b/packages/components/src/components/Icons/ColumndeleteIcon.tsx new file mode 100644 index 0000000000..734c9fd474 --- /dev/null +++ b/packages/components/src/components/Icons/ColumndeleteIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ColumndeleteIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ColumnsIcon.tsx b/packages/components/src/components/Icons/ColumnsIcon.tsx new file mode 100644 index 0000000000..11eca1d197 --- /dev/null +++ b/packages/components/src/components/Icons/ColumnsIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ColumnsIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CopyIcon.tsx b/packages/components/src/components/Icons/CopyIcon.tsx new file mode 100644 index 0000000000..90a523389b --- /dev/null +++ b/packages/components/src/components/Icons/CopyIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CopyIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/CutIcon.tsx b/packages/components/src/components/Icons/CutIcon.tsx new file mode 100644 index 0000000000..03664a9fc9 --- /dev/null +++ b/packages/components/src/components/Icons/CutIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const CutIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/DashIcon.tsx b/packages/components/src/components/Icons/DashIcon.tsx new file mode 100644 index 0000000000..f9b1d92008 --- /dev/null +++ b/packages/components/src/components/Icons/DashIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const DashIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/DiscussionIcon.tsx b/packages/components/src/components/Icons/DiscussionIcon.tsx new file mode 100644 index 0000000000..b3b842b1d4 --- /dev/null +++ b/packages/components/src/components/Icons/DiscussionIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const DiscussionIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/DraggableIcon.tsx b/packages/components/src/components/Icons/DraggableIcon.tsx new file mode 100644 index 0000000000..2fe2f50b23 --- /dev/null +++ b/packages/components/src/components/Icons/DraggableIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const DraggableIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/EditIcon.tsx b/packages/components/src/components/Icons/EditIcon.tsx new file mode 100644 index 0000000000..3a2bf44daf --- /dev/null +++ b/packages/components/src/components/Icons/EditIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const EditIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/EyeIcon.tsx b/packages/components/src/components/Icons/EyeIcon.tsx new file mode 100644 index 0000000000..5f5d722f1b --- /dev/null +++ b/packages/components/src/components/Icons/EyeIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const EyeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/FilterIcon.tsx b/packages/components/src/components/Icons/FilterIcon.tsx new file mode 100644 index 0000000000..b6cebb0f84 --- /dev/null +++ b/packages/components/src/components/Icons/FilterIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const FilterIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/FolderIcon.tsx b/packages/components/src/components/Icons/FolderIcon.tsx new file mode 100644 index 0000000000..fb78fac7d2 --- /dev/null +++ b/packages/components/src/components/Icons/FolderIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const FolderIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/FooterIcon.tsx b/packages/components/src/components/Icons/FooterIcon.tsx new file mode 100644 index 0000000000..fa77121914 --- /dev/null +++ b/packages/components/src/components/Icons/FooterIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const FooterIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ForegroundIcon.tsx b/packages/components/src/components/Icons/ForegroundIcon.tsx new file mode 100644 index 0000000000..c3a8fcd4a7 --- /dev/null +++ b/packages/components/src/components/Icons/ForegroundIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ForegroundIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/FullscreenIcon.tsx b/packages/components/src/components/Icons/FullscreenIcon.tsx new file mode 100644 index 0000000000..453551ae78 --- /dev/null +++ b/packages/components/src/components/Icons/FullscreenIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const FullscreenIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/HighlightIcon.tsx b/packages/components/src/components/Icons/HighlightIcon.tsx new file mode 100644 index 0000000000..ad1fd01e5b --- /dev/null +++ b/packages/components/src/components/Icons/HighlightIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const HighlightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/HistoryIcon.tsx b/packages/components/src/components/Icons/HistoryIcon.tsx new file mode 100644 index 0000000000..a01729b06f --- /dev/null +++ b/packages/components/src/components/Icons/HistoryIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const HistoryIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/HomeIcon.tsx b/packages/components/src/components/Icons/HomeIcon.tsx new file mode 100644 index 0000000000..789d116344 --- /dev/null +++ b/packages/components/src/components/Icons/HomeIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const HomeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ImageIcon.tsx b/packages/components/src/components/Icons/ImageIcon.tsx new file mode 100644 index 0000000000..096038b8a8 --- /dev/null +++ b/packages/components/src/components/Icons/ImageIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ImageIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ImagefitIcon.tsx b/packages/components/src/components/Icons/ImagefitIcon.tsx new file mode 100644 index 0000000000..9a7da42774 --- /dev/null +++ b/packages/components/src/components/Icons/ImagefitIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ImagefitIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ImagefullIcon.tsx b/packages/components/src/components/Icons/ImagefullIcon.tsx new file mode 100644 index 0000000000..de22f864e0 --- /dev/null +++ b/packages/components/src/components/Icons/ImagefullIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ImagefullIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ImageleftIcon.tsx b/packages/components/src/components/Icons/ImageleftIcon.tsx new file mode 100644 index 0000000000..2abaa460a9 --- /dev/null +++ b/packages/components/src/components/Icons/ImageleftIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ImageleftIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ImagerightIcon.tsx b/packages/components/src/components/Icons/ImagerightIcon.tsx new file mode 100644 index 0000000000..79767a4e40 --- /dev/null +++ b/packages/components/src/components/Icons/ImagerightIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ImagerightIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/InfoIcon.tsx b/packages/components/src/components/Icons/InfoIcon.tsx new file mode 100644 index 0000000000..033507ce74 --- /dev/null +++ b/packages/components/src/components/Icons/InfoIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const InfoIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ItalicIcon.tsx b/packages/components/src/components/Icons/ItalicIcon.tsx new file mode 100644 index 0000000000..09a3845ea4 --- /dev/null +++ b/packages/components/src/components/Icons/ItalicIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ItalicIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/LanguageIcon.tsx b/packages/components/src/components/Icons/LanguageIcon.tsx new file mode 100644 index 0000000000..3a26bc3d35 --- /dev/null +++ b/packages/components/src/components/Icons/LanguageIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const LanguageIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/LeadingIcon.tsx b/packages/components/src/components/Icons/LeadingIcon.tsx new file mode 100644 index 0000000000..61c2e88e87 --- /dev/null +++ b/packages/components/src/components/Icons/LeadingIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const LeadingIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/LeadingimageIcon.tsx b/packages/components/src/components/Icons/LeadingimageIcon.tsx new file mode 100644 index 0000000000..6bc15667da --- /dev/null +++ b/packages/components/src/components/Icons/LeadingimageIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const LeadingimageIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/LinkIcon.tsx b/packages/components/src/components/Icons/LinkIcon.tsx new file mode 100644 index 0000000000..2455343556 --- /dev/null +++ b/packages/components/src/components/Icons/LinkIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const LinkIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ListIcon.tsx b/packages/components/src/components/Icons/ListIcon.tsx new file mode 100644 index 0000000000..368fcaffab --- /dev/null +++ b/packages/components/src/components/Icons/ListIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ListIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ListnumbersIcon.tsx b/packages/components/src/components/Icons/ListnumbersIcon.tsx new file mode 100644 index 0000000000..1f1cd1f18a --- /dev/null +++ b/packages/components/src/components/Icons/ListnumbersIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ListnumbersIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MailIcon.tsx b/packages/components/src/components/Icons/MailIcon.tsx new file mode 100644 index 0000000000..510916dabf --- /dev/null +++ b/packages/components/src/components/Icons/MailIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MailIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MandatoryIcon.tsx b/packages/components/src/components/Icons/MandatoryIcon.tsx new file mode 100644 index 0000000000..a5f174642a --- /dev/null +++ b/packages/components/src/components/Icons/MandatoryIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MandatoryIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MapIcon.tsx b/packages/components/src/components/Icons/MapIcon.tsx new file mode 100644 index 0000000000..c438bea0b3 --- /dev/null +++ b/packages/components/src/components/Icons/MapIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MapIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MenuIcon.tsx b/packages/components/src/components/Icons/MenuIcon.tsx new file mode 100644 index 0000000000..4f36dcd43b --- /dev/null +++ b/packages/components/src/components/Icons/MenuIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MenuIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MergedIcon.tsx b/packages/components/src/components/Icons/MergedIcon.tsx new file mode 100644 index 0000000000..6a55e315ff --- /dev/null +++ b/packages/components/src/components/Icons/MergedIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MergedIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/MoreoptionsIcon.tsx b/packages/components/src/components/Icons/MoreoptionsIcon.tsx new file mode 100644 index 0000000000..12bbde31b4 --- /dev/null +++ b/packages/components/src/components/Icons/MoreoptionsIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const MoreoptionsIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/NavigationIcon.tsx b/packages/components/src/components/Icons/NavigationIcon.tsx new file mode 100644 index 0000000000..abdbeb37ec --- /dev/null +++ b/packages/components/src/components/Icons/NavigationIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const NavigationIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/NewsIcon.tsx b/packages/components/src/components/Icons/NewsIcon.tsx new file mode 100644 index 0000000000..2518611977 --- /dev/null +++ b/packages/components/src/components/Icons/NewsIcon.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const NewsIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/OutIcon.tsx b/packages/components/src/components/Icons/OutIcon.tsx new file mode 100644 index 0000000000..ea38107788 --- /dev/null +++ b/packages/components/src/components/Icons/OutIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const OutIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PageIcon.tsx b/packages/components/src/components/Icons/PageIcon.tsx new file mode 100644 index 0000000000..0c6c99e194 --- /dev/null +++ b/packages/components/src/components/Icons/PageIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PageIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ParagraphIcon.tsx b/packages/components/src/components/Icons/ParagraphIcon.tsx new file mode 100644 index 0000000000..08a30d2668 --- /dev/null +++ b/packages/components/src/components/Icons/ParagraphIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ParagraphIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PasteIcon.tsx b/packages/components/src/components/Icons/PasteIcon.tsx new file mode 100644 index 0000000000..a51e6cda0a --- /dev/null +++ b/packages/components/src/components/Icons/PasteIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PasteIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PauseIcon.tsx b/packages/components/src/components/Icons/PauseIcon.tsx new file mode 100644 index 0000000000..e3a8360906 --- /dev/null +++ b/packages/components/src/components/Icons/PauseIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PauseIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PencilIcon.tsx b/packages/components/src/components/Icons/PencilIcon.tsx new file mode 100644 index 0000000000..ece481a293 --- /dev/null +++ b/packages/components/src/components/Icons/PencilIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PencilIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PlayIcon.tsx b/packages/components/src/components/Icons/PlayIcon.tsx new file mode 100644 index 0000000000..c11a0c8a61 --- /dev/null +++ b/packages/components/src/components/Icons/PlayIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PlayIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/PropertiesIcon.tsx b/packages/components/src/components/Icons/PropertiesIcon.tsx new file mode 100644 index 0000000000..b6a123610c --- /dev/null +++ b/packages/components/src/components/Icons/PropertiesIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const PropertiesIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/QuotesIcon.tsx b/packages/components/src/components/Icons/QuotesIcon.tsx new file mode 100644 index 0000000000..f1ff52dcb2 --- /dev/null +++ b/packages/components/src/components/Icons/QuotesIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const QuotesIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RadiobuttonIcon.tsx b/packages/components/src/components/Icons/RadiobuttonIcon.tsx new file mode 100644 index 0000000000..9f3e9e7c59 --- /dev/null +++ b/packages/components/src/components/Icons/RadiobuttonIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RadiobuttonIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RedoIcon.tsx b/packages/components/src/components/Icons/RedoIcon.tsx new file mode 100644 index 0000000000..285a81d94a --- /dev/null +++ b/packages/components/src/components/Icons/RedoIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RedoIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RenameIcon.tsx b/packages/components/src/components/Icons/RenameIcon.tsx new file mode 100644 index 0000000000..3431df883a --- /dev/null +++ b/packages/components/src/components/Icons/RenameIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RenameIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ReverseIcon.tsx b/packages/components/src/components/Icons/ReverseIcon.tsx new file mode 100644 index 0000000000..b1c7f13f14 --- /dev/null +++ b/packages/components/src/components/Icons/ReverseIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ReverseIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ReviewIcon.tsx b/packages/components/src/components/Icons/ReviewIcon.tsx new file mode 100644 index 0000000000..3d62fbd402 --- /dev/null +++ b/packages/components/src/components/Icons/ReviewIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ReviewIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RowafterIcon.tsx b/packages/components/src/components/Icons/RowafterIcon.tsx new file mode 100644 index 0000000000..d25cc04ab9 --- /dev/null +++ b/packages/components/src/components/Icons/RowafterIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RowafterIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RowbeforeIcon.tsx b/packages/components/src/components/Icons/RowbeforeIcon.tsx new file mode 100644 index 0000000000..4b967cc074 --- /dev/null +++ b/packages/components/src/components/Icons/RowbeforeIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RowbeforeIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/RowdeleteIcon.tsx b/packages/components/src/components/Icons/RowdeleteIcon.tsx new file mode 100644 index 0000000000..790bacd8a2 --- /dev/null +++ b/packages/components/src/components/Icons/RowdeleteIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const RowdeleteIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SearchIcon.tsx b/packages/components/src/components/Icons/SearchIcon.tsx new file mode 100644 index 0000000000..24b87ea169 --- /dev/null +++ b/packages/components/src/components/Icons/SearchIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SearchIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SecurityIcon.tsx b/packages/components/src/components/Icons/SecurityIcon.tsx new file mode 100644 index 0000000000..d65deec4fc --- /dev/null +++ b/packages/components/src/components/Icons/SecurityIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SecurityIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SettingsIcon.tsx b/packages/components/src/components/Icons/SettingsIcon.tsx new file mode 100644 index 0000000000..3c3b6cfa5c --- /dev/null +++ b/packages/components/src/components/Icons/SettingsIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SettingsIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ShareIcon.tsx b/packages/components/src/components/Icons/ShareIcon.tsx new file mode 100644 index 0000000000..4274e2a232 --- /dev/null +++ b/packages/components/src/components/Icons/ShareIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ShareIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SliderIcon.tsx b/packages/components/src/components/Icons/SliderIcon.tsx new file mode 100644 index 0000000000..2370775cb8 --- /dev/null +++ b/packages/components/src/components/Icons/SliderIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SliderIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SocialIcon.tsx b/packages/components/src/components/Icons/SocialIcon.tsx new file mode 100644 index 0000000000..4180cd5f2f --- /dev/null +++ b/packages/components/src/components/Icons/SocialIcon.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SocialIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SpacerIcon.tsx b/packages/components/src/components/Icons/SpacerIcon.tsx new file mode 100644 index 0000000000..7aa56b4785 --- /dev/null +++ b/packages/components/src/components/Icons/SpacerIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SpacerIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/StateIcon.tsx b/packages/components/src/components/Icons/StateIcon.tsx new file mode 100644 index 0000000000..a234d46703 --- /dev/null +++ b/packages/components/src/components/Icons/StateIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const StateIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/SubtitleIcon.tsx b/packages/components/src/components/Icons/SubtitleIcon.tsx new file mode 100644 index 0000000000..1684aa1b41 --- /dev/null +++ b/packages/components/src/components/Icons/SubtitleIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const SubtitleIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/TableIcon.tsx b/packages/components/src/components/Icons/TableIcon.tsx new file mode 100644 index 0000000000..92fe6f762e --- /dev/null +++ b/packages/components/src/components/Icons/TableIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const TableIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/TagIcon.tsx b/packages/components/src/components/Icons/TagIcon.tsx new file mode 100644 index 0000000000..77e722fb6a --- /dev/null +++ b/packages/components/src/components/Icons/TagIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const TagIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/TextIcon.tsx b/packages/components/src/components/Icons/TextIcon.tsx new file mode 100644 index 0000000000..d2eeb554a1 --- /dev/null +++ b/packages/components/src/components/Icons/TextIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const TextIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/ThumbnailsIcon.tsx b/packages/components/src/components/Icons/ThumbnailsIcon.tsx new file mode 100644 index 0000000000..5748935fcc --- /dev/null +++ b/packages/components/src/components/Icons/ThumbnailsIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const ThumbnailsIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/TitleIcon.tsx b/packages/components/src/components/Icons/TitleIcon.tsx new file mode 100644 index 0000000000..f8c3d03ce8 --- /dev/null +++ b/packages/components/src/components/Icons/TitleIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const TitleIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/TocIcon.tsx b/packages/components/src/components/Icons/TocIcon.tsx new file mode 100644 index 0000000000..0e2b68f3d0 --- /dev/null +++ b/packages/components/src/components/Icons/TocIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const TocIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/UndoIcon.tsx b/packages/components/src/components/Icons/UndoIcon.tsx new file mode 100644 index 0000000000..aabb05039a --- /dev/null +++ b/packages/components/src/components/Icons/UndoIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const UndoIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/UploadIcon.tsx b/packages/components/src/components/Icons/UploadIcon.tsx new file mode 100644 index 0000000000..cf05bb6bc3 --- /dev/null +++ b/packages/components/src/components/Icons/UploadIcon.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const UploadIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/UserIcon.tsx b/packages/components/src/components/Icons/UserIcon.tsx new file mode 100644 index 0000000000..8eccdfa89e --- /dev/null +++ b/packages/components/src/components/Icons/UserIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const UserIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/VideoIcon.tsx b/packages/components/src/components/Icons/VideoIcon.tsx new file mode 100644 index 0000000000..5227152fed --- /dev/null +++ b/packages/components/src/components/Icons/VideoIcon.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const VideoIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/VoltoIcon.tsx b/packages/components/src/components/Icons/VoltoIcon.tsx new file mode 100644 index 0000000000..75fccee19a --- /dev/null +++ b/packages/components/src/components/Icons/VoltoIcon.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const VoltoIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/WindowedIcon.tsx b/packages/components/src/components/Icons/WindowedIcon.tsx new file mode 100644 index 0000000000..104e40e6f7 --- /dev/null +++ b/packages/components/src/components/Icons/WindowedIcon.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const WindowedIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/WorldIcon.tsx b/packages/components/src/components/Icons/WorldIcon.tsx new file mode 100644 index 0000000000..236ffe607f --- /dev/null +++ b/packages/components/src/components/Icons/WorldIcon.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Icon } from '../Icon/Icon'; +import type { IconPropsWithoutChildren } from '../Icon/Icon'; + +export const WorldIcon = (props: IconPropsWithoutChildren) => { + return ( + + + + + + ); +}; diff --git a/packages/components/src/components/Icons/index.ts b/packages/components/src/components/Icons/index.ts new file mode 100644 index 0000000000..ffb75068e4 --- /dev/null +++ b/packages/components/src/components/Icons/index.ts @@ -0,0 +1,104 @@ +export { AddIcon } from './AddIcon'; +export { AligncenterIcon } from './AligncenterIcon'; +export { AlignleftIcon } from './AlignleftIcon'; +export { AlignrightIcon } from './AlignrightIcon'; +export { ArchiveIcon } from './ArchiveIcon'; +export { ArrowdownIcon } from './ArrowdownIcon'; +export { ArrowleftIcon } from './ArrowleftIcon'; +export { ArrowrightIcon } from './ArrowrightIcon'; +export { ArrowtoprightIcon } from './ArrowtoprightIcon'; +export { ArrowupIcon } from './ArrowupIcon'; +export { AttachmentIcon } from './AttachmentIcon'; +export { AutomatedcontentIcon } from './AutomatedcontentIcon'; +export { BackgroundIcon } from './BackgroundIcon'; +export { BinIcon } from './BinIcon'; +export { BlindIcon } from './BlindIcon'; +export { BoldIcon } from './BoldIcon'; +export { CalendarIcon } from './CalendarIcon'; +export { CheckboxIcon } from './CheckboxIcon'; +export { ChevrondownIcon } from './ChevrondownIcon'; +export { ChevronleftIcon } from './ChevronleftIcon'; +export { ChevronrightIcon } from './ChevronrightIcon'; +export { ChevronupIcon } from './ChevronupIcon'; +export { CloseIcon } from './CloseIcon'; +export { CodeIcon } from './CodeIcon'; +export { CollectionIcon } from './CollectionIcon'; +export { ColumnafterIcon } from './ColumnafterIcon'; +export { ColumnbeforeIcon } from './ColumnbeforeIcon'; +export { ColumndeleteIcon } from './ColumndeleteIcon'; +export { ColumnsIcon } from './ColumnsIcon'; +export { CopyIcon } from './CopyIcon'; +export { CutIcon } from './CutIcon'; +export { DashIcon } from './DashIcon'; +export { DiscussionIcon } from './DiscussionIcon'; +export { DraggableIcon } from './DraggableIcon'; +export { EditIcon } from './EditIcon'; +export { EyeIcon } from './EyeIcon'; +export { FilterIcon } from './FilterIcon'; +export { FolderIcon } from './FolderIcon'; +export { FooterIcon } from './FooterIcon'; +export { ForegroundIcon } from './ForegroundIcon'; +export { FullscreenIcon } from './FullscreenIcon'; +export { HighlightIcon } from './HighlightIcon'; +export { HistoryIcon } from './HistoryIcon'; +export { HomeIcon } from './HomeIcon'; +export { ImagefitIcon } from './ImagefitIcon'; +export { ImagefullIcon } from './ImagefullIcon'; +export { ImageIcon } from './ImageIcon'; +export { ImageleftIcon } from './ImageleftIcon'; +export { ImagerightIcon } from './ImagerightIcon'; +export { InfoIcon } from './InfoIcon'; +export { ItalicIcon } from './ItalicIcon'; +export { LanguageIcon } from './LanguageIcon'; +export { LeadingIcon } from './LeadingIcon'; +export { LeadingimageIcon } from './LeadingimageIcon'; +export { LinkIcon } from './LinkIcon'; +export { ListIcon } from './ListIcon'; +export { ListnumbersIcon } from './ListnumbersIcon'; +export { MailIcon } from './MailIcon'; +export { MandatoryIcon } from './MandatoryIcon'; +export { MapIcon } from './MapIcon'; +export { MenuIcon } from './MenuIcon'; +export { MergedIcon } from './MergedIcon'; +export { MoreoptionsIcon } from './MoreoptionsIcon'; +export { NavigationIcon } from './NavigationIcon'; +export { NewsIcon } from './NewsIcon'; +export { OutIcon } from './OutIcon'; +export { PageIcon } from './PageIcon'; +export { ParagraphIcon } from './ParagraphIcon'; +export { PasteIcon } from './PasteIcon'; +export { PauseIcon } from './PauseIcon'; +export { PencilIcon } from './PencilIcon'; +export { PlayIcon } from './PlayIcon'; +export { PropertiesIcon } from './PropertiesIcon'; +export { QuotesIcon } from './QuotesIcon'; +export { RadiobuttonIcon } from './RadiobuttonIcon'; +export { RedoIcon } from './RedoIcon'; +export { RenameIcon } from './RenameIcon'; +export { ReverseIcon } from './ReverseIcon'; +export { ReviewIcon } from './ReviewIcon'; +export { RowafterIcon } from './RowafterIcon'; +export { RowbeforeIcon } from './RowbeforeIcon'; +export { RowdeleteIcon } from './RowdeleteIcon'; +export { SearchIcon } from './SearchIcon'; +export { SecurityIcon } from './SecurityIcon'; +export { SettingsIcon } from './SettingsIcon'; +export { ShareIcon } from './ShareIcon'; +export { SliderIcon } from './SliderIcon'; +export { SocialIcon } from './SocialIcon'; +export { SpacerIcon } from './SpacerIcon'; +export { StateIcon } from './StateIcon'; +export { SubtitleIcon } from './SubtitleIcon'; +export { TableIcon } from './TableIcon'; +export { TagIcon } from './TagIcon'; +export { TextIcon } from './TextIcon'; +export { ThumbnailsIcon } from './ThumbnailsIcon'; +export { TitleIcon } from './TitleIcon'; +export { TocIcon } from './TocIcon'; +export { UndoIcon } from './UndoIcon'; +export { UploadIcon } from './UploadIcon'; +export { UserIcon } from './UserIcon'; +export { VideoIcon } from './VideoIcon'; +export { VoltoIcon } from './VoltoIcon'; +export { WindowedIcon } from './WindowedIcon'; +export { WorldIcon } from './WorldIcon'; diff --git a/packages/components/src/components/Link/Link.stories.tsx b/packages/components/src/components/Link/Link.stories.tsx new file mode 100644 index 0000000000..c45c2710b4 --- /dev/null +++ b/packages/components/src/components/Link/Link.stories.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from './Link'; +import type { Meta, StoryObj } from '@storybook/react'; + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Components/Link', + component: Link, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Default: Story = { + args: { + href: '/', + children: 'The link', + }, +}; diff --git a/packages/components/src/components/Link/Link.test.tsx b/packages/components/src/components/Link/Link.test.tsx new file mode 100644 index 0000000000..291956214a --- /dev/null +++ b/packages/components/src/components/Link/Link.test.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { expect, it } from 'vitest'; +import { render, screen } from '@testing-library/react'; +import { axe, toHaveNoViolations } from 'jest-axe'; +import { Link } from './Link'; + +expect.extend(toHaveNoViolations); + +it('Link basic a11y test', async () => { + const { container } = render(The link); + + const asd = screen.getByText('The link'); + expect(asd).toHaveAttribute('href', '/'); + + const results = await axe(container); + + expect(results).toHaveNoViolations(); +}); diff --git a/packages/components/src/components/Link/Link.tsx b/packages/components/src/components/Link/Link.tsx new file mode 100644 index 0000000000..307c6528d3 --- /dev/null +++ b/packages/components/src/components/Link/Link.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { forwardRef, ForwardedRef } from 'react'; +import { Link as RACLink, LinkProps } from 'react-aria-components'; +import { useFlattenToAppURL } from '../../providers/flattenToAppURL'; + +type forwardRefType = typeof forwardRef; + +const Link = (props: LinkProps, ref: ForwardedRef) => { + const { flattenToAppURL } = useFlattenToAppURL(); + const flattenedURL = flattenToAppURL(props.href); + + return ( + + {props.children} + + ); +}; + +const _Link = /*#__PURE__*/ (forwardRef as forwardRefType)(Link); +export { _Link as Link }; diff --git a/packages/components/src/components/ListBox/ListBox.stories.tsx b/packages/components/src/components/ListBox/ListBox.stories.tsx new file mode 100644 index 0000000000..7fae25dcae --- /dev/null +++ b/packages/components/src/components/ListBox/ListBox.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { ListBox, ListBoxItem } from './ListBox'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/ListBox.css'; + +const meta = { + component: ListBox, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Chocolate + Mint + Strawberry + Vanilla + + ), + args: { + onAction: null, + selectionMode: 'single', + }, +}; diff --git a/packages/components/src/components/ListBox/ListBox.tsx b/packages/components/src/components/ListBox/ListBox.tsx new file mode 100644 index 0000000000..ac90dbe68f --- /dev/null +++ b/packages/components/src/components/ListBox/ListBox.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { + ListBox as RACListBox, + ListBoxItem as RACListBoxItem, + ListBoxItemProps, + ListBoxProps, +} from 'react-aria-components'; + +export function ListBox({ + children, + ...props +}: ListBoxProps) { + return {children}; +} + +export function ListBoxItem(props: ListBoxItemProps) { + return ; +} diff --git a/packages/components/src/components/Menu/Menu.stories.tsx b/packages/components/src/components/Menu/Menu.stories.tsx new file mode 100644 index 0000000000..f2ab26f00a --- /dev/null +++ b/packages/components/src/components/Menu/Menu.stories.tsx @@ -0,0 +1,264 @@ +import React from 'react'; +import { Menu, MenuItem } from './Menu'; +import { + Header, + Keyboard, + Section, + Selection, + Separator, + Text, +} from 'react-aria-components'; +import { SettingsIcon } from '../Icons/SettingsIcon'; +import type {} from 'react-aria-components'; +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Menu.css'; + +const meta = { + component: Menu, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Cut + Copy + Paste + + ), + args: {}, +}; + +export const WithTextSlots: Story = { + render: (args: any) => ( + + + + Cut + Cut to the clipboard + ⌘X + + + + Copy + Copy to the clipboard + ⌘C + + + + Paste + Paste from the clipboard + ⌘V + + + ), + args: {}, +}; + +export const WithIconButton: Story = { + render: (args: any) => ( + }> + Cut + Copy + Paste + + ), + args: {}, +}; + +export const DisabledItems: Story = { + render: (args: any) => ( + } disabledKeys={['paste']}> + Cut + Copy + Paste + + ), + args: {}, +}; + +export const AsADynamicCollection: Story = { + render: (args: any) => { + return ( + + {(item: { id: number; name: string }) => ( + {item.name} + )} + + ); + }, + args: { + items: [ + { id: 1, name: 'New' }, + { id: 2, name: 'Open' }, + { id: 3, name: 'Close' }, + { id: 4, name: 'Save' }, + { id: 5, name: 'Duplicate' }, + { id: 6, name: 'Rename' }, + { id: 7, name: 'Move' }, + ], + }, +}; + +export const WithSeparators: Story = { + render: (args: any) => ( + }> + Cut + Copy + Paste + + Bold + + ), + args: {}, +}; + +export const WithSections: Story = { + render: (args: any) => ( + }> +
+
Styles
+ Bold + Underline +
+
+
Align
+ Left + Middle + Right +
+
+ ), + args: {}, +}; + +export const AsLinks: Story = { + render: (args: any) => ( + }> + + Adobe + + + Apple + + + Google + + + Microsoft + + + ), + args: {}, +}; + +// export const OpenByDefault: Story = { +// render: (args: any) => ( +// } isOpen> +// Cut +// Copy +// Paste +// +// ), +// args: {}, +// }; + +export const SingleSelection: Story = { + render: (args: any) => { + let [selected, setSelected] = React.useState( + new Set(['center']), + ); + + return ( + <> + + Left + Center + Right + +

+ Current selection (controlled):{' '} + {selected === 'all' ? 'all' : [...selected].join(', ')} +

+ + ); + }, + args: {}, +}; + +export const MultipleSelection: Story = { + render: (args: any) => { + let [selected, setSelected] = React.useState( + new Set(['sidebar', 'console']), + ); + + return ( + <> + + Sidebar + Searchbar + Tools + Console + +

+ Current selection (controlled):{' '} + {selected === 'all' ? 'all' : [...selected].join(', ')} +

+ + ); + }, + args: {}, +}; + +export const ControlledState: Story = { + render: (args: any) => { + let [open, setOpen] = React.useState(false); + return ( + } + isOpen={open} + onOpenChange={setOpen} + > + Cut + Copy + Paste + + ); + }, + args: {}, +}; + +export const LongPress: Story = { + render: (args: any) => ( + }> + Cut + Copy + Paste + + ), + args: { + trigger: 'longPress', + onPress: () => alert('crop'), + onAction: (id) => alert(id), + }, +}; diff --git a/packages/components/src/components/Menu/Menu.tsx b/packages/components/src/components/Menu/Menu.tsx new file mode 100644 index 0000000000..db153971a6 --- /dev/null +++ b/packages/components/src/components/Menu/Menu.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { + Menu as RACMenu, + MenuItem as RACMenuItem, + MenuItemProps, + MenuProps, + MenuTrigger, + MenuTriggerProps, + Popover, + PressEvent, +} from 'react-aria-components'; + +import { Button } from '../Button/Button'; + +export interface MenuButtonProps + extends MenuProps, + Omit { + button?: React.ReactNode; + onPress?: (e: PressEvent) => void; +} + +export function Menu({ + button, + onPress, + children, + ...props +}: MenuButtonProps) { + return ( + + + + {children} + + + ); +} + +export function MenuItem(props: MenuItemProps) { + return ; +} diff --git a/packages/components/src/components/Meter/Meter.stories.tsx b/packages/components/src/components/Meter/Meter.stories.tsx new file mode 100644 index 0000000000..2e7f306c85 --- /dev/null +++ b/packages/components/src/components/Meter/Meter.stories.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Meter } from './Meter'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Meter.css'; + +const meta: Meta = { + title: 'Forms/Meter', + component: Meter, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Storage space', + value: 80, + }, +}; diff --git a/packages/components/src/components/Meter/Meter.tsx b/packages/components/src/components/Meter/Meter.tsx new file mode 100644 index 0000000000..fb06f8c57c --- /dev/null +++ b/packages/components/src/components/Meter/Meter.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { + Label, + Meter as RACMeter, + MeterProps as RACMeterProps, +} from 'react-aria-components'; + +export interface MeterProps extends RACMeterProps { + label?: string; +} + +export function Meter({ label, ...props }: MeterProps) { + return ( + + {({ percentage, valueText }) => ( + <> + + {valueText} +
+
+
+ + )} + + ); +} diff --git a/packages/components/src/components/Modal/Modal.stories.tsx b/packages/components/src/components/Modal/Modal.stories.tsx new file mode 100644 index 0000000000..d7e9cfebe0 --- /dev/null +++ b/packages/components/src/components/Modal/Modal.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Modal } from './Modal'; +import { Button } from '../Button/Button'; + +import { + Dialog, + DialogTrigger, + Heading, + Input, + Label, + TextField, +} from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Modal.css'; + +const meta = { + component: Modal, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + + + + {({ close }) => ( +
+ Sign up + + + + + + + + + +
+ )} +
+
+
+ ), +}; diff --git a/packages/components/src/components/Modal/Modal.tsx b/packages/components/src/components/Modal/Modal.tsx new file mode 100644 index 0000000000..83eb2e061c --- /dev/null +++ b/packages/components/src/components/Modal/Modal.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Modal as RACModal, ModalOverlayProps } from 'react-aria-components'; + +export function Modal(props: ModalOverlayProps) { + return ; +} diff --git a/packages/components/src/components/NumberField/NumberField.stories.tsx b/packages/components/src/components/NumberField/NumberField.stories.tsx new file mode 100644 index 0000000000..b9248790bb --- /dev/null +++ b/packages/components/src/components/NumberField/NumberField.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { NumberField } from './NumberField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/NumberField.css'; + +const meta = { + title: 'Forms/NumberField', + component: NumberField, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Cookies', + }, +}; diff --git a/packages/components/src/components/NumberField/NumberField.tsx b/packages/components/src/components/NumberField/NumberField.tsx new file mode 100644 index 0000000000..98781966fe --- /dev/null +++ b/packages/components/src/components/NumberField/NumberField.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { + FieldError, + Group, + Input, + Label, + NumberField as RACNumberField, + NumberFieldProps as RACNumberFieldProps, + Text, + ValidationResult, +} from 'react-aria-components'; +import { Button } from '../Button/Button'; +import { AddIcon } from '../Icons/AddIcon'; +import { DashIcon } from '../Icons/DashIcon'; + +export interface NumberFieldProps extends RACNumberFieldProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function NumberField({ + label, + description, + errorMessage, + ...props +}: NumberFieldProps) { + return ( + + + + + + + + {description && {description}} + {errorMessage} + + ); +} diff --git a/packages/components/src/components/Popover/Popover.stories.tsx b/packages/components/src/components/Popover/Popover.stories.tsx new file mode 100644 index 0000000000..21951fcd6f --- /dev/null +++ b/packages/components/src/components/Popover/Popover.stories.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Popover } from './Popover'; +import { Button } from '../Button/Button'; +import { DialogTrigger, Heading } from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Popover.css'; +import { InfoIcon } from '../Icons/InfoIcon'; + +const meta = { + component: Popover, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + + + Help +

For help accessing your account, please contact support.

+
+
+ ), + args: {}, +}; diff --git a/packages/components/src/components/Popover/Popover.tsx b/packages/components/src/components/Popover/Popover.tsx new file mode 100644 index 0000000000..d115987565 --- /dev/null +++ b/packages/components/src/components/Popover/Popover.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { + Dialog, + OverlayArrow, + Popover as RACPopover, + PopoverProps as RACPopoverProps, +} from 'react-aria-components'; + +export interface PopoverProps extends Omit { + children: React.ReactNode; +} + +export function Popover({ children, ...props }: PopoverProps) { + return ( + + + + + + + {children} + + ); +} diff --git a/packages/components/src/components/ProgressBar/ProgressBar.stories.tsx b/packages/components/src/components/ProgressBar/ProgressBar.stories.tsx new file mode 100644 index 0000000000..9beb0c6e13 --- /dev/null +++ b/packages/components/src/components/ProgressBar/ProgressBar.stories.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { ProgressBar } from './ProgressBar'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/ProgressBar.css'; + +const meta: Meta = { + title: 'Widgets/ProgressBar', + component: ProgressBar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Loading…', + value: 80, + }, +}; diff --git a/packages/components/src/components/ProgressBar/ProgressBar.tsx b/packages/components/src/components/ProgressBar/ProgressBar.tsx new file mode 100644 index 0000000000..cb72f500f5 --- /dev/null +++ b/packages/components/src/components/ProgressBar/ProgressBar.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { + Label, + ProgressBar as RACProgressBar, + ProgressBarProps as RACProgressBarProps, +} from 'react-aria-components'; + +export interface ProgressBarProps extends RACProgressBarProps { + label?: string; +} + +export function ProgressBar({ label, ...props }: ProgressBarProps) { + return ( + + {({ percentage, valueText }) => ( + <> + + {valueText} +
+
+
+ + )} + + ); +} diff --git a/packages/components/src/components/RadioGroup/RadioGroup.stories.tsx b/packages/components/src/components/RadioGroup/RadioGroup.stories.tsx new file mode 100644 index 0000000000..7ed4a5ee58 --- /dev/null +++ b/packages/components/src/components/RadioGroup/RadioGroup.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { RadioGroup } from './RadioGroup'; +import { Radio } from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/RadioGroup.css'; + +const meta = { + title: 'Widgets/RadioGroup', + component: RadioGroup, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Soccer + Baseball + Basketball + + ), + args: { + label: 'Favorite sport', + }, +}; diff --git a/packages/components/src/components/RadioGroup/RadioGroup.tsx b/packages/components/src/components/RadioGroup/RadioGroup.tsx new file mode 100644 index 0000000000..90fea840d4 --- /dev/null +++ b/packages/components/src/components/RadioGroup/RadioGroup.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { + FieldError, + Label, + RadioGroup as RACRadioGroup, + RadioGroupProps as RACRadioGroupProps, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface RadioGroupProps extends Omit { + children?: React.ReactNode; + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function RadioGroup({ + label, + description, + errorMessage, + children, + ...props +}: RadioGroupProps) { + return ( + + + {children} + {description && {description}} + {errorMessage} + + ); +} diff --git a/packages/components/src/components/RangeCalendar/RangeCalendar.stories.tsx b/packages/components/src/components/RangeCalendar/RangeCalendar.stories.tsx new file mode 100644 index 0000000000..e3fe33be4f --- /dev/null +++ b/packages/components/src/components/RangeCalendar/RangeCalendar.stories.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { RangeCalendar } from './RangeCalendar'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/RangeCalendar.css'; + +const meta: Meta = { + title: 'Widgets/RangeCalendar', + component: RangeCalendar, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , +}; diff --git a/packages/components/src/components/RangeCalendar/RangeCalendar.tsx b/packages/components/src/components/RangeCalendar/RangeCalendar.tsx new file mode 100644 index 0000000000..7881028477 --- /dev/null +++ b/packages/components/src/components/RangeCalendar/RangeCalendar.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { + Button, + CalendarCell, + CalendarGrid, + DateValue, + Heading, + RangeCalendar as RACRangeCalendar, + RangeCalendarProps as RACRangeCalendarProps, + Text, +} from 'react-aria-components'; + +export interface RangeCalendarProps + extends RACRangeCalendarProps { + errorMessage?: string; +} + +export function RangeCalendar({ + errorMessage, + ...props +}: RangeCalendarProps) { + return ( + +
+ + + +
+ {(date) => } + {errorMessage && {errorMessage}} +
+ ); +} diff --git a/packages/components/src/components/SearchField/SearchField.stories.tsx b/packages/components/src/components/SearchField/SearchField.stories.tsx new file mode 100644 index 0000000000..2d0ba9213a --- /dev/null +++ b/packages/components/src/components/SearchField/SearchField.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { SearchField } from './SearchField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/SearchField.css'; + +const meta: Meta = { + title: 'Forms/SearchField', + component: SearchField, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Search', + }, +}; diff --git a/packages/components/src/components/SearchField/SearchField.tsx b/packages/components/src/components/SearchField/SearchField.tsx new file mode 100644 index 0000000000..57f7946d4f --- /dev/null +++ b/packages/components/src/components/SearchField/SearchField.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { + Button, + FieldError, + Input, + Label, + SearchField as RACSearchField, + SearchFieldProps as RACSearchFieldProps, + Text, + ValidationResult, +} from 'react-aria-components'; + +export interface SearchFieldProps extends RACSearchFieldProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); +} + +export function SearchField({ + label, + description, + errorMessage, + ...props +}: SearchFieldProps) { + return ( + + + + + {description && {description}} + {errorMessage} + + ); +} diff --git a/packages/components/src/components/Select/Select.stories.tsx b/packages/components/src/components/Select/Select.stories.tsx new file mode 100644 index 0000000000..bec5ec99be --- /dev/null +++ b/packages/components/src/components/Select/Select.stories.tsx @@ -0,0 +1,174 @@ +import React from 'react'; +import { Select, SelectItem } from './Select'; +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Select.css'; + +export interface SelectItemObject { + label: string; + value: string; +} + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta = { + title: 'Forms/Select', + component: Select, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + decorators: [ + (Story) => ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +/** + * Select gets a fixed children as JSX + */ +export const Default: Story = { + args: { + name: 'empty', + label: 'field 1 title', + description: 'Optional help text', + placeholder: 'Select...', + children: ( + <> + Hello + Lorem Ipsum + + ), + }, +}; + +/** + * Select renders options via render props `(item)=> React.ReactNode` + */ +export const Items: Story = { + render: (args) => ( + // @ts-ignore I assume this is a storybook bug when passing args + + ), + args: { + name: 'field-empty', + label: 'field 1 title', + description: 'Optional help text', + placeholder: 'Select...', + items: [ + { label: '1', value: 'Aerospace' }, + { label: '2', value: 'Mechanical' }, + { label: '3', value: 'Civil' }, + { label: '4', value: 'Biomedical' }, + { label: '5', value: 'Nuclear' }, + { label: '6', value: 'Industrial' }, + { label: '7', value: 'Chemical' }, + { label: '8', value: 'Agricultural' }, + { label: '9', value: 'Electrical' }, + { label: '10', value: 'Telco' }, + ], + children: null, + }, +}; + +export const LotsOfItems: Story = { + render: (args) => ( + // @ts-ignore I assume this is a storybook bug when passing args + + ), + args: { + name: 'field-empty', + label: 'field 1 title', + description: 'Optional help text', + placeholder: 'Select...', + items: [ + { label: '1', value: 'Aerospace' }, + { label: '2', value: 'Mechanical' }, + { label: '3', value: 'Civil' }, + { label: '4', value: 'Biomedical' }, + { label: '5', value: 'Nuclear' }, + { label: '6', value: 'Industrial' }, + { label: '7', value: 'Chemical' }, + { label: '8', value: 'Agricultural' }, + { label: '9', value: 'Electrical' }, + { label: '10', value: 'Telco' }, + { label: '11', value: 'Aerospace' }, + { label: '12', value: 'Mechanical' }, + { label: '13', value: 'Civil' }, + { label: '14', value: 'Biomedical' }, + { label: '15', value: 'Nuclear' }, + { label: '16', value: 'Industrial' }, + { label: '17', value: 'Chemical' }, + { label: '18', value: 'Agricultural' }, + { label: '19', value: 'Electrical' }, + { label: '20', value: 'Telco' }, + { label: '21', value: 'Aerospace' }, + { label: '22', value: 'Mechanical' }, + { label: '23', value: 'Civil' }, + { label: '24', value: 'Biomedical' }, + { label: '25', value: 'Nuclear' }, + { label: '26', value: 'Industrial' }, + { label: '27', value: 'Chemical' }, + { label: '28', value: 'Agricultural' }, + { label: '29', value: 'Electrical' }, + { label: '30', value: 'Telco' }, + ], + children: null, + }, +}; + +export const Required: Story = { + ...Items, + args: { + ...Items.args, + name: 'field-required', + isRequired: true, + }, +}; + +export const Filled: Story = { + ...Items, + args: { + ...Items.args, + name: 'field-filled', + label: 'Filled field title', + defaultSelectedKey: '10', + isRequired: true, + }, +}; + +export const Errored: Story = { + ...Items, + args: { + ...Items.args, + name: 'field-errored', + label: 'Errored field title', + defaultSelectedKey: '10', + errorMessage: 'This is the error', + isInvalid: true, + isRequired: true, + }, +}; + +export const Disabled: Story = { + ...Items, + args: { + ...Items.args, + name: 'field-disabled', + label: 'Disabled field title', + isDisabled: true, + }, +}; diff --git a/packages/components/src/components/Select/Select.tsx b/packages/components/src/components/Select/Select.tsx new file mode 100644 index 0000000000..fdbe84c784 --- /dev/null +++ b/packages/components/src/components/Select/Select.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { + Button, + FieldError, + Label, + ListBox, + ListBoxItem, + ListBoxItemProps, + Popover, + PopoverContext, + Select as RACSelect, + SelectProps as RACSelectProps, + SelectValue, + Text, + useContextProps, + ValidationResult, +} from 'react-aria-components'; + +import { ChevrondownIcon } from '../Icons/ChevrondownIcon'; +import { ChevronupIcon } from '../Icons/ChevronupIcon'; + +export interface SelectProps + extends Omit, 'children'> { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); + items?: Iterable; + children: React.ReactNode | ((item: T) => React.ReactNode); +} + +/** + * See https://react-spectrum.adobe.com/react-aria/Select.html + * + * An iterable list of options is passed to the Select using the items prop. Each item + * accepts an id prop, which is passed to the onSelectionChange handler to identify + * the selected item. Alternatively, if the item objects contain an id property, as + * shown in the example below, then this is used automatically and an id prop is not + * required. + * + * Setting a selected option can be done by using the defaultSelectedKey or selectedKey + * prop. The selected key corresponds to the id prop of an item. When Select is used + * with a dynamic collection as described above, the id of each item is derived from + * the data. + * + */ +export function Select({ + label, + description, + errorMessage, + children, + items, + ...props +}: SelectProps) { + // In case that we want to customize the Popover, we proxy the PopoverContext props down + const [popoverProps] = useContextProps({}, null, PopoverContext); + + return ( + + {({ isOpen }) => ( + <> + + + {description && {description}} + {errorMessage} + + {children} + + + )} + + ); +} + +export function SelectItem(props: ListBoxItemProps) { + return ; +} diff --git a/packages/components/src/components/Slider/Slider.stories.tsx b/packages/components/src/components/Slider/Slider.stories.tsx new file mode 100644 index 0000000000..b6dd86587f --- /dev/null +++ b/packages/components/src/components/Slider/Slider.stories.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Slider } from './Slider'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Slider.css'; + +const meta: Meta = { + title: 'Components/Slider', + component: Slider, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Range', + defaultValue: [30, 60], + thumbLabels: ['start', 'end'], + }, +}; diff --git a/packages/components/src/components/Slider/Slider.tsx b/packages/components/src/components/Slider/Slider.tsx new file mode 100644 index 0000000000..f09e907195 --- /dev/null +++ b/packages/components/src/components/Slider/Slider.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { + Label, + Slider as RACSlider, + SliderOutput, + SliderProps as RACSliderProps, + SliderThumb, + SliderTrack, +} from 'react-aria-components'; + +export interface SliderProps extends RACSliderProps { + label?: string; + thumbLabels?: string[]; +} + +export function Slider({ + label, + thumbLabels, + ...props +}: SliderProps) { + return ( + + + + {({ state }) => + state.values.map((_, i) => state.getThumbValueLabel(i)).join(' – ') + } + + + {({ state }) => + state.values.map((_, i) => ( + + )) + } + + + ); +} diff --git a/packages/components/src/components/Switch/Switch.stories.tsx b/packages/components/src/components/Switch/Switch.stories.tsx new file mode 100644 index 0000000000..e61e936cef --- /dev/null +++ b/packages/components/src/components/Switch/Switch.stories.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Switch } from './Switch'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Switch.css'; + +const meta: Meta = { + title: 'Widgets/Switch', + component: Switch, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => Wi-Fi, +}; diff --git a/packages/components/src/components/Switch/Switch.tsx b/packages/components/src/components/Switch/Switch.tsx new file mode 100644 index 0000000000..5f0f2d0b64 --- /dev/null +++ b/packages/components/src/components/Switch/Switch.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { + Switch as RACSwitch, + SwitchProps as RACSwitchProps, +} from 'react-aria-components'; + +export interface SwitchProps extends Omit { + children: React.ReactNode; +} + +export function Switch({ children, ...props }: SwitchProps) { + return ( + +
+ {children} + + ); +} diff --git a/packages/components/src/components/Table/Table.stories.tsx b/packages/components/src/components/Table/Table.stories.tsx new file mode 100644 index 0000000000..82f5f9270a --- /dev/null +++ b/packages/components/src/components/Table/Table.stories.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Table, TableHeader, Row, Column } from './Table'; +import { Cell, TableBody } from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Table.css'; + +const meta: Meta = { + title: 'Components/Table', + component: Table, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + + Name + Type + Date Modified + + + + Games + File folder + 6/7/2020 + + + Program Files + File folder + 4/7/2021 + + + bootmgr + System file + 11/20/2010 + + +
+ ), + args: { + onRowAction: null, + // selectionMode: "multiple", + }, +}; diff --git a/packages/components/src/components/Table/Table.tsx b/packages/components/src/components/Table/Table.tsx new file mode 100644 index 0000000000..1fb3074d96 --- /dev/null +++ b/packages/components/src/components/Table/Table.tsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { + Button, + Cell, + Collection, + Column as RACColumn, + ColumnProps, + Row as RACRow, + RowProps, + Table as RACTable, + TableHeader as RACTableHeader, + TableHeaderProps, + TableProps, + useTableOptions, +} from 'react-aria-components'; + +import { Checkbox } from '../Checkbox/Checkbox'; + +export function Table(props: TableProps) { + return ; +} + +export function Column(props: ColumnProps) { + return ( + + {({ allowsSorting, sortDirection }) => ( + <> + {props.children} + {allowsSorting && ( + + )} + + )} + + ); +} + +export function TableHeader({ + columns, + children, +}: TableHeaderProps) { + let { selectionBehavior, selectionMode, allowsDragging } = useTableOptions(); + + return ( + + {/* Add extra columns for drag and drop and selection. */} + {allowsDragging && } + {selectionBehavior === 'toggle' && ( + + {selectionMode === 'multiple' && } + + )} + {children} + + ); +} + +export function Row({ + id, + columns, + children, + ...otherProps +}: RowProps) { + let { selectionBehavior, allowsDragging } = useTableOptions(); + + return ( + + {allowsDragging && ( + + + + )} + {selectionBehavior === 'toggle' && ( + + + + )} + {children} + + ); +} diff --git a/packages/components/src/components/Tabs/Tabs.stories.tsx b/packages/components/src/components/Tabs/Tabs.stories.tsx new file mode 100644 index 0000000000..056407945f --- /dev/null +++ b/packages/components/src/components/Tabs/Tabs.stories.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Tabs } from './Tabs'; +import { Tab, TabList, TabPanel } from 'react-aria-components'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/Tabs.css'; + +const meta: Meta = { + component: Tabs, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + + Founding of Rome + Monarchy and Republic + Empire + + + Arma virumque cano, Troiae qui primus ab oris. + + Senatus Populusque Romanus. + Alea jacta est. + + ), +}; diff --git a/packages/components/src/components/Tabs/Tabs.tsx b/packages/components/src/components/Tabs/Tabs.tsx new file mode 100644 index 0000000000..a0d4ab8cfd --- /dev/null +++ b/packages/components/src/components/Tabs/Tabs.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { Tabs as RACTabs, TabsProps } from 'react-aria-components'; + +export function Tabs(props: TabsProps) { + return ; +} diff --git a/packages/components/src/components/TagGroup/TagGroup.stories.tsx b/packages/components/src/components/TagGroup/TagGroup.stories.tsx new file mode 100644 index 0000000000..bae96b4509 --- /dev/null +++ b/packages/components/src/components/TagGroup/TagGroup.stories.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { Tag, TagGroup } from './TagGroup'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/TagGroup.css'; + +const meta = { + component: TagGroup, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => ( + + Chocolate + Mint + Strawberry + Vanilla + + ), + args: { + label: 'Ice cream flavor', + selectionMode: 'single', + }, +}; diff --git a/packages/components/src/components/TagGroup/TagGroup.tsx b/packages/components/src/components/TagGroup/TagGroup.tsx new file mode 100644 index 0000000000..1424dea383 --- /dev/null +++ b/packages/components/src/components/TagGroup/TagGroup.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { + Button, + Label, + Tag as RACTag, + TagGroup as RACTagGroup, + TagGroupProps as RACTagGroupProps, + TagList, + TagListProps, + TagProps, + Text, +} from 'react-aria-components'; + +export interface TagGroupProps + extends Omit, + Pick, 'items' | 'children' | 'renderEmptyState'> { + label?: string; + description?: string; + errorMessage?: string; +} + +export function TagGroup({ + label, + description, + errorMessage, + items, + children, + renderEmptyState, + ...props +}: TagGroupProps) { + return ( + + + + {children} + + {description && {description}} + {errorMessage && {errorMessage}} + + ); +} + +export function Tag({ children, ...props }: TagProps) { + let textValue = typeof children === 'string' ? children : undefined; + return ( + + {({ allowsRemoving }) => ( + <> + {children} + {allowsRemoving && } + + )} + + ); +} diff --git a/packages/components/src/components/TextAreaField/TextAreaField.stories.tsx b/packages/components/src/components/TextAreaField/TextAreaField.stories.tsx new file mode 100644 index 0000000000..05c0f59d70 --- /dev/null +++ b/packages/components/src/components/TextAreaField/TextAreaField.stories.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { TextAreaField } from './TextAreaField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +import '../../styles/basic/TextField.css'; + +const meta: Meta = { + title: 'Forms/TextAreaField', + component: TextAreaField, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: (args: any) => , + args: { + label: 'Name', + }, +}; diff --git a/packages/components/src/components/TextAreaField/TextAreaField.tsx b/packages/components/src/components/TextAreaField/TextAreaField.tsx new file mode 100644 index 0000000000..e79f5e78bb --- /dev/null +++ b/packages/components/src/components/TextAreaField/TextAreaField.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { + FieldError, + TextArea, + Label, + Text, + TextField as RACTextField, + TextFieldProps as RACTextFieldProps, + ValidationResult, +} from 'react-aria-components'; + +export interface TextAreaFieldProps extends RACTextFieldProps { + label?: string; + description?: string; + errorMessage?: string | ((validation: ValidationResult) => string); + placeholder?: string; +} + +export function TextAreaField({ + label, + description, + errorMessage, + ...props +}: TextAreaFieldProps) { + return ( + + +