@eeacms/volto-eea-website-theme 1.34.0 → 2.0.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 (54) hide show
  1. package/.eslintrc.js +7 -2
  2. package/CHANGELOG.md +44 -20
  3. package/docker-compose.yml +1 -1
  4. package/jest-addon.config.js +3 -0
  5. package/package.json +2 -1
  6. package/src/components/manage/Blocks/LayoutSettings/index.js +3 -1
  7. package/src/components/manage/Blocks/Title/index.js +3 -1
  8. package/src/components/manage/Blocks/Title/schema.js +3 -1
  9. package/src/components/theme/Banner/View.jsx +12 -5
  10. package/src/components/theme/DraftBackground/DraftBackground.jsx +1 -0
  11. package/src/components/theme/DraftBackground/DraftBackground.test.jsx +85 -0
  12. package/src/config.js +2 -0
  13. package/src/customizations/@plone/volto-slate/blocks/Text/TextBlockView.jsx +32 -0
  14. package/src/customizations/@plone/volto-slate/editor/render.jsx +75 -0
  15. package/src/customizations/@plone/volto-slate/elementEditor/utils.js +76 -75
  16. package/src/customizations/volto/components/manage/Blocks/Grid/Edit.jsx +70 -0
  17. package/src/customizations/volto/components/manage/Blocks/Grid/View.jsx +61 -0
  18. package/src/customizations/volto/components/manage/Blocks/Grid/readme.md +1 -0
  19. package/src/customizations/volto/components/manage/Blocks/Image/Edit.jsx +82 -23
  20. package/src/customizations/volto/components/manage/Blocks/Image/Edit.test.jsx +10 -3
  21. package/src/customizations/volto/components/manage/Blocks/Image/View.jsx +110 -111
  22. package/src/customizations/volto/components/manage/Blocks/Image/schema.js +17 -2
  23. package/src/customizations/volto/components/manage/Blocks/LeadImage/Edit.jsx +35 -14
  24. package/src/customizations/volto/components/manage/Blocks/LeadImage/View.jsx +65 -79
  25. package/src/customizations/volto/components/manage/Display/Display.jsx +306 -0
  26. package/src/customizations/volto/components/manage/Display/Readme.md +1 -0
  27. package/src/customizations/volto/components/manage/Sidebar/SidebarPopup copy.jsx +82 -0
  28. package/src/customizations/volto/components/manage/Toolbar/More.jsx +541 -0
  29. package/src/customizations/volto/components/manage/UniversalLink/UniversalLink.jsx +3 -1
  30. package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.jsx +24 -14
  31. package/src/customizations/volto/components/manage/Widgets/README.md +1 -0
  32. package/src/customizations/volto/components/manage/Workflow/README.txt +1 -0
  33. package/src/customizations/volto/components/manage/Workflow/Workflow.jsx +324 -0
  34. package/src/customizations/volto/components/manage/Workflow/Workflow.test.jsx +81 -0
  35. package/src/customizations/volto/components/theme/Comments/Comments.jsx +1 -2
  36. package/src/customizations/volto/components/theme/ContactForm/ContactForm.jsx +1 -1
  37. package/src/customizations/volto/components/theme/EventDetails/EventDetails.jsx +1 -0
  38. package/src/index.js +21 -16
  39. package/src/middleware/ok.js +4 -2
  40. package/src/middleware/voltoCustom.js +4 -2
  41. package/src/slate.js +10 -8
  42. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/README.txt +0 -1
  43. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/StyleMenu.jsx +0 -157
  44. package/src/customizations/@plone/volto-slate/editor/plugins/StyleMenu/utils.js +0 -168
  45. package/src/customizations/volto/components/manage/Add/Add.jsx +0 -498
  46. package/src/customizations/volto/components/manage/Add/readme.md +0 -1
  47. package/src/customizations/volto/components/manage/Contents/ContentsPropertiesModal.jsx +0 -232
  48. package/src/customizations/volto/components/manage/Form/Form.jsx +0 -810
  49. package/src/customizations/volto/components/manage/Form/Form.test.jsx +0 -1124
  50. package/src/customizations/volto/components/manage/Form/ModalForm.jsx +0 -326
  51. package/src/customizations/volto/components/manage/Sharing/Sharing.jsx +0 -528
  52. package/src/customizations/volto/components/manage/Sharing/Sharing.test.jsx +0 -72
  53. package/src/customizations/volto/components/manage/Widgets/ObjectBrowserWidget.test.jsx +0 -193
  54. package/src/customizations/volto/components/theme/AppExtras/AppExtras.jsx +0 -27
@@ -1,528 +0,0 @@
1
- /**
2
- * Sharing container.
3
- * @module components/manage/Sharing/Sharing
4
- */
5
- import React, { Component } from 'react';
6
- import PropTypes from 'prop-types';
7
- import { Plug, Pluggable } from '@plone/volto/components/manage/Pluggable';
8
- import { Helmet } from '@plone/volto/helpers';
9
- import { connect } from 'react-redux';
10
- import { compose } from 'redux';
11
- import { Link, withRouter } from 'react-router-dom';
12
- import { find, isEqual, map } from 'lodash';
13
- import { Portal } from 'react-portal';
14
- import {
15
- Button,
16
- Checkbox,
17
- Container as SemanticContainer,
18
- Form,
19
- Icon as IconOld,
20
- Input,
21
- Segment,
22
- Table,
23
- } from 'semantic-ui-react';
24
- import jwtDecode from 'jwt-decode';
25
- import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
26
-
27
- import { updateSharing, getSharing } from '@plone/volto/actions';
28
- import { getBaseUrl } from '@plone/volto/helpers';
29
- import { Icon, Toolbar, Toast } from '@plone/volto/components';
30
- import { toast } from 'react-toastify';
31
- import config from '@plone/volto/registry';
32
-
33
- import aheadSVG from '@plone/volto/icons/ahead.svg';
34
- import clearSVG from '@plone/volto/icons/clear.svg';
35
- import backSVG from '@plone/volto/icons/back.svg';
36
-
37
- const messages = defineMessages({
38
- searchForUserOrGroup: {
39
- id: 'Search for user or group',
40
- defaultMessage: 'Search for user or group',
41
- },
42
- inherit: {
43
- id: 'Inherit permissions from higher levels',
44
- defaultMessage: 'Inherit permissions from higher levels',
45
- },
46
- save: {
47
- id: 'Save',
48
- defaultMessage: 'Save',
49
- },
50
- cancel: {
51
- id: 'Cancel',
52
- defaultMessage: 'Cancel',
53
- },
54
- back: {
55
- id: 'Back',
56
- defaultMessage: 'Back',
57
- },
58
- sharing: {
59
- id: 'Sharing',
60
- defaultMessage: 'Sharing',
61
- },
62
- user: {
63
- id: 'User',
64
- defaultMessage: 'User',
65
- },
66
- group: {
67
- id: 'Group',
68
- defaultMessage: 'Group',
69
- },
70
- globalRole: {
71
- id: 'Global role',
72
- defaultMessage: 'Global role',
73
- },
74
- inheritedValue: {
75
- id: 'Inherited value',
76
- defaultMessage: 'Inherited value',
77
- },
78
- permissionsUpdated: {
79
- id: 'Permissions updated',
80
- defaultMessage: 'Permissions updated',
81
- },
82
- permissionsUpdatedSuccessfully: {
83
- id: 'Permissions have been updated successfully',
84
- defaultMessage: 'Permissions have been updated successfully',
85
- },
86
- });
87
-
88
- /**
89
- * SharingComponent class.
90
- * @class SharingComponent
91
- * @extends Component
92
- */
93
- class SharingComponent extends Component {
94
- /**
95
- * Property types.
96
- * @property {Object} propTypes Property types.
97
- * @static
98
- */
99
- static propTypes = {
100
- updateSharing: PropTypes.func.isRequired,
101
- getSharing: PropTypes.func.isRequired,
102
- updateRequest: PropTypes.shape({
103
- loading: PropTypes.bool,
104
- loaded: PropTypes.bool,
105
- }).isRequired,
106
- pathname: PropTypes.string.isRequired,
107
- entries: PropTypes.arrayOf(
108
- PropTypes.shape({
109
- id: PropTypes.string,
110
- login: PropTypes.string,
111
- roles: PropTypes.object,
112
- title: PropTypes.string,
113
- type: PropTypes.string,
114
- }),
115
- ).isRequired,
116
- available_roles: PropTypes.arrayOf(PropTypes.object).isRequired,
117
- inherit: PropTypes.bool,
118
- title: PropTypes.string.isRequired,
119
- login: PropTypes.string,
120
- };
121
-
122
- /**
123
- * Default properties
124
- * @property {Object} defaultProps Default properties.
125
- * @static
126
- */
127
- static defaultProps = {
128
- inherit: null,
129
- login: '',
130
- };
131
-
132
- /**
133
- * Constructor
134
- * @method constructor
135
- * @param {Object} props Component properties
136
- * @constructs Sharing
137
- */
138
- constructor(props) {
139
- super(props);
140
- this.onCancel = this.onCancel.bind(this);
141
- this.onChange = this.onChange.bind(this);
142
- this.onChangeSearch = this.onChangeSearch.bind(this);
143
- this.onSearch = this.onSearch.bind(this);
144
- this.onSubmit = this.onSubmit.bind(this);
145
- this.onToggleInherit = this.onToggleInherit.bind(this);
146
- this.state = {
147
- search: '',
148
- isLoading: false,
149
- inherit: props.inherit,
150
- entries: props.entries,
151
- isClient: false,
152
- };
153
- }
154
-
155
- /**
156
- * Component did mount
157
- * @method componentDidMount
158
- * @returns {undefined}
159
- */
160
- componentDidMount() {
161
- this.props.getSharing(getBaseUrl(this.props.pathname), this.state.search);
162
- this.setState({ isClient: true });
163
- }
164
-
165
- /**
166
- * Component will receive props
167
- * @method componentWillReceiveProps
168
- * @param {Object} nextProps Next properties
169
- * @returns {undefined}
170
- */
171
- UNSAFE_componentWillReceiveProps(nextProps) {
172
- if (this.props.updateRequest.loading && nextProps.updateRequest.loaded) {
173
- this.props.getSharing(getBaseUrl(this.props.pathname), this.state.search);
174
- toast.success(
175
- <Toast
176
- success
177
- title={this.props.intl.formatMessage(messages.permissionsUpdated)}
178
- content={this.props.intl.formatMessage(
179
- messages.permissionsUpdatedSuccessfully,
180
- )}
181
- />,
182
- );
183
- }
184
- this.setState({
185
- inherit:
186
- this.props.inherit === null ? nextProps.inherit : this.state.inherit,
187
- entries: map(nextProps.entries, (entry) => {
188
- const values = find(this.state.entries, { id: entry.id });
189
- return {
190
- ...entry,
191
- roles: values ? values.roles : entry.roles,
192
- };
193
- }),
194
- });
195
- }
196
-
197
- /**
198
- * Submit handler
199
- * @method onSubmit
200
- * @param {object} event Event object.
201
- * @returns {undefined}
202
- */
203
- onSubmit(event) {
204
- const data = { entries: [] };
205
- event.preventDefault();
206
- if (this.props.inherit !== this.state.inherit) {
207
- data.inherit = this.state.inherit;
208
- }
209
- for (let i = 0; i < this.props.entries.length; i += 1) {
210
- if (!isEqual(this.props.entries[i].roles, this.state.entries[i].roles)) {
211
- data.entries.push({
212
- id: this.state.entries[i].id,
213
- type: this.state.entries[i].type,
214
- roles: this.state.entries[i].roles,
215
- });
216
- }
217
- }
218
- this.props.updateSharing(getBaseUrl(this.props.pathname), data);
219
- }
220
-
221
- /**
222
- * Search handler
223
- * @method onSearch
224
- * @param {object} event Event object.
225
- * @returns {undefined}
226
- */
227
- onSearch(event) {
228
- event.preventDefault();
229
- this.setState({ isLoading: true });
230
- this.props
231
- .getSharing(getBaseUrl(this.props.pathname), this.state.search)
232
- .then(() => {
233
- this.setState({ isLoading: false });
234
- })
235
- .catch((error) => {
236
- this.setState({ isLoading: false });
237
- // eslint-disable-next-line no-console
238
- console.error('Error searching users or groups', error);
239
- });
240
- }
241
-
242
- /**
243
- * On change search handler
244
- * @method onChangeSearch
245
- * @param {object} event Event object.
246
- * @returns {undefined}
247
- */
248
- onChangeSearch(event) {
249
- this.setState({
250
- search: event.target.value,
251
- });
252
- }
253
-
254
- /**
255
- * On toggle inherit handler
256
- * @method onToggleInherit
257
- * @returns {undefined}
258
- */
259
- onToggleInherit() {
260
- this.setState((state) => ({
261
- inherit: !state.inherit,
262
- }));
263
- }
264
-
265
- /**
266
- * On change handler
267
- * @method onChange
268
- * @param {object} event Event object
269
- * @param {string} value Entry value
270
- * @returns {undefined}
271
- */
272
- onChange(event, { value }) {
273
- const [principal, role] = value.split(':');
274
- this.setState({
275
- entries: map(this.state.entries, (entry) => ({
276
- ...entry,
277
- roles:
278
- entry.id === principal
279
- ? {
280
- ...entry.roles,
281
- [role]: !entry.roles[role],
282
- }
283
- : entry.roles,
284
- })),
285
- });
286
- }
287
-
288
- /**
289
- * Cancel handler
290
- * @method onCancel
291
- * @returns {undefined}
292
- */
293
- onCancel() {
294
- this.props.history.push(getBaseUrl(this.props.pathname));
295
- }
296
-
297
- /**
298
- * Render method.
299
- * @method render
300
- * @returns {string} Markup for the component.
301
- */
302
- render() {
303
- const Container =
304
- config.getComponent({ name: 'Container' }).component || SemanticContainer;
305
-
306
- return (
307
- <Container id="page-sharing">
308
- <Helmet title={this.props.intl.formatMessage(messages.sharing)} />
309
- <Segment.Group raised>
310
- <Pluggable
311
- name="sharing-component"
312
- params={{ isLoading: this.state.isLoading }}
313
- />
314
- <Plug pluggable="sharing-component" id="sharing-component-title">
315
- <Segment className="primary">
316
- <FormattedMessage
317
- id="Sharing for {title}"
318
- defaultMessage="Sharing for {title}"
319
- values={{ title: <q>{this.props.title}</q> }}
320
- />
321
- </Segment>
322
- </Plug>
323
- <Plug
324
- pluggable="sharing-component"
325
- id="sharing-component-description"
326
- >
327
- <Segment secondary>
328
- <FormattedMessage
329
- id="You can control who can view and edit your item using the list below."
330
- defaultMessage="You can control who can view and edit your item using the list below."
331
- />
332
- </Segment>
333
- </Plug>
334
- <Plug pluggable="sharing-component" id="sharing-component-search">
335
- {({ isLoading }) => {
336
- return (
337
- <Segment>
338
- <Form onSubmit={this.onSearch}>
339
- <Form.Field>
340
- <Input
341
- name="SearchableText"
342
- action={{
343
- icon: 'search',
344
- loading: isLoading,
345
- disabled: isLoading,
346
- }}
347
- placeholder={this.props.intl.formatMessage(
348
- messages.searchForUserOrGroup,
349
- )}
350
- onChange={this.onChangeSearch}
351
- id="sharing-component-search"
352
- />
353
- </Form.Field>
354
- </Form>
355
- </Segment>
356
- );
357
- }}
358
- </Plug>
359
- <Plug
360
- pluggable="sharing-component"
361
- id="sharing-component-form"
362
- dependencies={[this.state.entries, this.props.available_roles]}
363
- >
364
- <Form onSubmit={this.onSubmit}>
365
- <Table celled padded striped attached>
366
- <Table.Header>
367
- <Table.Row>
368
- <Table.HeaderCell>
369
- <FormattedMessage id="Name" defaultMessage="Name" />
370
- </Table.HeaderCell>
371
- {this.props.available_roles?.map((role) => (
372
- <Table.HeaderCell key={role.id}>
373
- {role.title}
374
- </Table.HeaderCell>
375
- ))}
376
- </Table.Row>
377
- </Table.Header>
378
- <Table.Body>
379
- {this.state.entries?.map((entry) => (
380
- <Table.Row key={entry.id}>
381
- <Table.Cell>
382
- <IconOld
383
- name={entry.type === 'user' ? 'user' : 'users'}
384
- title={
385
- entry.type === 'user'
386
- ? this.props.intl.formatMessage(messages.user)
387
- : this.props.intl.formatMessage(messages.group)
388
- }
389
- />{' '}
390
- {entry.title}
391
- {entry.login && ` (${entry.login})`}
392
- </Table.Cell>
393
- {this.props.available_roles?.map((role) => (
394
- <Table.Cell key={role.id}>
395
- {entry.roles[role.id] === 'global' && (
396
- <IconOld
397
- name="check circle outline"
398
- title={this.props.intl.formatMessage(
399
- messages.globalRole,
400
- )}
401
- color="blue"
402
- />
403
- )}
404
- {entry.roles[role.id] === 'acquired' && (
405
- <IconOld
406
- name="check circle outline"
407
- color="green"
408
- title={this.props.intl.formatMessage(
409
- messages.inheritedValue,
410
- )}
411
- />
412
- )}
413
- {typeof entry.roles[role.id] === 'boolean' && (
414
- <Checkbox
415
- onChange={this.onChange}
416
- value={`${entry.id}:${role.id}`}
417
- checked={entry.roles[role.id]}
418
- disabled={entry.login === this.props.login}
419
- />
420
- )}
421
- </Table.Cell>
422
- ))}
423
- </Table.Row>
424
- ))}
425
- </Table.Body>
426
- </Table>
427
- <Segment attached>
428
- <Form.Field>
429
- <Checkbox
430
- id="inherit-permissions-checkbox"
431
- name="inherit-permissions-checkbox"
432
- defaultChecked={this.state.inherit}
433
- onChange={this.onToggleInherit}
434
- label={
435
- <label htmlFor="inherit-permissions-checkbox">
436
- {this.props.intl.formatMessage(messages.inherit)}
437
- </label>
438
- }
439
- />
440
- </Form.Field>
441
- <p className="help">
442
- <FormattedMessage
443
- id="By default, permissions from the container of this item are inherited. If you disable this, only the explicitly defined sharing permissions will be valid. In the overview, the symbol {inherited} indicates an inherited value. Similarly, the symbol {global} indicates a global role, which is managed by the site administrator."
444
- defaultMessage="By default, permissions from the container of this item are inherited. If you disable this, only the explicitly defined sharing permissions will be valid. In the overview, the symbol {inherited} indicates an inherited value. Similarly, the symbol {global} indicates a global role, which is managed by the site administrator."
445
- values={{
446
- inherited: (
447
- <IconOld name="check circle outline" color="green" />
448
- ),
449
- global: (
450
- <IconOld name="check circle outline" color="blue" />
451
- ),
452
- }}
453
- />
454
- </p>
455
- </Segment>
456
- <Segment className="actions" attached clearing>
457
- <Button
458
- basic
459
- icon
460
- primary
461
- floated="right"
462
- type="submit"
463
- aria-label={this.props.intl.formatMessage(messages.save)}
464
- title={this.props.intl.formatMessage(messages.save)}
465
- loading={this.props.updateRequest.loading}
466
- onClick={this.onSubmit}
467
- >
468
- <Icon className="circled" name={aheadSVG} size="30px" />
469
- </Button>
470
- <Button
471
- basic
472
- icon
473
- secondary
474
- aria-label={this.props.intl.formatMessage(messages.cancel)}
475
- title={this.props.intl.formatMessage(messages.cancel)}
476
- floated="right"
477
- onClick={this.onCancel}
478
- >
479
- <Icon className="circled" name={clearSVG} size="30px" />
480
- </Button>
481
- </Segment>
482
- </Form>
483
- </Plug>
484
- </Segment.Group>
485
- {this.state.isClient && (
486
- <Portal node={document.getElementById('toolbar')}>
487
- <Toolbar
488
- pathname={this.props.pathname}
489
- hideDefaultViewButtons
490
- inner={
491
- <Link
492
- to={`${getBaseUrl(this.props.pathname)}`}
493
- className="item"
494
- >
495
- <Icon
496
- name={backSVG}
497
- className="contents circled"
498
- size="30px"
499
- title={this.props.intl.formatMessage(messages.back)}
500
- />
501
- </Link>
502
- }
503
- />
504
- </Portal>
505
- )}
506
- </Container>
507
- );
508
- }
509
- }
510
-
511
- export default compose(
512
- withRouter,
513
- injectIntl,
514
- connect(
515
- (state, props) => ({
516
- entries: state.sharing.data.entries,
517
- inherit: state.sharing.data.inherit,
518
- available_roles: state.sharing.data.available_roles,
519
- updateRequest: state.sharing.update,
520
- pathname: props.location.pathname,
521
- title: state.content.data.title,
522
- login: state.userSession.token
523
- ? jwtDecode(state.userSession.token).sub
524
- : '',
525
- }),
526
- { updateSharing, getSharing },
527
- ),
528
- )(SharingComponent);
@@ -1,72 +0,0 @@
1
- import React from 'react';
2
- import renderer from 'react-test-renderer';
3
- import configureStore from 'redux-mock-store';
4
- import { Provider } from 'react-intl-redux';
5
- import jwt from 'jsonwebtoken';
6
- import { MemoryRouter } from 'react-router-dom';
7
- import { PluggablesProvider } from '@plone/volto/components/manage/Pluggable';
8
-
9
- import Sharing from './Sharing';
10
-
11
- const mockStore = configureStore();
12
-
13
- jest.mock('react-portal', () => ({
14
- Portal: jest.fn(() => <div id="Portal" />),
15
- }));
16
-
17
- describe('Sharing', () => {
18
- it('renders a sharing component', () => {
19
- const store = mockStore({
20
- userSession: {
21
- token: jwt.sign({ sub: 'john-doe' }, 'secret'),
22
- },
23
- sharing: {
24
- data: {
25
- entries: [
26
- {
27
- id: 'john-doe',
28
- disabled: false,
29
- login: 'john-doe',
30
- roles: {
31
- Contributer: true,
32
- },
33
- title: 'John Doe',
34
- type: 'user',
35
- },
36
- ],
37
- inherit: true,
38
- available_roles: [
39
- {
40
- id: 'Contributor',
41
- title: 'Can add',
42
- },
43
- ],
44
- },
45
- update: {
46
- loading: false,
47
- loaded: true,
48
- },
49
- },
50
- content: {
51
- data: {
52
- title: 'Blog',
53
- },
54
- },
55
- intl: {
56
- locale: 'en',
57
- messages: {},
58
- },
59
- });
60
- const component = renderer.create(
61
- <Provider store={store}>
62
- <PluggablesProvider>
63
- <MemoryRouter>
64
- <Sharing location={{ pathname: '/blog' }} />
65
- </MemoryRouter>
66
- </PluggablesProvider>
67
- </Provider>,
68
- );
69
- const json = component.toJSON();
70
- expect(json).toMatchSnapshot();
71
- });
72
- });