From c5a1c370eec27a0ebea9df51dde12040580def2f Mon Sep 17 00:00:00 2001 From: alin Date: Thu, 28 Mar 2024 17:30:37 +0200 Subject: [PATCH 1/9] chore: Cleanup package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78e17702..11d25e50 100644 --- a/package.json +++ b/package.json @@ -79,4 +79,4 @@ "cypress:open": "make cypress-open", "prepare": "husky install" } -} \ No newline at end of file +} From 644d1fdba23b2f66df9e695eee86d77d52dd4330 Mon Sep 17 00:00:00 2001 From: Krisztina Elekes Date: Mon, 1 Apr 2024 14:45:09 +0300 Subject: [PATCH 2/9] feat(blocks): add option to create body classes in the Layout Settings block - refs #265731 (#222) * feat(blocks): add option to create body classes in the Layout Settings block - refs #265731 * test: add tests for LayoutSettingsView to increase coverage * change(widget): rename creatableselect as creatable_select to follow the Volto pattern --- .../LayoutSettingsView.test.jsx | 68 ++++ .../manage/Blocks/LayoutSettings/schema.js | 1 + .../theme/Widgets/CreatableSelectWidget.jsx | 304 ++++++++++++++++++ .../Widgets/CreatableSelectWidget.test.jsx | 89 +++++ src/helpers/schema-utils.js | 8 +- src/index.js | 3 + src/index.test.js | 2 + 7 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 src/components/manage/Blocks/LayoutSettings/LayoutSettingsView.test.jsx create mode 100644 src/components/theme/Widgets/CreatableSelectWidget.jsx create mode 100644 src/components/theme/Widgets/CreatableSelectWidget.test.jsx diff --git a/src/components/manage/Blocks/LayoutSettings/LayoutSettingsView.test.jsx b/src/components/manage/Blocks/LayoutSettings/LayoutSettingsView.test.jsx new file mode 100644 index 00000000..a954a6a2 --- /dev/null +++ b/src/components/manage/Blocks/LayoutSettings/LayoutSettingsView.test.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Provider } from 'react-intl-redux'; +import configureStore from 'redux-mock-store'; +import { Router } from 'react-router-dom'; +import { createMemoryHistory } from 'history'; +import LayoutSettingsView from './LayoutSettingsView'; + +const mockStore = configureStore(); +let history = createMemoryHistory(); + +describe('LayoutSettingsView Component', () => { + it('renders without crashing', () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + }); + + const data = { + '@layout': 'e28ec238-4cd7-4b72-8025-66da44a6062f', + '@type': 'layoutSettings', + block: '87911ec6-4242-4bae-b6a5-9b28151169fa', + body_class: 'body-class-1', + layout_size: 'container_view', + }; + + const { container } = render( + + + + + , + ); + + expect(container).toBeTruthy(); + }); +}); + +describe('LayoutSettingsView Component', () => { + it('renders without crashing with multiple classes', () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + }); + + const data = { + '@layout': 'e28ec238-4cd7-4b72-8025-66da44a6062f', + '@type': 'layoutSettings', + block: '87911ec6-4242-4bae-b6a5-9b28151169fa', + body_class: ['body-class-1', 'body-class-2'], + layout_size: 'container_view', + }; + + const { container } = render( + + + + + , + ); + + expect(container).toBeTruthy(); + }); +}); diff --git a/src/components/manage/Blocks/LayoutSettings/schema.js b/src/components/manage/Blocks/LayoutSettings/schema.js index b5849804..6a15e57a 100644 --- a/src/components/manage/Blocks/LayoutSettings/schema.js +++ b/src/components/manage/Blocks/LayoutSettings/schema.js @@ -32,6 +32,7 @@ export const EditSchema = () => { ['homepage', 'Homepage'], ['homepage-inverse', 'Homepage inverse'], ], + widget: 'creatable_select', }, }, }; diff --git a/src/components/theme/Widgets/CreatableSelectWidget.jsx b/src/components/theme/Widgets/CreatableSelectWidget.jsx new file mode 100644 index 00000000..fcc6bfb0 --- /dev/null +++ b/src/components/theme/Widgets/CreatableSelectWidget.jsx @@ -0,0 +1,304 @@ +/** + * CreatableSelectWidget component. + * @module components/manage/Widgets/SelectWidget + * + * A copy of the SelectWidget component. The only difference is that is uses the Creatable component as a base + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { compose } from 'redux'; +import { map } from 'lodash'; +import { defineMessages, injectIntl } from 'react-intl'; +import { + getVocabFromHint, + getVocabFromField, + getVocabFromItems, +} from '@plone/volto/helpers'; +import { FormFieldWrapper } from '@plone/volto/components'; +import { getVocabulary, getVocabularyTokenTitle } from '@plone/volto/actions'; +import { normalizeValue } from '@plone/volto/components/manage/Widgets/SelectUtils'; + +import { + customSelectStyles, + DropdownIndicator, + ClearIndicator, + Option, + selectTheme, + MenuList, + MultiValueContainer, +} from '@plone/volto/components/manage/Widgets/SelectStyling'; +import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable'; + +import loadable from '@loadable/component'; + +export const Creatable = loadable(() => import('react-select/creatable')); + +const messages = defineMessages({ + default: { + id: 'Default', + defaultMessage: 'Default', + }, + idTitle: { + id: 'Short Name', + defaultMessage: 'Short Name', + }, + idDescription: { + id: 'Used for programmatic access to the fieldset.', + defaultMessage: 'Used for programmatic access to the fieldset.', + }, + title: { + id: 'Title', + defaultMessage: 'Title', + }, + description: { + id: 'Description', + defaultMessage: 'Description', + }, + close: { + id: 'Close', + defaultMessage: 'Close', + }, + choices: { + id: 'Choices', + defaultMessage: 'Choices', + }, + required: { + id: 'Required', + defaultMessage: 'Required', + }, + select: { + id: 'Select…', + defaultMessage: 'Select…', + }, + no_value: { + id: 'No value', + defaultMessage: 'No value', + }, + no_options: { + id: 'No options', + defaultMessage: 'No options', + }, +}); + +/** + * SelectWidget component class. + * @function SelectWidget + * @returns {string} Markup of the component. + */ +class SelectWidget extends Component { + /** + * Property types. + * @property {Object} propTypes Property types. + * @static + */ + static propTypes = { + id: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + description: PropTypes.string, + required: PropTypes.bool, + error: PropTypes.arrayOf(PropTypes.string), + getVocabulary: PropTypes.func.isRequired, + getVocabularyTokenTitle: PropTypes.func.isRequired, + choices: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.object, PropTypes.array]), + ), + items: PropTypes.shape({ + vocabulary: PropTypes.object, + }), + widgetOptions: PropTypes.shape({ + vocabulary: PropTypes.object, + }), + value: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.string, + PropTypes.bool, + PropTypes.func, + PropTypes.array, + ]), + onChange: PropTypes.func.isRequired, + onBlur: PropTypes.func, + onClick: PropTypes.func, + onEdit: PropTypes.func, + onDelete: PropTypes.func, + wrapped: PropTypes.bool, + noValueOption: PropTypes.bool, + customOptionStyling: PropTypes.any, + isMulti: PropTypes.bool, + placeholder: PropTypes.string, + }; + + /** + * Default properties + * @property {Object} defaultProps Default properties. + * @static + */ + static defaultProps = { + description: null, + required: false, + items: { + vocabulary: null, + }, + widgetOptions: { + vocabulary: null, + }, + error: [], + choices: [], + value: null, + onChange: () => {}, + onBlur: () => {}, + onClick: () => {}, + onEdit: null, + onDelete: null, + noValueOption: true, + customOptionStyling: null, + }; + + /** + * Component did mount + * @method componentDidMount + * @returns {undefined} + */ + componentDidMount() { + if ( + (!this.props.choices || this.props.choices?.length === 0) && + this.props.vocabBaseUrl + ) { + this.props.getVocabulary({ + vocabNameOrURL: this.props.vocabBaseUrl, + size: -1, + subrequest: this.props.lang, + }); + } + } + + componentDidUpdate(prevProps) { + if ( + this.props.vocabBaseUrl !== prevProps.vocabBaseUrl && + (!this.props.choices || this.props.choices?.length === 0) + ) { + this.props.getVocabulary({ + vocabNameOrURL: this.props.vocabBaseUrl, + size: -1, + subrequest: this.props.lang, + }); + } + } + + /** + * Render method. + * @method render + * @returns {string} Markup for the component. + */ + render() { + const { id, choices, value, intl, onChange } = this.props; + const normalizedValue = normalizeValue(choices, value, intl); + // Make sure that both disabled and isDisabled (from the DX layout feat work) + const disabled = this.props.disabled || this.props.isDisabled; + + let options = this.props.vocabBaseUrl + ? this.props.choices + : [ + ...map(choices, (option) => ({ + value: option[0], + label: + // Fix "None" on the serializer, to remove when fixed in p.restapi + option[1] !== 'None' && option[1] ? option[1] : option[0], + })), + // Only set "no-value" option if there's no default in the field + // TODO: also if this.props.defaultValue? + ...(this.props.noValueOption && + (this.props.default === undefined || this.props.default === null) + ? [ + { + label: this.props.intl.formatMessage(messages.no_value), + value: 'no-value', + }, + ] + : []), + ]; + + return ( + + 25 && { + MenuList, + }), + MultiValueContainer, + DropdownIndicator, + ClearIndicator, + Option: this.props.customOptionStyling || Option, + }} + value={normalizedValue} + placeholder={ + this.props.placeholder ?? + this.props.intl.formatMessage(messages.select) + } + onChange={(selectedOption) => { + return onChange( + id, + selectedOption.map((el) => el.value), + ); + }} + isClearable + /> + + ); + } +} + +export const SelectWidgetComponent = injectIntl(SelectWidget); + +export default compose( + injectLazyLibs(['reactSelect']), + connect( + (state, props) => { + const vocabBaseUrl = !props.choices + ? getVocabFromHint(props) || + getVocabFromField(props) || + getVocabFromItems(props) + : ''; + + const vocabState = + state.vocabularies?.[vocabBaseUrl]?.subrequests?.[state.intl.locale]; + + // If the schema already has the choices in it, then do not try to get the vocab, + // even if there is one + if (props.choices) { + return { + choices: props.choices, + lang: state.intl.locale, + }; + } else if (vocabState) { + return { + vocabBaseUrl, + choices: vocabState?.items ?? [], + lang: state.intl.locale, + }; + // There is a moment that vocabState is not there yet, so we need to pass the + // vocabBaseUrl to the component. + } else if (vocabBaseUrl) { + return { + vocabBaseUrl, + lang: state.intl.locale, + }; + } + return { lang: state.intl.locale }; + }, + { getVocabulary, getVocabularyTokenTitle }, + ), +)(SelectWidgetComponent); diff --git a/src/components/theme/Widgets/CreatableSelectWidget.test.jsx b/src/components/theme/Widgets/CreatableSelectWidget.test.jsx new file mode 100644 index 00000000..d72408d5 --- /dev/null +++ b/src/components/theme/Widgets/CreatableSelectWidget.test.jsx @@ -0,0 +1,89 @@ +import React from 'react'; +import configureStore from 'redux-mock-store'; +import { Provider } from 'react-intl-redux'; +import { waitFor, render, screen, fireEvent } from '@testing-library/react'; + +import CreatableSelectWidget from './CreatableSelectWidget'; + +const mockStore = configureStore(); + +jest.mock('@plone/volto/helpers/Loadable/Loadable'); +beforeAll( + async () => + await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(), +); + +test('renders a select widget component', async () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + vocabularies: { + 'plone.app.vocabularies.Keywords': { + items: [{ title: 'My item', value: 'myitem' }], + itemsTotal: 1, + }, + }, + }); + + const { container } = render( + + {}} + onBlur={() => {}} + onClick={() => {}} + /> + , + ); + + await waitFor(() => screen.getByText('My field')); + expect(container).toBeTruthy(); +}); + +test("No 'No value' option when default value is 0", async () => { + const store = mockStore({ + intl: { + locale: 'en', + messages: {}, + }, + }); + + const choices = [ + ['0', 'None'], + ['1', 'One'], + ]; + + const value = { + value: '0', + label: 'None', + }; + + const _default = 0; + + const { container } = render( + + {}} + onBlur={() => {}} + onClick={() => {}} + /> + , + ); + + await waitFor(() => screen.getByText('None')); + fireEvent.mouseDown( + container.querySelector('.react-select__dropdown-indicator'), + { button: 0 }, + ); + expect(container).toBeTruthy(); +}); diff --git a/src/helpers/schema-utils.js b/src/helpers/schema-utils.js index 360203b3..3b784ab3 100644 --- a/src/helpers/schema-utils.js +++ b/src/helpers/schema-utils.js @@ -66,7 +66,13 @@ export const getVoltoStyles = (props) => { if (styles[key] === true) { output[key] = key; } else { - output[value] = value; + if (Array.isArray(value)) { + value.forEach((el, i) => { + output[el] = el; + }); + } else { + output[value] = value; + } } } return output; diff --git a/src/index.js b/src/index.js index a49cbd01..c7df628b 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,8 @@ import HomePageView from '@eeacms/volto-eea-website-theme/components/theme/Homep import NotFound from '@eeacms/volto-eea-website-theme/components/theme/NotFound/NotFound'; import { TokenWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/TokenWidget'; import { TopicsWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/TopicsWidget'; +import CreatableSelectWidget from '@eeacms/volto-eea-website-theme/components/theme/Widgets/CreatableSelectWidget'; + import { Icon } from '@plone/volto/components'; import { getBlocks } from '@plone/volto/helpers'; import { serializeNodesToText } from '@plone/volto-slate/editor/render'; @@ -336,6 +338,7 @@ const applyConfig = (config) => { config.widgets.views.id.topics = TopicsWidget; config.widgets.views.id.subjects = TokenWidget; config.widgets.views.widget.tags = TokenWidget; + config.widgets.widget.creatable_select = CreatableSelectWidget; // /voltoCustom.css express-middleware // /ok express-middleware - see also: https://github.com/plone/volto/pull/4432 diff --git a/src/index.test.js b/src/index.test.js index 1758381b..01a7aee1 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -91,6 +91,7 @@ describe('applyConfig', () => { tags: undefined, }, }, + widget: {}, }, settings: { eea: { @@ -243,6 +244,7 @@ describe('applyConfig', () => { tags: undefined, }, }, + widget: {}, }, settings: { eea: {}, From 869ae7cbe2ec555ebfe563d66bb00e5bc80651c2 Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Tue, 2 Apr 2024 14:00:25 +0300 Subject: [PATCH 3/9] fix(toc): use the correct function to render entries in toc --- src/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index c7df628b..32c90e97 100644 --- a/src/index.js +++ b/src/index.js @@ -304,16 +304,16 @@ const applyConfig = (config) => { if (config.blocks.blocksConfig.columnsBlock) { config.blocks.blocksConfig.columnsBlock.available_colors = eea.colors; config.blocks.blocksConfig.columnsBlock.tocEntries = ( - tocData, block = {}, + tocData, ) => { // integration with volto-block-toc const headlines = tocData.levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; let entries = []; - const sorted_column_blocks = getBlocks(block?.data || {}); - sorted_column_blocks.forEach((column_block) => { - const sorted_blocks = getBlocks(column_block[1]); - sorted_blocks.forEach((block) => { + const columns = getBlocks(block?.data || {}); + columns.forEach((column) => { + const blocks = getBlocks(column[1]); + blocks.forEach((block) => { const { value, plaintext } = block[1]; const type = value?.[0]?.type; if (headlines.includes(type)) { From 2bbc620d0a375d69ba7982c8e3113628365bb8da Mon Sep 17 00:00:00 2001 From: David Ichim Date: Tue, 2 Apr 2024 17:24:22 +0300 Subject: [PATCH 4/9] Revert "fix(blocks): Allow image block urls to be external (#214)" This reverts commit f9dd860ba46b34f09e263550044e9350eff70873. --- .../volto/components/manage/Blocks/Image/View.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/customizations/volto/components/manage/Blocks/Image/View.jsx b/src/customizations/volto/components/manage/Blocks/Image/View.jsx index b1c86aae..3814856d 100644 --- a/src/customizations/volto/components/manage/Blocks/Image/View.jsx +++ b/src/customizations/volto/components/manage/Blocks/Image/View.jsx @@ -20,7 +20,7 @@ import { Copyright } from '@eeacms/volto-eea-design-system/ui'; */ export const View = (props) => { const { data, detached } = props; - const href = data?.href?.[0]?.['@id'] ?? (data?.href || ''); + const href = data?.href?.[0]?.['@id'] || ''; const { copyright, copyrightIcon, copyrightPosition } = data; // const [hovering, setHovering] = React.useState(false); const [viewLoaded, setViewLoaded] = React.useState(false); From a0ecadf6efcdeb0fec4ee533d27a6c6787029373 Mon Sep 17 00:00:00 2001 From: ichim-david Date: Tue, 2 Apr 2024 17:50:02 +0300 Subject: [PATCH 5/9] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 11d25e50..d1af8281 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@eeacms/volto-eea-website-theme", - "version": "1.32.1", + "version": "1.33.0", "description": "@eeacms/volto-eea-website-theme: Volto add-on", "main": "src/index.js", "author": "European Environment Agency: IDM2 A-Team", From 458cee62b3d405fe6b3205c439ffe56e9164217f Mon Sep 17 00:00:00 2001 From: EEA Jenkins <@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:00:15 +0000 Subject: [PATCH 6/9] Automated release 1.33.0 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d927dceb..b1157208 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +### [1.33.0](https://github.com/eea/volto-eea-website-theme/compare/1.32.1...1.33.0) - 2 April 2024 + +#### :bug: Bug Fixes + +- fix(toc): use the correct function to render entries in toc [Miu Razvan - [`869ae7c`](https://github.com/eea/volto-eea-website-theme/commit/869ae7cbe2ec555ebfe563d66bb00e5bc80651c2)] + +#### :house: Internal changes + +- chore: Cleanup package.json [alin - [`c5a1c37`](https://github.com/eea/volto-eea-website-theme/commit/c5a1c370eec27a0ebea9df51dde12040580def2f)] + +#### :hammer_and_wrench: Others + +- Update package.json [ichim-david - [`a0ecadf`](https://github.com/eea/volto-eea-website-theme/commit/a0ecadf6efcdeb0fec4ee533d27a6c6787029373)] +- Revert "fix(blocks): Allow image block urls to be external (#214)" [David Ichim - [`2bbc620`](https://github.com/eea/volto-eea-website-theme/commit/2bbc620d0a375d69ba7982c8e3113628365bb8da)] ### [1.32.1](https://github.com/eea/volto-eea-website-theme/compare/1.32.0...1.32.1) - 26 March 2024 #### :rocket: New Features From eb55ff8753e443c83fd4a8bb3dca8c2b2a78a782 Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Tue, 2 Apr 2024 18:20:33 +0300 Subject: [PATCH 7/9] feat(columnsBlock): move tocEntries definition to volto-columns-block --- src/index.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/index.js b/src/index.js index 32c90e97..8037b6c7 100644 --- a/src/index.js +++ b/src/index.js @@ -303,26 +303,6 @@ const applyConfig = (config) => { // Apply columns block customization if (config.blocks.blocksConfig.columnsBlock) { config.blocks.blocksConfig.columnsBlock.available_colors = eea.colors; - config.blocks.blocksConfig.columnsBlock.tocEntries = ( - block = {}, - tocData, - ) => { - // integration with volto-block-toc - const headlines = tocData.levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; - let entries = []; - const columns = getBlocks(block?.data || {}); - columns.forEach((column) => { - const blocks = getBlocks(column[1]); - blocks.forEach((block) => { - const { value, plaintext } = block[1]; - const type = value?.[0]?.type; - if (headlines.includes(type)) { - entries.push([parseInt(type.slice(1)), plaintext, block[0]]); - } - }); - }); - return entries; - }; } // Description block custom CSS From 89b9cefbe35f780bdd07fa6f44234fbfc2fe7bb0 Mon Sep 17 00:00:00 2001 From: ichim-david Date: Tue, 2 Apr 2024 19:05:32 +0300 Subject: [PATCH 8/9] Update index.js to fix jslint issue --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index 8037b6c7..93d56634 100644 --- a/src/index.js +++ b/src/index.js @@ -9,7 +9,6 @@ import { TopicsWidget } from '@eeacms/volto-eea-website-theme/components/theme/W import CreatableSelectWidget from '@eeacms/volto-eea-website-theme/components/theme/Widgets/CreatableSelectWidget'; import { Icon } from '@plone/volto/components'; -import { getBlocks } from '@plone/volto/helpers'; import { serializeNodesToText } from '@plone/volto-slate/editor/render'; import Tag from '@eeacms/volto-eea-design-system/ui/Tag/Tag'; From 56015f467e639d284fe93ea662bb941db92b2831 Mon Sep 17 00:00:00 2001 From: EEA Jenkins <@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:16:42 +0000 Subject: [PATCH 9/9] Automated release 1.33.0 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1157208..f9271273 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### [1.33.0](https://github.com/eea/volto-eea-website-theme/compare/1.32.1...1.33.0) - 2 April 2024 +#### :rocket: New Features + +- feat(columnsBlock): move tocEntries definition to volto-columns-block [Miu Razvan - [`eb55ff8`](https://github.com/eea/volto-eea-website-theme/commit/eb55ff8753e443c83fd4a8bb3dca8c2b2a78a782)] + #### :bug: Bug Fixes - fix(toc): use the correct function to render entries in toc [Miu Razvan - [`869ae7c`](https://github.com/eea/volto-eea-website-theme/commit/869ae7cbe2ec555ebfe563d66bb00e5bc80651c2)] @@ -16,6 +20,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). #### :hammer_and_wrench: Others +- Update index.js to fix jslint issue [ichim-david - [`89b9cef`](https://github.com/eea/volto-eea-website-theme/commit/89b9cefbe35f780bdd07fa6f44234fbfc2fe7bb0)] - Update package.json [ichim-david - [`a0ecadf`](https://github.com/eea/volto-eea-website-theme/commit/a0ecadf6efcdeb0fec4ee533d27a6c6787029373)] - Revert "fix(blocks): Allow image block urls to be external (#214)" [David Ichim - [`2bbc620`](https://github.com/eea/volto-eea-website-theme/commit/2bbc620d0a375d69ba7982c8e3113628365bb8da)] ### [1.32.1](https://github.com/eea/volto-eea-website-theme/compare/1.32.0...1.32.1) - 26 March 2024