@eeacms/volto-eea-website-theme 3.12.0 → 3.13.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 +5 -0
- package/jest-addon.config.js +2 -2
- package/package.json +1 -1
- package/src/components/theme/Widgets/NavigationBehaviorWidget.jsx +17 -25
- package/src/components/theme/Widgets/NavigationBehaviorWidget.test.jsx +114 -0
- package/src/config.js +6 -0
- package/src/customizations/volto/components/theme/Header/Header.jsx +15 -9
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,11 @@ 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
|
+
### [3.13.0](https://github.com/eea/volto-eea-website-theme/compare/3.12.0...3.13.0) - 4 November 2025
|
|
8
|
+
|
|
9
|
+
#### :hammer_and_wrench: Others
|
|
10
|
+
|
|
11
|
+
- Bump version from 3.12.1 to 3.13.0 [David Ichim - [`c182fea`](https://github.com/eea/volto-eea-website-theme/commit/c182fea83aad1c0b224c37287a5c2935a2e893d0)]
|
|
7
12
|
### [3.12.0](https://github.com/eea/volto-eea-website-theme/compare/3.11.0...3.12.0) - 4 November 2025
|
|
8
13
|
|
|
9
14
|
#### :bug: Bug Fixes
|
package/jest-addon.config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require('dotenv').config({ path: __dirname + '/.env' })
|
|
1
|
+
require('dotenv').config({ path: __dirname + '/.env' });
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
testMatch: ['**/src/addons/**/?(*.)+(spec|test).[jt]s?(x)'],
|
|
@@ -48,4 +48,4 @@ module.exports = {
|
|
|
48
48
|
'<rootDir>/node_modules/@eeacms/volto-eea-website-theme/jest.setup.js',
|
|
49
49
|
],
|
|
50
50
|
}),
|
|
51
|
-
}
|
|
51
|
+
};
|
package/package.json
CHANGED
|
@@ -8,6 +8,8 @@ import { getNavigation } from '@plone/volto/actions';
|
|
|
8
8
|
import { defineMessages, useIntl } from 'react-intl';
|
|
9
9
|
import config from '@plone/volto/registry';
|
|
10
10
|
|
|
11
|
+
import { numbersToMenuItemColumns } from '@eeacms/volto-eea-design-system/ui/Header/utils';
|
|
12
|
+
|
|
11
13
|
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
12
14
|
import downSVG from '@plone/volto/icons/down-key.svg';
|
|
13
15
|
|
|
@@ -36,30 +38,6 @@ const defaultRouteSettings = {
|
|
|
36
38
|
// Don't include empty arrays in default settings
|
|
37
39
|
};
|
|
38
40
|
|
|
39
|
-
// Helper functions for menuItemColumns conversion (numbers to semantic UI format)
|
|
40
|
-
const numberToColumnString = (num) => {
|
|
41
|
-
const numbers = [
|
|
42
|
-
'',
|
|
43
|
-
'one',
|
|
44
|
-
'two',
|
|
45
|
-
'three',
|
|
46
|
-
'four',
|
|
47
|
-
'five',
|
|
48
|
-
'six',
|
|
49
|
-
'seven',
|
|
50
|
-
'eight',
|
|
51
|
-
'nine',
|
|
52
|
-
];
|
|
53
|
-
return numbers[num] ? `${numbers[num]} wide column` : '';
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const numbersToMenuItemColumns = (numbers) => {
|
|
57
|
-
if (!Array.isArray(numbers)) return [];
|
|
58
|
-
return numbers
|
|
59
|
-
.map((num) => numberToColumnString(parseInt(num)))
|
|
60
|
-
.filter((col) => col !== '');
|
|
61
|
-
};
|
|
62
|
-
|
|
63
41
|
const columnStringToNumber = (colString) => {
|
|
64
42
|
const numbers = {
|
|
65
43
|
one: 1,
|
|
@@ -78,7 +56,7 @@ const columnStringToNumber = (colString) => {
|
|
|
78
56
|
return match ? numbers[match[1]] : null;
|
|
79
57
|
};
|
|
80
58
|
|
|
81
|
-
const menuItemColumnsToNumbers = (columns) => {
|
|
59
|
+
export const menuItemColumnsToNumbers = (columns) => {
|
|
82
60
|
if (!Array.isArray(columns)) return [];
|
|
83
61
|
return columns
|
|
84
62
|
.map((col) => columnStringToNumber(col))
|
|
@@ -420,6 +398,20 @@ const NavigationBehaviorWidget = (props) => {
|
|
|
420
398
|
portal_type: ______,
|
|
421
399
|
...settings
|
|
422
400
|
} = route;
|
|
401
|
+
|
|
402
|
+
// // Convert menuItemColumns from numbers back to semantic UI format for backend storage
|
|
403
|
+
if (
|
|
404
|
+
settings.menuItemColumns !== null &&
|
|
405
|
+
settings.menuItemColumns &&
|
|
406
|
+
Array.isArray(settings.menuItemColumns)
|
|
407
|
+
) {
|
|
408
|
+
if (settings.menuItemColumns.length > 0) {
|
|
409
|
+
settings.menuItemColumns = numbersToMenuItemColumns(
|
|
410
|
+
settings.menuItemColumns,
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
423
415
|
newSettings[routeId] = settings;
|
|
424
416
|
});
|
|
425
417
|
|
|
@@ -490,6 +490,120 @@ describe('NavigationBehaviorWidget', () => {
|
|
|
490
490
|
expect(screen.getByText('Test Route 2')).toBeInTheDocument();
|
|
491
491
|
});
|
|
492
492
|
|
|
493
|
+
it('handles menuItemColumns as integers from backend (develop server format)', async () => {
|
|
494
|
+
const existingSettings = {
|
|
495
|
+
'http://localhost:3000/test-route-1': {
|
|
496
|
+
hideChildrenFromNavigation: false,
|
|
497
|
+
menuItemColumns: [8, 4], // Integer format from develop server
|
|
498
|
+
},
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
render(
|
|
502
|
+
<Provider store={store}>
|
|
503
|
+
<NavigationBehaviorWidget
|
|
504
|
+
id="test"
|
|
505
|
+
value={JSON.stringify(existingSettings)}
|
|
506
|
+
onChange={mockOnChange}
|
|
507
|
+
/>
|
|
508
|
+
</Provider>,
|
|
509
|
+
);
|
|
510
|
+
|
|
511
|
+
const accordionTitles = screen.getAllByTestId('accordion-title');
|
|
512
|
+
fireEvent.click(accordionTitles[0]);
|
|
513
|
+
|
|
514
|
+
await waitFor(() => {
|
|
515
|
+
expect(
|
|
516
|
+
screen.getByText('Hide Children From Navigation'),
|
|
517
|
+
).toBeInTheDocument();
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
// Verify the widget displays the values correctly (converted to numbers for display)
|
|
521
|
+
// The widget should handle integer input and display it properly
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
it('handles menuItemColumns as semantic UI strings from backend (production format)', async () => {
|
|
525
|
+
const existingSettings = {
|
|
526
|
+
'http://localhost:3000/test-route-1': {
|
|
527
|
+
hideChildrenFromNavigation: false,
|
|
528
|
+
menuItemColumns: ['eight wide column', 'four wide column'], // String format from production
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
render(
|
|
533
|
+
<Provider store={store}>
|
|
534
|
+
<NavigationBehaviorWidget
|
|
535
|
+
id="test"
|
|
536
|
+
value={JSON.stringify(existingSettings)}
|
|
537
|
+
onChange={mockOnChange}
|
|
538
|
+
/>
|
|
539
|
+
</Provider>,
|
|
540
|
+
);
|
|
541
|
+
|
|
542
|
+
const accordionTitles = screen.getAllByTestId('accordion-title');
|
|
543
|
+
fireEvent.click(accordionTitles[0]);
|
|
544
|
+
|
|
545
|
+
await waitFor(() => {
|
|
546
|
+
expect(
|
|
547
|
+
screen.getByText('Hide Children From Navigation'),
|
|
548
|
+
).toBeInTheDocument();
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// Verify the widget displays the values correctly (converted from strings to numbers for display)
|
|
552
|
+
// The widget should handle semantic UI string input and convert it to numbers for display
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
it('converts menuItemColumns to semantic UI format when saving', async () => {
|
|
556
|
+
const existingSettings = {
|
|
557
|
+
'http://localhost:3000/test-route-1': {
|
|
558
|
+
hideChildrenFromNavigation: false,
|
|
559
|
+
menuItemColumns: [2, 3], // Numbers that should be converted to semantic UI format
|
|
560
|
+
},
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
render(
|
|
564
|
+
<Provider store={store}>
|
|
565
|
+
<NavigationBehaviorWidget
|
|
566
|
+
id="test"
|
|
567
|
+
value={JSON.stringify(existingSettings)}
|
|
568
|
+
onChange={mockOnChange}
|
|
569
|
+
/>
|
|
570
|
+
</Provider>,
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
const accordionTitles = screen.getAllByTestId('accordion-title');
|
|
574
|
+
fireEvent.click(accordionTitles[0]);
|
|
575
|
+
|
|
576
|
+
await waitFor(() => {
|
|
577
|
+
expect(
|
|
578
|
+
screen.getByText('Hide Children From Navigation'),
|
|
579
|
+
).toBeInTheDocument();
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Simulate a change by clicking the checkbox
|
|
583
|
+
const checkboxes = screen.getAllByRole('checkbox');
|
|
584
|
+
fireEvent.click(checkboxes[0]);
|
|
585
|
+
|
|
586
|
+
await waitFor(() => {
|
|
587
|
+
expect(mockOnChange).toHaveBeenCalled();
|
|
588
|
+
const lastCallIndex = mockOnChange.mock.calls.length - 1;
|
|
589
|
+
const savedValue = JSON.parse(mockOnChange.mock.calls[lastCallIndex][1]);
|
|
590
|
+
|
|
591
|
+
// Find the route settings
|
|
592
|
+
const routeKey = Object.keys(savedValue).find((key) =>
|
|
593
|
+
key.includes('test-route-1'),
|
|
594
|
+
);
|
|
595
|
+
const route1Settings = savedValue[routeKey];
|
|
596
|
+
|
|
597
|
+
// Verify menuItemColumns are saved in semantic UI format, not as integers
|
|
598
|
+
if (route1Settings && route1Settings.menuItemColumns) {
|
|
599
|
+
route1Settings.menuItemColumns.forEach((col) => {
|
|
600
|
+
expect(typeof col).toBe('string');
|
|
601
|
+
expect(col).toMatch(/wide column$/);
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
});
|
|
606
|
+
|
|
493
607
|
it('displays route paths in accordion titles', () => {
|
|
494
608
|
render(
|
|
495
609
|
<Provider store={store}>
|
package/src/config.js
CHANGED
|
@@ -112,6 +112,8 @@ export const footerOpts = {
|
|
|
112
112
|
tablet: 6,
|
|
113
113
|
computer: 4,
|
|
114
114
|
},
|
|
115
|
+
width: 270,
|
|
116
|
+
height: 100,
|
|
115
117
|
},
|
|
116
118
|
{
|
|
117
119
|
url: 'https://www.eionet.europa.eu/',
|
|
@@ -123,6 +125,8 @@ export const footerOpts = {
|
|
|
123
125
|
tablet: 6,
|
|
124
126
|
computer: 4,
|
|
125
127
|
},
|
|
128
|
+
width: 330,
|
|
129
|
+
height: 100,
|
|
126
130
|
},
|
|
127
131
|
],
|
|
128
132
|
social: [
|
|
@@ -240,6 +244,8 @@ export const headerOpts = {
|
|
|
240
244
|
},
|
|
241
245
|
],
|
|
242
246
|
},
|
|
247
|
+
logoWidth: 350,
|
|
248
|
+
logoHeight: 130,
|
|
243
249
|
};
|
|
244
250
|
|
|
245
251
|
export const languages = [
|
|
@@ -62,9 +62,7 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
62
62
|
const navigationSettings = useSelector(
|
|
63
63
|
(state) => state.navigationSettings?.settings || {},
|
|
64
64
|
);
|
|
65
|
-
const
|
|
66
|
-
(state) => state.navigationSettings?.loaded,
|
|
67
|
-
);
|
|
65
|
+
const updateRequest = useSelector((state) => state.content.update);
|
|
68
66
|
|
|
69
67
|
// Combine navigation settings from backend with config fallback
|
|
70
68
|
const configLayouts = config.settings?.menuItemsLayouts || {};
|
|
@@ -112,6 +110,17 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
112
110
|
});
|
|
113
111
|
}
|
|
114
112
|
|
|
113
|
+
React.useEffect(() => {
|
|
114
|
+
if (
|
|
115
|
+
updateRequest?.loaded &&
|
|
116
|
+
removeTrailingSlash(updateRequest?.content?.['@id'] || '') ===
|
|
117
|
+
removeTrailingSlash(pathname)
|
|
118
|
+
) {
|
|
119
|
+
dispatch(getNavigationSettings(pathname));
|
|
120
|
+
}
|
|
121
|
+
dispatch(getNavigationSettings(pathname));
|
|
122
|
+
}, [updateRequest, dispatch, pathname]);
|
|
123
|
+
|
|
115
124
|
React.useEffect(() => {
|
|
116
125
|
const base_url = getBaseUrl(pathname);
|
|
117
126
|
const { settings } = config;
|
|
@@ -125,12 +134,7 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
125
134
|
if (token !== previousToken) {
|
|
126
135
|
dispatch(getNavigation(base_url, settings.navDepth));
|
|
127
136
|
}
|
|
128
|
-
|
|
129
|
-
// Fetch navigation settings
|
|
130
|
-
if (!navigationLoaded) {
|
|
131
|
-
dispatch(getNavigationSettings(pathname));
|
|
132
|
-
}
|
|
133
|
-
}, [pathname, token, dispatch, previousToken, navigationLoaded]);
|
|
137
|
+
}, [pathname, token, dispatch, previousToken]);
|
|
134
138
|
|
|
135
139
|
return (
|
|
136
140
|
<Header menuItems={items}>
|
|
@@ -215,6 +219,8 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
|
|
|
215
219
|
title={eea.websiteTitle}
|
|
216
220
|
alt={eea.organisationName}
|
|
217
221
|
url={eea.logoTargetUrl}
|
|
222
|
+
height={headerOpts.logoHeight}
|
|
223
|
+
width={headerOpts.logoWidth}
|
|
218
224
|
/>
|
|
219
225
|
|
|
220
226
|
{!!subsite && subsite.title && (
|