@eeacms/volto-eea-website-theme 2.2.2 → 2.4.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +26 -22
  2. package/package.json +3 -1
  3. package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.jsx +45 -0
  4. package/src/components/manage/Blocks/ContextNavigation/ContextNavigationEdit.test.jsx +88 -0
  5. package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.jsx +14 -0
  6. package/src/components/manage/Blocks/ContextNavigation/ContextNavigationView.test.jsx +71 -0
  7. package/src/components/manage/Blocks/ContextNavigation/index.js +30 -0
  8. package/src/components/manage/Blocks/ContextNavigation/schema.js +88 -0
  9. package/src/components/manage/Blocks/ContextNavigation/variations/Accordion.jsx +179 -0
  10. package/src/components/manage/Blocks/ContextNavigation/variations/Default.jsx +9 -0
  11. package/src/components/manage/Blocks/ContextNavigation/variations/index.js +18 -0
  12. package/src/components/manage/Blocks/Title/Edit.jsx +7 -4
  13. package/src/components/manage/Blocks/Title/View.jsx +14 -24
  14. package/src/components/manage/Blocks/Title/index.js +52 -0
  15. package/src/components/manage/Blocks/Title/variations/Default.jsx +43 -0
  16. package/src/components/manage/Blocks/Title/variations/WebReport.jsx +69 -0
  17. package/src/components/manage/Blocks/Title/variations/WebReportPage.jsx +59 -0
  18. package/src/components/manage/Blocks/Title/variations/styles.less +28 -0
  19. package/src/components/theme/Banner/View.jsx +5 -1
  20. package/src/components/theme/SubsiteClass.jsx +3 -1
  21. package/src/components/theme/WebReport/WebReportSectionView.jsx +49 -0
  22. package/src/components/theme/Widgets/DateWidget.jsx +32 -0
  23. package/src/components/theme/Widgets/DateWidget.test.js +67 -0
  24. package/src/components/theme/Widgets/DatetimeWidget.jsx +45 -0
  25. package/src/components/theme/Widgets/DatetimeWidget.test.js +63 -0
  26. package/src/customizations/volto/components/theme/Breadcrumbs/Breadcrumbs.jsx +20 -2
  27. package/src/customizations/volto/components/theme/Header/Header.jsx +3 -3
  28. package/src/customizations/volto/components/theme/View/DefaultView.jsx +190 -0
  29. package/src/hocs/withDeviceSize.test.jsx +79 -0
  30. package/src/index.js +37 -14
  31. package/src/index.test.js +2 -0
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import { DateWidget } from './DateWidget';
4
+ import { Provider } from 'react-intl-redux';
5
+ import configureStore from 'redux-mock-store';
6
+ import thunk from 'redux-thunk';
7
+
8
+ const mockStore = configureStore([thunk]);
9
+
10
+ const store = mockStore({
11
+ intl: {
12
+ locale: 'en-gb',
13
+ messages: {},
14
+ },
15
+ });
16
+
17
+ describe('DateWidget', () => {
18
+ it('renders an empty date view widget component', () => {
19
+ const component = renderer.create(
20
+ <Provider store={store}>
21
+ <DateWidget />
22
+ </Provider>,
23
+ );
24
+ const json = component.toJSON();
25
+ expect(json).toMatchSnapshot();
26
+ });
27
+
28
+ it('renders a date view widget component', () => {
29
+ const component = renderer.create(
30
+ <Provider store={store}>
31
+ <DateWidget className="metadata" value="2020-08-04T09:00:00" />
32
+ </Provider>,
33
+ );
34
+ const json = component.toJSON();
35
+ expect(json).toMatchSnapshot();
36
+ });
37
+
38
+ it('renders a date view widget component with custom format', () => {
39
+ const component = renderer.create(
40
+ <Provider store={store}>
41
+ <DateWidget
42
+ className="metadata"
43
+ value="2020-08-04T09:00:00"
44
+ format={{
45
+ year: 'numeric',
46
+ month: 'short',
47
+ day: '2-digit',
48
+ }}
49
+ />
50
+ </Provider>,
51
+ );
52
+ const json = component.toJSON();
53
+ expect(json).toMatchSnapshot();
54
+ });
55
+
56
+ it('renders a date view widget component with children', () => {
57
+ const component = renderer.create(
58
+ <Provider store={store}>
59
+ <DateWidget className="metadata" value="2020-08-04T09:00:00">
60
+ {(child) => <strong>{child}</strong>}
61
+ </DateWidget>
62
+ </Provider>,
63
+ );
64
+ const json = component.toJSON();
65
+ expect(json).toMatchSnapshot();
66
+ });
67
+ });
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+ import { useSelector } from 'react-redux';
4
+ import { toBackendLang } from '@plone/volto/helpers';
5
+ import { formatDate } from '@plone/volto/helpers/Utils/Date';
6
+ import config from '@plone/volto/registry';
7
+
8
+ export const DatetimeWidget = ({ value, children, className }) => {
9
+ const lang = useSelector((state) => state.intl.locale);
10
+ const backendLang = toBackendLang(lang);
11
+ const locale =
12
+ backendLang === 'en' ? config.settings.dateLocale : backendLang;
13
+ const formatOptions = {
14
+ date: value,
15
+ format: {
16
+ year: 'numeric',
17
+ month: 'short',
18
+ day: '2-digit',
19
+ hour: '2-digit',
20
+ minute: '2-digit',
21
+ },
22
+ locale,
23
+ includeTime: true,
24
+ formatToParts: true,
25
+ };
26
+
27
+ let formattedParts = formatDate(formatOptions);
28
+
29
+ const formattedDate = formattedParts
30
+ .map((part) => {
31
+ if (part.type === 'literal' && part.value === ', ') {
32
+ return ' ';
33
+ }
34
+ return part.value;
35
+ })
36
+ .join('');
37
+
38
+ return value ? (
39
+ <span className={cx(className, 'datetime', 'widget')}>
40
+ {children ? children(formattedDate) : formattedDate}
41
+ </span>
42
+ ) : (
43
+ ''
44
+ );
45
+ };
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import renderer from 'react-test-renderer';
3
+ import { DatetimeWidget } from './DatetimeWidget';
4
+ import { Provider } from 'react-intl-redux';
5
+ import configureStore from 'redux-mock-store';
6
+ import thunk from 'redux-thunk';
7
+
8
+ const mockStore = configureStore([thunk]);
9
+
10
+ const store = mockStore({
11
+ intl: {
12
+ locale: 'en-gb',
13
+ messages: {},
14
+ },
15
+ });
16
+
17
+ describe('DatetimeWidget', () => {
18
+ it('renders an empty datetime view widget component', () => {
19
+ const component = renderer.create(
20
+ <Provider store={store}>
21
+ <DatetimeWidget />
22
+ </Provider>,
23
+ );
24
+ const json = component.toJSON();
25
+ expect(json).toMatchSnapshot();
26
+ });
27
+
28
+ it('renders a datetime view widget component with a date and time', () => {
29
+ const component = renderer.create(
30
+ <Provider store={store}>
31
+ <DatetimeWidget className="metadata" value="2024-09-05T15:34:00" />
32
+ </Provider>,
33
+ );
34
+ const json = component.toJSON();
35
+ expect(json).toMatchSnapshot();
36
+ });
37
+
38
+ it('renders a datetime view widget component with children formatting', () => {
39
+ const component = renderer.create(
40
+ <Provider store={store}>
41
+ <DatetimeWidget className="metadata" value="2024-09-05T15:34:00">
42
+ {(formattedDate) => <strong>{formattedDate}</strong>}
43
+ </DatetimeWidget>
44
+ </Provider>,
45
+ );
46
+ const json = component.toJSON();
47
+ expect(json).toMatchSnapshot();
48
+ });
49
+
50
+ it('removes the comma in the formatted date and shows correct time', () => {
51
+ const component = renderer.create(
52
+ <Provider store={store}>
53
+ <DatetimeWidget className="metadata" value="2024-09-05T15:34:00" />
54
+ </Provider>,
55
+ );
56
+ const json = component.toJSON();
57
+ expect(json).toMatchSnapshot();
58
+
59
+ const instance = component.root;
60
+ const span = instance.findByType('span');
61
+ expect(span.props.children).toContain('05 Sept 2024 15:34');
62
+ });
63
+ });
@@ -3,7 +3,7 @@
3
3
  * @module components/theme/Breadcrumbs/Breadcrumbs
4
4
  */
5
5
 
6
- import React, { useEffect } from 'react';
6
+ import React, { useEffect, useMemo } from 'react';
7
7
  import { useDispatch, useSelector } from 'react-redux';
8
8
 
9
9
  import { useLocation } from 'react-router';
@@ -32,10 +32,23 @@ const isContentRoute = (pathname) => {
32
32
  const Breadcrumbs = (props) => {
33
33
  const dispatch = useDispatch();
34
34
  const { items = [], root = '/' } = useSelector((state) => state?.breadcrumbs);
35
+ const content = useSelector((state) => state?.content?.data);
36
+
35
37
  // const pathname = useSelector((state) => state.location.pathname);
36
38
  const location = useLocation();
37
39
  const { pathname } = location;
38
40
 
41
+ const linkLevels = useMemo(() => {
42
+ if (content) {
43
+ const type = content['@type'];
44
+ const isContentTypesToAvoid =
45
+ config.settings.contentTypeToAvoidAsLinks || {};
46
+ if (isContentTypesToAvoid[type]) {
47
+ return isContentTypesToAvoid[type];
48
+ }
49
+ }
50
+ }, [content]);
51
+
39
52
  const sections = items.map((item) => ({
40
53
  title: item.title,
41
54
  href: item.url,
@@ -54,7 +67,12 @@ const Breadcrumbs = (props) => {
54
67
  return (
55
68
  <React.Fragment>
56
69
  <div id="page-header" />
57
- <EEABreadcrumbs pathname={pathname} sections={sections} root={root} />
70
+ <EEABreadcrumbs
71
+ pathname={pathname}
72
+ sections={sections}
73
+ root={root}
74
+ linkLevels={linkLevels}
75
+ />
58
76
  </React.Fragment>
59
77
  );
60
78
  };
@@ -17,7 +17,6 @@ import eeaFlag from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/
17
17
 
18
18
  import config from '@plone/volto/registry';
19
19
  import { compose } from 'recompose';
20
- import { BodyClass } from '@plone/volto/helpers';
21
20
 
22
21
  import cx from 'classnames';
23
22
  import loadable from '@loadable/component';
@@ -43,10 +42,12 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
43
42
  const has_home_layout =
44
43
  layout === 'homepage_inverse_view' ||
45
44
  (__CLIENT__ && document.body.classList.contains('homepage-inverse'));
45
+
46
46
  return (
47
47
  has_home_layout &&
48
48
  (removeTrailingSlash(pathname) === router_pathname ||
49
- router_pathname.endsWith('/edit'))
49
+ router_pathname.endsWith('/edit') ||
50
+ router_pathname.endsWith('/add'))
50
51
  );
51
52
  });
52
53
 
@@ -75,7 +76,6 @@ const EEAHeader = ({ pathname, token, items, history, subsite }) => {
75
76
 
76
77
  return (
77
78
  <Header menuItems={items}>
78
- {isHomePageInverse && <BodyClass className="homepage" />}
79
79
  <Header.TopHeader>
80
80
  <Header.TopItem className="official-union">
81
81
  <Image src={eeaFlag} alt="European Union flag"></Image>
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Document view component.
3
+ * @module components/theme/View/DefaultView
4
+ */
5
+
6
+ import React from 'react';
7
+ import PropTypes from 'prop-types';
8
+
9
+ import {
10
+ Container as SemanticContainer,
11
+ Segment,
12
+ Grid,
13
+ Label,
14
+ } from 'semantic-ui-react';
15
+ import config from '@plone/volto/registry';
16
+ import { getSchema } from '@plone/volto/actions';
17
+ import { getWidget } from '@plone/volto/helpers/Widget/utils';
18
+ import { RenderBlocks } from '@plone/volto/components';
19
+
20
+ import { hasBlocksData, getBaseUrl } from '@plone/volto/helpers';
21
+ import { useDispatch, shallowEqual, useSelector } from 'react-redux';
22
+
23
+ import isEqual from 'lodash/isEqual';
24
+ import AccordionContextNavigation from '@eeacms/volto-eea-website-theme/components/manage/Blocks/ContextNavigation/variations/Accordion';
25
+
26
+ /**
27
+ * Component to display the default view.
28
+ * @function DefaultView
29
+ * @param {Object} content Content object.
30
+ * @returns {string} Markup of the component.
31
+ */
32
+ const DefaultView = (props) => {
33
+ const { content, location } = props;
34
+ const [hasLightLayout, setHasLightLayout] = React.useState(false);
35
+
36
+ React.useEffect(() => {
37
+ const updateLightLayout = () => {
38
+ if (__CLIENT__) {
39
+ setHasLightLayout(document.body.classList.contains('light-header'));
40
+ }
41
+ };
42
+
43
+ updateLightLayout();
44
+
45
+ if (__CLIENT__) {
46
+ const observer = new MutationObserver(updateLightLayout);
47
+ observer.observe(document.body, {
48
+ attributes: true,
49
+ attributeFilter: ['class'],
50
+ });
51
+
52
+ return () => observer.disconnect();
53
+ }
54
+ }, []);
55
+
56
+ const { contextNavigationActions } = useSelector(
57
+ (state) => ({
58
+ contextNavigationActions: state.actions?.actions?.context_navigation,
59
+ }),
60
+ shallowEqual,
61
+ );
62
+
63
+ const navigation_paths = contextNavigationActions || [];
64
+ const path = getBaseUrl(location?.pathname || '');
65
+ const dispatch = useDispatch();
66
+ const { views } = config.widgets;
67
+ const contentSchema = useSelector((state) => state.schema?.schema);
68
+ const fieldsetsToExclude = [
69
+ 'categorization',
70
+ 'dates',
71
+ 'ownership',
72
+ 'settings',
73
+ ];
74
+ const fieldsets = contentSchema?.fieldsets.filter(
75
+ (fs) => !fieldsetsToExclude.includes(fs.id),
76
+ );
77
+
78
+ // TL;DR: There is a flash of the non block-based view because of the reset
79
+ // of the content on route change. Subscribing to the content change at this
80
+ // level has nasty implications, so we can't watch the Redux state for loaded
81
+ // content flag here (because it forces an additional component update)
82
+ // Instead, we can watch if the content is "empty", but this has a drawback
83
+ // since the locking mechanism inserts a `lock` key before the content is there.
84
+ // So "empty" means `content` is present, but only with a `lock` key, thus the next
85
+ // ugly condition comes to life
86
+ const contentLoaded = content && !isEqual(Object.keys(content), ['lock']);
87
+
88
+ React.useEffect(() => {
89
+ content?.['@type'] &&
90
+ !hasBlocksData(content) &&
91
+ dispatch(getSchema(content['@type'], location.pathname));
92
+ // eslint-disable-next-line react-hooks/exhaustive-deps
93
+ }, []);
94
+
95
+ const Container =
96
+ config.getComponent({ name: 'Container' }).component || SemanticContainer;
97
+ const matchingNavigationPath = navigation_paths.find((navPath) =>
98
+ path.includes(navPath.url),
99
+ );
100
+
101
+ // If the content is not yet loaded, then do not show anything
102
+ return contentLoaded ? (
103
+ hasBlocksData(content) ? (
104
+ <>
105
+ <Container id="page-document">
106
+ <RenderBlocks {...props} path={path} />
107
+ </Container>
108
+ {hasLightLayout && matchingNavigationPath && (
109
+ <AccordionContextNavigation
110
+ params={{
111
+ name: matchingNavigationPath.title,
112
+ no_thumbs: matchingNavigationPath.no_thumbs || true,
113
+ no_icons: matchingNavigationPath.no_icons || true,
114
+ root_path: matchingNavigationPath.url,
115
+ includeTop: matchingNavigationPath.includeTop || true,
116
+ bottomLevel: matchingNavigationPath.bottomLevel || 3,
117
+ topLevel: matchingNavigationPath.topLevel || 1,
118
+ currentFolderOnly:
119
+ matchingNavigationPath.currentFolderOnly || false,
120
+ }}
121
+ />
122
+ )}
123
+ </>
124
+ ) : (
125
+ <Container id="page-document">
126
+ {fieldsets?.map((fs) => {
127
+ return (
128
+ <div className="fieldset" key={fs.id}>
129
+ {fs.id !== 'default' && <h2>{fs.title}</h2>}
130
+ {fs.fields?.map((f, key) => {
131
+ let field = {
132
+ ...contentSchema?.properties[f],
133
+ id: f,
134
+ widget: getWidget(f, contentSchema?.properties[f]),
135
+ };
136
+ let Widget = views?.getWidget(field);
137
+ return f !== 'title' ? (
138
+ <Grid celled="internally" key={key}>
139
+ <Grid.Row>
140
+ <Label title={field.id}>{field.title}:</Label>
141
+ </Grid.Row>
142
+ <Grid.Row>
143
+ <Segment basic>
144
+ <Widget value={content[f]} />
145
+ </Segment>
146
+ </Grid.Row>
147
+ </Grid>
148
+ ) : (
149
+ <Widget key={key} value={content[f]} />
150
+ );
151
+ })}
152
+ </div>
153
+ );
154
+ })}
155
+ </Container>
156
+ )
157
+ ) : null;
158
+ };
159
+
160
+ /**
161
+ * Property types.
162
+ * @property {Object} propTypes Property types.
163
+ * @static
164
+ */
165
+ DefaultView.propTypes = {
166
+ /**
167
+ * Content of the object
168
+ */
169
+ content: PropTypes.shape({
170
+ /**
171
+ * Title of the object
172
+ */
173
+ title: PropTypes.string,
174
+ /**
175
+ * Description of the object
176
+ */
177
+ description: PropTypes.string,
178
+ /**
179
+ * Text of the object
180
+ */
181
+ text: PropTypes.shape({
182
+ /**
183
+ * Data of the text of the object
184
+ */
185
+ data: PropTypes.string,
186
+ }),
187
+ }).isRequired,
188
+ };
189
+
190
+ export default DefaultView;
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import { render, act } from '@testing-library/react';
3
+ import withDeviceSize from './withDeviceSize.jsx';
4
+
5
+ describe('withDeviceSize HOC', () => {
6
+ // Mock the WrappedComponent
7
+ const WrappedComponent = ({ device }) => (
8
+ <div data-testid="device">{device}</div>
9
+ );
10
+
11
+ const mockResize = (width) => {
12
+ Object.defineProperty(document.documentElement, 'clientWidth', {
13
+ writable: true,
14
+ configurable: true,
15
+ value: width,
16
+ });
17
+ window.dispatchEvent(new Event('resize'));
18
+ };
19
+
20
+ it('should return mobile for screen width less than 768px', () => {
21
+ const ComponentWithDeviceSize = withDeviceSize(WrappedComponent);
22
+
23
+ const { getByTestId } = render(<ComponentWithDeviceSize />);
24
+
25
+ act(() => {
26
+ mockResize(500); // Simulating a mobile screen
27
+ });
28
+
29
+ expect(getByTestId('device').textContent).toBe('mobile');
30
+ });
31
+
32
+ it('should return tablet for screen width between 768px and 992px', () => {
33
+ const ComponentWithDeviceSize = withDeviceSize(WrappedComponent);
34
+
35
+ const { getByTestId } = render(<ComponentWithDeviceSize />);
36
+
37
+ act(() => {
38
+ mockResize(800); // Simulating a tablet screen
39
+ });
40
+
41
+ expect(getByTestId('device').textContent).toBe('tablet');
42
+ });
43
+
44
+ it('should return computer for screen width between 992px and 1200px', () => {
45
+ const ComponentWithDeviceSize = withDeviceSize(WrappedComponent);
46
+
47
+ const { getByTestId } = render(<ComponentWithDeviceSize />);
48
+
49
+ act(() => {
50
+ mockResize(1000); // Simulating a computer screen
51
+ });
52
+
53
+ expect(getByTestId('device').textContent).toBe('computer');
54
+ });
55
+
56
+ it('should return large for screen width between 1200px and 1920px', () => {
57
+ const ComponentWithDeviceSize = withDeviceSize(WrappedComponent);
58
+
59
+ const { getByTestId } = render(<ComponentWithDeviceSize />);
60
+
61
+ act(() => {
62
+ mockResize(1500); // Simulating a large screen
63
+ });
64
+
65
+ expect(getByTestId('device').textContent).toBe('large');
66
+ });
67
+
68
+ it('should return widescreen for screen width above 1920px', () => {
69
+ const ComponentWithDeviceSize = withDeviceSize(WrappedComponent);
70
+
71
+ const { getByTestId } = render(<ComponentWithDeviceSize />);
72
+
73
+ act(() => {
74
+ mockResize(2000); // Simulating a widescreen display
75
+ });
76
+
77
+ expect(getByTestId('device').textContent).toBe('widescreen');
78
+ });
79
+ });
package/src/index.js CHANGED
@@ -1,16 +1,24 @@
1
+ import React from 'react';
2
+ import { v4 as uuid } from 'uuid';
3
+ import { Icon } from '@plone/volto/components';
4
+ import { default as TokenWidgetEdit } from '@plone/volto/components/manage/Widgets/TokenWidget';
5
+ import SelectAutoCompleteWidget from '@plone/volto/components/manage/Widgets/SelectAutoComplete';
6
+ import { serializeNodesToText } from '@plone/volto-slate/editor/render';
7
+ import { nanoid } from '@plone/volto-slate/utils';
8
+
1
9
  import InpageNavigation from '@eeacms/volto-eea-design-system/ui/InpageNavigation/InpageNavigation';
2
10
  import CustomCSS from '@eeacms/volto-eea-website-theme/components/theme/CustomCSS/CustomCSS';
3
11
  import DraftBackground from '@eeacms/volto-eea-website-theme/components/theme/DraftBackground/DraftBackground';
4
12
  import HomePageInverseView from '@eeacms/volto-eea-website-theme/components/theme/Homepage/HomePageInverseView';
5
13
  import HomePageView from '@eeacms/volto-eea-website-theme/components/theme/Homepage/HomePageView';
14
+ import WebReportSectionView from '@eeacms/volto-eea-website-theme/components/theme/WebReport/WebReportSectionView';
6
15
  import NotFound from '@eeacms/volto-eea-website-theme/components/theme/NotFound/NotFound';
7
16
  import { TokenWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/TokenWidget';
8
17
  import { TopicsWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/TopicsWidget';
18
+ import { DateWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/DateWidget';
19
+ import { DatetimeWidget } from '@eeacms/volto-eea-website-theme/components/theme/Widgets/DatetimeWidget';
9
20
  import CreatableSelectWidget from '@eeacms/volto-eea-website-theme/components/theme/Widgets/CreatableSelectWidget';
10
21
 
11
- import { Icon } from '@plone/volto/components';
12
- import { default as TokenWidgetEdit } from '@plone/volto/components/manage/Widgets/TokenWidget';
13
- import { serializeNodesToText } from '@plone/volto-slate/editor/render';
14
22
  import Tag from '@eeacms/volto-eea-design-system/ui/Tag/Tag';
15
23
 
16
24
  import {
@@ -19,6 +27,7 @@ import {
19
27
  } from '@eeacms/volto-eea-website-theme/helpers/schema-utils';
20
28
 
21
29
  import installLayoutSettingsBlock from '@eeacms/volto-eea-website-theme/components/manage/Blocks/LayoutSettings';
30
+ import installContextNavigationBlock from '@eeacms/volto-eea-website-theme/components/manage/Blocks/ContextNavigation';
22
31
  import installCustomTitle from '@eeacms/volto-eea-website-theme/components/manage/Blocks/Title';
23
32
 
24
33
  import FlexGroup from '@eeacms/volto-eea-website-theme/components/manage/Blocks/GroupBlockTemplate/FlexGroup/FlexGroup';
@@ -30,11 +39,8 @@ import okMiddleware from './middleware/ok';
30
39
  import voltoCustomMiddleware from './middleware/voltoCustom';
31
40
  import installSlate from './slate';
32
41
  import { print } from './reducers';
33
- import { nanoid } from '@plone/volto-slate/utils';
34
- import { v4 as uuid } from 'uuid';
35
42
 
36
43
  import * as eea from './config';
37
- import React from 'react';
38
44
 
39
45
  const restrictedBlocks = ['imagesGrid', 'teaser', 'dataFigure', 'plotly_chart'];
40
46
 
@@ -237,7 +243,14 @@ const applyConfig = (config) => {
237
243
  ...(config.views.layoutViewsNamesMapping || {}),
238
244
  homepage_view: 'Homepage view',
239
245
  homepage_inverse_view: 'Homepage white view',
246
+ web_report_section: 'Web report section',
240
247
  };
248
+
249
+ config.views.contentTypesViews = {
250
+ ...(config.views.contentTypesViews || {}),
251
+ web_report_section: WebReportSectionView,
252
+ };
253
+
241
254
  config.views.errorViews = {
242
255
  ...config.views.errorViews,
243
256
  404: NotFound,
@@ -330,11 +343,17 @@ const applyConfig = (config) => {
330
343
  }
331
344
 
332
345
  // Custom Widgets
333
- config.widgets.id.other_organisations = TokenWidgetEdit;
346
+ // config.widgets.id.other_organisations = TokenWidgetEdit;
347
+ config.widgets.vocabulary['eea.coremetadata.other_organisations'] =
348
+ TokenWidgetEdit;
349
+ config.widgets.views.widget.datetime = DatetimeWidget;
350
+ config.widgets.views.widget.date = DateWidget;
334
351
  config.widgets.views.id.topics = TopicsWidget;
335
352
  config.widgets.views.id.subjects = TokenWidget;
336
353
  config.widgets.views.widget.tags = TokenWidget;
337
354
  config.widgets.widget.creatable_select = CreatableSelectWidget;
355
+ config.widgets.vocabulary['plone.app.vocabularies.Users'] =
356
+ SelectAutoCompleteWidget;
338
357
 
339
358
  // /voltoCustom.css express-middleware
340
359
  // /ok express-middleware - see also: https://github.com/plone/volto/pull/4432
@@ -476,11 +495,11 @@ const applyConfig = (config) => {
476
495
  // },
477
496
  };
478
497
 
479
- // layout settings
480
- config = [installLayoutSettingsBlock].reduce(
481
- (acc, apply) => apply(acc),
482
- config,
483
- );
498
+ //If you don't want to show the content type as a link in the breadcrumbs, you can set it to a number
499
+ // where 1 is the last item in the breadcrumbs, 2 is the second last, etc.
500
+ config.settings.contentTypeToAvoidAsLinks = {
501
+ web_report_section: 2,
502
+ };
484
503
 
485
504
  // Group
486
505
  if (config.blocks.blocksConfig.group) {
@@ -549,8 +568,12 @@ const applyConfig = (config) => {
549
568
  GET_CONTENT: ['breadcrumbs'], // 'navigation', 'actions', 'types'],
550
569
  });
551
570
 
552
- // Custom blocks: Title
553
- return [installCustomTitle].reduce((acc, apply) => apply(acc), config);
571
+ // Custom blocks: Title,Layout settings, Context navigation
572
+ return [
573
+ installCustomTitle,
574
+ installLayoutSettingsBlock,
575
+ installContextNavigationBlock,
576
+ ].reduce((acc, apply) => apply(acc), config);
554
577
  };
555
578
 
556
579
  export default applyConfig;
package/src/index.test.js CHANGED
@@ -92,6 +92,7 @@ describe('applyConfig', () => {
92
92
  },
93
93
  },
94
94
  widget: {},
95
+ vocabulary: {},
95
96
  id: {},
96
97
  },
97
98
  settings: {
@@ -247,6 +248,7 @@ describe('applyConfig', () => {
247
248
  },
248
249
  widget: {},
249
250
  id: {},
251
+ vocabulary: {},
250
252
  },
251
253
  settings: {
252
254
  eea: {},