@plone/volto 17.0.0-alpha.20 → 17.0.0-alpha.22
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 +49 -0
- package/cypress/support/commands.js +2 -1
- package/cypress/support/e2e.js +1 -2
- package/locales/ca/LC_MESSAGES/volto.po +24 -5
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +37 -18
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +25 -6
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +25 -6
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +24 -5
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +24 -5
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +24 -5
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +250 -231
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +24 -5
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +24 -5
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +24 -5
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +25 -6
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +24 -5
- package/locales/ro.json +1 -1
- package/locales/volto.pot +25 -6
- package/locales/zh_CN/LC_MESSAGES/volto.po +24 -5
- package/locales/zh_CN.json +1 -1
- package/news/4547.breaking~ +1 -0
- package/package.json +6 -6
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/relations/rebuild.js +7 -7
- package/src/components/index.js +1 -0
- 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 +13 -1
- package/src/components/manage/Blocks/Image/Edit.jsx +40 -5
- package/src/components/manage/Blocks/Image/Edit.test.jsx +2 -0
- package/src/components/manage/Blocks/Image/ImageSidebar.jsx +64 -15
- package/src/components/manage/Blocks/Image/View.jsx +26 -5
- package/src/components/manage/Blocks/Image/View.test.jsx +20 -0
- package/src/components/manage/Blocks/Image/schema.js +1 -9
- package/src/components/manage/Blocks/Image/utils.js +14 -0
- package/src/components/manage/Blocks/LeadImage/Edit.jsx +32 -10
- package/src/components/manage/Blocks/LeadImage/Edit.test.jsx +11 -1
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.jsx +28 -9
- package/src/components/manage/Blocks/LeadImage/LeadImageSidebar.test.jsx +8 -2
- package/src/components/manage/Blocks/LeadImage/View.jsx +50 -38
- package/src/components/manage/Blocks/LeadImage/View.test.jsx +11 -1
- package/src/components/manage/Blocks/Listing/SummaryTemplate.jsx +1 -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/Blocks/Teaser/DefaultBody.jsx +13 -23
- package/src/components/manage/Contents/Contents.jsx +8 -6
- 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/Sidebar/AlignBlock.jsx +1 -1
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Workflow/Workflow.jsx +75 -184
- package/src/components/theme/Image/Image.jsx +96 -0
- package/src/components/theme/Image/Image.test.jsx +125 -0
- package/src/components/theme/Logo/Logo.jsx +2 -0
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +95 -170
- package/src/components/theme/PreviewImage/PreviewImage.jsx +25 -14
- package/src/components/theme/PreviewImage/PreviewImage.test.js +39 -16
- package/src/components/theme/View/AlbumView.jsx +11 -15
- package/src/components/theme/View/EventView.jsx +30 -23
- package/src/components/theme/View/ImageView.jsx +5 -2
- package/src/components/theme/View/ImageView.test.jsx +4 -0
- package/src/components/theme/View/ListingView.jsx +5 -3
- package/src/components/theme/View/NewsItemView.jsx +7 -13
- package/src/components/theme/View/SummaryView.jsx +4 -3
- package/src/config/Blocks.jsx +2 -0
- package/src/config/Components.jsx +3 -1
- 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/helpers/Url/Url.js +22 -1
- package/src/helpers/Url/Url.test.js +41 -0
- package/src/reducers/relations/relations.js +1 -1
- package/test-setup-config.js +9 -1
- package/theme/themes/pastanaga/extras/blocks.less +3 -1
- package/theme/themes/pastanaga/extras/main.less +5 -0
- 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
- package/src/components/manage/Blocks/Teaser/utils.js +0 -44
- package/src/components/manage/Blocks/Teaser/utils.test.jsx +0 -229
|
@@ -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'}
|
|
@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { Message } from 'semantic-ui-react';
|
|
4
4
|
import { defineMessages, useIntl } from 'react-intl';
|
|
5
5
|
import imageBlockSVG from '@plone/volto/components/manage/Blocks/Image/block-image.svg';
|
|
6
|
-
import {
|
|
7
|
-
import { getTeaserImageURL } from './utils';
|
|
6
|
+
import { isInternalURL } from '@plone/volto/helpers';
|
|
8
7
|
import { MaybeWrap } from '@plone/volto/components';
|
|
9
8
|
import { UniversalLink } from '@plone/volto/components';
|
|
10
9
|
import cx from 'classnames';
|
|
@@ -22,28 +21,11 @@ const TeaserDefaultTemplate = (props) => {
|
|
|
22
21
|
const { className, data, isEditMode } = props;
|
|
23
22
|
const intl = useIntl();
|
|
24
23
|
const href = data.href?.[0];
|
|
25
|
-
const
|
|
26
|
-
const align = data?.styles?.align;
|
|
24
|
+
const image = data.preview_image?.[0];
|
|
27
25
|
|
|
26
|
+
const Image = config.getComponent('Image').component;
|
|
28
27
|
const { openExternalLinkInNewTab } = config.settings;
|
|
29
28
|
|
|
30
|
-
let renderedImage = null;
|
|
31
|
-
if (href && (imageOverride || href.hasPreviewImage || href.image_field)) {
|
|
32
|
-
let Image = config.getComponent('Image').component;
|
|
33
|
-
if (Image) {
|
|
34
|
-
// custom image component expects item summary as src
|
|
35
|
-
renderedImage = (
|
|
36
|
-
<Image src={imageOverride || href} alt="" loading="lazy" />
|
|
37
|
-
);
|
|
38
|
-
} else {
|
|
39
|
-
// default img expects string src
|
|
40
|
-
const src = flattenToAppURL(
|
|
41
|
-
getTeaserImageURL({ href, imageOverride, align }),
|
|
42
|
-
);
|
|
43
|
-
renderedImage = <img src={src} alt="" loading="lazy" />;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
29
|
return (
|
|
48
30
|
<div className={cx('block teaser', className)}>
|
|
49
31
|
<>
|
|
@@ -68,8 +50,16 @@ const TeaserDefaultTemplate = (props) => {
|
|
|
68
50
|
}
|
|
69
51
|
>
|
|
70
52
|
<div className="teaser-item default">
|
|
71
|
-
{
|
|
72
|
-
<div className="image-wrapper">
|
|
53
|
+
{(href.hasPreviewImage || href.image_field || image) && (
|
|
54
|
+
<div className="image-wrapper">
|
|
55
|
+
<Image
|
|
56
|
+
item={image || href}
|
|
57
|
+
imageField={image ? image.image_field : href.image_field}
|
|
58
|
+
alt=""
|
|
59
|
+
loading="lazy"
|
|
60
|
+
responsive={true}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
73
63
|
)}
|
|
74
64
|
<div className="content">
|
|
75
65
|
{data?.head_title && (
|
|
@@ -450,7 +450,7 @@ class Contents extends Component {
|
|
|
450
450
|
sort_on: this.props.sort?.on || 'getObjPositionInParent',
|
|
451
451
|
sort_order: this.props.sort?.order || 'ascending',
|
|
452
452
|
isClient: false,
|
|
453
|
-
linkIntegrityBreakages:
|
|
453
|
+
linkIntegrityBreakages: [],
|
|
454
454
|
};
|
|
455
455
|
this.filterTimeout = null;
|
|
456
456
|
}
|
|
@@ -1236,7 +1236,10 @@ class Contents extends Component {
|
|
|
1236
1236
|
Show all items
|
|
1237
1237
|
</Button>
|
|
1238
1238
|
)}
|
|
1239
|
-
{this.state.linkIntegrityBreakages.
|
|
1239
|
+
{this.state.linkIntegrityBreakages.reduce(
|
|
1240
|
+
(a, b) => a + b.breaches.length,
|
|
1241
|
+
0,
|
|
1242
|
+
) ? (
|
|
1240
1243
|
<div>
|
|
1241
1244
|
<h3>
|
|
1242
1245
|
{this.props.intl.formatMessage(
|
|
@@ -1249,9 +1252,8 @@ class Contents extends Component {
|
|
|
1249
1252
|
)}
|
|
1250
1253
|
</p>
|
|
1251
1254
|
<ul className="content">
|
|
1252
|
-
{map(
|
|
1253
|
-
|
|
1254
|
-
(item) => (
|
|
1255
|
+
{map(this.state.linkIntegrityBreakages, (item) =>
|
|
1256
|
+
item.breaches.length ? (
|
|
1255
1257
|
<li key={item['@id']}>
|
|
1256
1258
|
<a href={item['@id']}>{item.title}</a>
|
|
1257
1259
|
<p>
|
|
@@ -1269,7 +1271,7 @@ class Contents extends Component {
|
|
|
1269
1271
|
))}
|
|
1270
1272
|
</ul>
|
|
1271
1273
|
</li>
|
|
1272
|
-
),
|
|
1274
|
+
) : null,
|
|
1273
1275
|
)}
|
|
1274
1276
|
</ul>
|
|
1275
1277
|
</div>
|
|
@@ -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>
|