@eeacms/volto-eea-website-policy 1.7.3 → 1.9.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 +23 -0
- package/docker-compose.yml +5 -1
- package/locales/en/LC_MESSAGES/volto.po +14 -0
- package/package.json +1 -1
- package/src/components/Widgets/FrequencyOfDissemination.test.js +29 -0
- package/src/customizations/volto/components/manage/Workflow/README.txt +1 -0
- package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +380 -0
- package/src/customizations/volto/components/manage/Workflow/Workflow.test.jsx +81 -0
- package/src/index.js +0 -4
- package/src/components/Widgets/DataProvenance.jsx +0 -12
- package/src/components/Widgets/InstitutionalMandate.jsx +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ 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.9.0](https://github.com/eea/volto-eea-website-policy/compare/1.8.0...1.9.0) - 1 September 2023
|
|
8
|
+
|
|
9
|
+
#### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
- feat: Create new version workflow redirect - refs #256563 [Alin Voinea - [`1fede39`](https://github.com/eea/volto-eea-website-policy/commit/1fede390b90f3a66a60031a106e78d50cc430cd6)]
|
|
12
|
+
|
|
13
|
+
#### :house: Internal changes
|
|
14
|
+
|
|
15
|
+
- style: Fix eslint [Alin Voinea - [`a634acf`](https://github.com/eea/volto-eea-website-policy/commit/a634acf05c0279fafa825783dd236123c2edc0f6)]
|
|
16
|
+
|
|
17
|
+
#### :hammer_and_wrench: Others
|
|
18
|
+
|
|
19
|
+
- Release 1.9.0 [Alin Voinea - [`428c55b`](https://github.com/eea/volto-eea-website-policy/commit/428c55b1fd9603a6ed57d858d704fc9337421f41)]
|
|
20
|
+
- test: Add cypress test for customized Workflow - refs #256563 [Alin Voinea - [`e9eab09`](https://github.com/eea/volto-eea-website-policy/commit/e9eab09f53393589fe6c0d4a318638e3eb7b7eae)]
|
|
21
|
+
- test: Add jest tests for FrequencyOfDissemination widget [Alin Voinea - [`d28b2fe`](https://github.com/eea/volto-eea-website-policy/commit/d28b2febb74f6846ebba277d32d38deffe2fc023)]
|
|
22
|
+
- i18n: Add en [Alin Voinea - [`d5be8b1`](https://github.com/eea/volto-eea-website-policy/commit/d5be8b12e7c007fb88ae9d240ab45ba81d427772)]
|
|
23
|
+
- test: Update Makefile and docker-compose to align it with Jenkinsfile [valentinab25 - [`b2ee189`](https://github.com/eea/volto-eea-website-policy/commit/b2ee18920646dc1854a69faf931c87e814eddb5a)]
|
|
24
|
+
### [1.8.0](https://github.com/eea/volto-eea-website-policy/compare/1.7.3...1.8.0) - 15 August 2023
|
|
25
|
+
|
|
26
|
+
#### :nail_care: Enhancements
|
|
27
|
+
|
|
28
|
+
- refactor: Move DataProvenance code to dedicated widget addon - refs #256379 [Alin Voinea - [`3e7b046`](https://github.com/eea/volto-eea-website-policy/commit/3e7b046f3396c9aa73757916c6f02156aa18a6c2)]
|
|
29
|
+
|
|
7
30
|
### [1.7.3](https://github.com/eea/volto-eea-website-policy/compare/1.7.2...1.7.3) - 1 August 2023
|
|
8
31
|
|
|
9
32
|
#### :house: Documentation changes
|
package/docker-compose.yml
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
version: "3"
|
|
2
2
|
services:
|
|
3
3
|
backend:
|
|
4
|
-
image:
|
|
4
|
+
image: eeacms/plone-backend
|
|
5
5
|
ports:
|
|
6
6
|
- "8080:8080"
|
|
7
7
|
environment:
|
|
8
8
|
SITE: "Plone"
|
|
9
|
+
PROFILES: "eea.kitkat:testing"
|
|
9
10
|
|
|
10
11
|
frontend:
|
|
11
12
|
build:
|
|
@@ -23,6 +24,9 @@ services:
|
|
|
23
24
|
volumes:
|
|
24
25
|
- ./:/app/src/addons/${ADDON_PATH}
|
|
25
26
|
environment:
|
|
27
|
+
CI: "true"
|
|
28
|
+
NODE_ENV: "development"
|
|
29
|
+
RAZZLE_JEST_CONFIG: "src/addons/${ADDON_PATH}/jest-addon.config.js"
|
|
26
30
|
RAZZLE_INTERNAL_API_PATH: "http://backend:8080/Plone"
|
|
27
31
|
RAZZLE_DEV_PROXY_API_PATH: "http://backend:8080/Plone"
|
|
28
32
|
HOST: "0.0.0.0"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: \n"
|
|
4
|
+
"Report-Msgid-Bugs-To: \n"
|
|
5
|
+
"POT-Creation-Date: \n"
|
|
6
|
+
"PO-Revision-Date: \n"
|
|
7
|
+
"Last-Translator: \n"
|
|
8
|
+
"Language: \n"
|
|
9
|
+
"Language-Team: \n"
|
|
10
|
+
"Content-Type: \n"
|
|
11
|
+
"Content-Transfer-Encoding: \n"
|
|
12
|
+
"Plural-Forms: \n"
|
|
13
|
+
|
|
14
|
+
|
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { FrequencyOfDissemination } from './FrequencyOfDissemination';
|
|
4
|
+
|
|
5
|
+
describe('FrequencyOfDissemination', () => {
|
|
6
|
+
it('renders "Once a year" when value is 1', () => {
|
|
7
|
+
const { getByText } = render(<FrequencyOfDissemination value={1} />);
|
|
8
|
+
expect(getByText('Once a year')).toMatchSnapshot();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('renders "Every 2 years" when value is 2', () => {
|
|
12
|
+
const { getByText } = render(<FrequencyOfDissemination value={2} />);
|
|
13
|
+
expect(getByText('Every 2 years')).toMatchSnapshot();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('renders custom text when children prop is provided', () => {
|
|
17
|
+
const { getByText } = render(
|
|
18
|
+
<FrequencyOfDissemination value={3}>
|
|
19
|
+
{(text) => `Frequency: ${text}`}
|
|
20
|
+
</FrequencyOfDissemination>,
|
|
21
|
+
);
|
|
22
|
+
expect(getByText('Frequency: Every 3 years')).toMatchSnapshot();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('renders nothing when value is falsy', () => {
|
|
26
|
+
const { container } = render(<FrequencyOfDissemination value={0} />);
|
|
27
|
+
expect(container.firstChild).toMatchSnapshot();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Workflow.jsx - copied from @plone/volto 16.22.2 - refs #256563
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow component.
|
|
3
|
+
* @module components/manage/Workflow/Workflow
|
|
4
|
+
*/
|
|
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
|
+
import { FormFieldWrapper, Icon, Toast } from '@plone/volto/components';
|
|
15
|
+
import {
|
|
16
|
+
flattenToAppURL,
|
|
17
|
+
getCurrentStateMapping,
|
|
18
|
+
getWorkflowOptions,
|
|
19
|
+
} from '@plone/volto/helpers';
|
|
20
|
+
|
|
21
|
+
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
getContent,
|
|
25
|
+
getWorkflow,
|
|
26
|
+
transitionWorkflow,
|
|
27
|
+
} from '@plone/volto/actions';
|
|
28
|
+
|
|
29
|
+
import downSVG from '@plone/volto/icons/down-key.svg';
|
|
30
|
+
import upSVG from '@plone/volto/icons/up-key.svg';
|
|
31
|
+
import checkSVG from '@plone/volto/icons/check.svg';
|
|
32
|
+
|
|
33
|
+
const messages = defineMessages({
|
|
34
|
+
messageUpdated: {
|
|
35
|
+
id: 'Workflow updated.',
|
|
36
|
+
defaultMessage: 'Workflow updated.',
|
|
37
|
+
},
|
|
38
|
+
messageNoWorkflow: {
|
|
39
|
+
id: 'No workflow',
|
|
40
|
+
defaultMessage: 'No workflow',
|
|
41
|
+
},
|
|
42
|
+
state: {
|
|
43
|
+
id: 'State',
|
|
44
|
+
defaultMessage: 'State',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const SingleValue = injectLazyLibs('reactSelect')(({ children, ...props }) => {
|
|
49
|
+
const stateDecorator = {
|
|
50
|
+
marginRight: '10px',
|
|
51
|
+
display: 'inline-block',
|
|
52
|
+
backgroundColor: props.selectProps.value.color || null,
|
|
53
|
+
content: ' ',
|
|
54
|
+
height: '10px',
|
|
55
|
+
width: '10px',
|
|
56
|
+
borderRadius: '50%',
|
|
57
|
+
};
|
|
58
|
+
const { SingleValue } = props.reactSelect.components;
|
|
59
|
+
return (
|
|
60
|
+
<SingleValue {...props}>
|
|
61
|
+
<span style={stateDecorator} />
|
|
62
|
+
{children}
|
|
63
|
+
</SingleValue>
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const Option = injectLazyLibs('reactSelect')((props) => {
|
|
68
|
+
const stateDecorator = {
|
|
69
|
+
marginRight: '10px',
|
|
70
|
+
display: 'inline-block',
|
|
71
|
+
backgroundColor:
|
|
72
|
+
props.selectProps.value.value === props.data.value
|
|
73
|
+
? props.selectProps.value.color
|
|
74
|
+
: null,
|
|
75
|
+
content: ' ',
|
|
76
|
+
height: '10px',
|
|
77
|
+
width: '10px',
|
|
78
|
+
borderRadius: '50%',
|
|
79
|
+
border:
|
|
80
|
+
props.selectProps.value.value !== props.data.value
|
|
81
|
+
? `1px solid ${props.data.color}`
|
|
82
|
+
: null,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const { Option } = props['reactSelect'].components;
|
|
86
|
+
return (
|
|
87
|
+
<Option {...props}>
|
|
88
|
+
<span style={stateDecorator} />
|
|
89
|
+
<div style={{ marginRight: 'auto' }}>{props.label}</div>
|
|
90
|
+
{props.isFocused && !props.isSelected && (
|
|
91
|
+
<Icon name={checkSVG} size="18px" color="#b8c6c8" />
|
|
92
|
+
)}
|
|
93
|
+
{props.isSelected && <Icon name={checkSVG} size="18px" color="#007bc1" />}
|
|
94
|
+
</Option>
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const DropdownIndicator = injectLazyLibs('reactSelect')((props) => {
|
|
99
|
+
const { DropdownIndicator } = props.reactSelect.components;
|
|
100
|
+
return (
|
|
101
|
+
<DropdownIndicator {...props} data-testid="workflow-select-dropdown">
|
|
102
|
+
{props.selectProps.menuIsOpen ? (
|
|
103
|
+
<Icon name={upSVG} size="24px" color="#007bc1" />
|
|
104
|
+
) : (
|
|
105
|
+
<Icon name={downSVG} size="24px" color="#007bc1" />
|
|
106
|
+
)}
|
|
107
|
+
</DropdownIndicator>
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const selectTheme = (theme) => ({
|
|
112
|
+
...theme,
|
|
113
|
+
borderRadius: 0,
|
|
114
|
+
colors: {
|
|
115
|
+
...theme.colors,
|
|
116
|
+
primary25: 'hotpink',
|
|
117
|
+
primary: '#b8c6c8',
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const customSelectStyles = {
|
|
122
|
+
control: (styles, state) => ({
|
|
123
|
+
...styles,
|
|
124
|
+
border: 'none',
|
|
125
|
+
borderBottom: '2px solid #b8c6c8',
|
|
126
|
+
boxShadow: 'none',
|
|
127
|
+
borderBottomStyle: state.menuIsOpen ? 'dotted' : 'solid',
|
|
128
|
+
}),
|
|
129
|
+
menu: (styles, state) => ({
|
|
130
|
+
...styles,
|
|
131
|
+
top: null,
|
|
132
|
+
marginTop: 0,
|
|
133
|
+
boxShadow: 'none',
|
|
134
|
+
borderBottom: '2px solid #b8c6c8',
|
|
135
|
+
}),
|
|
136
|
+
indicatorSeparator: (styles) => ({
|
|
137
|
+
...styles,
|
|
138
|
+
width: null,
|
|
139
|
+
}),
|
|
140
|
+
valueContainer: (styles) => ({
|
|
141
|
+
...styles,
|
|
142
|
+
padding: 0,
|
|
143
|
+
}),
|
|
144
|
+
option: (styles, state) => ({
|
|
145
|
+
...styles,
|
|
146
|
+
backgroundColor: null,
|
|
147
|
+
minHeight: '50px',
|
|
148
|
+
display: 'flex',
|
|
149
|
+
justifyContent: 'space-between',
|
|
150
|
+
alignItems: 'center',
|
|
151
|
+
padding: '12px 12px',
|
|
152
|
+
color: state.isSelected
|
|
153
|
+
? '#007bc1'
|
|
154
|
+
: state.isFocused
|
|
155
|
+
? '#4a4a4a'
|
|
156
|
+
: 'inherit',
|
|
157
|
+
':active': {
|
|
158
|
+
backgroundColor: null,
|
|
159
|
+
},
|
|
160
|
+
span: {
|
|
161
|
+
flex: '0 0 auto',
|
|
162
|
+
},
|
|
163
|
+
svg: {
|
|
164
|
+
flex: '0 0 auto',
|
|
165
|
+
},
|
|
166
|
+
}),
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Workflow container class.
|
|
171
|
+
* @class Workflow
|
|
172
|
+
* @extends Component
|
|
173
|
+
*/
|
|
174
|
+
class Workflow extends Component {
|
|
175
|
+
/**
|
|
176
|
+
* Property types.
|
|
177
|
+
* @property {Object} propTypes Property types.
|
|
178
|
+
* @static
|
|
179
|
+
*/
|
|
180
|
+
static propTypes = {
|
|
181
|
+
getContent: PropTypes.func.isRequired,
|
|
182
|
+
getWorkflow: PropTypes.func.isRequired,
|
|
183
|
+
transitionWorkflow: PropTypes.func.isRequired,
|
|
184
|
+
workflowLoaded: PropTypes.func,
|
|
185
|
+
loaded: PropTypes.bool.isRequired,
|
|
186
|
+
pathname: PropTypes.string.isRequired,
|
|
187
|
+
contentHistory: PropTypes.arrayOf(
|
|
188
|
+
PropTypes.shape({
|
|
189
|
+
review_state: PropTypes.string,
|
|
190
|
+
}),
|
|
191
|
+
),
|
|
192
|
+
transitions: PropTypes.arrayOf(
|
|
193
|
+
PropTypes.shape({
|
|
194
|
+
'@id': PropTypes.string,
|
|
195
|
+
title: PropTypes.string,
|
|
196
|
+
}),
|
|
197
|
+
),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Default properties
|
|
202
|
+
* @property {Object} defaultProps Default properties.
|
|
203
|
+
* @static
|
|
204
|
+
*/
|
|
205
|
+
static defaultProps = {
|
|
206
|
+
history: [],
|
|
207
|
+
transitions: [],
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
state = {
|
|
211
|
+
selectedOption: this.props.currentStateValue,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
componentDidMount() {
|
|
215
|
+
this.props.getWorkflow(this.props.pathname);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Component will receive props
|
|
220
|
+
* @method componentWillReceiveProps
|
|
221
|
+
* @param {Object} nextProps Next properties
|
|
222
|
+
* @returns {undefined}
|
|
223
|
+
*/
|
|
224
|
+
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
225
|
+
if (nextProps.pathname !== this.props.pathname) {
|
|
226
|
+
this.props.getWorkflow(nextProps.pathname);
|
|
227
|
+
}
|
|
228
|
+
if (!this.props.loaded && nextProps.loaded) {
|
|
229
|
+
this.props.getWorkflow(nextProps.pathname);
|
|
230
|
+
this.props.getContent(nextProps.pathname);
|
|
231
|
+
}
|
|
232
|
+
if (!this.props.workflowLoaded && nextProps.workflowLoaded) {
|
|
233
|
+
this.props.getContent(nextProps.pathname);
|
|
234
|
+
// #153145 - Redirect to the newly created version
|
|
235
|
+
if (this.state?.selectedOption?.value === 'createNewVersion') {
|
|
236
|
+
this.props.history.push(`${nextProps.pathname}.1`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* On transition handler
|
|
243
|
+
* @method transition
|
|
244
|
+
* @param {string} event Event object
|
|
245
|
+
* @returns {undefined}
|
|
246
|
+
*/
|
|
247
|
+
transition = (selectedOption) => {
|
|
248
|
+
this.props.transitionWorkflow(flattenToAppURL(selectedOption.url));
|
|
249
|
+
this.setState({ selectedOption });
|
|
250
|
+
toast.success(
|
|
251
|
+
<Toast
|
|
252
|
+
success
|
|
253
|
+
title={this.props.intl.formatMessage(messages.messageUpdated)}
|
|
254
|
+
content=""
|
|
255
|
+
/>,
|
|
256
|
+
);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
selectValue = (option) => {
|
|
260
|
+
const stateDecorator = {
|
|
261
|
+
marginLeft: '10px',
|
|
262
|
+
marginRight: '10px',
|
|
263
|
+
display: 'inline-block',
|
|
264
|
+
backgroundColor: option.color || null,
|
|
265
|
+
content: ' ',
|
|
266
|
+
height: '10px',
|
|
267
|
+
width: '10px',
|
|
268
|
+
borderRadius: '50%',
|
|
269
|
+
};
|
|
270
|
+
return (
|
|
271
|
+
<Fragment>
|
|
272
|
+
<span style={stateDecorator} />
|
|
273
|
+
<span className="Select-value-label">{option.label}</span>
|
|
274
|
+
</Fragment>
|
|
275
|
+
);
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
optionRenderer = (option) => {
|
|
279
|
+
const stateDecorator = {
|
|
280
|
+
marginLeft: '10px',
|
|
281
|
+
marginRight: '10px',
|
|
282
|
+
display: 'inline-block',
|
|
283
|
+
backgroundColor:
|
|
284
|
+
this.props.currentStateValue.value === option.value
|
|
285
|
+
? option.color
|
|
286
|
+
: null,
|
|
287
|
+
content: ' ',
|
|
288
|
+
height: '10px',
|
|
289
|
+
width: '10px',
|
|
290
|
+
borderRadius: '50%',
|
|
291
|
+
border:
|
|
292
|
+
this.props.currentStateValue.value !== option.value
|
|
293
|
+
? `1px solid ${option.color}`
|
|
294
|
+
: null,
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
return (
|
|
298
|
+
<Fragment>
|
|
299
|
+
<span style={stateDecorator} />
|
|
300
|
+
<span style={{ marginRight: 'auto' }}>{option.label}</span>
|
|
301
|
+
<Icon name={checkSVG} size="24px" />
|
|
302
|
+
</Fragment>
|
|
303
|
+
);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
render() {
|
|
307
|
+
const { Placeholder } = this.props.reactSelect.components;
|
|
308
|
+
const Select = this.props.reactSelect.default;
|
|
309
|
+
// Remove markForDeletion transition if item is published
|
|
310
|
+
// in order not to un-publish items by mistake. This transition
|
|
311
|
+
// can still be executed from /contents - refs #256563, #153145
|
|
312
|
+
const transitions = this.props.transitions.filter((transition) => {
|
|
313
|
+
if (
|
|
314
|
+
transition?.['@id']?.endsWith('markForDeletion') &&
|
|
315
|
+
this.props?.content?.review_state === 'published'
|
|
316
|
+
) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
return true;
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
return (
|
|
323
|
+
<FormFieldWrapper
|
|
324
|
+
id="state-select"
|
|
325
|
+
title={this.props.intl.formatMessage(messages.state)}
|
|
326
|
+
{...this.props}
|
|
327
|
+
>
|
|
328
|
+
<Select
|
|
329
|
+
name="state-select"
|
|
330
|
+
className="react-select-container"
|
|
331
|
+
classNamePrefix="react-select"
|
|
332
|
+
isDisabled={
|
|
333
|
+
!this.props.content.review_state || transitions.length === 0
|
|
334
|
+
}
|
|
335
|
+
options={uniqBy(
|
|
336
|
+
transitions.map((transition) => getWorkflowOptions(transition)),
|
|
337
|
+
'label',
|
|
338
|
+
).concat(this.props.currentStateValue)}
|
|
339
|
+
styles={customSelectStyles}
|
|
340
|
+
theme={selectTheme}
|
|
341
|
+
components={{
|
|
342
|
+
DropdownIndicator,
|
|
343
|
+
Placeholder,
|
|
344
|
+
Option,
|
|
345
|
+
SingleValue,
|
|
346
|
+
}}
|
|
347
|
+
onChange={this.transition}
|
|
348
|
+
value={
|
|
349
|
+
this.props.content.review_state
|
|
350
|
+
? this.props.currentStateValue
|
|
351
|
+
: {
|
|
352
|
+
label: this.props.intl.formatMessage(
|
|
353
|
+
messages.messageNoWorkflow,
|
|
354
|
+
),
|
|
355
|
+
value: 'noworkflow',
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
isSearchable={false}
|
|
359
|
+
/>
|
|
360
|
+
</FormFieldWrapper>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export default compose(
|
|
366
|
+
injectIntl,
|
|
367
|
+
injectLazyLibs(['reactSelect']),
|
|
368
|
+
withRouter,
|
|
369
|
+
connect(
|
|
370
|
+
(state) => ({
|
|
371
|
+
loaded: state.workflow.transition.loaded,
|
|
372
|
+
content: state.content.data,
|
|
373
|
+
workflowLoaded: state.workflow.get?.loaded,
|
|
374
|
+
contentHistory: state.workflow.history,
|
|
375
|
+
transitions: state.workflow.transitions,
|
|
376
|
+
currentStateValue: getCurrentStateMapping(state.workflow.currentState),
|
|
377
|
+
}),
|
|
378
|
+
{ getContent, getWorkflow, transitionWorkflow },
|
|
379
|
+
),
|
|
380
|
+
)(Workflow);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import configureStore from 'redux-mock-store';
|
|
3
|
+
import { Provider } from 'react-intl-redux';
|
|
4
|
+
import { waitFor, render, screen } from '@testing-library/react';
|
|
5
|
+
import { MemoryRouter } from 'react-router-dom';
|
|
6
|
+
import config from '@plone/volto/registry';
|
|
7
|
+
|
|
8
|
+
import Workflow from './Workflow';
|
|
9
|
+
|
|
10
|
+
const mockStore = configureStore();
|
|
11
|
+
|
|
12
|
+
jest.mock('@plone/volto/helpers/Loadable/Loadable');
|
|
13
|
+
beforeAll(
|
|
14
|
+
async () =>
|
|
15
|
+
await require('@plone/volto/helpers/Loadable/Loadable').__setLoadables(),
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
config.settings.workflowMapping = {
|
|
20
|
+
published: { value: 'published', color: '#007bc1' },
|
|
21
|
+
publish: { value: 'publish', color: '#007bc1' },
|
|
22
|
+
private: { value: 'private', color: '#ed4033' },
|
|
23
|
+
pending: { value: 'pending', color: '#f6a808' },
|
|
24
|
+
send_back: { value: 'private', color: '#ed4033' },
|
|
25
|
+
retract: { value: 'private', color: '#ed4033' },
|
|
26
|
+
submit: { value: 'review', color: '#f4e037' },
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Workflow', () => {
|
|
31
|
+
it('renders an empty workflow component', async () => {
|
|
32
|
+
const store = mockStore({
|
|
33
|
+
workflow: {
|
|
34
|
+
currentState: { id: 'published', title: 'Published' },
|
|
35
|
+
history: [],
|
|
36
|
+
transition: { loaded: true },
|
|
37
|
+
transitions: [],
|
|
38
|
+
},
|
|
39
|
+
intl: {
|
|
40
|
+
locale: 'en',
|
|
41
|
+
messages: {},
|
|
42
|
+
},
|
|
43
|
+
content: { data: { review_state: 'published' } },
|
|
44
|
+
});
|
|
45
|
+
const { container } = render(
|
|
46
|
+
<Provider store={store}>
|
|
47
|
+
<MemoryRouter>
|
|
48
|
+
<Workflow pathname="/test" />
|
|
49
|
+
</MemoryRouter>
|
|
50
|
+
</Provider>,
|
|
51
|
+
);
|
|
52
|
+
await waitFor(() => screen.getByText(/Published/));
|
|
53
|
+
expect(container).toMatchSnapshot();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('renders a workflow component', async () => {
|
|
57
|
+
const store = mockStore({
|
|
58
|
+
workflow: {
|
|
59
|
+
currentState: { id: 'private', title: 'Private' },
|
|
60
|
+
history: [{ review_state: 'private' }],
|
|
61
|
+
transition: { loaded: true },
|
|
62
|
+
transitions: [{ '@id': 'http://publish', title: 'Publish' }],
|
|
63
|
+
},
|
|
64
|
+
intl: {
|
|
65
|
+
locale: 'en',
|
|
66
|
+
messages: {},
|
|
67
|
+
},
|
|
68
|
+
content: { data: { review_state: 'private' } },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<Provider store={store}>
|
|
73
|
+
<MemoryRouter>
|
|
74
|
+
<Workflow pathname="/test" />
|
|
75
|
+
</MemoryRouter>
|
|
76
|
+
</Provider>,
|
|
77
|
+
);
|
|
78
|
+
await waitFor(() => screen.getByText('Private'));
|
|
79
|
+
expect(container).toMatchSnapshot();
|
|
80
|
+
});
|
|
81
|
+
});
|
package/src/index.js
CHANGED
|
@@ -2,8 +2,6 @@ import { runtimeConfig } from '@plone/volto/runtime_config';
|
|
|
2
2
|
import installContextNavigationBlock from '@eeacms/volto-eea-website-policy/components/Blocks/ContextNavigation';
|
|
3
3
|
import { appendGroup } from './helpers';
|
|
4
4
|
import { FrequencyOfDissemination } from '@eeacms/volto-eea-website-policy/components/Widgets/FrequencyOfDissemination';
|
|
5
|
-
import { DataProvenance } from '@eeacms/volto-eea-website-policy/components/Widgets/DataProvenance';
|
|
6
|
-
import { InstitutionalMandate } from '@eeacms/volto-eea-website-policy/components/Widgets/InstitutionalMandate';
|
|
7
5
|
|
|
8
6
|
const restrictedBlocks = [
|
|
9
7
|
'imagecards',
|
|
@@ -120,8 +118,6 @@ const applyConfig = (config) => {
|
|
|
120
118
|
});
|
|
121
119
|
|
|
122
120
|
// Custom widgets
|
|
123
|
-
config.widgets.id.data_provenance = DataProvenance;
|
|
124
|
-
config.widgets.id.institutional_mandate = InstitutionalMandate;
|
|
125
121
|
config.widgets.views.id.frequency_of_dissemination = FrequencyOfDissemination;
|
|
126
122
|
|
|
127
123
|
// Subsite
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import RichTextWidget from '@plone/volto-slate/widgets/RichTextWidget';
|
|
2
|
-
import { DataProvenance as NextDataProvenance } from '@eeacms/volto-widget-dataprovenance/components/theme/Widgets/DataProvenance';
|
|
3
|
-
|
|
4
|
-
export const DataProvenance = (props) => {
|
|
5
|
-
if (props.behavior === 'eea.coremetadata.behavior') {
|
|
6
|
-
return <NextDataProvenance {...props} />;
|
|
7
|
-
}
|
|
8
|
-
if (props.behavior === 'eea.dexterity.indicators.metadata') {
|
|
9
|
-
return <RichTextWidget {...props} />;
|
|
10
|
-
}
|
|
11
|
-
return ' Data Provenance ';
|
|
12
|
-
};
|