@eeacms/volto-eea-website-policy 1.13.1 → 1.14.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/.eslintrc.js ADDED
@@ -0,0 +1,65 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const projectRootPath = fs.realpathSync(__dirname + '/../../../');
4
+
5
+ let voltoPath = path.join(projectRootPath, 'node_modules/@plone/volto');
6
+ let configFile;
7
+ if (fs.existsSync(`${projectRootPath}/tsconfig.json`))
8
+ configFile = `${projectRootPath}/tsconfig.json`;
9
+ else if (fs.existsSync(`${projectRootPath}/jsconfig.json`))
10
+ configFile = `${projectRootPath}/jsconfig.json`;
11
+
12
+ if (configFile) {
13
+ const jsConfig = require(configFile).compilerOptions;
14
+ const pathsConfig = jsConfig.paths;
15
+ if (pathsConfig['@plone/volto'])
16
+ voltoPath = `./${jsConfig.baseUrl}/${pathsConfig['@plone/volto'][0]}`;
17
+ }
18
+
19
+ const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`);
20
+ const reg = new AddonConfigurationRegistry(projectRootPath);
21
+
22
+ // Extends ESlint configuration for adding the aliases to `src` directories in Volto addons
23
+ const addonAliases = Object.keys(reg.packages).map((o) => [
24
+ o,
25
+ reg.packages[o].modulePath,
26
+ ]);
27
+
28
+ const addonExtenders = reg.getEslintExtenders().map((m) => require(m));
29
+
30
+ const defaultConfig = {
31
+ extends: `${voltoPath}/.eslintrc`,
32
+ settings: {
33
+ 'import/resolver': {
34
+ alias: {
35
+ map: [
36
+ ['@plone/volto', '@plone/volto/src'],
37
+ ['@plone/volto-slate', '@plone/volto/packages/volto-slate/src'],
38
+ ...addonAliases,
39
+ ['@package', `${__dirname}/src`],
40
+ ['@root', `${__dirname}/src`],
41
+ ['~', `${__dirname}/src`],
42
+ ],
43
+ extensions: ['.js', '.jsx', '.json'],
44
+ },
45
+ 'babel-plugin-root-import': {
46
+ rootPathSuffix: 'src',
47
+ },
48
+ },
49
+ },
50
+ rules: {
51
+ 'react/jsx-no-target-blank': [
52
+ 'error',
53
+ {
54
+ allowReferrer: true,
55
+ },
56
+ ],
57
+ }
58
+ };
59
+
60
+ const config = addonExtenders.reduce(
61
+ (acc, extender) => extender.modify(acc),
62
+ defaultConfig,
63
+ );
64
+
65
+ module.exports = config;
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ 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
+ ### [1.14.0](https://github.com/eea/volto-eea-website-policy/compare/1.13.1...1.14.0) - 16 April 2024
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat: Default view layout restriction to Manager - refs #268249 [ichim-david - [`1840c1b`](https://github.com/eea/volto-eea-website-policy/commit/1840c1bd9aae6ce18a23800ce618f8bbe47525ab)]
12
+ - feat: Volto 17 - refs #264527 [EEA Jenkins - [`253a322`](https://github.com/eea/volto-eea-website-policy/commit/253a3221e36500b4f0f3b160bb2455a066ff3ebd)]
13
+
14
+ #### :hammer_and_wrench: Others
15
+
16
+ - Update Jenkinsfile [Alexandru Ghica - [`c962b11`](https://github.com/eea/volto-eea-website-policy/commit/c962b118d4e2dbe6f5fe938cb8aa1fe610a09d3a)]
7
17
  ### [1.13.1](https://github.com/eea/volto-eea-website-policy/compare/1.13.0...1.13.1) - 28 March 2024
8
18
 
9
19
  #### :bug: Bug Fixes
@@ -31,7 +41,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
31
41
 
32
42
  #### :hammer_and_wrench: Others
33
43
 
34
- - test: [JENKINS] fail with logs on coverage [valentinab25 - [`5cf68f8`](https://github.com/eea/volto-eea-website-policy/commit/5cf68f8db34448d10fe993d16541ad9732434cc8)]
35
44
  ### [1.12.0-beta.1](https://github.com/eea/volto-eea-website-policy/compare/1.11.1...1.12.0-beta.1) - 12 January 2024
36
45
 
37
46
  #### :hammer_and_wrench: Others
@@ -52,11 +61,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
52
61
  #### :hammer_and_wrench: Others
53
62
 
54
63
  - Release 1.11.0 [Alin Voinea - [`3249160`](https://github.com/eea/volto-eea-website-policy/commit/3249160422c6c6e0cf14823b614f8885101a847a)]
55
- - test: [JENKINS] Use java17 for sonarqube scanner [valentinab25 - [`8beb7e7`](https://github.com/eea/volto-eea-website-policy/commit/8beb7e7a12cbc314e56e4b1aceab5ef8d00ca6f3)]
56
- - test: [JENKINS] Run cypress in started frontend container [valentinab25 - [`12d3da1`](https://github.com/eea/volto-eea-website-policy/commit/12d3da12e9a3b0882cf55efe2d40f3032724d41b)]
57
- - test: [JENKINS] Add cpu limit on cypress docker [valentinab25 - [`0af0764`](https://github.com/eea/volto-eea-website-policy/commit/0af076467120ed9a80c697931e869837b92a0a4c)]
58
- - test: [JENKINS] Increase shm-size to cypress docker [valentinab25 - [`8662e3e`](https://github.com/eea/volto-eea-website-policy/commit/8662e3e5fc3640d678ce320eb8856a37d419306c)]
59
- - test: [JENKINS] Improve cypress time [valentinab25 - [`ef1074f`](https://github.com/eea/volto-eea-website-policy/commit/ef1074fdf968cafdf476d4ee4951eb18ebac048a)]
60
64
  ### [1.10.0](https://github.com/eea/volto-eea-website-policy/compare/1.9.2...1.10.0) - 2 November 2023
61
65
 
62
66
  #### :rocket: New Features
@@ -65,7 +69,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
65
69
 
66
70
  #### :house: Internal changes
67
71
 
68
- - chore: [JENKINS] Refactor automated testing [valentinab25 - [`8b1b422`](https://github.com/eea/volto-eea-website-policy/commit/8b1b42297b46d9fb7325589b3bd043233c0d66e9)]
69
72
  - chore: husky, lint-staged use fixed versions [valentinab25 - [`44ac62e`](https://github.com/eea/volto-eea-website-policy/commit/44ac62e6f8b7e5b7d57edfbf82812c91dc5d6bba)]
70
73
  - chore:volto 16 in tests, update docs, fix stylelint overrides [valentinab25 - [`b9a46d8`](https://github.com/eea/volto-eea-website-policy/commit/b9a46d85a64739188a3df9e8cbe645418b5d8b0a)]
71
74
 
@@ -186,7 +189,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
186
189
 
187
190
  - Release 1.5.0 [Alin Voinea - [`a3dea8e`](https://github.com/eea/volto-eea-website-policy/commit/a3dea8ea15cb8d2a876dc10da926ece3a5707ea9)]
188
191
  - test(Jenkinsfile): Use latest stable volto for testing [Alin Voinea - [`a8f7123`](https://github.com/eea/volto-eea-website-policy/commit/a8f712364187f9638886667c249fa102cb49b5c0)]
189
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`124a8f8`](https://github.com/eea/volto-eea-website-policy/commit/124a8f8ad4ced507aeec27012d725f2e2b977e08)]
190
192
  ### [1.4.0](https://github.com/eea/volto-eea-website-policy/compare/1.3.4...1.4.0) - 21 February 2023
191
193
 
192
194
  #### :rocket: New Features
@@ -266,7 +268,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
266
268
  #### :hammer_and_wrench: Others
267
269
 
268
270
  - Release 1.1.0 [Alin Voinea - [`0291b3b`](https://github.com/eea/volto-eea-website-policy/commit/0291b3bb7b4c6ab09ca98728885cea4051eac8e3)]
269
- - yarn 3 [Alin Voinea - [`593aa58`](https://github.com/eea/volto-eea-website-policy/commit/593aa58eaa4d28aced0603b7f7dd125c857a6f54)]
270
271
  ### [1.0.4](https://github.com/eea/volto-eea-website-policy/compare/1.0.3...1.0.4) - 22 November 2022
271
272
 
272
273
  #### :nail_care: Enhancements
@@ -312,7 +313,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
312
313
 
313
314
  #### :hammer_and_wrench: Others
314
315
 
315
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`d153f54`](https://github.com/eea/volto-eea-website-policy/commit/d153f54e55e918fa4746e05488c734624eaf14a9)]
316
316
  ### [0.4.0](https://github.com/eea/volto-eea-website-policy/compare/0.3.3...0.4.0) - 19 September 2022
317
317
 
318
318
  #### :hammer_and_wrench: Others
@@ -388,7 +388,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
388
388
  - format index.js [Andrei Grigore - [`db4481a`](https://github.com/eea/volto-eea-website-policy/commit/db4481aeeba59a769272659f33278c902fc69bec)]
389
389
  - Update index.js [Alexandru Ghica - [`dc09886`](https://github.com/eea/volto-eea-website-policy/commit/dc0988640a76a9914381b120f58bb61a9ab1eb39)]
390
390
  - Added externalRoutes [Alexandru Ghica - [`b68135b`](https://github.com/eea/volto-eea-website-policy/commit/b68135b013fafa93a41ea602ea2fad30879abe0f)]
391
- - Add Sonarqube tag using eea-website-frontend addons list [EEA Jenkins - [`575cca6`](https://github.com/eea/volto-eea-website-policy/commit/575cca674602ca2e1c2a41300c47ba594ff49aa0)]
392
391
  ### [0.1.1](https://github.com/eea/volto-eea-website-policy/compare/0.1.0...0.1.1) - 4 March 2022
393
392
 
394
393
  #### :hammer_and_wrench: Others
@@ -401,5 +400,4 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
401
400
 
402
401
  #### :hammer_and_wrench: Others
403
402
 
404
- - yarn bootstrap [Alin Voinea - [`9b4d197`](https://github.com/eea/volto-eea-website-policy/commit/9b4d197cbc7992566cb36524d190078d5ad21a44)]
405
403
  - Initial commit [Alin Voinea - [`3800692`](https://github.com/eea/volto-eea-website-policy/commit/3800692f7a4de6460815bd6061facacb986cbef0)]
@@ -1,3 +1,5 @@
1
+ require('dotenv').config({ path: __dirname + '/.env' })
2
+
1
3
  module.exports = {
2
4
  testMatch: ['**/src/addons/**/?(*.)+(spec|test).[jt]s?(x)'],
3
5
  collectCoverageFrom: [
@@ -9,18 +11,26 @@ module.exports = {
9
11
  '@plone/volto/cypress': '<rootDir>/node_modules/@plone/volto/cypress',
10
12
  '@plone/volto/babel': '<rootDir>/node_modules/@plone/volto/babel',
11
13
  '@plone/volto/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
12
- '@package/(.*)$': '<rootDir>/src/$1',
13
- '@root/(.*)$': '<rootDir>/src/$1',
14
+ '@package/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
15
+ '@root/(.*)$': '<rootDir>/node_modules/@plone/volto/src/$1',
14
16
  '@plone/volto-quanta/(.*)$': '<rootDir>/src/addons/volto-quanta/src/$1',
17
+ '@eeacms/search/(.*)$': '<rootDir>/src/addons/volto-searchlib/searchlib/$1',
18
+ '@eeacms/search': '<rootDir>/src/addons/volto-searchlib/searchlib',
15
19
  '@eeacms/(.*?)/(.*)$': '<rootDir>/node_modules/@eeacms/$1/src/$2',
16
- '@plone/volto-slate':
20
+ '@plone/volto-slate$':
17
21
  '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src',
22
+ '@plone/volto-slate/(.*)$':
23
+ '<rootDir>/node_modules/@plone/volto/packages/volto-slate/src/$1',
18
24
  '~/(.*)$': '<rootDir>/src/$1',
19
25
  'load-volto-addons':
20
26
  '<rootDir>/node_modules/@plone/volto/jest-addons-loader.js',
21
27
  },
28
+ transformIgnorePatterns: [
29
+ '/node_modules/(?!(@plone|@root|@package|@eeacms)/).*/',
30
+ ],
22
31
  transform: {
23
32
  '^.+\\.js(x)?$': 'babel-jest',
33
+ '^.+\\.ts(x)?$': 'babel-jest',
24
34
  '^.+\\.(png)$': 'jest-file',
25
35
  '^.+\\.(jpg)$': 'jest-file',
26
36
  '^.+\\.(svg)$': './node_modules/@plone/volto/jest-svgsystem-transform.js',
@@ -33,4 +43,9 @@ module.exports = {
33
43
  statements: 5,
34
44
  },
35
45
  },
36
- };
46
+ ...(process.env.JEST_USE_SETUP === 'ON' && {
47
+ setupFilesAfterEnv: [
48
+ '<rootDir>/node_modules/@eeacms/volto-eea-website-policy/jest.setup.js',
49
+ ],
50
+ }),
51
+ }
package/jest.setup.js ADDED
@@ -0,0 +1,65 @@
1
+ import { jest } from '@jest/globals';
2
+ import configureStore from 'redux-mock-store';
3
+ import thunk from 'redux-thunk';
4
+ import { blocksConfig } from '@plone/volto/config/Blocks';
5
+ import installSlate from '@plone/volto-slate/index';
6
+
7
+ var mockSemanticComponents = jest.requireActual('semantic-ui-react');
8
+ var mockComponents = jest.requireActual('@plone/volto/components');
9
+ var config = jest.requireActual('@plone/volto/registry').default;
10
+
11
+ config.blocks.blocksConfig = {
12
+ ...blocksConfig,
13
+ ...config.blocks.blocksConfig,
14
+ };
15
+
16
+ jest.doMock('semantic-ui-react', () => ({
17
+ __esModule: true,
18
+ ...mockSemanticComponents,
19
+ Popup: ({ content, trigger }) => {
20
+ return (
21
+ <div className="popup">
22
+ <div className="trigger">{trigger}</div>
23
+ <div className="content">{content}</div>
24
+ </div>
25
+ );
26
+ },
27
+ }));
28
+
29
+ jest.doMock('@plone/volto/components', () => {
30
+ return {
31
+ __esModule: true,
32
+ ...mockComponents,
33
+ SidebarPortal: ({ children }) => <div id="sidebar">{children}</div>,
34
+ };
35
+ });
36
+
37
+ jest.doMock('@plone/volto/registry', () =>
38
+ [installSlate].reduce((acc, apply) => apply(acc), config),
39
+ );
40
+
41
+ const mockStore = configureStore([thunk]);
42
+
43
+ global.fetch = jest.fn(() =>
44
+ Promise.resolve({
45
+ json: () => Promise.resolve({}),
46
+ }),
47
+ );
48
+
49
+ global.store = mockStore({
50
+ intl: {
51
+ locale: 'en',
52
+ messages: {},
53
+ formatMessage: jest.fn(),
54
+ },
55
+ content: {
56
+ create: {},
57
+ subrequests: [],
58
+ },
59
+ connected_data_parameters: {},
60
+ screen: {
61
+ page: {
62
+ width: 768,
63
+ },
64
+ },
65
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-website-policy",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "@eeacms/volto-eea-website-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -26,6 +26,7 @@
26
26
  "@cypress/code-coverage": "^3.10.0",
27
27
  "@plone/scripts": "*",
28
28
  "babel-plugin-transform-class-properties": "^6.24.1",
29
+ "dotenv": "^16.3.2",
29
30
  "husky": "^8.0.3",
30
31
  "lint-staged": "^14.0.1",
31
32
  "md5": "^2.3.0"
@@ -3,7 +3,7 @@ import ContextNavigationEdit from './ContextNavigationEdit';
3
3
  import ContextNavigationView from './ContextNavigationView';
4
4
  import BlockSettingsSchema from '@plone/volto/components/manage/Blocks/Block/Schema';
5
5
 
6
- export default (config) => {
6
+ const applyConfig = (config) => {
7
7
  config.blocks.blocksConfig.contextNavigation = {
8
8
  id: 'contextNavigation',
9
9
  title: 'Navigation',
@@ -24,3 +24,5 @@ export default (config) => {
24
24
 
25
25
  return config;
26
26
  };
27
+
28
+ export default applyConfig;
@@ -0,0 +1,306 @@
1
+ import React, { Component, Fragment } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { connect } from 'react-redux';
4
+ import { compose } from 'redux';
5
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
6
+
7
+ import jwtDecode from 'jwt-decode';
8
+ import {
9
+ getSchema,
10
+ getUser,
11
+ updateContent,
12
+ getContent,
13
+ } from '@plone/volto/actions';
14
+ import { getLayoutFieldname } from '@plone/volto/helpers';
15
+ import { FormFieldWrapper, Icon } from '@plone/volto/components';
16
+ import { defineMessages, injectIntl } from 'react-intl';
17
+ import config from '@plone/volto/registry';
18
+
19
+ import downSVG from '@plone/volto/icons/down-key.svg';
20
+ import upSVG from '@plone/volto/icons/up-key.svg';
21
+ import checkSVG from '@plone/volto/icons/check.svg';
22
+
23
+ const messages = defineMessages({
24
+ Viewmode: {
25
+ id: 'Viewmode',
26
+ defaultMessage: 'View',
27
+ },
28
+ });
29
+
30
+ const Option = injectLazyLibs('reactSelect')((props) => {
31
+ const { Option } = props.reactSelect.components;
32
+ return (
33
+ <Option {...props}>
34
+ <div>{props.label}</div>
35
+ {props.isFocused && !props.isSelected && (
36
+ <Icon name={checkSVG} size="18px" color="#b8c6c8" />
37
+ )}
38
+ {props.isSelected && <Icon name={checkSVG} size="18px" color="#007bc1" />}
39
+ </Option>
40
+ );
41
+ });
42
+
43
+ const DropdownIndicator = injectLazyLibs('reactSelect')((props) => {
44
+ const { DropdownIndicator } = props.reactSelect.components;
45
+ return (
46
+ <DropdownIndicator {...props}>
47
+ {props.selectProps.menuIsOpen ? (
48
+ <Icon name={upSVG} size="24px" color="#007bc1" />
49
+ ) : (
50
+ <Icon name={downSVG} size="24px" color="#007bc1" />
51
+ )}
52
+ </DropdownIndicator>
53
+ );
54
+ });
55
+
56
+ const selectTheme = (theme) => ({
57
+ ...theme,
58
+ borderRadius: 0,
59
+ colors: {
60
+ ...theme.colors,
61
+ primary25: 'hotpink',
62
+ primary: '#b8c6c8',
63
+ },
64
+ });
65
+
66
+ const customSelectStyles = {
67
+ control: (styles, state) => ({
68
+ ...styles,
69
+ border: 'none',
70
+ borderBottom: '2px solid #b8c6c8',
71
+ boxShadow: 'none',
72
+ borderBottomStyle: state.menuIsOpen ? 'dotted' : 'solid',
73
+ }),
74
+ menu: (styles, state) => ({
75
+ ...styles,
76
+ top: null,
77
+ marginTop: 0,
78
+ boxShadow: 'none',
79
+ borderBottom: '2px solid #b8c6c8',
80
+ }),
81
+ menuList: (styles, state) => ({
82
+ ...styles,
83
+ maxHeight: '400px',
84
+ }),
85
+ indicatorSeparator: (styles) => ({
86
+ ...styles,
87
+ width: null,
88
+ }),
89
+ valueContainer: (styles) => ({
90
+ ...styles,
91
+ padding: 0,
92
+ }),
93
+ option: (styles, state) => ({
94
+ ...styles,
95
+ backgroundColor: null,
96
+ minHeight: '50px',
97
+ display: 'flex',
98
+ justifyContent: 'space-between',
99
+ alignItems: 'center',
100
+ padding: '12px 12px',
101
+ color: state.isSelected
102
+ ? '#007bc1'
103
+ : state.isFocused
104
+ ? '#4a4a4a'
105
+ : 'inherit',
106
+ ':active': {
107
+ backgroundColor: null,
108
+ },
109
+ span: {
110
+ flex: '0 0 auto',
111
+ },
112
+ svg: {
113
+ flex: '0 0 auto',
114
+ },
115
+ }),
116
+ };
117
+
118
+ /**
119
+ * Display container class.
120
+ * @class Display
121
+ * @extends Component
122
+ */
123
+ class DisplaySelect extends Component {
124
+ /**
125
+ * Property types.
126
+ * @property {Object} propTypes Property types.
127
+ * @static
128
+ */
129
+ static propTypes = {
130
+ getSchema: PropTypes.func.isRequired,
131
+ updateContent: PropTypes.func.isRequired,
132
+ getContent: PropTypes.func.isRequired,
133
+ loaded: PropTypes.bool.isRequired,
134
+ pathname: PropTypes.string.isRequired,
135
+ layouts: PropTypes.arrayOf(PropTypes.string),
136
+ layout: PropTypes.string,
137
+ type: PropTypes.string.isRequired,
138
+ };
139
+
140
+ /**
141
+ * Default properties
142
+ * @property {Object} defaultProps Default properties.
143
+ * @static
144
+ */
145
+ static defaultProps = {
146
+ layouts: [],
147
+ layout: '',
148
+ rolesWhoCanChangeLayout: [],
149
+ };
150
+
151
+ state = {
152
+ hasMatchingRole: false,
153
+ selectedOption: {
154
+ value: this.props.layout,
155
+ label: config.views.layoutViewsNamesMapping?.[this.props.layout]
156
+ ? this.props.intl.formatMessage({
157
+ id: config.views.layoutViewsNamesMapping?.[this.props.layout],
158
+ defaultMessage:
159
+ config.views.layoutViewsNamesMapping?.[this.props.layout],
160
+ })
161
+ : this.props.layout,
162
+ },
163
+ };
164
+
165
+ componentDidMount() {
166
+ this.props.getSchema(this.props.type);
167
+ }
168
+
169
+ UNSAFE_componentWillMount() {
170
+ if (!this.props.rolesWhoCanChangeLayout.length) {
171
+ this.props.rolesWhoCanChangeLayout.push(
172
+ ...(config?.settings?.eea?.rolesWhoCanChangeLayout || []),
173
+ );
174
+ }
175
+ if (!this.props.layouts.length) {
176
+ this.props.getSchema(this.props.type);
177
+ }
178
+ if (Object.keys(this.props.user).length === 0) {
179
+ this.props.getUser(this.props.userId);
180
+ } else {
181
+ const hasMatchingRole = this.props.user.roles.some((role) =>
182
+ this.props.rolesWhoCanChangeLayout.includes(role),
183
+ );
184
+ if (hasMatchingRole !== this.state.hasMatchingRole) {
185
+ this.setState({ hasMatchingRole });
186
+ }
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Component will receive props
192
+ * @method componentWillReceiveProps
193
+ * @param {Object} nextProps Next properties
194
+ * @returns {undefined}
195
+ */
196
+ UNSAFE_componentWillReceiveProps(nextProps) {
197
+ if (nextProps.pathname !== this.props.pathname) {
198
+ this.props.getSchema(nextProps.type);
199
+ }
200
+ if (!this.props.loaded && nextProps.loaded) {
201
+ this.props.getContent(nextProps.pathname);
202
+ }
203
+
204
+ if (Object.keys(nextProps.user).length !== 0) {
205
+ const hasMatchingRole = nextProps.user.roles.some((role) =>
206
+ this.props.rolesWhoCanChangeLayout.includes(role),
207
+ );
208
+ if (hasMatchingRole !== this.state.hasMatchingRole) {
209
+ this.setState({ hasMatchingRole });
210
+ }
211
+ }
212
+ }
213
+
214
+ /**
215
+ * On set layout handler
216
+ * @method setLayout
217
+ * @param {Object} event Event object
218
+ * @returns {undefined}
219
+ */
220
+ setLayout = (selectedOption) => {
221
+ this.props.updateContent(this.props.pathname, {
222
+ layout: selectedOption.value,
223
+ });
224
+ this.setState({ selectedOption });
225
+ };
226
+
227
+ selectValue = (option) => (
228
+ <Fragment>
229
+ <span className="Select-value-label">{option.label}</span>
230
+ </Fragment>
231
+ );
232
+
233
+ optionRenderer = (option) => (
234
+ <Fragment>
235
+ <span style={{ marginRight: 'auto' }}>{option.label}</span>
236
+ <Icon name={checkSVG} size="24px" />
237
+ </Fragment>
238
+ );
239
+
240
+ render() {
241
+ if (!this.state.hasMatchingRole) {
242
+ return null;
243
+ }
244
+ const { selectedOption } = this.state;
245
+ const Select = this.props.reactSelect.default;
246
+ const layoutsNames = config.views.layoutViewsNamesMapping;
247
+ const layoutOptions = this.props.layouts
248
+ .filter(
249
+ (layout) =>
250
+ Object.keys(config.views.contentTypesViews).includes(layout) ||
251
+ Object.keys(config.views.layoutViews).includes(layout),
252
+ )
253
+ .map((item) => ({
254
+ value: item,
255
+ label:
256
+ this.props.intl.formatMessage({
257
+ id: layoutsNames[item],
258
+ defaultMessage: layoutsNames[item],
259
+ }) || item,
260
+ }));
261
+
262
+ return layoutOptions?.length > 1 ? (
263
+ <FormFieldWrapper
264
+ id="display-select"
265
+ title={this.props.intl.formatMessage(messages.Viewmode)}
266
+ {...this.props}
267
+ >
268
+ <Select
269
+ name="display-select"
270
+ className="react-select-container"
271
+ classNamePrefix="react-select"
272
+ options={layoutOptions}
273
+ styles={customSelectStyles}
274
+ theme={selectTheme}
275
+ components={{ DropdownIndicator, Option }}
276
+ onChange={this.setLayout}
277
+ defaultValue={selectedOption}
278
+ isSearchable={false}
279
+ />
280
+ </FormFieldWrapper>
281
+ ) : null;
282
+ }
283
+ }
284
+
285
+ export default compose(
286
+ injectIntl,
287
+ injectLazyLibs('reactSelect'),
288
+ connect(
289
+ (state) => ({
290
+ loaded: state.content.update.loaded,
291
+ layouts: state.schema.schema ? state.schema.schema.layouts : [],
292
+ layout: state.content.data
293
+ ? state.content.data[getLayoutFieldname(state.content.data)]
294
+ : '',
295
+ layout_fieldname: state.content.data
296
+ ? getLayoutFieldname(state.content.data)
297
+ : '',
298
+ type: state.content.data ? state.content.data['@type'] : '',
299
+ user: state.users.user,
300
+ userId: state.userSession.token
301
+ ? jwtDecode(state.userSession.token).sub
302
+ : '',
303
+ }),
304
+ { getSchema, getUser, updateContent, getContent },
305
+ ),
306
+ )(DisplaySelect);
@@ -0,0 +1 @@
1
+ Added customization to condition the display of the layout options based on the user's roles.
@@ -82,8 +82,7 @@ const messages = defineMessages({
82
82
  defaultMessage: 'Changes applied',
83
83
  },
84
84
  workingCopyAppliedBy: {
85
- id:
86
- 'Made by {creator} on {date}. This is not a working copy anymore, but the main content.',
85
+ id: 'Made by {creator} on {date}. This is not a working copy anymore, but the main content.',
87
86
  defaultMessage:
88
87
  'Made by {creator} on {date}. This is not a working copy anymore, but the main content.',
89
88
  },
@@ -342,7 +341,7 @@ class More extends Component {
342
341
  <div className="pastanaga-menu-list">
343
342
  <ul>
344
343
  {pluggables.map((p) => (
345
- <>{p()}</>
344
+ <React.Fragment key={p.id}>{p()}</React.Fragment>
346
345
  ))}
347
346
  </ul>
348
347
  </div>
@@ -3,20 +3,20 @@
3
3
  * @module components/manage/Workflow/Workflow
4
4
  */
5
5
 
6
- import React, { Component, Fragment } from 'react';
7
- import PropTypes from 'prop-types';
8
- import { withRouter } from 'react-router-dom';
9
- import { compose } from 'redux';
10
- import { connect } from 'react-redux';
11
- import { uniqBy } from 'lodash';
12
- import { toast } from 'react-toastify';
13
- import { defineMessages, injectIntl } from 'react-intl';
14
6
  import { FormFieldWrapper, Icon, Toast } from '@plone/volto/components';
15
7
  import {
16
8
  flattenToAppURL,
17
9
  getCurrentStateMapping,
18
10
  getWorkflowOptions,
19
11
  } from '@plone/volto/helpers';
12
+ import { uniqBy } from 'lodash';
13
+ import PropTypes from 'prop-types';
14
+ import { Component, Fragment } from 'react';
15
+ import { defineMessages, injectIntl } from 'react-intl';
16
+ import { connect } from 'react-redux';
17
+ import { withRouter } from 'react-router-dom';
18
+ import { toast } from 'react-toastify';
19
+ import { compose } from 'redux';
20
20
 
21
21
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
22
22
 
@@ -26,9 +26,9 @@ import {
26
26
  transitionWorkflow,
27
27
  } from '@plone/volto/actions';
28
28
 
29
+ import checkSVG from '@plone/volto/icons/check.svg';
29
30
  import downSVG from '@plone/volto/icons/down-key.svg';
30
31
  import upSVG from '@plone/volto/icons/up-key.svg';
31
- import checkSVG from '@plone/volto/icons/check.svg';
32
32
 
33
33
  const messages = defineMessages({
34
34
  messageUpdated: {
@@ -200,7 +200,7 @@ class Workflow extends Component {
200
200
  getContent: PropTypes.func.isRequired,
201
201
  getWorkflow: PropTypes.func.isRequired,
202
202
  transitionWorkflow: PropTypes.func.isRequired,
203
- workflowLoaded: PropTypes.func,
203
+ workflowLoaded: PropTypes.bool,
204
204
  loaded: PropTypes.bool.isRequired,
205
205
  pathname: PropTypes.string.isRequired,
206
206
 
package/src/index.js CHANGED
@@ -39,7 +39,8 @@ const overrideBlocks = {
39
39
 
40
40
  const applyConfig = (config) => {
41
41
  // #158717#note-25 any path that isn't static, en or controlpanel is treated as external
42
- const notInEN = /^(?!(#|\/en|\/login-authomatic|\/fallback_login|\/static|\/controlpanel|\/cypress|\/login|\/logout|\/contact-form|\/passwordreset)).*$/;
42
+ const notInEN =
43
+ /^(?!(#|\/en|\/login-authomatic|\/fallback_login|\/static|\/controlpanel|\/cypress|\/login|\/logout|\/contact-form|\/passwordreset)).*$/;
43
44
  config.settings.externalRoutes = [
44
45
  ...(config.settings.externalRoutes || []),
45
46
  {
@@ -92,6 +93,12 @@ const applyConfig = (config) => {
92
93
  if (config.settings.eea) {
93
94
  config.settings.eea.logoTargetUrl = '/en';
94
95
  }
96
+ // #268249 - only allow managers to change layout from more menu
97
+ config.settings.eea = {
98
+ ...config.settings.eea,
99
+ rolesWhoCanChangeLayout: ['Manager'],
100
+ };
101
+ // config.settings.eea.rolesWhoCanChangeLayout = ['Manager'];
95
102
 
96
103
  // Custom blocks
97
104
  // context navigation
@@ -1,48 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- const projectRootPath = fs.existsSync('./project')
5
- ? fs.realpathSync('./project')
6
- : fs.realpathSync('./../../../');
7
- const packageJson = require(path.join(projectRootPath, 'package.json'));
8
- const jsConfig = require(path.join(projectRootPath, 'jsconfig.json')).compilerOptions;
9
-
10
- const pathsConfig = jsConfig.paths;
11
-
12
- let voltoPath = path.join(projectRootPath, 'node_modules/@plone/volto');
13
-
14
- Object.keys(pathsConfig).forEach(pkg => {
15
- if (pkg === '@plone/volto') {
16
- voltoPath = `./${jsConfig.baseUrl}/${pathsConfig[pkg][0]}`;
17
- }
18
- });
19
- const AddonConfigurationRegistry = require(`${voltoPath}/addon-registry.js`);
20
- const reg = new AddonConfigurationRegistry(projectRootPath);
21
-
22
- // Extends ESlint configuration for adding the aliases to `src` directories in Volto addons
23
- const addonAliases = Object.keys(reg.packages).map(o => [
24
- o,
25
- reg.packages[o].modulePath,
26
- ]);
27
-
28
-
29
- module.exports = {
30
- extends: `${projectRootPath}/node_modules/@plone/volto/.eslintrc`,
31
- settings: {
32
- 'import/resolver': {
33
- alias: {
34
- map: [
35
- ['@plone/volto', '@plone/volto/src'],
36
- ...addonAliases,
37
- ['@package', `${__dirname}/src`],
38
- ['~', `${__dirname}/src`],
39
- ],
40
- extensions: ['.js', '.jsx', '.json'],
41
- },
42
- 'babel-plugin-root-import': {
43
- rootPathSuffix: 'src',
44
- },
45
- },
46
- },
47
- };
48
-