@plone/volto 18.0.0-alpha.40 → 18.0.0-alpha.41
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 +19 -0
- package/package.json +2 -2
- package/src/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm.jsx +1 -1
- package/src/components/manage/AnchorPlugin/useLinkEditor.jsx +21 -21
- package/src/components/manage/Form/InlineForm.jsx +2 -2
- package/src/components/manage/Widgets/ImageWidget.jsx +31 -8
- package/src/components/theme/Login/Login.jsx +25 -4
- package/src/components/theme/Logout/Logout.jsx +2 -2
- package/theme/themes/pastanaga/collections/form.overrides +2 -2
- package/theme/themes/pastanaga/extras/blocks.less +14 -5
- package/types/components/theme/Logout/Logout.d.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,25 @@ myst:
|
|
|
17
17
|
|
|
18
18
|
<!-- towncrier release notes start -->
|
|
19
19
|
|
|
20
|
+
## 18.0.0-alpha.41 (2024-07-05)
|
|
21
|
+
|
|
22
|
+
### Breaking
|
|
23
|
+
|
|
24
|
+
- Fixed image widget position and look and feel in sidebar. @ichim-david
|
|
25
|
+
|
|
26
|
+
Breaking:
|
|
27
|
+
- Updated the markup of the widget in the sidebar to render the widget on a single column bellow the label.
|
|
28
|
+
- AddLink Pop-up of the widget is now rendered inside `toolbar-inner` instead of the document body, this fixes the positioning of the toolbar when scrolling. [#6159](https://github.com/plone/volto/issues/6159)
|
|
29
|
+
|
|
30
|
+
### Bugfix
|
|
31
|
+
|
|
32
|
+
- Revisit login/logout process, better catching of edge cases @sneridagh [#6155](https://github.com/plone/volto/issues/6155)
|
|
33
|
+
- Restored browse link in `Slate` `AddLink` Pop-up. @ichim-david
|
|
34
|
+
Fixed recursive error when uploading an image using the `Image` widget. @sneridagh
|
|
35
|
+
Fixed image display when using an external URL. @sneridagh
|
|
36
|
+
Fixed the position of the `Image` widget toolbar when scrolling by changing the position of the toolbar to be within the widget area instead of the body. @ichim-david
|
|
37
|
+
Improved display of `AddLink` Pop-up when using it inside the `Image` widget where we don't have a link picker. @ichim-david [#6159](https://github.com/plone/volto/issues/6159)
|
|
38
|
+
|
|
20
39
|
## 18.0.0-alpha.40 (2024-07-03)
|
|
21
40
|
|
|
22
41
|
### Bugfix
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "18.0.0-alpha.
|
|
12
|
+
"version": "18.0.0-alpha.41",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git@github.com:plone/volto.git"
|
|
@@ -236,8 +236,8 @@
|
|
|
236
236
|
"url": "^0.11.3",
|
|
237
237
|
"use-deep-compare-effect": "1.8.1",
|
|
238
238
|
"uuid": "^8.3.2",
|
|
239
|
-
"@plone/volto-slate": "18.0.0-alpha.16",
|
|
240
239
|
"@plone/registry": "1.7.0",
|
|
240
|
+
"@plone/volto-slate": "18.0.0-alpha.17",
|
|
241
241
|
"@plone/scripts": "3.6.2"
|
|
242
242
|
},
|
|
243
243
|
"devDependencies": {
|
|
@@ -64,6 +64,7 @@ class AddLinkForm extends Component {
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
static defaultProps = {
|
|
67
|
+
objectBrowserPickerType: 'link',
|
|
67
68
|
placeholder: 'Enter URL or select an item',
|
|
68
69
|
};
|
|
69
70
|
|
|
@@ -246,7 +247,6 @@ class AddLinkForm extends Component {
|
|
|
246
247
|
<div className="wrapper">
|
|
247
248
|
<Input
|
|
248
249
|
className={className}
|
|
249
|
-
id={`field-link`}
|
|
250
250
|
name="link"
|
|
251
251
|
value={value || ''}
|
|
252
252
|
onChange={({ target }) => this.onChange(target.value)}
|
|
@@ -16,36 +16,38 @@ import React from 'react';
|
|
|
16
16
|
import { PositionedToolbar } from '@plone/volto-slate/editor/ui';
|
|
17
17
|
import AddLinkForm from '@plone/volto/components/manage/AnchorPlugin/components/LinkButton/AddLinkForm';
|
|
18
18
|
|
|
19
|
-
function getPositionStyle(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
19
|
+
function getPositionStyle(position) {
|
|
20
|
+
return (
|
|
21
|
+
position || {
|
|
22
|
+
style: {
|
|
23
|
+
opacity: 1,
|
|
24
|
+
top: -5,
|
|
25
|
+
left: 55,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const useLinkEditor = () => {
|
|
32
32
|
const [showLinkEditor, setShowLinkEditor] = React.useState(false);
|
|
33
33
|
const show = React.useCallback(() => setShowLinkEditor(true), []);
|
|
34
|
-
const savedPosition = React.useRef();
|
|
35
34
|
const anchorNode = React.useRef();
|
|
36
35
|
|
|
37
|
-
if (anchorNode.current) {
|
|
38
|
-
savedPosition.current = getPositionStyle(anchorNode.current);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
36
|
const LinkEditor = React.useCallback(
|
|
42
37
|
(props) => {
|
|
43
|
-
const {
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
const {
|
|
39
|
+
id,
|
|
40
|
+
value,
|
|
41
|
+
onChange,
|
|
42
|
+
placeholder,
|
|
43
|
+
objectBrowserPickerType,
|
|
44
|
+
position,
|
|
45
|
+
} = props;
|
|
46
|
+
return showLinkEditor && anchorNode.current ? (
|
|
46
47
|
<PositionedToolbar
|
|
47
48
|
className="add-link"
|
|
48
|
-
|
|
49
|
+
toggleButton={anchorNode.current}
|
|
50
|
+
position={getPositionStyle(position)}
|
|
49
51
|
>
|
|
50
52
|
<AddLinkForm
|
|
51
53
|
placeholder={placeholder}
|
|
@@ -53,13 +55,11 @@ const useLinkEditor = () => {
|
|
|
53
55
|
theme={{}}
|
|
54
56
|
objectBrowserPickerType={objectBrowserPickerType}
|
|
55
57
|
onChangeValue={(url) => {
|
|
56
|
-
savedPosition.current = null;
|
|
57
58
|
setShowLinkEditor(false);
|
|
58
59
|
onChange(id, url);
|
|
59
60
|
}}
|
|
60
61
|
onClear={() => {}}
|
|
61
62
|
onOverrideContent={(c) => {
|
|
62
|
-
savedPosition.current = null;
|
|
63
63
|
setShowLinkEditor(false);
|
|
64
64
|
}}
|
|
65
65
|
/>
|
|
@@ -153,8 +153,8 @@ const InlineForm = (props) => {
|
|
|
153
153
|
focus={index === focusIndex}
|
|
154
154
|
value={formData[field]}
|
|
155
155
|
required={schema.required.indexOf(field) !== -1}
|
|
156
|
-
onChange={(id, value) => {
|
|
157
|
-
onChangeField(id, value);
|
|
156
|
+
onChange={(id, value, itemInfo) => {
|
|
157
|
+
onChangeField(id, value, itemInfo);
|
|
158
158
|
}}
|
|
159
159
|
key={field}
|
|
160
160
|
error={errors[field]}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getBaseUrl,
|
|
15
15
|
isInternalURL,
|
|
16
16
|
validateFileUploadSize,
|
|
17
|
+
usePrevious,
|
|
17
18
|
} from '@plone/volto/helpers';
|
|
18
19
|
import { createContent } from '@plone/volto/actions';
|
|
19
20
|
import { readAsDataURL } from 'promise-file-reader';
|
|
@@ -91,13 +92,14 @@ const UnconnectedImageInput = (props) => {
|
|
|
91
92
|
|
|
92
93
|
const requestId = `image-upload-${id}`;
|
|
93
94
|
|
|
94
|
-
const
|
|
95
|
+
const loaded = props.request.loaded;
|
|
95
96
|
const { content } = props;
|
|
96
97
|
const imageId = content?.['@id'];
|
|
97
98
|
const image = content?.image;
|
|
99
|
+
let loading = false;
|
|
98
100
|
|
|
99
101
|
useEffect(() => {
|
|
100
|
-
if (uploading &&
|
|
102
|
+
if (uploading && loading && loaded) {
|
|
101
103
|
setUploading(false);
|
|
102
104
|
onChange(id, imageId, {
|
|
103
105
|
image_field: 'image',
|
|
@@ -106,6 +108,8 @@ const UnconnectedImageInput = (props) => {
|
|
|
106
108
|
}
|
|
107
109
|
}, [loading, loaded, uploading, imageId, image, id, onChange]); // Explicitly list all dependencies
|
|
108
110
|
|
|
111
|
+
loading = usePrevious(props.request?.loading);
|
|
112
|
+
|
|
109
113
|
const handleUpload = React.useCallback(
|
|
110
114
|
(eventOrFile) => {
|
|
111
115
|
if (restrictFileUpload === true) return;
|
|
@@ -161,7 +165,11 @@ const UnconnectedImageInput = (props) => {
|
|
|
161
165
|
{selected && <ImageToolbar {...props} />}
|
|
162
166
|
<img
|
|
163
167
|
className={props.className}
|
|
164
|
-
src={
|
|
168
|
+
src={
|
|
169
|
+
isInternalURL(value)
|
|
170
|
+
? `${flattenToAppURL(value)}/@@images/image/${imageSize}`
|
|
171
|
+
: value
|
|
172
|
+
}
|
|
165
173
|
alt=""
|
|
166
174
|
/>
|
|
167
175
|
</div>
|
|
@@ -302,10 +310,25 @@ export const ImageInput = compose(
|
|
|
302
310
|
),
|
|
303
311
|
)(withObjectBrowser(UnconnectedImageInput));
|
|
304
312
|
|
|
305
|
-
const ImageUploadWidget = (props) =>
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
313
|
+
const ImageUploadWidget = (props) => {
|
|
314
|
+
const { fieldSet, id, title } = props;
|
|
315
|
+
return (
|
|
316
|
+
<FormFieldWrapper
|
|
317
|
+
{...props}
|
|
318
|
+
columns={1}
|
|
319
|
+
className="block image-upload-widget"
|
|
320
|
+
>
|
|
321
|
+
<div className="wrapper">
|
|
322
|
+
<label
|
|
323
|
+
id={`fieldset-${fieldSet}-field-label-${id}`}
|
|
324
|
+
htmlFor={`field-${id}`}
|
|
325
|
+
>
|
|
326
|
+
{title}
|
|
327
|
+
</label>
|
|
328
|
+
</div>
|
|
329
|
+
<ImageInput {...props} />
|
|
330
|
+
</FormFieldWrapper>
|
|
331
|
+
);
|
|
332
|
+
};
|
|
310
333
|
|
|
311
334
|
export default ImageUploadWidget;
|
|
@@ -12,10 +12,15 @@ import {
|
|
|
12
12
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
13
13
|
import qs from 'query-string';
|
|
14
14
|
|
|
15
|
-
import { Helmet } from '@plone/volto/helpers';
|
|
15
|
+
import { Helmet, usePrevious } from '@plone/volto/helpers';
|
|
16
16
|
import config from '@plone/volto/registry';
|
|
17
17
|
import { Icon } from '@plone/volto/components';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
login,
|
|
20
|
+
logout,
|
|
21
|
+
resetLoginRequest,
|
|
22
|
+
purgeMessages,
|
|
23
|
+
} from '@plone/volto/actions';
|
|
19
24
|
import { toast } from 'react-toastify';
|
|
20
25
|
import { Toast } from '@plone/volto/components';
|
|
21
26
|
import aheadSVG from '@plone/volto/icons/ahead.svg';
|
|
@@ -78,8 +83,22 @@ const Login = (props) => {
|
|
|
78
83
|
location.pathname.replace(/\/login\/?$/, '').replace(/\/logout\/?$/, '') ||
|
|
79
84
|
'/';
|
|
80
85
|
|
|
86
|
+
const previousToken = usePrevious(token);
|
|
87
|
+
|
|
81
88
|
useEffect(() => {
|
|
82
|
-
if (
|
|
89
|
+
if (location?.state?.isLogout) {
|
|
90
|
+
// Execute a true Logout action
|
|
91
|
+
// This is needed to cover the use case of being logged in in
|
|
92
|
+
// another backend (eg. in development), having a token for
|
|
93
|
+
// localhost and try to use it, the login route has to know that
|
|
94
|
+
// it's the same as it comes from a logout
|
|
95
|
+
// See also Unauthorized.jsx
|
|
96
|
+
dispatch(logout());
|
|
97
|
+
dispatch(purgeMessages());
|
|
98
|
+
// Reset the location state
|
|
99
|
+
history.push(`${location.pathname}${location.search}`);
|
|
100
|
+
} else if (token && token !== previousToken) {
|
|
101
|
+
// We just did a true login action
|
|
83
102
|
history.push(returnUrl || '/');
|
|
84
103
|
if (toast.isActive('loggedOut')) {
|
|
85
104
|
toast.dismiss('loggedOut');
|
|
@@ -116,8 +135,10 @@ const Login = (props) => {
|
|
|
116
135
|
intl,
|
|
117
136
|
history,
|
|
118
137
|
returnUrl,
|
|
119
|
-
|
|
138
|
+
location.search,
|
|
139
|
+
location.pathname,
|
|
120
140
|
location?.state?.isLogout,
|
|
141
|
+
previousToken,
|
|
121
142
|
]);
|
|
122
143
|
|
|
123
144
|
const onLogin = (event) => {
|
|
@@ -3,7 +3,7 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
|
3
3
|
import { useHistory } from 'react-router-dom';
|
|
4
4
|
import { defineMessages, useIntl } from 'react-intl';
|
|
5
5
|
import qs from 'query-string';
|
|
6
|
-
import {
|
|
6
|
+
import { Toast } from '@plone/volto/components';
|
|
7
7
|
import { logout, purgeMessages } from '@plone/volto/actions';
|
|
8
8
|
import { toast } from 'react-toastify';
|
|
9
9
|
|
|
@@ -55,7 +55,7 @@ const Logout = ({ location }) => {
|
|
|
55
55
|
}
|
|
56
56
|
}, [history, returnUrl, intl, token]);
|
|
57
57
|
|
|
58
|
-
return
|
|
58
|
+
return '';
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
export default Logout;
|
|
@@ -151,13 +151,13 @@
|
|
|
151
151
|
.ui.form .inline.field .link-form-container {
|
|
152
152
|
.wrapper {
|
|
153
153
|
display: flex;
|
|
154
|
-
border-bottom: 1px solid @lightGreyBorderColor;
|
|
155
154
|
|
|
156
155
|
.ui.input.input-anchorlink-theme {
|
|
157
156
|
vertical-align: unset;
|
|
158
157
|
|
|
159
158
|
input {
|
|
160
|
-
|
|
159
|
+
width: 100%;
|
|
160
|
+
height: unset; // input is only 40px and form.overrides sets height to 60px
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
}
|
|
@@ -446,6 +446,7 @@ div.image-upload-widget-image {
|
|
|
446
446
|
text-align: center;
|
|
447
447
|
|
|
448
448
|
.toolbar-wrapper {
|
|
449
|
+
position: relative;
|
|
449
450
|
display: flex;
|
|
450
451
|
flex-direction: column;
|
|
451
452
|
justify-content: flex-end;
|
|
@@ -726,10 +727,22 @@ div.image-upload-widget-image {
|
|
|
726
727
|
|
|
727
728
|
.link-form-container {
|
|
728
729
|
.inline.field .wrapper {
|
|
729
|
-
|
|
730
|
+
width: 270px; // needed to ensure placeholder shows and buttons are aligned to the right
|
|
731
|
+
min-height: initial; // overrides .input.field .wrapper
|
|
732
|
+
justify-content: space-between;
|
|
730
733
|
border-bottom: none;
|
|
731
734
|
}
|
|
732
735
|
|
|
736
|
+
.ui.input-anchorlink-theme {
|
|
737
|
+
width: 100% !important; // overrides form.less width: auto
|
|
738
|
+
max-width: 81%; // needed so buttons don't shift to the right when value is present
|
|
739
|
+
margin-left: 0 !important; // overrides .block .toolbar-inner .ui.input
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.ui.buttons {
|
|
743
|
+
width: auto; // for Add Link popup button to be aligned to the right
|
|
744
|
+
}
|
|
745
|
+
|
|
733
746
|
button {
|
|
734
747
|
padding: 0;
|
|
735
748
|
border: 0;
|
|
@@ -743,10 +756,6 @@ div.image-upload-widget-image {
|
|
|
743
756
|
outline: none;
|
|
744
757
|
}
|
|
745
758
|
}
|
|
746
|
-
|
|
747
|
-
.ui.input {
|
|
748
|
-
min-width: 250px;
|
|
749
|
-
}
|
|
750
759
|
}
|
|
751
760
|
|
|
752
761
|
.blocks-chooser {
|