@plone/volto 17.0.0-alpha.23 → 17.0.0-alpha.25
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/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +58 -1
- package/CONTRIBUTING.md +5 -1
- package/README.md +2 -1
- package/locales/ca/LC_MESSAGES/volto.po +37 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +37 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +37 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +37 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +37 -0
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +37 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +37 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +37 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +37 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +37 -0
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +37 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +37 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +37 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +38 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +37 -0
- package/locales/zh_CN.json +1 -1
- package/package.json +2 -2
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +6 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +10 -0
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +30 -0
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +10 -0
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +6 -0
- package/packages/volto-slate/package.json +1 -1
- package/src/actions/index.js +1 -0
- package/src/actions/relations/relations.js +17 -0
- package/src/components/manage/Blocks/Image/schema.js +5 -1
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -11
- package/src/components/manage/Blocks/ToC/Schema.jsx +36 -7
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +4 -3
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
- package/src/components/manage/Contents/Contents.jsx +27 -0
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +11 -9
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +3 -3
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +15 -9
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +25 -10
- package/src/components/manage/Diff/DiffField.jsx +25 -1
- package/src/components/manage/LinksToItem/LinksToItem.jsx +1 -1
- package/src/components/manage/LinksToItem/LinksToItem.test.jsx +1 -1
- package/src/components/manage/Sharing/Sharing.jsx +11 -5
- package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
- package/src/components/theme/Comments/Comment.stories.jsx +84 -0
- package/src/components/theme/Comments/Comments.jsx +273 -378
- package/src/components/theme/Error/ServerError.jsx +29 -0
- package/src/components/theme/Logout/Logout.jsx +36 -83
- package/src/components/theme/Search/SearchTags.jsx +30 -60
- package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
- package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
- package/src/config/Views.jsx +2 -0
- package/src/constants/ActionTypes.js +1 -0
- package/src/middleware/api.js +14 -2
- package/src/reducers/relations/relations.js +74 -46
- package/src/server.jsx +9 -0
- package/theme/themes/pastanaga/collections/form.overrides +46 -0
- package/theme/themes/pastanaga/elements/input.overrides +6 -0
- package/theme/themes/pastanaga/elements/label.overrides +10 -0
- package/.gitignore~ +0 -71
- package/news/4547.breaking~ +0 -1
- package/src/config/index.js~ +0 -223
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module components/theme/Error/ServerError
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { FormattedMessage } from 'react-intl';
|
|
7
|
+
import { Container } from 'semantic-ui-react';
|
|
8
|
+
import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* server error
|
|
12
|
+
* @function ServerError
|
|
13
|
+
* @returns {string} Markup of the server error page.
|
|
14
|
+
*/
|
|
15
|
+
const ServerError = () => (
|
|
16
|
+
<Container className="view-wrapper">
|
|
17
|
+
<h1>
|
|
18
|
+
<FormattedMessage id="Server Error" defaultMessage="Server Error" />
|
|
19
|
+
</h1>
|
|
20
|
+
<p className="description">
|
|
21
|
+
<FormattedMessage
|
|
22
|
+
id="We apologize for the inconvenience, but there was an unexpected error on the server."
|
|
23
|
+
defaultMessage="We apologize for the inconvenience, but there was an unexpected error on the server."
|
|
24
|
+
/>
|
|
25
|
+
</p>
|
|
26
|
+
</Container>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default withServerErrorCode(500)(ServerError);
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import React, { Component } from 'react';
|
|
7
|
-
import PropTypes from 'prop-types';
|
|
8
|
-
import { connect } from 'react-redux';
|
|
9
|
-
import { compose } from 'redux';
|
|
10
|
-
import { defineMessages, injectIntl } from 'react-intl';
|
|
1
|
+
import { useEffect, useMemo } from 'react';
|
|
2
|
+
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
3
|
+
import { useHistory } from 'react-router-dom';
|
|
4
|
+
import { defineMessages, useIntl } from 'react-intl';
|
|
11
5
|
import qs from 'query-string';
|
|
12
|
-
|
|
13
|
-
import { Login } from '@plone/volto/components';
|
|
6
|
+
import { Login, Toast } from '@plone/volto/components';
|
|
14
7
|
import { logout, purgeMessages } from '@plone/volto/actions';
|
|
15
8
|
import { toast } from 'react-toastify';
|
|
16
|
-
import { Toast } from '@plone/volto/components';
|
|
17
9
|
|
|
18
10
|
const messages = defineMessages({
|
|
19
11
|
loggedOut: {
|
|
@@ -26,83 +18,44 @@ const messages = defineMessages({
|
|
|
26
18
|
},
|
|
27
19
|
});
|
|
28
20
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
static defaultProps = {
|
|
54
|
-
query: null,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
componentDidMount() {
|
|
58
|
-
this.props.logout();
|
|
59
|
-
this.props.purgeMessages();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Component will receive props
|
|
64
|
-
* @method componentWillReceiveProps
|
|
65
|
-
* @param {Object} nextProps Next properties
|
|
66
|
-
* @returns {undefined}
|
|
67
|
-
*/
|
|
68
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
69
|
-
if (!nextProps.token) {
|
|
70
|
-
this.props.history.replace(this.props.returnUrl || '/');
|
|
21
|
+
const Logout = ({ location }) => {
|
|
22
|
+
const token = useSelector((state) => state.userSession.token, shallowEqual);
|
|
23
|
+
const history = useHistory();
|
|
24
|
+
const dispatch = useDispatch();
|
|
25
|
+
const intl = useIntl();
|
|
26
|
+
|
|
27
|
+
const returnUrl = useMemo(
|
|
28
|
+
() =>
|
|
29
|
+
qs.parse(location.search).return_url ||
|
|
30
|
+
location.pathname
|
|
31
|
+
.replace(/\/login\/?$/, '')
|
|
32
|
+
.replace(/\/logout\/?$/, '') ||
|
|
33
|
+
'/',
|
|
34
|
+
[location],
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
dispatch(logout());
|
|
39
|
+
dispatch(purgeMessages());
|
|
40
|
+
}, [dispatch]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!token) {
|
|
44
|
+
history.replace(returnUrl || '/');
|
|
71
45
|
if (!toast.isActive('loggedOut')) {
|
|
72
46
|
toast.info(
|
|
73
47
|
<Toast
|
|
74
48
|
info
|
|
75
|
-
title={
|
|
76
|
-
content={
|
|
49
|
+
title={intl.formatMessage(messages.loggedOut)}
|
|
50
|
+
content={intl.formatMessage(messages.loggedOutContent)}
|
|
77
51
|
/>,
|
|
78
52
|
{ autoClose: false, toastId: 'loggedOut' },
|
|
79
53
|
);
|
|
80
54
|
}
|
|
81
55
|
}
|
|
82
|
-
}
|
|
56
|
+
}, [history, returnUrl, intl, token]);
|
|
57
|
+
|
|
58
|
+
return <Login location={{ query: location.query }} />;
|
|
59
|
+
};
|
|
83
60
|
|
|
84
|
-
|
|
85
|
-
* Render method.
|
|
86
|
-
* @method render
|
|
87
|
-
* @returns {string} Markup for the component.
|
|
88
|
-
*/
|
|
89
|
-
render() {
|
|
90
|
-
return <Login location={{ query: this.props.location.query }} />;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
export default compose(
|
|
94
|
-
injectIntl,
|
|
95
|
-
connect(
|
|
96
|
-
(state, props) => ({
|
|
97
|
-
query: qs.parse(props.location.search),
|
|
98
|
-
token: state.userSession.token,
|
|
99
|
-
returnUrl:
|
|
100
|
-
qs.parse(props.location.search).return_url ||
|
|
101
|
-
props.location.pathname
|
|
102
|
-
.replace(/\/login\/?$/, '')
|
|
103
|
-
.replace(/\/logout\/?$/, '') ||
|
|
104
|
-
'/',
|
|
105
|
-
}),
|
|
106
|
-
{ logout, purgeMessages },
|
|
107
|
-
),
|
|
108
|
-
)(Logout);
|
|
61
|
+
export default Logout;
|
|
@@ -1,71 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @module components/theme/Search/SearchTags
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React, { Component } from 'react';
|
|
7
|
-
import PropTypes from 'prop-types';
|
|
8
|
-
import { connect } from 'react-redux';
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
9
3
|
import { Link } from 'react-router-dom';
|
|
10
4
|
|
|
11
5
|
import { getVocabulary } from '@plone/volto/actions';
|
|
12
6
|
|
|
13
7
|
const vocabulary = 'plone.app.vocabularies.Keywords';
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @class SearchTags
|
|
18
|
-
* @extends Component
|
|
19
|
-
*/
|
|
20
|
-
class SearchTags extends Component {
|
|
21
|
-
/**
|
|
22
|
-
* Property types.
|
|
23
|
-
* @property {Object} propTypes Property types.
|
|
24
|
-
* @static
|
|
25
|
-
*/
|
|
26
|
-
static propTypes = {
|
|
27
|
-
getVocabulary: PropTypes.func.isRequired,
|
|
28
|
-
items: PropTypes.arrayOf(
|
|
29
|
-
PropTypes.shape({
|
|
30
|
-
label: PropTypes.string,
|
|
31
|
-
}),
|
|
32
|
-
).isRequired,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
componentDidMount() {
|
|
36
|
-
this.props.getVocabulary({ vocabNameOrURL: vocabulary });
|
|
37
|
-
}
|
|
9
|
+
const SearchTags = () => {
|
|
10
|
+
const dispatch = useDispatch();
|
|
38
11
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
* @returns {string} Markup for the component.
|
|
43
|
-
*/
|
|
44
|
-
render() {
|
|
45
|
-
return this.props.items && this.props.items.length > 0 ? (
|
|
46
|
-
<div>
|
|
47
|
-
{this.props.items.map((item) => (
|
|
48
|
-
<Link
|
|
49
|
-
className="ui label"
|
|
50
|
-
to={`/search?Subject=${item.label}`}
|
|
51
|
-
key={item.label}
|
|
52
|
-
>
|
|
53
|
-
{item.label}
|
|
54
|
-
</Link>
|
|
55
|
-
))}
|
|
56
|
-
</div>
|
|
57
|
-
) : (
|
|
58
|
-
<span />
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
dispatch(getVocabulary({ vocabNameOrURL: vocabulary }));
|
|
14
|
+
}, [dispatch]);
|
|
62
15
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
items:
|
|
16
|
+
const items = useSelector(
|
|
17
|
+
(state) =>
|
|
66
18
|
state.vocabularies[vocabulary] && state.vocabularies[vocabulary].items
|
|
67
19
|
? state.vocabularies[vocabulary].items
|
|
68
20
|
: [],
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
21
|
+
shallowEqual,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return items && items.length > 0 ? (
|
|
25
|
+
<div>
|
|
26
|
+
{items.map((item) => (
|
|
27
|
+
<Link
|
|
28
|
+
className="ui label"
|
|
29
|
+
to={`/search?Subject=${item.label}`}
|
|
30
|
+
key={item.label}
|
|
31
|
+
>
|
|
32
|
+
{item.label}
|
|
33
|
+
</Link>
|
|
34
|
+
))}
|
|
35
|
+
</div>
|
|
36
|
+
) : (
|
|
37
|
+
<span />
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default SearchTags;
|
|
@@ -22,6 +22,13 @@ const messages = defineMessages({
|
|
|
22
22
|
defaultMessage: 'Sitemap',
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
export function getSitemapPath(pathname = '', lang) {
|
|
27
|
+
const prefix = pathname.replace(/\/sitemap$/gm, '').replace(/^\//, '');
|
|
28
|
+
const path = prefix || lang || '';
|
|
29
|
+
return path;
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
/**
|
|
26
33
|
* Sitemap class.
|
|
27
34
|
* @class Sitemap
|
|
@@ -39,11 +46,13 @@ class Sitemap extends Component {
|
|
|
39
46
|
|
|
40
47
|
componentDidMount() {
|
|
41
48
|
const { settings } = config;
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
|
|
50
|
+
const lang = settings.isMultilingual
|
|
51
|
+
? `${toBackendLang(this.props.lang)}`
|
|
52
|
+
: null;
|
|
53
|
+
|
|
54
|
+
const path = getSitemapPath(this.props.location.pathname, lang);
|
|
55
|
+
this.props.getNavigation(path, 4);
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/**
|
|
@@ -105,15 +114,17 @@ export default compose(
|
|
|
105
114
|
{
|
|
106
115
|
key: 'navigation',
|
|
107
116
|
promise: ({ location, store: { dispatch, getState } }) => {
|
|
117
|
+
if (!__SERVER__) return;
|
|
108
118
|
const { settings } = config;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
|
|
120
|
+
const path = getSitemapPath(
|
|
121
|
+
location.pathname,
|
|
122
|
+
settings.isMultilingual
|
|
123
|
+
? toBackendLang(getState().intl.locale)
|
|
124
|
+
: null,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
return dispatch(getNavigation(path, 4));
|
|
117
128
|
},
|
|
118
129
|
},
|
|
119
130
|
]),
|
|
@@ -4,7 +4,7 @@ import configureStore from 'redux-mock-store';
|
|
|
4
4
|
import { Provider } from 'react-intl-redux';
|
|
5
5
|
import { MemoryRouter } from 'react-router-dom';
|
|
6
6
|
|
|
7
|
-
import { __test__ as Sitemap } from './Sitemap';
|
|
7
|
+
import { __test__ as Sitemap, getSitemapPath } from './Sitemap';
|
|
8
8
|
|
|
9
9
|
const mockStore = configureStore();
|
|
10
10
|
|
|
@@ -46,7 +46,7 @@ describe('Sitemap', () => {
|
|
|
46
46
|
const component = renderer.create(
|
|
47
47
|
<Provider store={store}>
|
|
48
48
|
<MemoryRouter>
|
|
49
|
-
<Sitemap />
|
|
49
|
+
<Sitemap location={{ pathname: '/page-1' }} />
|
|
50
50
|
</MemoryRouter>
|
|
51
51
|
</Provider>,
|
|
52
52
|
);
|
|
@@ -54,3 +54,24 @@ describe('Sitemap', () => {
|
|
|
54
54
|
expect(json).toMatchSnapshot();
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
|
+
|
|
58
|
+
describe('getSitemapPath', () => {
|
|
59
|
+
it('accepts empty path', () => {
|
|
60
|
+
expect(getSitemapPath('', null)).toBe('');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('accepts a path', () => {
|
|
64
|
+
expect(getSitemapPath('/page-1/sitemap', null)).toBe('page-1');
|
|
65
|
+
});
|
|
66
|
+
it('accepts a path', () => {
|
|
67
|
+
expect(getSitemapPath('/page-1/sitemap', null)).toBe('page-1');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('uses a language as default root', () => {
|
|
71
|
+
expect(getSitemapPath('/', 'de')).toBe('de');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('accepts language-rooted paths', () => {
|
|
75
|
+
expect(getSitemapPath('/de/mission', 'de')).toBe('de/mission');
|
|
76
|
+
});
|
|
77
|
+
});
|
package/src/config/Views.jsx
CHANGED
|
@@ -16,6 +16,7 @@ import RequestTimeout from '@plone/volto/components/theme/RequestTimeout/Request
|
|
|
16
16
|
import AlbumView from '@plone/volto/components/theme/View/AlbumView';
|
|
17
17
|
import Unauthorized from '@plone/volto/components/theme/Unauthorized/Unauthorized';
|
|
18
18
|
import Forbidden from '@plone/volto/components/theme/Forbidden/Forbidden';
|
|
19
|
+
import ServerError from '@plone/volto/components/theme/Error/ServerError';
|
|
19
20
|
|
|
20
21
|
const EventView = loadable(() =>
|
|
21
22
|
import('@plone/volto/components/theme/View/EventView'),
|
|
@@ -114,6 +115,7 @@ export const errorViews = {
|
|
|
114
115
|
'401': Unauthorized,
|
|
115
116
|
'403': Forbidden,
|
|
116
117
|
'408': RequestTimeout,
|
|
118
|
+
'500': ServerError,
|
|
117
119
|
ECONNREFUSED: ConnectionRefused,
|
|
118
120
|
corsError: CorsError,
|
|
119
121
|
};
|
|
@@ -39,6 +39,7 @@ export const GET_QUERYSTRING_RESULTS = 'GET_QUERYSTRING_RESULTS';
|
|
|
39
39
|
export const CREATE_RELATIONS = 'CREATE_RELATIONS';
|
|
40
40
|
export const DELETE_RELATIONS = 'DELETE_RELATIONS';
|
|
41
41
|
export const LIST_RELATIONS = 'LIST_RELATIONS';
|
|
42
|
+
export const STATS_RELATIONS = 'STATS_RELATIONS';
|
|
42
43
|
export const REBUILD_RELATIONS = 'REBUILD_RELATIONS';
|
|
43
44
|
export const GET_SCHEMA = 'GET_SCHEMA';
|
|
44
45
|
export const POST_SCHEMA = 'POST_SCHEMA';
|
package/src/middleware/api.js
CHANGED
|
@@ -264,10 +264,22 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
|
|
|
264
264
|
};
|
|
265
265
|
});
|
|
266
266
|
}
|
|
267
|
-
|
|
267
|
+
try {
|
|
268
|
+
return next({ ...rest, result, type: `${type}_SUCCESS` });
|
|
269
|
+
} catch (error) {
|
|
270
|
+
// There was an exception while processing reducers or downstream middleware.
|
|
271
|
+
next({
|
|
272
|
+
...rest,
|
|
273
|
+
error: { status: 500, error },
|
|
274
|
+
type: `${type}_FAIL`,
|
|
275
|
+
});
|
|
276
|
+
// Rethrow the original exception on the client side only,
|
|
277
|
+
// so it doesn't fall through to express on the server.
|
|
278
|
+
if (__CLIENT__) throw error;
|
|
279
|
+
}
|
|
268
280
|
},
|
|
269
281
|
(error) => {
|
|
270
|
-
// Only
|
|
282
|
+
// Only SSR can set ECONNREFUSED
|
|
271
283
|
if (error.code === 'ECONNREFUSED') {
|
|
272
284
|
next({
|
|
273
285
|
...rest,
|
|
@@ -7,23 +7,29 @@ import {
|
|
|
7
7
|
CREATE_RELATIONS,
|
|
8
8
|
DELETE_RELATIONS,
|
|
9
9
|
LIST_RELATIONS,
|
|
10
|
+
STATS_RELATIONS,
|
|
10
11
|
REBUILD_RELATIONS,
|
|
11
12
|
} from '@plone/volto/constants/ActionTypes';
|
|
12
13
|
|
|
13
14
|
const initialState = {
|
|
14
|
-
relations:
|
|
15
|
-
stats: null,
|
|
16
|
-
create: {
|
|
15
|
+
relations: {
|
|
17
16
|
error: null,
|
|
18
17
|
loaded: false,
|
|
19
18
|
loading: false,
|
|
19
|
+
data: null,
|
|
20
20
|
},
|
|
21
|
-
|
|
21
|
+
stats: {
|
|
22
|
+
error: null,
|
|
23
|
+
loaded: false,
|
|
24
|
+
loading: false,
|
|
25
|
+
data: null,
|
|
26
|
+
},
|
|
27
|
+
create: {
|
|
22
28
|
error: null,
|
|
23
29
|
loaded: false,
|
|
24
30
|
loading: false,
|
|
25
31
|
},
|
|
26
|
-
|
|
32
|
+
delete: {
|
|
27
33
|
error: null,
|
|
28
34
|
loaded: false,
|
|
29
35
|
loading: false,
|
|
@@ -55,17 +61,6 @@ function getRequestKey(actionType) {
|
|
|
55
61
|
*/
|
|
56
62
|
export default function relations(state = initialState, action = {}) {
|
|
57
63
|
switch (action.type) {
|
|
58
|
-
case `${CREATE_RELATIONS}_PENDING`:
|
|
59
|
-
case `${DELETE_RELATIONS}_PENDING`:
|
|
60
|
-
case `${REBUILD_RELATIONS}_PENDING`:
|
|
61
|
-
return {
|
|
62
|
-
...state,
|
|
63
|
-
[getRequestKey(action.type)]: {
|
|
64
|
-
loading: true,
|
|
65
|
-
loaded: false,
|
|
66
|
-
error: null,
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
64
|
case `${LIST_RELATIONS}_PENDING`:
|
|
70
65
|
return action.subrequest
|
|
71
66
|
? {
|
|
@@ -73,10 +68,7 @@ export default function relations(state = initialState, action = {}) {
|
|
|
73
68
|
subrequests: {
|
|
74
69
|
...state.subrequests,
|
|
75
70
|
[action.subrequest]: {
|
|
76
|
-
|
|
77
|
-
relations: null,
|
|
78
|
-
stats: null,
|
|
79
|
-
}),
|
|
71
|
+
data: null,
|
|
80
72
|
loaded: false,
|
|
81
73
|
loading: true,
|
|
82
74
|
error: null,
|
|
@@ -85,7 +77,8 @@ export default function relations(state = initialState, action = {}) {
|
|
|
85
77
|
}
|
|
86
78
|
: {
|
|
87
79
|
...state,
|
|
88
|
-
|
|
80
|
+
relations: {
|
|
81
|
+
data: null,
|
|
89
82
|
loading: true,
|
|
90
83
|
loaded: false,
|
|
91
84
|
error: null,
|
|
@@ -98,39 +91,22 @@ export default function relations(state = initialState, action = {}) {
|
|
|
98
91
|
subrequests: {
|
|
99
92
|
...state.subrequests,
|
|
100
93
|
[action.subrequest]: {
|
|
94
|
+
data: action.result.relations,
|
|
101
95
|
loading: false,
|
|
102
96
|
loaded: true,
|
|
103
97
|
error: null,
|
|
104
|
-
relations: action.result.relations
|
|
105
|
-
? action.result.relations
|
|
106
|
-
: [],
|
|
107
|
-
stats: null,
|
|
108
98
|
},
|
|
109
99
|
},
|
|
110
100
|
}
|
|
111
101
|
: {
|
|
112
102
|
...state,
|
|
113
|
-
relations:
|
|
114
|
-
|
|
115
|
-
: state.relations,
|
|
116
|
-
stats: action.result.stats ? action.result : state.stats,
|
|
117
|
-
[getRequestKey(action.type)]: {
|
|
103
|
+
relations: {
|
|
104
|
+
data: action.result.relations,
|
|
118
105
|
loading: false,
|
|
119
106
|
loaded: true,
|
|
120
107
|
error: null,
|
|
121
108
|
},
|
|
122
109
|
};
|
|
123
|
-
case `${CREATE_RELATIONS}_SUCCESS`:
|
|
124
|
-
case `${DELETE_RELATIONS}_SUCCESS`:
|
|
125
|
-
case `${REBUILD_RELATIONS}_SUCCESS`:
|
|
126
|
-
return {
|
|
127
|
-
...state,
|
|
128
|
-
[getRequestKey(action.type)]: {
|
|
129
|
-
loading: false,
|
|
130
|
-
loaded: true,
|
|
131
|
-
error: null,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
110
|
case `${LIST_RELATIONS}_FAIL`:
|
|
135
111
|
return action.subrequest
|
|
136
112
|
? {
|
|
@@ -138,8 +114,7 @@ export default function relations(state = initialState, action = {}) {
|
|
|
138
114
|
subrequests: {
|
|
139
115
|
...state.subrequests,
|
|
140
116
|
[action.subrequest]: {
|
|
141
|
-
|
|
142
|
-
stats: null,
|
|
117
|
+
data: null,
|
|
143
118
|
loading: false,
|
|
144
119
|
loaded: false,
|
|
145
120
|
error: action.error,
|
|
@@ -148,14 +123,67 @@ export default function relations(state = initialState, action = {}) {
|
|
|
148
123
|
}
|
|
149
124
|
: {
|
|
150
125
|
...state,
|
|
151
|
-
relations:
|
|
152
|
-
|
|
153
|
-
[getRequestKey(action.type)]: {
|
|
126
|
+
relations: {
|
|
127
|
+
data: null,
|
|
154
128
|
loading: false,
|
|
155
129
|
loaded: false,
|
|
156
130
|
error: action.error,
|
|
157
131
|
},
|
|
158
132
|
};
|
|
133
|
+
|
|
134
|
+
case `${STATS_RELATIONS}_PENDING`:
|
|
135
|
+
return {
|
|
136
|
+
...state,
|
|
137
|
+
[getRequestKey(action.type)]: {
|
|
138
|
+
loading: true,
|
|
139
|
+
loaded: false,
|
|
140
|
+
error: null,
|
|
141
|
+
data: null,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
case `${STATS_RELATIONS}_SUCCESS`:
|
|
145
|
+
return {
|
|
146
|
+
...state,
|
|
147
|
+
[getRequestKey(action.type)]: {
|
|
148
|
+
loading: false,
|
|
149
|
+
loaded: true,
|
|
150
|
+
error: null,
|
|
151
|
+
data: action.result,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
case `${STATS_RELATIONS}_FAIL`:
|
|
155
|
+
return {
|
|
156
|
+
...state,
|
|
157
|
+
[getRequestKey(action.type)]: {
|
|
158
|
+
loading: false,
|
|
159
|
+
loaded: false,
|
|
160
|
+
error: action.error,
|
|
161
|
+
data: null,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
case `${CREATE_RELATIONS}_PENDING`:
|
|
166
|
+
case `${DELETE_RELATIONS}_PENDING`:
|
|
167
|
+
case `${REBUILD_RELATIONS}_PENDING`:
|
|
168
|
+
return {
|
|
169
|
+
...state,
|
|
170
|
+
[getRequestKey(action.type)]: {
|
|
171
|
+
loading: true,
|
|
172
|
+
loaded: false,
|
|
173
|
+
error: null,
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
case `${CREATE_RELATIONS}_SUCCESS`:
|
|
177
|
+
case `${DELETE_RELATIONS}_SUCCESS`:
|
|
178
|
+
case `${REBUILD_RELATIONS}_SUCCESS`:
|
|
179
|
+
return {
|
|
180
|
+
...state,
|
|
181
|
+
[getRequestKey(action.type)]: {
|
|
182
|
+
loading: false,
|
|
183
|
+
loaded: true,
|
|
184
|
+
error: null,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
159
187
|
case `${CREATE_RELATIONS}_FAIL`:
|
|
160
188
|
case `${DELETE_RELATIONS}_FAIL`:
|
|
161
189
|
case `${REBUILD_RELATIONS}_FAIL`:
|
package/src/server.jsx
CHANGED
|
@@ -263,6 +263,15 @@ server.get('/*', (req, res) => {
|
|
|
263
263
|
const readCriticalCss =
|
|
264
264
|
config.settings.serverConfig.readCriticalCss || defaultReadCriticalCss;
|
|
265
265
|
|
|
266
|
+
// If we are showing an "old browser" warning,
|
|
267
|
+
// make sure it doesn't get cached in a shared cache
|
|
268
|
+
const browserdetect = store.getState().browserdetect;
|
|
269
|
+
if (config.settings.notSupportedBrowsers.includes(browserdetect?.name)) {
|
|
270
|
+
res.set({
|
|
271
|
+
'Cache-Control': 'private',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
266
275
|
if (context.url) {
|
|
267
276
|
res.redirect(flattenToAppURL(context.url));
|
|
268
277
|
} else if (context.error_code) {
|
|
@@ -49,6 +49,52 @@
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
.ui.form .fields.error .field textarea,
|
|
53
|
+
.ui.form .fields.error .field select,
|
|
54
|
+
.ui.form .fields.error .field input:not([type]),
|
|
55
|
+
.ui.form .fields.error .field input[type='date'],
|
|
56
|
+
.ui.form .fields.error .field input[type='datetime-local'],
|
|
57
|
+
.ui.form .fields.error .field input[type='email'],
|
|
58
|
+
.ui.form .fields.error .field input[type='number'],
|
|
59
|
+
.ui.form .fields.error .field input[type='password'],
|
|
60
|
+
.ui.form .fields.error .field input[type='search'],
|
|
61
|
+
.ui.form .fields.error .field input[type='tel'],
|
|
62
|
+
.ui.form .fields.error .field input[type='time'],
|
|
63
|
+
.ui.form .fields.error .field input[type='text'],
|
|
64
|
+
.ui.form .fields.error .field input[type='file'],
|
|
65
|
+
.ui.form .fields.error .field input[type='url'],
|
|
66
|
+
.ui.form .field.error textarea,
|
|
67
|
+
.ui.form .field.error select,
|
|
68
|
+
.ui.form .field.error input:not([type]),
|
|
69
|
+
.ui.form .field.error input[type='date'],
|
|
70
|
+
.ui.form .field.error input[type='datetime-local'],
|
|
71
|
+
.ui.form .field.error input[type='email'],
|
|
72
|
+
.ui.form .field.error input[type='number'],
|
|
73
|
+
.ui.form .field.error input[type='password'],
|
|
74
|
+
.ui.form .field.error input[type='search'],
|
|
75
|
+
.ui.form .field.error input[type='tel'],
|
|
76
|
+
.ui.form .field.error input[type='time'],
|
|
77
|
+
.ui.form .field.error input[type='text'],
|
|
78
|
+
.ui.form .field.error input[type='file'],
|
|
79
|
+
.ui.form .field.error input[type='url'],
|
|
80
|
+
.ui.form .field.error textarea:focus,
|
|
81
|
+
.ui.form .field.error select:focus,
|
|
82
|
+
.ui.form .field.error input:not([type]):focus,
|
|
83
|
+
.ui.form .field.error input[type='date']:focus,
|
|
84
|
+
.ui.form .field.error input[type='datetime-local']:focus,
|
|
85
|
+
.ui.form .field.error input[type='email']:focus,
|
|
86
|
+
.ui.form .field.error input[type='number']:focus,
|
|
87
|
+
.ui.form .field.error input[type='password']:focus,
|
|
88
|
+
.ui.form .field.error input[type='search']:focus,
|
|
89
|
+
.ui.form .field.error input[type='tel']:focus,
|
|
90
|
+
.ui.form .field.error input[type='time']:focus,
|
|
91
|
+
.ui.form .field.error input[type='text']:focus,
|
|
92
|
+
.ui.form .field.error input[type='file']:focus,
|
|
93
|
+
.ui.form .field.error input[type='url']:focus {
|
|
94
|
+
border-color: #d01157;
|
|
95
|
+
background: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
52
98
|
.ui.form .field > .selection.dropdown {
|
|
53
99
|
height: 60px;
|
|
54
100
|
}
|