@eeacms/volto-eea-website-theme 4.1.0 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [4.2.0](https://github.com/eea/volto-eea-website-theme/compare/4.1.1...4.2.0) - 21 April 2026
8
+
9
+ #### :nail_care: Enhancements
10
+
11
+ - refactor: replace eea-settings controlpanel with header-settings via asyncPropsExtenders [Miu Razvan - [`f7d169b`](https://github.com/eea/volto-eea-website-theme/commit/f7d169b1bd12446cef74b78969cca1ddb19a7531)]
12
+
13
+ #### :hammer_and_wrench: Others
14
+
15
+ - Release 4.2.0 [Alin Voinea - [`8f7d6d0`](https://github.com/eea/volto-eea-website-theme/commit/8f7d6d0d0547dbe384c835375b56ccdb87c5dd44)]
16
+ ### [4.1.1](https://github.com/eea/volto-eea-website-theme/compare/4.1.0...4.1.1) - 17 April 2026
17
+
18
+ #### :bug: Bug Fixes
19
+
20
+ - fix(order-sidebar): respect required and fixed block restrictions - refs #302095 [Alin Voinea - [`51557f2`](https://github.com/eea/volto-eea-website-theme/commit/51557f220fbe3992110e96862f4ab0ba987d42ed)]
21
+
7
22
  ### [4.1.0](https://github.com/eea/volto-eea-website-theme/compare/4.0.5...4.1.0) - 17 April 2026
8
23
 
9
24
  #### :house: Internal changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-website-theme",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "@eeacms/volto-eea-website-theme: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -0,0 +1,9 @@
1
+ import { GET_HEADER_SETTINGS } from '../constants/ActionTypes';
2
+
3
+ export const getHeaderSettings = () => ({
4
+ type: GET_HEADER_SETTINGS,
5
+ request: {
6
+ op: 'get',
7
+ path: '/@header-settings',
8
+ },
9
+ });
@@ -1,3 +1,3 @@
1
1
  export * from './print';
2
2
  export * from './navigation';
3
- export * from './eea-settings';
3
+ export * from './header-settings';
@@ -6,4 +6,4 @@
6
6
  export const SET_ISPRINT = 'SET_ISPRINT';
7
7
  export const SET_PRINT_LOADING = 'SET_PRINT_LOADING';
8
8
  export const GET_NAVIGATION_SETTINGS = 'GET_NAVIGATION_SETTINGS';
9
- export const GET_EEA_SETTINGS = 'GET_EEA_SETTINGS';
9
+ export const GET_HEADER_SETTINGS = 'GET_HEADER_SETTINGS';
@@ -0,0 +1,146 @@
1
+ import React, { forwardRef } from 'react';
2
+ import classNames from 'classnames';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+ import includes from 'lodash/includes';
5
+ import isBoolean from 'lodash/isBoolean';
6
+ import cx from 'classnames';
7
+ import Icon from '@plone/volto/components/theme/Icon/Icon';
8
+ import { setUIState } from '@plone/volto/actions/form/form';
9
+ import config from '@plone/volto/registry';
10
+
11
+ import deleteSVG from '@plone/volto/icons/delete.svg';
12
+ import dragSVG from '@plone/volto/icons/drag.svg';
13
+
14
+ // TEMPORARY PATCH (Volto issue #6481):
15
+ // Remove this customization once the upstream fixes are released and adopted.
16
+ // Upstream PRs: https://github.com/plone/volto/pull/8124 and
17
+ // https://github.com/plone/volto/pull/8125
18
+ export const Item = forwardRef(
19
+ (
20
+ {
21
+ clone,
22
+ data,
23
+ depth,
24
+ disableSelection,
25
+ disableInteraction,
26
+ ghost,
27
+ id,
28
+ handleProps,
29
+ indentationWidth,
30
+ onRemove,
31
+ onSelectBlock,
32
+ parentId,
33
+ parentType,
34
+ style,
35
+ value,
36
+ wrapperRef,
37
+ errors,
38
+ ...props
39
+ },
40
+ ref,
41
+ ) => {
42
+ const selected = useSelector((state) => state.form.ui.selected);
43
+ const hovered = useSelector((state) => state.form.ui.hovered);
44
+ const multiSelected = useSelector((state) => state.form.ui.multiSelected);
45
+ const gridSelected = useSelector((state) => state.form.ui.gridSelected);
46
+ const dispatch = useDispatch();
47
+
48
+ const icon =
49
+ config.blocks.blocksConfig[data?.['@type']]?.icon ||
50
+ config.blocks.blocksConfig.title?.icon;
51
+
52
+ const required = isBoolean(data?.required)
53
+ ? data.required
54
+ : includes(config.blocks.requiredBlocks, data?.['@type']);
55
+ const fixed = !!data?.fixed;
56
+
57
+ return (
58
+ <li
59
+ className={classNames(
60
+ 'tree-item-wrapper',
61
+ clone && 'clone',
62
+ ghost && 'ghost',
63
+ disableSelection && 'disable-selection',
64
+ disableInteraction && 'disable-interaction',
65
+ )}
66
+ role="presentation"
67
+ onMouseOver={() => dispatch(setUIState({ hovered: id }))}
68
+ onFocus={() => dispatch(setUIState({ hovered: id }))}
69
+ onMouseLeave={() => dispatch(setUIState({ hovered: null }))}
70
+ onClick={(e) => {
71
+ if (depth === 0) {
72
+ const isMultipleSelection = e.shiftKey || e.ctrlKey || e.metaKey;
73
+ selected !== id &&
74
+ onSelectBlock(
75
+ id,
76
+ selected === id ? false : isMultipleSelection,
77
+ e,
78
+ );
79
+ } else {
80
+ dispatch(
81
+ setUIState({
82
+ selected: parentId,
83
+ multiSelected: [],
84
+ gridSelected: id,
85
+ }),
86
+ );
87
+ }
88
+ }}
89
+ ref={wrapperRef}
90
+ style={{
91
+ '--spacing': `${indentationWidth * depth}px`,
92
+ }}
93
+ {...props}
94
+ >
95
+ <div
96
+ className={classNames(
97
+ 'tree-item',
98
+ (selected === id || gridSelected === id) && 'selected',
99
+ hovered === id && 'hovered',
100
+ includes(multiSelected, id) && 'multiSelected',
101
+ `depth-${depth}`,
102
+ )}
103
+ ref={ref}
104
+ style={style}
105
+ >
106
+ {!fixed && (
107
+ <button
108
+ ref={ref}
109
+ {...handleProps}
110
+ className={classNames('action', 'drag')}
111
+ tabIndex={0}
112
+ data-cypress="draggable-handle"
113
+ >
114
+ <Icon name={dragSVG} size="16px" />
115
+ </button>
116
+ )}
117
+ <span
118
+ className={cx('text', {
119
+ errored: errors && Object.keys(errors).length > 0,
120
+ })}
121
+ >
122
+ {icon && (
123
+ <Icon
124
+ name={icon}
125
+ size="20px"
126
+ style={{ verticalAlign: 'middle' }}
127
+ />
128
+ )}{' '}
129
+ {data?.plaintext ||
130
+ config.blocks.blocksConfig[data?.['@type']]?.title ||
131
+ data?.title}
132
+ </span>
133
+ {!clone && onRemove && !required && (
134
+ <button
135
+ onClick={onRemove}
136
+ className={classNames('action', 'delete')}
137
+ tabIndex={0}
138
+ >
139
+ <Icon name={deleteSVG} size="18" />
140
+ </button>
141
+ )}
142
+ </div>
143
+ </li>
144
+ );
145
+ },
146
+ );
@@ -61,9 +61,12 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
61
61
  const width = useSelector((state) => state.screen?.width);
62
62
  const dispatch = useDispatch();
63
63
 
64
- const eeaSettings = useSelector((state) => state.eeaSettings?.data);
64
+ const headerSettings = useSelector(
65
+ (state) => state.reduxAsyncConnect?.headerSettings,
66
+ );
67
+
65
68
  const headerSearchBox =
66
- eeaSettings?.header?.searchBox || eea.headerSearchBox || [];
69
+ headerSettings?.searchBox || eea.headerSearchBox || [];
67
70
  const previousToken = usePrevious(token);
68
71
  const navigationSettings =
69
72
  useSelector((state) => state.navigationSettings?.settings) ||
@@ -33,7 +33,6 @@ import {
33
33
  import { changeLanguage } from '@plone/volto/actions/language/language';
34
34
 
35
35
  import userSession from '@plone/volto/reducers/userSession/userSession';
36
- import { getEEASettings } from '@eeacms/volto-eea-website-theme/actions';
37
36
 
38
37
  import configureStore from '@plone/volto/store';
39
38
  import ErrorPage from '@plone/volto/error';
@@ -264,7 +263,6 @@ server.get('/*', (req, res) => {
264
263
  const location = parseUrl(url);
265
264
 
266
265
  loadOnServer({ store, location, routes, api })
267
- .then(() => Promise.all([store.dispatch(getEEASettings())]).catch(() => {}))
268
266
  .then(() => {
269
267
  const initialLang =
270
268
  req.universalCookies.get('I18N_LANGUAGE') ||
@@ -0,0 +1,20 @@
1
+ import { getHeaderSettings } from '@eeacms/volto-eea-website-theme/actions';
2
+
3
+ // asyncPropsExtenders entry. Loads header settings during SSR so they're
4
+ // available to the Header component on the first render. Result lands in
5
+ // state.reduxAsyncConnect.headerSettings.
6
+ export const headerSettingsExtender = {
7
+ path: '/',
8
+ extend: (dispatchActions) => {
9
+ if (
10
+ dispatchActions.filter((a) => a.key === 'headerSettings').length === 0
11
+ ) {
12
+ dispatchActions.push({
13
+ key: 'headerSettings',
14
+ promise: ({ store: { dispatch } }) =>
15
+ __SERVER__ && dispatch(getHeaderSettings()),
16
+ });
17
+ }
18
+ return dispatchActions;
19
+ },
20
+ };
package/src/index.js CHANGED
@@ -49,7 +49,8 @@ import okMiddleware from './middleware/ok';
49
49
  import voltoCustomCSSMiddleware from './middleware/voltoCustom';
50
50
  import { voltoCustomJsMiddleware } from './middleware/voltoCustom';
51
51
  import installSlate from './slate';
52
- import { print, navigationSettings, eeaSettings } from './reducers';
52
+ import { print, navigationSettings } from './reducers';
53
+ import { headerSettingsExtender } from './helpers/headerSettingsExtender';
53
54
 
54
55
  import * as eea from './config';
55
56
 
@@ -676,9 +677,13 @@ const applyConfig = (config) => {
676
677
  ...(config.addonReducers || {}),
677
678
  print,
678
679
  navigationSettings,
679
- eeaSettings,
680
680
  };
681
681
 
682
+ config.settings.asyncPropsExtenders = [
683
+ ...(config.settings.asyncPropsExtenders || []),
684
+ headerSettingsExtender,
685
+ ];
686
+
682
687
  // Mega menu object
683
688
  if (!config.settings.menuItemsLayouts) {
684
689
  config.settings.menuItemsLayouts = {};
@@ -1,5 +1,4 @@
1
1
  import print from './print';
2
2
  import navigationSettings from './navigation';
3
- import eeaSettings from './eea-settings';
4
3
 
5
- export { print, navigationSettings, eeaSettings };
4
+ export { print, navigationSettings };
@@ -1,9 +0,0 @@
1
- import { GET_EEA_SETTINGS } from '../constants/ActionTypes';
2
-
3
- export const getEEASettings = () => ({
4
- type: GET_EEA_SETTINGS,
5
- request: {
6
- op: 'get',
7
- path: '/@eea.settings',
8
- },
9
- });
@@ -1,33 +0,0 @@
1
- import { GET_EEA_SETTINGS } from '../constants/ActionTypes';
2
-
3
- const initialState = {
4
- error: null,
5
- loaded: false,
6
- loading: false,
7
- data: {},
8
- };
9
-
10
- export default function eeaSettings(state = initialState, action = {}) {
11
- switch (action.type) {
12
- case `${GET_EEA_SETTINGS}_PENDING`:
13
- return { ...state, error: null, loaded: false, loading: true };
14
- case `${GET_EEA_SETTINGS}_SUCCESS`:
15
- return {
16
- ...state,
17
- error: null,
18
- loaded: true,
19
- loading: false,
20
- data: action.result || {},
21
- };
22
- case `${GET_EEA_SETTINGS}_FAIL`:
23
- return {
24
- ...state,
25
- error: action.error,
26
- loaded: false,
27
- loading: false,
28
- data: {},
29
- };
30
- default:
31
- return state;
32
- }
33
- }