diff --git a/.gitignore b/.gitignore index 28d280fb5a..99907cc0fd 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ cypress/screenshots # Local environment setup .env public/critical.css +packages/volto/data # Sphinx and MyST docs/_build/ diff --git a/docs/source/contributing/developing-core.md b/docs/source/contributing/developing-core.md index 4c3dc40a88..f522d21490 100644 --- a/docs/source/contributing/developing-core.md +++ b/docs/source/contributing/developing-core.md @@ -172,6 +172,19 @@ pnpm install ## Start the backend and Volto +`````{versionadded} 18.0.0-alpha.42 +Persist backend data across Docker sessions. + +````{warning} +Do not use this method of persistence in a production environment. +It is intended only for development. + +```{seealso} +{doc}`../deploying/index` +``` +```` +````` + Every time you want to run Volto for core development, you will need to create two terminal sessions, one for the backend and one for the frontend. For both sessions, change your working directory to the root of your Volto clone. @@ -181,7 +194,20 @@ In the first session, start the backend. make backend-docker-start ``` -When you run this command for the first time, it will download Docker images, configure the backend, and start the backend. +When you run this command for the first time, it will download Docker images, configure the backend, create a Docker volume to persist the data named `volto-backend-data`, and start the backend. + +Subsequently, when you run `make backend-docker-start`, it will only start the backend using the existing configuration and Docker image and volume. + +````{note} +If you would like to start the backend with a clean data volume, you can run the following command. + +```shell +docker volume rm volto-backend-data +``` + +Then run `make backend-docker-start` again to start the backend with a clean data volume. +```` + Browse to the backend running at http://localhost:8080. In the second session, start the frontend. diff --git a/docs/source/development/i18n.md b/docs/source/development/i18n.md index 9359ef4e6f..15e9c32e8c 100644 --- a/docs/source/development/i18n.md +++ b/docs/source/development/i18n.md @@ -163,10 +163,12 @@ Then it will synchronize the extracted messages with the `.pot` main template an This script will combine the messages located in Volto itself and the current project, and combine them into the `.json` files. +(override-i18n-messages)= + ## Override i18n messages If you want to override an existing translation, you should declare the original message again somewhere else in your project. -For example in `src/config.js`: +For example in `src/messages.js`: ```js import { defineMessages } from 'react-intl'; @@ -191,11 +193,16 @@ msgstr "My overridden translation" After you set the override, then run `yarn i18n` again to create the `de.json` translation files. Restart Volto to see the changes applied. -```{note} -Shadowed components do _not_ override translations. -99% of the time you do not want them to do that. -Thus the `customizations` folder is excluded from the i18n build. -``` + +(translations-in-shadowed-components-label)= + +### Translations in shadowed components + +The `customizations` folder is excluded from the i18n build. +This means that shadowed components do _not_ override translations. +If this was not the case, then all the translations in the customized components would be collected again, forcing you to translate them all again in the local project. +You can add or override translated messages in your customizations by following the steps described in {ref}`override-i18n-messages`. + ## Contribute translations for an unsupported language diff --git a/docs/source/upgrade-guide/index.md b/docs/source/upgrade-guide/index.md index 803a0b7f28..ecb77f6195 100644 --- a/docs/source/upgrade-guide/index.md +++ b/docs/source/upgrade-guide/index.md @@ -376,6 +376,24 @@ It is unlikely that your code uses it, unless you heavily customized the Jest te The `react-share` library and `SocialSharing` component has not been used in the core since some time ago, and it is more suitable as an add-on and not in core. If you still use it, you can add it to your main add-on dependency, and extract the `SocialSharing` component from Volto 17 as a custom component in your add-on code. + +### `SchemaWidget` widget registration change + +Previously in the widget mapping, the `SchemaWidget` was registered in the `id` object and assigned to the `schema` key. +Due to this common key name, this definition could leak the widget and be applied to unwanted fields. +The `SchemaWidget` is now registered under the `widget` object. +If you use it in your project or add-ons, you should update the field definition, and add the `widget` property. + +```ts +// more form definition above... +schema: { + title: 'Schema', + widget: 'schema' +} +// rest of the form definition... +``` + + (volto-upgrade-guide-17.x.x)= ## Upgrading to Volto 17.x.x diff --git a/packages/volto/Makefile b/packages/volto/Makefile index 51236a9395..225a878497 100644 --- a/packages/volto/Makefile +++ b/packages/volto/Makefile @@ -98,7 +98,7 @@ release-notes-copy-to-docs: ## Copy release notes into documentation .PHONY: backend-docker-start backend-docker-start: ## Starts a Docker-based backend for development - docker run -it --rm --name=backend -p 8080:8080 -e SITE=Plone -e ADDONS='$(KGS)' $(DOCKER_IMAGE) + docker run -it --rm --name=backend -p 8080:8080 -v volto-backend-data:/data -e SITE=Plone -e ADDONS='$(KGS)' $(DOCKER_IMAGE) .PHONY: frontend-docker-start frontend-docker-start: ## Starts a Docker-based frontend for development diff --git a/packages/volto/news/6153.internal b/packages/volto/news/6153.internal new file mode 100644 index 0000000000..6c8fd1188e --- /dev/null +++ b/packages/volto/news/6153.internal @@ -0,0 +1 @@ +Debounced searching for users and groups in the `User Group Membership` Control Panel. @pnicolli diff --git a/packages/volto/news/6157.bugfix b/packages/volto/news/6157.bugfix new file mode 100644 index 0000000000..88e356670e --- /dev/null +++ b/packages/volto/news/6157.bugfix @@ -0,0 +1,4 @@ +Persist data for the `backend-docker-start` Docker container in a Docker volume named `volto-backend-data`. +This way the data is persisted between runs of the container. +You can also delete the `data` volume to start fresh. +@ichim-david \ No newline at end of file diff --git a/packages/volto/news/6188.documentation b/packages/volto/news/6188.documentation new file mode 100644 index 0000000000..623807c594 --- /dev/null +++ b/packages/volto/news/6188.documentation @@ -0,0 +1 @@ +Improved i18n docs regarding new translated messages not being picked up by the i18n translation mechanism when added in shadowed components. @pnicolli diff --git a/packages/volto/news/6189.breaking b/packages/volto/news/6189.breaking new file mode 100644 index 0000000000..89e756306a --- /dev/null +++ b/packages/volto/news/6189.breaking @@ -0,0 +1 @@ +In the widget mapping, moved the `SchemaWidget` registration from the `id` object to the `widget` object, and added the `widget` key to the `schema` object in the `properties` object for `makeSchemaList`. @sneridagh diff --git a/packages/volto/news/6189.bugfix b/packages/volto/news/6189.bugfix new file mode 100644 index 0000000000..b25ea08e8a --- /dev/null +++ b/packages/volto/news/6189.bugfix @@ -0,0 +1 @@ +Improve CSS for the `SchemaWidget` widget. @robgietema @sneridagh diff --git a/packages/volto/news/6192.documentation b/packages/volto/news/6192.documentation new file mode 100644 index 0000000000..a518e15d24 --- /dev/null +++ b/packages/volto/news/6192.documentation @@ -0,0 +1 @@ +Add a label and minor grammar fixes to i18n documentation. @stevepiercy diff --git a/packages/volto/news/6193.documentation b/packages/volto/news/6193.documentation new file mode 100644 index 0000000000..54a9474dcc --- /dev/null +++ b/packages/volto/news/6193.documentation @@ -0,0 +1 @@ +Polish upgrade docs and news items for `SchemaWidget`. @stevepiercy diff --git a/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx b/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx index 6aaeeff4ab..1215aaeb61 100644 --- a/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx +++ b/packages/volto/src/components/manage/Controlpanels/ContentTypeSchema.jsx @@ -213,6 +213,7 @@ class ContentTypeSchema extends Component { title: 'Form schema', type: 'schema', id: 'schema', + widget: 'schema', }, }, required: [], diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx index 7c3559f6b9..4530107479 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx @@ -1,5 +1,5 @@ -import React, { useEffect, useState } from 'react'; -import { cloneDeep, uniqBy } from 'lodash'; +import React, { useEffect, useState, useMemo } from 'react'; +import { cloneDeep, uniqBy, debounce } from 'lodash'; import { useIntl } from 'react-intl'; import { useSelector, useDispatch, shallowEqual } from 'react-redux'; import jwtDecode from 'jwt-decode'; @@ -114,25 +114,41 @@ const ListingTemplate = ({ matrix_options = []; } + const debouncedListUsers = useMemo( + () => + debounce((query_user, groups_filter, userLimit) => { + dispatch( + listUsers({ + search: query_user, + groups_filter: groups_filter.map((el) => el.value), + limit: userLimit, + }), + ); + }, 300), + [dispatch], + ); + useEffect(() => { // Get users. if (show_users) { - dispatch( - listUsers({ - search: query_user, - groups_filter: groups_filter.map((el) => el.value), - limit: userLimit, - }), - ); + debouncedListUsers(query_user, groups_filter, userLimit); } - }, [dispatch, query_user, groups_filter, show_users, userLimit]); + }, [debouncedListUsers, query_user, groups_filter, show_users, userLimit]); + + const debouncedListGroups = useMemo( + () => + debounce((query_group) => { + dispatch(listGroups(query_group)); + }, 300), + [dispatch], + ); useEffect(() => { // Get matrix groups. if (show_matrix_options) { - dispatch(listGroups(query_group)); + debouncedListGroups(query_group); } - }, [dispatch, query_group, show_matrix_options, groups_filter]); + }, [debouncedListGroups, query_group, show_matrix_options]); const onSelectOptionHandler = (selectedvalue, checked, singleClick) => { singleClick = singleClick ?? false; diff --git a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx index ca41f24f4f..371acfd32c 100644 --- a/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +++ b/packages/volto/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx @@ -1,9 +1,9 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useIntl } from 'react-intl'; import { Checkbox, Form, Input } from 'semantic-ui-react'; -import { isEqual } from 'lodash'; +import { isEqual, debounce } from 'lodash'; import { messages } from '@plone/volto/helpers'; import { listGroups } from '@plone/volto/actions'; // getRegistry @@ -38,12 +38,20 @@ const UserGroupMembershipMatrix = ({ many_users, many_groups }) => { }); } + const debouncedListGroups = useMemo( + () => + debounce((query_group_filter) => { + dispatch(listGroups('', query_group_filter)); + }, 300), + [dispatch], + ); + useEffect(() => { // TODO fetch group for at least query_group_filter.length > 1? if (!many_groups || (many_groups && query_group_filter.length > 1)) { - dispatch(listGroups('', query_group_filter)); + debouncedListGroups(query_group_filter); } - }, [dispatch, many_groups, query_group_filter]); + }, [debouncedListGroups, many_groups, query_group_filter]); const onReset = (event) => { // event.preventDefault(); diff --git a/packages/volto/src/config/Widgets.jsx b/packages/volto/src/config/Widgets.jsx index 435d23b949..07f2a72c57 100644 --- a/packages/volto/src/config/Widgets.jsx +++ b/packages/volto/src/config/Widgets.jsx @@ -55,7 +55,6 @@ import ImageWidget from '@plone/volto/components/manage/Widgets/ImageWidget'; // Widgets mapping export const widgetMapping = { id: { - schema: SchemaWidget, subjects: TokenWidget, query: QuerystringWidget, recurrence: RecurrenceWidget, @@ -89,6 +88,7 @@ export const widgetMapping = { autocomplete: SelectAutoComplete, color_picker: ColorPickerWidget, select: SelectWidget, + schema: SchemaWidget, }, vocabulary: { 'plone.app.vocabularies.Catalog': ObjectBrowserWidget, diff --git a/packages/volto/theme/themes/pastanaga/collections/form.overrides b/packages/volto/theme/themes/pastanaga/collections/form.overrides index 963bf4b6c4..3d5ae5e965 100644 --- a/packages/volto/theme/themes/pastanaga/collections/form.overrides +++ b/packages/volto/theme/themes/pastanaga/collections/form.overrides @@ -123,16 +123,50 @@ z-index: 1; top: 0; right: 0; + left: auto; display: flex; height: 60px; align-items: center; margin-right: 1rem; + background: transparent; + box-shadow: none; + transform: none; .item { cursor: pointer; } } +.block.form { + [data-rbd-draggable-context-id] { + margin-bottom: 0; + } + + .ui.menu .item > i.icon { + margin-left: -2px; + } + + .square.icon { + margin-top: -2px; + } + + .ui.segments > div { + background: white !important; + } + + .drag.handle { + cursor: grab; + } + + .tabular.menu > .item { + height: 66px; + + button { + border-bottom-width: 5px; + } + } +} + .ui.form .field .ui.basic.button.delete-button { padding: 0; border: none;