From 46b9d76ce4ac42e593c89dbec876ef5556138cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20de=20Alba?= Date: Wed, 5 Jun 2024 23:17:28 +0200 Subject: [PATCH 01/49] Fix `poToJson` script, making it support `volto.config.js` (#6073) --- packages/scripts/i18n.cjs | 19 +++++++++++-------- packages/scripts/news/6073.bugfix | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 packages/scripts/news/6073.bugfix diff --git a/packages/scripts/i18n.cjs b/packages/scripts/i18n.cjs index 1eace16642..4dd219baf4 100755 --- a/packages/scripts/i18n.cjs +++ b/packages/scripts/i18n.cjs @@ -13,7 +13,6 @@ const babel = require('@babel/core'); const path = require('path'); const projectRootPath = path.resolve('.'); -const packageJson = require(path.join(projectRootPath, 'package.json')); const { program } = require('commander'); const chalk = require('chalk'); @@ -155,9 +154,9 @@ function poToJson({ registry, addonMode }) { (item.comments[0] && item.comments[0].startsWith('. Default: ') ? item.comments[0].replace('. Default: ', '') : item.comments[0] && - item.comments[0].startsWith('defaultMessage:') - ? item.comments[0].replace('defaultMessage: ', '') - : '') + item.comments[0].startsWith('defaultMessage:') + ? item.comments[0].replace('defaultMessage: ', '') + : '') : item.msgstr[0]; } }); @@ -183,8 +182,11 @@ function poToJson({ registry, addonMode }) { if (!addonMode) { // Merge addons locales - if (packageJson.addons) { - registry.getAddonDependencies().forEach((addon) => { + registry.getAddonDependencies().forEach((addonDep) => { + // What comes from getAddonDependencies is in the form of `@package/addon:profile` + const addon = addonDep.split(':')[0]; + // Check if the addon is available in the registry, just in case + if (registry.packages[addon]) { const addonlocale = `${registry.packages[addon].modulePath}/../${filename}`; if (fs.existsSync(addonlocale)) { const addonItems = Pofile.parse( @@ -197,9 +199,10 @@ function poToJson({ registry, addonMode }) { console.log(`Merging ${addon} locales for ${lang}`); } } - }); - } + } + }); } + // Merge project locales, the project customization wins mergeMessages(result, projectLocalesItems, lang); fs.writeFileSync(`locales/${lang}.json`, JSON.stringify(result)); diff --git a/packages/scripts/news/6073.bugfix b/packages/scripts/news/6073.bugfix new file mode 100644 index 0000000000..3faf066a6a --- /dev/null +++ b/packages/scripts/news/6073.bugfix @@ -0,0 +1 @@ +'Fix `poToJson` script, making it support `volto.config.js` @sneridagh From 3d8d3b3e08c6894bf7366ca0653f8296875dac72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20de=20Alba?= Date: Thu, 6 Jun 2024 15:38:14 +0200 Subject: [PATCH 02/49] Support for configurable `public` directory defined per add-on (#6072) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Steve Piercy Co-authored-by: Érico Andrei --- docs/source/addons/index.md | 1 + docs/source/addons/public-folder.md | 29 ++++++++++ packages/scripts/i18n.cjs | 4 +- packages/scripts/news/6072.documentation | 1 + packages/volto/news/6072.feature | 1 + packages/volto/package.json | 1 + packages/volto/razzle.config.js | 49 ++++++++++++++++ .../volto/src/express-middleware/static.js | 56 ++++++++++++------- pnpm-lock.yaml | 9 +++ 9 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 docs/source/addons/public-folder.md create mode 100644 packages/scripts/news/6072.documentation create mode 100644 packages/volto/news/6072.feature diff --git a/docs/source/addons/index.md b/docs/source/addons/index.md index 94dd2a6c12..ed13a38d17 100644 --- a/docs/source/addons/index.md +++ b/docs/source/addons/index.md @@ -15,6 +15,7 @@ myst: i18n best-practices theme +public-folder ``` There are several advanced scenarios where we might want to have more control diff --git a/docs/source/addons/public-folder.md b/docs/source/addons/public-folder.md new file mode 100644 index 0000000000..188a9e155a --- /dev/null +++ b/docs/source/addons/public-folder.md @@ -0,0 +1,29 @@ +--- +myst: + html_meta: + "description": "How to add static served files from your add-on to your build" + "property=og:description": "How to add static served files to the build from an add-on" + "property=og:title": "Add static files from your add-on to your build" + "keywords": "Volto, Plone, Semantic UI, CSS, Volto theme, add-on, static, assets, files, build" +--- + +# Add static files from your add-on to your build + +In the Volto build process, you can add static files to your build, then serve them along with the compiled files. +Static files are not transformed or compiled by the build process. +They are served as is from the root of the Volto site. +It is useful to define static files such as the following: + +- {file}`robots.txt` +- favicon files +- manifest files +- any other static files + + +## Procedure to include static files + +Create a folder named `public` at the root of your add-on, and add the static files to it. +The build process will copy the files, taking into account all add-ons' defined order. +The build process copies first the static files defined by Volto, then the static files from add-ons as defined by their configuration order. +The last defined file overwrites any previously defined files. + diff --git a/packages/scripts/i18n.cjs b/packages/scripts/i18n.cjs index 4dd219baf4..bd4a1a1f87 100755 --- a/packages/scripts/i18n.cjs +++ b/packages/scripts/i18n.cjs @@ -181,7 +181,9 @@ function poToJson({ registry, addonMode }) { } if (!addonMode) { - // Merge addons locales + // Merge addons locales - using getAddonDependencies because it preserves + // the order of the addons in the registry, even if they are add-on dependencies + // of an add-on registry.getAddonDependencies().forEach((addonDep) => { // What comes from getAddonDependencies is in the form of `@package/addon:profile` const addon = addonDep.split(':')[0]; diff --git a/packages/scripts/news/6072.documentation b/packages/scripts/news/6072.documentation new file mode 100644 index 0000000000..ebdab983d0 --- /dev/null +++ b/packages/scripts/news/6072.documentation @@ -0,0 +1 @@ +Improve comments @sneridagh diff --git a/packages/volto/news/6072.feature b/packages/volto/news/6072.feature new file mode 100644 index 0000000000..9bdb62904f --- /dev/null +++ b/packages/volto/news/6072.feature @@ -0,0 +1 @@ +Add support for configurable `public` directory defined per add-on. @sneridagh diff --git a/packages/volto/package.json b/packages/volto/package.json index ef3ea8ae14..6bb8a495c9 100644 --- a/packages/volto/package.json +++ b/packages/volto/package.json @@ -281,6 +281,7 @@ "@babel/plugin-syntax-export-namespace-from": "7.8.3", "@babel/runtime": "7.20.6", "@babel/types": "7.20.5", + "@fiverr/afterbuild-webpack-plugin": "^1.0.0", "@jest/globals": "^29.7.0", "@loadable/babel-plugin": "5.13.2", "@loadable/webpack-plugin": "5.15.2", diff --git a/packages/volto/razzle.config.js b/packages/volto/razzle.config.js index 925a9fcae9..69faf1557f 100644 --- a/packages/volto/razzle.config.js +++ b/packages/volto/razzle.config.js @@ -15,6 +15,7 @@ const CircularDependencyPlugin = require('circular-dependency-plugin'); const TerserPlugin = require('terser-webpack-plugin'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); const MomentLocalesPlugin = require('moment-locales-webpack-plugin'); +const AfterBuildPlugin = require('@fiverr/afterbuild-webpack-plugin'); const fileLoaderFinder = makeLoaderFinder('file-loader'); @@ -30,6 +31,7 @@ const defaultModify = ({ webpackConfig: config, webpackObject: webpack, options, + paths, }) => { // Compile language JSON files from po files poToJson({ registry, addonMode: false }); @@ -156,6 +158,51 @@ const defaultModify = ({ placeholders: true, }), ); + + // This copies the publicPath files set in voltoConfigJS with the local `public` + // directory at build time + config.plugins.push( + new AfterBuildPlugin(() => { + const mergeDirectories = (sourceDir, targetDir) => { + const files = fs.readdirSync(sourceDir); + files.forEach((file) => { + const sourcePath = path.join(sourceDir, file); + const targetPath = path.join(targetDir, file); + fs.copyFileSync(sourcePath, targetPath); + }); + }; + + registry.getAddonDependencies().forEach((addonDep) => { + // What comes from getAddonDependencies is in the form of `@package/addon:profile` + const addon = addonDep.split(':')[0]; + // Check if the addon is available in the registry, just in case + if (registry.packages[addon]) { + const p = fs.realpathSync( + `${registry.packages[addon].modulePath}/../.`, + ); + if (fs.existsSync(path.join(p, 'public'))) { + if (!dev) { + mergeDirectories(path.join(p, 'public'), paths.appBuildPublic); + } + if ( + dev && + !registry.isVoltoProject && + registry.addonNames.length > 0 + ) { + const devPublicPath = `${projectRootPath}/../../../public`; + if (!fs.existsSync(devPublicPath)) { + fs.mkdirSync(devPublicPath); + } + mergeDirectories( + path.join(p, 'public'), + `${projectRootPath}/../../../public`, + ); + } + } + } + }); + }), + ); } if (target === 'node') { @@ -387,12 +434,14 @@ module.exports = { webpackConfig, webpackObject, options, + paths, }) => { const defaultConfig = defaultModify({ env: { target, dev }, webpackConfig, webpackObject, options, + paths, }); const res = addonExtenders.reduce( diff --git a/packages/volto/src/express-middleware/static.js b/packages/volto/src/express-middleware/static.js index d7392ce668..258af2136e 100644 --- a/packages/volto/src/express-middleware/static.js +++ b/packages/volto/src/express-middleware/static.js @@ -1,28 +1,46 @@ import express from 'express'; import path from 'path'; +import AddonConfigurationRegistry from '@plone/registry/src/addon-registry'; import config from '@plone/volto/registry'; -const staticMiddlewareFn = express.static( - process.env.BUILD_DIR - ? path.join(process.env.BUILD_DIR, 'public') - : process.env.RAZZLE_PUBLIC_DIR, - { - setHeaders: function (res, path) { - const pathLib = require('path'); - const base = pathLib.resolve(process.env.RAZZLE_PUBLIC_DIR); - const relpath = path.substr(base.length); - config.settings.serverConfig.staticFiles.some((elem) => { - if (relpath.match(elem.match)) { - for (const name in elem.headers) { - res.setHeader(name, elem.headers[name] || 'undefined'); - } - return true; +const projectRootPath = path.resolve('.'); +const registry = new AddonConfigurationRegistry(projectRootPath); + +const staticDirectory = () => { + if (process.env.BUILD_DIR) { + return path.join(process.env.BUILD_DIR, 'public'); + } + // Only for development, when Volto detects that it's working on itself (not an + // old fashioned Volto project), there are add-ons (so it's the new setup) then + // point to the public folder in the root of the setup, instead of the inner Volto + // public folder. + if ( + process.env.NODE_ENV !== 'production' && + !registry.isVoltoProject && + registry.addonNames.length > 0 + ) { + return path.join(projectRootPath, '../../../public'); + } + // Is always set (Razzle does it) + return process.env.RAZZLE_PUBLIC_DIR; +}; + +const staticMiddlewareFn = express.static(staticDirectory(), { + setHeaders: function (res, path) { + const pathLib = require('path'); + const base = pathLib.resolve(process.env.RAZZLE_PUBLIC_DIR); + const relpath = path.substr(base.length); + config.settings.serverConfig.staticFiles.some((elem) => { + if (relpath.match(elem.match)) { + for (const name in elem.headers) { + res.setHeader(name, elem.headers[name] || 'undefined'); } - return false; - }); - }, + return true; + } + return false; + }); }, -); +}); export default function staticsMiddleware() { const middleware = express.Router(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee6e765396..bc748fc4c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1989,6 +1989,9 @@ importers: '@babel/types': specifier: 7.20.5 version: 7.20.5 + '@fiverr/afterbuild-webpack-plugin': + specifier: ^1.0.0 + version: 1.0.0 '@jest/globals': specifier: ^29.7.0 version: 29.7.0 @@ -3871,6 +3874,10 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@fiverr/afterbuild-webpack-plugin@1.0.0': + resolution: {integrity: sha512-ZoeJ6Y91WAbavW0w4lBBzJlQ8jQPxJslVoajuvLSPXpJPBYbSRgfSJPrp/NTsv9C2nMqde4kYf/IW2rmmtPB+w==} + engines: {node: '>= 14.0.0'} + '@fluentui/react-component-event-listener@0.63.1': resolution: {integrity: sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==} peerDependencies: @@ -20892,6 +20899,8 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@fiverr/afterbuild-webpack-plugin@1.0.0': {} + '@fluentui/react-component-event-listener@0.63.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.20.6 From e0364c36b0b4bfee4a1ea4575d80366ac610ceb3 Mon Sep 17 00:00:00 2001 From: Wesley Barroso Lopes Date: Thu, 6 Jun 2024 11:15:30 -0300 Subject: [PATCH 03/49] Fix js events association on error pages (#6057) Co-authored-by: Steve Piercy --- .../configuration/settings-reference.md | 7 -- docs/source/upgrade-guide/index.md | 8 +++ packages/volto/news/6048.breaking | 1 + packages/volto/src/config/server.js | 1 - packages/volto/src/helpers/Html/Html.jsx | 14 ++-- packages/volto/src/server.jsx | 70 +++++++++---------- 6 files changed, 49 insertions(+), 52 deletions(-) create mode 100644 packages/volto/news/6048.breaking diff --git a/docs/source/configuration/settings-reference.md b/docs/source/configuration/settings-reference.md index 87ba1afce2..b42797413c 100644 --- a/docs/source/configuration/settings-reference.md +++ b/docs/source/configuration/settings-reference.md @@ -522,11 +522,4 @@ criticalCssPath this file exists it is loaded and its content is embedded inline into the generated HTML. By default this path is `public/critical.css`. See the {doc}`../deploying/performance` section for more details. - -extractScripts - An object that allows you to configure the insertion of scripts on the page - in some particular cases. - For the moment it admits only one property: `errorPages` whose value is a Boolean. - - If `extractScripts.errorPages` is `true`, the JS will be inserted into the error page. ``` diff --git a/docs/source/upgrade-guide/index.md b/docs/source/upgrade-guide/index.md index 119f96f537..c05feed0c3 100644 --- a/docs/source/upgrade-guide/index.md +++ b/docs/source/upgrade-guide/index.md @@ -40,6 +40,14 @@ For this purpose, we have developed a {ref}`new utility {/* Add the crossorigin while in development */} - {this.props.extractScripts !== false - ? extractor.getScriptElements().map((elem) => - React.cloneElement(elem, { - crossOrigin: - process.env.NODE_ENV === 'production' ? undefined : 'true', - }), - ) - : ''} + {extractor.getScriptElements().map((elem) => + React.cloneElement(elem, { + crossOrigin: + process.env.NODE_ENV === 'production' ? undefined : 'true', + }), + )} ); diff --git a/packages/volto/src/server.jsx b/packages/volto/src/server.jsx index 0f90b0404c..106573eb9c 100644 --- a/packages/volto/src/server.jsx +++ b/packages/volto/src/server.jsx @@ -272,50 +272,48 @@ server.get('/*', (req, res) => { }); } + const sendHtmlResponse = ( + res, + statusCode, + extractor, + markup, + store, + req, + config, + ) => { + res.status(statusCode).send( + ` + ${renderToString( + , + )} + `, + ); + }; + if (context.url) { res.redirect(flattenToAppURL(context.url)); } else if (context.error_code) { res.set({ 'Cache-Control': 'no-cache', }); - - res.status(context.error_code).send( - ` - ${renderToString( - , - )} - `, + sendHtmlResponse( + res, + context.error_code, + extractor, + markup, + store, + req, + config, ); } else { - res.status(200).send( - ` - ${renderToString( - , - )} - `, - ); + sendHtmlResponse(res, 200, extractor, markup, store, req, config); } }, errorHandler) .catch(errorHandler); From b3cde7596dd98393f2cc624d45fdec6ce1dfb175 Mon Sep 17 00:00:00 2001 From: sabrina-bongiovanni <116291154+sabrina-bongiovanni@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:19:23 +0200 Subject: [PATCH 04/49] Byday and byyear-byday buttons padding in recurrence form (#6070) Co-authored-by: Steve Piercy --- packages/volto/news/6070.bugfix | 1 + .../themes/pastanaga/extras/widgets.less | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 packages/volto/news/6070.bugfix diff --git a/packages/volto/news/6070.bugfix b/packages/volto/news/6070.bugfix new file mode 100644 index 0000000000..2989ef4f3f --- /dev/null +++ b/packages/volto/news/6070.bugfix @@ -0,0 +1 @@ +Remove left and right padding from _Event > Edit recurrence > Repeat on_ buttons when repeating for weekly or yearly events for big fonts, preventing overflow. @sabrina-bongiovanni diff --git a/packages/volto/theme/themes/pastanaga/extras/widgets.less b/packages/volto/theme/themes/pastanaga/extras/widgets.less index 37fabade5f..d3afe8466a 100644 --- a/packages/volto/theme/themes/pastanaga/extras/widgets.less +++ b/packages/volto/theme/themes/pastanaga/extras/widgets.less @@ -153,3 +153,22 @@ body.babel-view .field.language-independent-field { .react-select__option { .word-break(); } + +// makes sure event recurrence form buttons don't overflow when font is big +.recurrence-form { + .byday-field { + .button { + flex-grow: 1; + padding-right: 0px; + padding-left: 0px; + } + } + + .byyear-field { + .byyear-byday { + display: flex; + flex-wrap: wrap; + align-items: center; + } + } +} From 5d1a5420abe9a0ac2cf0f2eac4676274526e8ce6 Mon Sep 17 00:00:00 2001 From: Jefferson Bledsoe Date: Thu, 6 Jun 2024 15:21:00 +0100 Subject: [PATCH 05/49] Add tabindex to each of the skiplink elements to better handle focus (#5959) Co-authored-by: ichim-david --- packages/volto/news/5959.bugfix | 1 + packages/volto/src/components/theme/Footer/Footer.jsx | 1 + .../volto/src/components/theme/Navigation/Navigation.jsx | 2 +- .../__snapshots__/Navigation.Multilingual.test.jsx.snap | 4 ++++ .../theme/Navigation/__snapshots__/Navigation.test.jsx.snap | 5 +++++ packages/volto/src/components/theme/View/View.jsx | 2 +- .../components/theme/View/__snapshots__/View.test.jsx.snap | 3 +++ 7 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 packages/volto/news/5959.bugfix diff --git a/packages/volto/news/5959.bugfix b/packages/volto/news/5959.bugfix new file mode 100644 index 0000000000..3cf2fa08bb --- /dev/null +++ b/packages/volto/news/5959.bugfix @@ -0,0 +1 @@ +Fixed skiplink links not tracking focus correctly @JeffersonBledsoe \ No newline at end of file diff --git a/packages/volto/src/components/theme/Footer/Footer.jsx b/packages/volto/src/components/theme/Footer/Footer.jsx index 7e08be8873..6bbabbf87f 100644 --- a/packages/volto/src/components/theme/Footer/Footer.jsx +++ b/packages/volto/src/components/theme/Footer/Footer.jsx @@ -42,6 +42,7 @@ const Footer = ({ intl }) => { textAlign="center" id="footer" aria-label="Footer" + tabIndex="-1" > diff --git a/packages/volto/src/components/theme/Navigation/Navigation.jsx b/packages/volto/src/components/theme/Navigation/Navigation.jsx index d60bad4bf3..56cc0a6d19 100644 --- a/packages/volto/src/components/theme/Navigation/Navigation.jsx +++ b/packages/volto/src/components/theme/Navigation/Navigation.jsx @@ -49,7 +49,7 @@ const Navigation = (props) => { setisMobileMenuOpen(false); }; return ( -