@plone/volto 17.0.0-alpha.21 → 17.0.0-alpha.23
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/.gitignore~ +71 -0
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +41 -0
- package/locales/ca/LC_MESSAGES/volto.po +14 -4
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +27 -17
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +15 -5
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +15 -5
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +14 -4
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +14 -4
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +14 -4
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +239 -229
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +14 -4
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +14 -4
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +14 -4
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +15 -5
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +14 -4
- package/locales/ro.json +1 -1
- package/locales/volto.pot +15 -5
- package/locales/zh_CN/LC_MESSAGES/volto.po +14 -4
- package/locales/zh_CN.json +1 -1
- package/news/4547.breaking~ +1 -0
- package/package.json +3 -3
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/relations/rebuild.js +7 -7
- package/src/components/manage/Actions/Actions.jsx +133 -243
- package/src/components/manage/Blocks/Container/Edit.jsx +4 -1
- package/src/components/manage/Blocks/Container/EditBlockWrapper.jsx +1 -0
- package/src/components/manage/Blocks/Grid/Edit.jsx +15 -1
- package/src/components/manage/Blocks/Image/View.jsx +2 -1
- package/src/components/manage/Blocks/Maps/Edit.jsx +135 -209
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +3 -2
- package/src/components/manage/Contents/ContentsPropertiesModal.jsx +1 -13
- package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +2 -2
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +30 -7
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +2 -2
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +53 -59
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +2 -2
- package/src/components/manage/Delete/Delete.jsx +96 -171
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Workflow/Workflow.jsx +75 -184
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +95 -170
- package/src/config/Components.jsx +1 -0
- package/src/config/index.js~ +223 -0
- package/src/express-middleware/files.js +8 -6
- package/src/express-middleware/images.js +7 -1
- package/src/helpers/MessageLabels/MessageLabels.js +6 -0
- package/src/reducers/relations/relations.js +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +0 -90
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +0 -6
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +0 -30
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +0 -10
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +0 -6
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +0 -6
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
* Edit map block.
|
|
3
|
-
* @module components/manage/Blocks/Maps/Edit
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { Component } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
7
2
|
import PropTypes from 'prop-types';
|
|
8
3
|
import { Button, Input, Message } from 'semantic-ui-react';
|
|
9
|
-
import { defineMessages, FormattedMessage,
|
|
4
|
+
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|
10
5
|
import cx from 'classnames';
|
|
11
|
-
import { isEqual } from 'lodash';
|
|
12
6
|
import { withBlockExtensions } from '@plone/volto/helpers';
|
|
13
7
|
import { compose } from 'redux';
|
|
14
8
|
import { Icon, SidebarPortal, MapsSidebar } from '@plone/volto/components';
|
|
@@ -43,230 +37,162 @@ const messages = defineMessages({
|
|
|
43
37
|
},
|
|
44
38
|
});
|
|
45
39
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
*/
|
|
51
|
-
class Edit extends Component {
|
|
52
|
-
/**
|
|
53
|
-
* Property types.
|
|
54
|
-
* @property {Object} propTypes Property types.
|
|
55
|
-
* @static
|
|
56
|
-
*/
|
|
57
|
-
static propTypes = {
|
|
58
|
-
selected: PropTypes.bool.isRequired,
|
|
59
|
-
block: PropTypes.string.isRequired,
|
|
60
|
-
index: PropTypes.number.isRequired,
|
|
61
|
-
data: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
62
|
-
pathname: PropTypes.string.isRequired,
|
|
63
|
-
onChangeBlock: PropTypes.func.isRequired,
|
|
64
|
-
onSelectBlock: PropTypes.func.isRequired,
|
|
65
|
-
onDeleteBlock: PropTypes.func.isRequired,
|
|
66
|
-
onFocusPreviousBlock: PropTypes.func.isRequired,
|
|
67
|
-
onFocusNextBlock: PropTypes.func.isRequired,
|
|
68
|
-
handleKeyDown: PropTypes.func.isRequired,
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Constructor
|
|
73
|
-
* @method constructor
|
|
74
|
-
* @param {Object} props Component properties
|
|
75
|
-
* @constructs WysiwygEditor
|
|
76
|
-
*/
|
|
77
|
-
constructor(props) {
|
|
78
|
-
super(props);
|
|
79
|
-
this.getSrc = this.getSrc.bind(this);
|
|
80
|
-
this.state = {
|
|
81
|
-
url: '',
|
|
82
|
-
error: null,
|
|
83
|
-
};
|
|
84
|
-
this.onSubmitUrl = this.onSubmitUrl.bind(this);
|
|
85
|
-
this.onKeyDownVariantMenuForm = this.onKeyDownVariantMenuForm.bind(this);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @param {*} nextProps
|
|
90
|
-
* @returns {boolean}
|
|
91
|
-
* @memberof Edit
|
|
92
|
-
*/
|
|
93
|
-
shouldComponentUpdate(nextProps) {
|
|
94
|
-
return (
|
|
95
|
-
this.props.selected ||
|
|
96
|
-
nextProps.selected ||
|
|
97
|
-
!isEqual(this.props.data, nextProps.data)
|
|
98
|
-
);
|
|
99
|
-
}
|
|
40
|
+
const Edit = React.memo((props) => {
|
|
41
|
+
const intl = useIntl();
|
|
42
|
+
const [url, setUrl] = useState('');
|
|
43
|
+
const [error, setError] = useState(null);
|
|
100
44
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
* @param {Object} target Target object
|
|
105
|
-
* @returns {undefined}
|
|
106
|
-
*/
|
|
107
|
-
onChangeUrl = ({ target }) => {
|
|
108
|
-
this.setState({
|
|
109
|
-
url: target.value,
|
|
110
|
-
});
|
|
45
|
+
const { onChangeBlock, data, block, selected } = props;
|
|
46
|
+
const onChangeUrl = ({ target }) => {
|
|
47
|
+
setUrl(target.value);
|
|
111
48
|
};
|
|
112
49
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* @returns {undefined}
|
|
118
|
-
*/
|
|
119
|
-
onSubmitUrl() {
|
|
120
|
-
this.props.onChangeBlock(this.props.block, {
|
|
121
|
-
...this.props.data,
|
|
122
|
-
url: this.getSrc(this.state.url),
|
|
50
|
+
const onSubmitUrl = useCallback(() => {
|
|
51
|
+
onChangeBlock(block, {
|
|
52
|
+
...data,
|
|
53
|
+
url: getSrc(url),
|
|
123
54
|
});
|
|
124
|
-
}
|
|
55
|
+
}, [onChangeBlock, block, data, url]);
|
|
125
56
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
e.preventDefault();
|
|
141
|
-
e.stopPropagation();
|
|
142
|
-
// TODO: Do something on ESC key
|
|
143
|
-
}
|
|
144
|
-
}
|
|
57
|
+
const onKeyDownVariantMenuForm = useCallback(
|
|
58
|
+
(e) => {
|
|
59
|
+
if (e.key === 'Enter') {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
onSubmitUrl();
|
|
63
|
+
} else if (e.key === 'Escape') {
|
|
64
|
+
e.preventDefault();
|
|
65
|
+
e.stopPropagation();
|
|
66
|
+
// TODO: Do something on ESC key
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
[onSubmitUrl],
|
|
70
|
+
);
|
|
145
71
|
|
|
146
|
-
|
|
147
|
-
* get getSrc handler
|
|
148
|
-
* @method getSrc
|
|
149
|
-
* @param {string} embed Embed HTML code from Google Maps share option
|
|
150
|
-
* @returns {string} Source URL
|
|
151
|
-
*/
|
|
152
|
-
getSrc(embed) {
|
|
72
|
+
const getSrc = (embed) => {
|
|
153
73
|
const parser = new DOMParser();
|
|
154
74
|
const doc = parser.parseFromString(embed, 'text/html');
|
|
155
75
|
const iframe = doc.getElementsByTagName('iframe');
|
|
156
76
|
if (iframe.length === 0) {
|
|
157
|
-
|
|
77
|
+
setError(true);
|
|
158
78
|
return '';
|
|
159
79
|
}
|
|
160
|
-
|
|
80
|
+
setError(false);
|
|
161
81
|
return iframe[0].src;
|
|
162
|
-
}
|
|
82
|
+
};
|
|
163
83
|
|
|
164
|
-
resetSubmitUrl = () => {
|
|
165
|
-
|
|
166
|
-
url: '',
|
|
167
|
-
});
|
|
84
|
+
const resetSubmitUrl = () => {
|
|
85
|
+
setUrl('');
|
|
168
86
|
};
|
|
169
87
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// of the upload browser dialog
|
|
217
|
-
onClick={(e) => e.stopPropagation()}
|
|
218
|
-
/>
|
|
219
|
-
{this.state.url && (
|
|
220
|
-
<Button.Group>
|
|
221
|
-
<Button
|
|
222
|
-
basic
|
|
223
|
-
className="cancel"
|
|
224
|
-
onClick={(e) => {
|
|
225
|
-
e.stopPropagation();
|
|
226
|
-
this.setState({ url: '' });
|
|
227
|
-
}}
|
|
228
|
-
>
|
|
229
|
-
<Icon name={clearSVG} size="30px" />
|
|
230
|
-
</Button>
|
|
231
|
-
</Button.Group>
|
|
232
|
-
)}
|
|
88
|
+
const placeholder = useMemo(
|
|
89
|
+
() =>
|
|
90
|
+
data.placeholder ||
|
|
91
|
+
intl.formatMessage(messages.MapsBlockInputPlaceholder),
|
|
92
|
+
[data, intl],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div
|
|
97
|
+
className={cx(
|
|
98
|
+
'block maps align',
|
|
99
|
+
{
|
|
100
|
+
center: !Boolean(data.align),
|
|
101
|
+
},
|
|
102
|
+
data.align,
|
|
103
|
+
)}
|
|
104
|
+
>
|
|
105
|
+
{data.url ? (
|
|
106
|
+
<div
|
|
107
|
+
className={cx('maps-inner', {
|
|
108
|
+
'full-width': data.align === 'full',
|
|
109
|
+
})}
|
|
110
|
+
>
|
|
111
|
+
<iframe
|
|
112
|
+
title={intl.formatMessage(messages.GoogleMapsEmbeddedBlock)}
|
|
113
|
+
src={data.url}
|
|
114
|
+
className="google-map"
|
|
115
|
+
frameBorder="0"
|
|
116
|
+
allowFullScreen
|
|
117
|
+
/>
|
|
118
|
+
</div>
|
|
119
|
+
) : (
|
|
120
|
+
<Message>
|
|
121
|
+
<center>
|
|
122
|
+
<img src={mapsBlockSVG} alt="" />
|
|
123
|
+
<div className="toolbar-inner">
|
|
124
|
+
<Input
|
|
125
|
+
onKeyDown={onKeyDownVariantMenuForm}
|
|
126
|
+
onChange={onChangeUrl}
|
|
127
|
+
placeholder={placeholder}
|
|
128
|
+
value={url}
|
|
129
|
+
// Prevents propagation to the Dropzone and the opening
|
|
130
|
+
// of the upload browser dialog
|
|
131
|
+
onClick={(e) => e.stopPropagation()}
|
|
132
|
+
/>
|
|
133
|
+
{url && (
|
|
233
134
|
<Button.Group>
|
|
234
135
|
<Button
|
|
235
136
|
basic
|
|
236
|
-
|
|
137
|
+
className="cancel"
|
|
237
138
|
onClick={(e) => {
|
|
238
139
|
e.stopPropagation();
|
|
239
|
-
|
|
140
|
+
setUrl('');
|
|
240
141
|
}}
|
|
241
142
|
>
|
|
242
|
-
<Icon name={
|
|
143
|
+
<Icon name={clearSVG} size="30px" />
|
|
243
144
|
</Button>
|
|
244
145
|
</Button.Group>
|
|
245
|
-
|
|
246
|
-
<
|
|
247
|
-
<
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
146
|
+
)}
|
|
147
|
+
<Button.Group>
|
|
148
|
+
<Button
|
|
149
|
+
basic
|
|
150
|
+
primary
|
|
151
|
+
onClick={(e) => {
|
|
152
|
+
e.stopPropagation();
|
|
153
|
+
onSubmitUrl();
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
<Icon name={aheadSVG} size="30px" />
|
|
157
|
+
</Button>
|
|
158
|
+
</Button.Group>
|
|
159
|
+
</div>
|
|
160
|
+
<div className="message-text">
|
|
161
|
+
<FormattedMessage
|
|
162
|
+
id="Please enter the Embed Code provided by Google Maps -> Share -> Embed map. It should contain the <iframe> code on it."
|
|
163
|
+
defaultMessage="Please enter the Embed Code provided by Google Maps -> Share -> Embed map. It should contain the <iframe> code on it."
|
|
164
|
+
/>
|
|
165
|
+
{error && (
|
|
166
|
+
<div style={{ color: 'red' }}>
|
|
167
|
+
<FormattedMessage
|
|
168
|
+
id="Embed code error, please follow the instructions and try again."
|
|
169
|
+
defaultMessage="Embed code error, please follow the instructions and try again."
|
|
170
|
+
/>
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
</center>
|
|
175
|
+
</Message>
|
|
176
|
+
)}
|
|
177
|
+
{!selected && <div className="map-overlay" />}
|
|
178
|
+
<SidebarPortal selected={selected}>
|
|
179
|
+
<MapsSidebar {...props} resetSubmitUrl={resetSubmitUrl} />
|
|
180
|
+
</SidebarPortal>
|
|
181
|
+
</div>
|
|
182
|
+
);
|
|
183
|
+
});
|
|
271
184
|
|
|
272
|
-
|
|
185
|
+
Edit.propTypes = {
|
|
186
|
+
selected: PropTypes.bool.isRequired,
|
|
187
|
+
block: PropTypes.string.isRequired,
|
|
188
|
+
index: PropTypes.number.isRequired,
|
|
189
|
+
data: PropTypes.objectOf(PropTypes.any).isRequired,
|
|
190
|
+
pathname: PropTypes.string.isRequired,
|
|
191
|
+
onChangeBlock: PropTypes.func.isRequired,
|
|
192
|
+
onSelectBlock: PropTypes.func.isRequired,
|
|
193
|
+
onDeleteBlock: PropTypes.func.isRequired,
|
|
194
|
+
onFocusPreviousBlock: PropTypes.func.isRequired,
|
|
195
|
+
onFocusNextBlock: PropTypes.func.isRequired,
|
|
196
|
+
handleKeyDown: PropTypes.func.isRequired,
|
|
197
|
+
};
|
|
198
|
+
export default compose(withBlockExtensions)(Edit);
|
|
@@ -9,6 +9,7 @@ import { withSearch, withQueryString } from './hocs';
|
|
|
9
9
|
import { compose } from 'redux';
|
|
10
10
|
import { useSelector } from 'react-redux';
|
|
11
11
|
import { isEqual, isFunction } from 'lodash';
|
|
12
|
+
import cx from 'classnames';
|
|
12
13
|
|
|
13
14
|
const getListingBodyVariation = (data) => {
|
|
14
15
|
const { variations } = config.blocks.blocksConfig.listing;
|
|
@@ -57,7 +58,7 @@ const applyDefaults = (data, root) => {
|
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
const SearchBlockView = (props) => {
|
|
60
|
-
const { id, data, searchData, mode = 'view', variation } = props;
|
|
61
|
+
const { id, data, searchData, mode = 'view', variation, className } = props;
|
|
61
62
|
|
|
62
63
|
const Layout = variation.view;
|
|
63
64
|
|
|
@@ -81,7 +82,7 @@ const SearchBlockView = (props) => {
|
|
|
81
82
|
const listingBodyVariation = variations.find(({ id }) => id === selectedView);
|
|
82
83
|
|
|
83
84
|
return (
|
|
84
|
-
<div className=
|
|
85
|
+
<div className={cx('block search', selectedView, className)}>
|
|
85
86
|
<Layout
|
|
86
87
|
{...props}
|
|
87
88
|
isEditMode={mode === 'edit'}
|
|
@@ -70,14 +70,6 @@ const messages = defineMessages({
|
|
|
70
70
|
defaultMessage:
|
|
71
71
|
'If selected, this item will not appear in the navigation tree',
|
|
72
72
|
},
|
|
73
|
-
yes: {
|
|
74
|
-
id: 'Yes',
|
|
75
|
-
defaultMessage: 'Yes',
|
|
76
|
-
},
|
|
77
|
-
no: {
|
|
78
|
-
id: 'No',
|
|
79
|
-
defaultMessage: 'No',
|
|
80
|
-
},
|
|
81
73
|
});
|
|
82
74
|
|
|
83
75
|
/**
|
|
@@ -209,11 +201,7 @@ class ContentsPropertiesModal extends Component {
|
|
|
209
201
|
title: this.props.intl.formatMessage(
|
|
210
202
|
messages.excludeFromNavTitle,
|
|
211
203
|
),
|
|
212
|
-
type: '
|
|
213
|
-
choices: [
|
|
214
|
-
[true, this.props.intl.formatMessage(messages.yes)],
|
|
215
|
-
[false, this.props.intl.formatMessage(messages.no)],
|
|
216
|
-
],
|
|
204
|
+
type: 'boolean',
|
|
217
205
|
},
|
|
218
206
|
},
|
|
219
207
|
required: [],
|
|
@@ -57,7 +57,7 @@ class RenderGroups extends Component {
|
|
|
57
57
|
* @memberof UsersControlpanelUser
|
|
58
58
|
*/
|
|
59
59
|
onChange(event, { value }) {
|
|
60
|
-
const [group, role] = value.split('
|
|
60
|
+
const [group, role] = value.split('&role=');
|
|
61
61
|
this.props.updateGroups(group, role);
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -97,7 +97,7 @@ class RenderGroups extends Component {
|
|
|
97
97
|
: this.props.group.roles.includes(role.id)
|
|
98
98
|
}
|
|
99
99
|
onChange={this.onChange}
|
|
100
|
-
value={`${this.props.group.id}
|
|
100
|
+
value={`${this.props.group.id}&role=${role.id}`}
|
|
101
101
|
/>
|
|
102
102
|
)}
|
|
103
103
|
</Table.Cell>
|
|
@@ -34,15 +34,31 @@ const BrokenRelations = () => {
|
|
|
34
34
|
<div key={relationname}>
|
|
35
35
|
<Divider section hidden />
|
|
36
36
|
<h4>
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
<FormattedMessage
|
|
38
|
+
id="countBrokenRelations"
|
|
39
|
+
defaultMessage="{countofrelation} broken {countofrelation, plural, one {relation} other {relations}} of type {typeofrelation}"
|
|
40
|
+
values={{
|
|
41
|
+
countofrelation: brokenRelationStats[relationname],
|
|
42
|
+
typeofrelation: relationname,
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
39
45
|
</h4>
|
|
40
|
-
<Table>
|
|
46
|
+
<Table compact="very">
|
|
47
|
+
<Table.Header>
|
|
48
|
+
<Table.Row>
|
|
49
|
+
<Table.HeaderCell width={6}>
|
|
50
|
+
<FormattedMessage id="Source" defaultMessage="Source" />
|
|
51
|
+
</Table.HeaderCell>
|
|
52
|
+
<Table.HeaderCell>
|
|
53
|
+
<FormattedMessage id="Target" defaultMessage="Target" />
|
|
54
|
+
</Table.HeaderCell>
|
|
55
|
+
</Table.Row>
|
|
56
|
+
</Table.Header>
|
|
41
57
|
<Table.Body>
|
|
42
58
|
{uniqBy(brokenRelations[relationname].items, function (el) {
|
|
43
|
-
return el
|
|
44
|
-
}).map((el) => (
|
|
45
|
-
<Table.Row key={
|
|
59
|
+
return el.toString();
|
|
60
|
+
}).map((el, index) => (
|
|
61
|
+
<Table.Row key={index}>
|
|
46
62
|
<Table.Cell>
|
|
47
63
|
<UniversalLink
|
|
48
64
|
href={`${flattenToAppURL(el[0])}/edit`}
|
|
@@ -51,7 +67,14 @@ const BrokenRelations = () => {
|
|
|
51
67
|
{flattenToAppURL(el[0])}
|
|
52
68
|
</UniversalLink>
|
|
53
69
|
</Table.Cell>
|
|
54
|
-
<Table.Cell>
|
|
70
|
+
<Table.Cell>
|
|
71
|
+
<UniversalLink
|
|
72
|
+
href={`${flattenToAppURL(el[1])}/edit`}
|
|
73
|
+
openLinkInNewTab={true}
|
|
74
|
+
>
|
|
75
|
+
{flattenToAppURL(el[1])}
|
|
76
|
+
</UniversalLink>
|
|
77
|
+
</Table.Cell>
|
|
55
78
|
</Table.Row>
|
|
56
79
|
))}
|
|
57
80
|
</Table.Body>
|
|
@@ -63,8 +63,8 @@ const RelationsControlPanel = () => {
|
|
|
63
63
|
<Divider hidden />
|
|
64
64
|
<Message warning>
|
|
65
65
|
<FormattedMessage
|
|
66
|
-
id="Please upgrade to plone.restapi >= 8.
|
|
67
|
-
defaultMessage="Please upgrade to plone.restapi >= 8.
|
|
66
|
+
id="Please upgrade to plone.restapi >= 8.39.0."
|
|
67
|
+
defaultMessage="Please upgrade to plone.restapi >= 8.39.0."
|
|
68
68
|
/>
|
|
69
69
|
</Message>
|
|
70
70
|
</React.Fragment>
|
|
@@ -452,68 +452,62 @@ const RelationsMatrix = (props) => {
|
|
|
452
452
|
menuItem: intl.formatMessage(messages.fixRelations),
|
|
453
453
|
pane: (
|
|
454
454
|
<Tab.Pane attached={true} key="rebuild">
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
<
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
455
|
+
<div>
|
|
456
|
+
{!(brokenRelations && Object.keys(brokenRelations).length > 0) && (
|
|
457
|
+
<div>
|
|
458
|
+
<FormattedMessage
|
|
459
|
+
id="No broken relations found."
|
|
460
|
+
defaultMessage="No broken relations found."
|
|
461
|
+
/>
|
|
462
|
+
</div>
|
|
463
|
+
)}
|
|
464
|
+
{can_fix_relations ? (
|
|
465
|
+
<React.Fragment>
|
|
466
|
+
<Divider hidden />
|
|
467
|
+
<h2>
|
|
468
|
+
{capitalize(intl.formatMessage(messages.rebuildRelations))}
|
|
469
|
+
</h2>
|
|
463
470
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
471
|
+
<Button.Group>
|
|
472
|
+
<Button
|
|
473
|
+
primary
|
|
474
|
+
onClick={() => rebuildRelationsHandler(false)}
|
|
475
|
+
content={intl.formatMessage(messages.rebuildRelations)}
|
|
476
|
+
aria-label={intl.formatMessage(messages.rebuildRelations)}
|
|
477
|
+
/>
|
|
478
|
+
</Button.Group>
|
|
472
479
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
480
|
+
<Divider hidden />
|
|
481
|
+
<h2>
|
|
482
|
+
{capitalize(
|
|
483
|
+
intl.formatMessage(messages.flushAndRebuildRelations),
|
|
484
|
+
)}
|
|
485
|
+
</h2>
|
|
486
|
+
<div
|
|
487
|
+
dangerouslySetInnerHTML={{
|
|
488
|
+
__html: intl.formatMessage(
|
|
489
|
+
messages.flushAndRebuildRelationsHints,
|
|
490
|
+
),
|
|
491
|
+
}}
|
|
492
|
+
/>
|
|
493
|
+
<Divider hidden />
|
|
494
|
+
<Button.Group>
|
|
495
|
+
<Button
|
|
496
|
+
secondary
|
|
497
|
+
color="red"
|
|
498
|
+
onClick={() => rebuildRelationsHandler(true)}
|
|
499
|
+
content={intl.formatMessage(
|
|
500
|
+
messages.flushAndRebuildRelations,
|
|
477
501
|
)}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<p>
|
|
488
|
-
<b>Warning</b>: If you have add-ons relying on intIds, you
|
|
489
|
-
should not flush them.
|
|
490
|
-
</p>
|
|
491
|
-
<Divider hidden />
|
|
492
|
-
<Button.Group>
|
|
493
|
-
<Button
|
|
494
|
-
secondary
|
|
495
|
-
color="red"
|
|
496
|
-
onClick={() => rebuildRelationsHandler(true)}
|
|
497
|
-
content={intl.formatMessage(
|
|
498
|
-
messages.flushAndRebuildRelations,
|
|
499
|
-
)}
|
|
500
|
-
aria-label={intl.formatMessage(
|
|
501
|
-
messages.flushAndRebuildRelations,
|
|
502
|
-
)}
|
|
503
|
-
/>
|
|
504
|
-
</Button.Group>
|
|
505
|
-
</React.Fragment>
|
|
506
|
-
) : null}
|
|
507
|
-
<BrokenRelations />
|
|
508
|
-
</div>
|
|
509
|
-
) : (
|
|
510
|
-
<div>
|
|
511
|
-
<FormattedMessage
|
|
512
|
-
id="No broken relations found."
|
|
513
|
-
defaultMessage="No broken relations found."
|
|
514
|
-
/>
|
|
515
|
-
</div>
|
|
516
|
-
)}
|
|
502
|
+
aria-label={intl.formatMessage(
|
|
503
|
+
messages.flushAndRebuildRelations,
|
|
504
|
+
)}
|
|
505
|
+
/>
|
|
506
|
+
</Button.Group>
|
|
507
|
+
</React.Fragment>
|
|
508
|
+
) : null}
|
|
509
|
+
<BrokenRelations />
|
|
510
|
+
</div>
|
|
517
511
|
</Tab.Pane>
|
|
518
512
|
),
|
|
519
513
|
},
|
|
@@ -53,7 +53,7 @@ class RenderUsers extends Component {
|
|
|
53
53
|
*/
|
|
54
54
|
|
|
55
55
|
onChange(event, { value }) {
|
|
56
|
-
const [user, role] = value.split('
|
|
56
|
+
const [user, role] = value.split('&role=');
|
|
57
57
|
this.props.updateUser(user, role);
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
@@ -83,7 +83,7 @@ class RenderUsers extends Component {
|
|
|
83
83
|
<Checkbox
|
|
84
84
|
checked={this.props.user.roles.includes(role.id)}
|
|
85
85
|
onChange={this.onChange}
|
|
86
|
-
value={`${this.props.user.id}
|
|
86
|
+
value={`${this.props.user.id}&role=${role.id}`}
|
|
87
87
|
/>
|
|
88
88
|
)}
|
|
89
89
|
</Table.Cell>
|