@plone/volto 17.0.0-alpha.1 → 17.0.0-alpha.10
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 +396 -16
- package/CONTRIBUTING.md +1 -1
- package/README.md +12 -15
- package/addon-registry.js +34 -0
- package/create-theme-addons-loader.js +79 -0
- package/cypress/support/commands.js +25 -0
- package/locales/ca/LC_MESSAGES/volto.po +187 -6
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +206 -25
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +186 -5
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +187 -6
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +187 -6
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +4792 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +187 -6
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +187 -6
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +187 -6
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +842 -649
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +187 -6
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +195 -14
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +187 -6
- package/locales/ro.json +1 -1
- package/locales/volto.pot +187 -6
- package/locales/zh_CN/LC_MESSAGES/volto.po +187 -6
- package/locales/zh_CN.json +1 -1
- package/package-why.json +0 -1
- package/package.json +9 -8
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/blocks/Table/index.js +2 -0
- package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
- package/packages/volto-slate/src/editor/deserialize.js +0 -1
- package/packages/volto-slate/src/editor/plugins/StyleMenu/StyleMenu.jsx +14 -4
- package/razzle.config.js +28 -0
- package/src/actions/index.js +6 -0
- package/src/actions/language/language.js +9 -8
- package/src/actions/querystringsearch/querystringsearch.js +20 -14
- package/src/actions/relations/rebuild.js +25 -0
- package/src/actions/relations/relations.js +86 -0
- package/src/actions/relations/relations.test.js +15 -0
- package/src/components/index.js +1 -0
- package/src/components/manage/Add/Add.jsx +2 -2
- package/src/components/manage/BlockChooser/BlockChooser.jsx +14 -5
- package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -19
- package/src/components/manage/Blocks/Listing/ListingBody.jsx +77 -61
- package/src/components/manage/Blocks/Listing/View.jsx +0 -4
- package/src/components/manage/Blocks/Listing/getAsyncData.js +10 -2
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -13
- package/src/components/manage/Blocks/Search/SearchBlockEdit.jsx +5 -4
- package/src/components/manage/Blocks/Search/SearchBlockView.jsx +2 -1
- package/src/components/manage/Blocks/Search/components/DateRangeFacet.jsx +4 -1
- package/src/components/manage/Blocks/Search/components/Facets.jsx +58 -2
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +24 -11
- package/src/components/manage/Blocks/Search/layout/LeftColumnFacets.jsx +17 -5
- package/src/components/manage/Blocks/Search/layout/RightColumnFacets.jsx +17 -5
- package/src/components/manage/Blocks/Search/layout/TopSideFacets.jsx +21 -5
- package/src/components/manage/Blocks/Search/schema.js +16 -1
- package/src/components/manage/Blocks/ToC/Edit.jsx +1 -0
- package/src/components/manage/Contents/Contents.jsx +69 -33
- package/src/components/manage/Contents/ContentsItem.jsx +6 -0
- package/src/components/manage/Controlpanels/AddonsControlpanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Controlpanels.jsx +199 -224
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
- package/src/components/manage/DragDropList/DragDropList.jsx +63 -42
- package/src/components/manage/Form/BlocksToolbar.jsx +5 -1
- package/src/components/manage/Form/Form.jsx +11 -5
- package/src/components/manage/Form/InlineForm.jsx +39 -9
- package/src/components/manage/Form/InlineFormState.js +8 -0
- package/src/components/manage/Multilingual/CreateTranslation.jsx +2 -2
- package/src/components/manage/Multilingual/TranslationObject.jsx +4 -3
- package/src/components/manage/Preferences/ChangePassword.jsx +2 -2
- package/src/components/manage/Preferences/PersonalPreferences.jsx +2 -2
- package/src/components/manage/Toast/Toast.jsx +1 -1
- package/src/components/manage/Toolbar/Types.jsx +2 -2
- package/src/components/manage/Widgets/DatetimeWidget.jsx +9 -5
- package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
- package/src/components/manage/Widgets/RecurrenceWidget/ByDayField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/MonthOfTheYearField.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/Occurences.jsx +2 -1
- package/src/components/manage/Widgets/RecurrenceWidget/RecurrenceWidget.jsx +7 -2
- package/src/components/manage/Widgets/RecurrenceWidget/WeekdayOfTheMonthField.jsx +2 -1
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/manage/Widgets/SelectWidget.jsx +1 -1
- package/src/components/theme/Footer/Footer.jsx +2 -13
- package/src/components/theme/Header/Header.jsx +37 -63
- package/src/components/theme/Header/Header.test.jsx +18 -0
- package/src/components/theme/Icon/Icon.jsx +2 -2
- package/src/components/theme/LanguageSelector/LanguageSelector.js +8 -3
- package/src/components/theme/Login/Login.jsx +1 -0
- package/src/components/theme/Logo/Logo.jsx +2 -1
- package/src/components/theme/MultilingualRedirector/MultilingualRedirector.jsx +2 -2
- package/src/components/theme/Navigation/NavItem.jsx +4 -2
- package/src/components/theme/NotFound/NotFound.jsx +55 -41
- package/src/components/theme/PasswordReset/PasswordReset.jsx +7 -4
- package/src/components/theme/PasswordReset/RequestPasswordReset.jsx +1 -1
- package/src/components/theme/Sitemap/Sitemap.jsx +5 -3
- package/src/components/theme/View/DefaultView.jsx +1 -1
- package/src/components/theme/View/EventDatesInfo.jsx +2 -1
- package/src/components/theme/View/RenderBlocks.jsx +7 -1
- package/src/components/theme/Widgets/DateWidget.jsx +2 -1
- package/src/components/theme/Widgets/DatetimeWidget.jsx +2 -1
- package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
- package/src/config/ControlPanels.js +2 -0
- package/src/config/Widgets.jsx +1 -0
- package/src/config/index.js +2 -0
- package/src/constants/ActionTypes.js +4 -0
- package/src/constants/Languages.js +8 -4
- package/src/express-middleware/sitemap.js +36 -4
- package/src/helpers/Api/Api.js +1 -1
- package/src/helpers/FormValidation/FormValidation.js +11 -2
- package/src/helpers/FormValidation/FormValidation.test.js +73 -0
- package/src/helpers/Html/Html.jsx +3 -1
- package/src/helpers/Html/Html.test.jsx +5 -0
- package/src/helpers/MessageLabels/MessageLabels.js +72 -0
- package/src/helpers/Robots/Robots.js +24 -6
- package/src/helpers/Sitemap/Sitemap.js +44 -2
- package/src/helpers/Url/Url.js +27 -6
- package/src/helpers/Url/Url.test.js +26 -0
- package/src/helpers/Utils/Utils.js +38 -13
- package/src/helpers/Utils/Utils.test.js +4 -4
- package/src/helpers/index.js +7 -2
- package/src/hooks/userSession/useToken.js +5 -0
- package/src/middleware/Api.test.js +54 -0
- package/src/middleware/api.js +8 -4
- package/src/reducers/actions/actions.js +1 -1
- package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
- package/src/reducers/index.js +2 -0
- package/src/reducers/navigation/navigation.js +1 -1
- package/src/reducers/relations/relations.js +173 -0
- package/src/reducers/types/types.js +1 -1
- package/src/routes.js +5 -0
- package/src/server.jsx +28 -23
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/extras/contents.less +1 -0
- package/theme/themes/pastanaga/extras/main.less +80 -1
- package/theme/themes/pastanaga/extras/search.less +6 -0
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
- package/.changelog.draft +0 -28
- package/.editorconfig +0 -36
- package/.storybook/main.js +0 -127
- package/.storybook/manager.js +0 -15
- package/.storybook/preview.js +0 -21
- package/.storybook/static/previewImage.svg +0 -48
- package/.yarnrc.yml +0 -5
- package/jsdoc.json +0 -16
- package/netlify.toml +0 -5
- package/pyvenv.cfg +0 -3
- package/share/man/man1/ttx.1 +0 -225
- package/src/components/theme/Header/Header.md +0 -27
- package/towncrier.toml +0 -33
|
@@ -1,53 +1,67 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @module components/theme/NotFound/NotFound
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React from 'react';
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { BodyClass, toBackendLang } from '@plone/volto/helpers';
|
|
7
3
|
import { FormattedMessage } from 'react-intl';
|
|
8
4
|
import { Link } from 'react-router-dom';
|
|
9
5
|
import { Container } from 'semantic-ui-react';
|
|
10
6
|
import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
|
|
7
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
8
|
+
import { getNavigation } from '@plone/volto/actions';
|
|
9
|
+
import config from '@plone/volto/registry';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Not found function.
|
|
14
13
|
* @function NotFound
|
|
15
14
|
* @returns {string} Markup of the not found page.
|
|
16
15
|
*/
|
|
17
|
-
const NotFound = () =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
16
|
+
const NotFound = () => {
|
|
17
|
+
const dispatch = useDispatch();
|
|
18
|
+
const lang = useSelector((state) => state.intl.locale);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
dispatch(
|
|
22
|
+
getNavigation(
|
|
23
|
+
config.settings.isMultilingual ? `/${toBackendLang(lang)}` : '/',
|
|
24
|
+
config.settings.navDepth,
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
}, [dispatch, lang]);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Container className="view-wrapper">
|
|
31
|
+
<BodyClass className="page-not-found" />
|
|
32
|
+
<h1>
|
|
33
|
+
<FormattedMessage
|
|
34
|
+
id="This page does not seem to exist…"
|
|
35
|
+
defaultMessage="This page does not seem to exist…"
|
|
36
|
+
/>
|
|
37
|
+
</h1>
|
|
38
|
+
<p className="description">
|
|
39
|
+
<FormattedMessage
|
|
40
|
+
id="We apologize for the inconvenience, but the page you were trying to access is not at this address. You can use the links below to help you find what you are looking for."
|
|
41
|
+
defaultMessage="We apologize for the inconvenience, but the page you were trying to access is not at this address. You can use the links below to help you find what you are looking for."
|
|
42
|
+
/>
|
|
43
|
+
</p>
|
|
44
|
+
<p>
|
|
45
|
+
<FormattedMessage
|
|
46
|
+
id="If you are certain you have the correct web address but are encountering an error, please contact the {site_admin}."
|
|
47
|
+
defaultMessage="If you are certain you have the correct web address but are encountering an error, please contact the {site_admin}."
|
|
48
|
+
values={{
|
|
49
|
+
site_admin: (
|
|
50
|
+
<Link to="/contact-form">
|
|
51
|
+
<FormattedMessage
|
|
52
|
+
id="Site Administration"
|
|
53
|
+
defaultMessage="Site Administration"
|
|
54
|
+
/>
|
|
55
|
+
</Link>
|
|
56
|
+
),
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
</p>
|
|
60
|
+
<p>
|
|
61
|
+
<FormattedMessage id="Thank you." defaultMessage="Thank you." />
|
|
62
|
+
</p>
|
|
63
|
+
</Container>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
52
66
|
|
|
53
67
|
export default withServerErrorCode(404)(NotFound);
|
|
@@ -31,7 +31,7 @@ const messages = defineMessages({
|
|
|
31
31
|
},
|
|
32
32
|
usernameTitle: {
|
|
33
33
|
id: 'My username is',
|
|
34
|
-
defaultMessage: 'My
|
|
34
|
+
defaultMessage: 'My user name is',
|
|
35
35
|
},
|
|
36
36
|
emailTitle: {
|
|
37
37
|
id: 'My email is',
|
|
@@ -50,8 +50,8 @@ const messages = defineMessages({
|
|
|
50
50
|
defaultMessage: 'New password',
|
|
51
51
|
},
|
|
52
52
|
passwordDescription: {
|
|
53
|
-
id: 'Enter your new password. Minimum
|
|
54
|
-
defaultMessage: 'Enter your new password. Minimum
|
|
53
|
+
id: 'Enter your new password. Minimum 8 characters.',
|
|
54
|
+
defaultMessage: 'Enter your new password. Minimum 8 characters.',
|
|
55
55
|
},
|
|
56
56
|
passwordRepeatTitle: {
|
|
57
57
|
id: 'Confirm password',
|
|
@@ -227,6 +227,9 @@ class PasswordReset extends Component {
|
|
|
227
227
|
);
|
|
228
228
|
}
|
|
229
229
|
if (this.props.token) {
|
|
230
|
+
const errmsg = this.props.error
|
|
231
|
+
? this.props.error.response.body.error
|
|
232
|
+
: null;
|
|
230
233
|
return (
|
|
231
234
|
<div id="page-password-reset">
|
|
232
235
|
<Helmet
|
|
@@ -238,7 +241,7 @@ class PasswordReset extends Component {
|
|
|
238
241
|
description={this.props.intl.formatMessage(messages.description)}
|
|
239
242
|
onSubmit={this.onSubmit}
|
|
240
243
|
onCancel={this.onCancel}
|
|
241
|
-
error={this.state.error ||
|
|
244
|
+
error={this.state.error || errmsg}
|
|
242
245
|
schema={{
|
|
243
246
|
fieldsets: [
|
|
244
247
|
{
|
|
@@ -10,7 +10,7 @@ import { connect } from 'react-redux';
|
|
|
10
10
|
import { asyncConnect } from '@plone/volto/helpers';
|
|
11
11
|
import { defineMessages, injectIntl } from 'react-intl';
|
|
12
12
|
import { Container } from 'semantic-ui-react';
|
|
13
|
-
import { Helmet } from '@plone/volto/helpers';
|
|
13
|
+
import { Helmet, toBackendLang } from '@plone/volto/helpers';
|
|
14
14
|
import { Link } from 'react-router-dom';
|
|
15
15
|
import config from '@plone/volto/registry';
|
|
16
16
|
|
|
@@ -40,7 +40,7 @@ class Sitemap extends Component {
|
|
|
40
40
|
componentDidMount() {
|
|
41
41
|
const { settings } = config;
|
|
42
42
|
if (settings.isMultilingual) {
|
|
43
|
-
this.props.getNavigation(`${this.props.lang}`, 4);
|
|
43
|
+
this.props.getNavigation(`${toBackendLang(this.props.lang)}`, 4);
|
|
44
44
|
} else {
|
|
45
45
|
this.props.getNavigation('', 4);
|
|
46
46
|
}
|
|
@@ -108,7 +108,9 @@ export default compose(
|
|
|
108
108
|
const { settings } = config;
|
|
109
109
|
const lang = getState().intl.locale;
|
|
110
110
|
if (settings.isMultilingual) {
|
|
111
|
-
return
|
|
111
|
+
return (
|
|
112
|
+
__SERVER__ && dispatch(getNavigation(`${toBackendLang(lang)}`, 4))
|
|
113
|
+
);
|
|
112
114
|
} else {
|
|
113
115
|
return __SERVER__ && dispatch(getNavigation('', 4));
|
|
114
116
|
}
|
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { List } from 'semantic-ui-react';
|
|
4
4
|
import cx from 'classnames';
|
|
5
5
|
|
|
6
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
6
7
|
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
|
|
7
8
|
import { useSelector } from 'react-redux';
|
|
8
9
|
|
|
@@ -28,7 +29,7 @@ const When_ = ({ start, end, whole_day, open_end, moment: momentlib }) => {
|
|
|
28
29
|
const lang = useSelector((state) => state.intl.locale);
|
|
29
30
|
|
|
30
31
|
const moment = momentlib.default;
|
|
31
|
-
moment.locale(lang);
|
|
32
|
+
moment.locale(toBackendLang(lang));
|
|
32
33
|
|
|
33
34
|
const datesInfo = datesForDisplay(start, end, moment);
|
|
34
35
|
if (!datesInfo) {
|
|
@@ -44,7 +44,13 @@ const RenderBlocks = (props) => {
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
return Block ? (
|
|
47
|
-
<StyleWrapper
|
|
47
|
+
<StyleWrapper
|
|
48
|
+
key={block}
|
|
49
|
+
{...props}
|
|
50
|
+
id={block}
|
|
51
|
+
block={block}
|
|
52
|
+
data={blockData}
|
|
53
|
+
>
|
|
48
54
|
<Block
|
|
49
55
|
id={block}
|
|
50
56
|
metadata={metadata}
|
|
@@ -2,10 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import moment from 'moment';
|
|
4
4
|
import { useSelector } from 'react-redux';
|
|
5
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
5
6
|
|
|
6
7
|
const DateWidget = ({ value, children, className, format = 'll' }) => {
|
|
7
8
|
const lang = useSelector((state) => state.intl.locale);
|
|
8
|
-
moment.locale(lang);
|
|
9
|
+
moment.locale(toBackendLang(lang));
|
|
9
10
|
return value ? (
|
|
10
11
|
<span className={cx(className, 'date', 'widget')}>
|
|
11
12
|
{children
|
|
@@ -2,10 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import cx from 'classnames';
|
|
3
3
|
import moment from 'moment';
|
|
4
4
|
import { useSelector } from 'react-redux';
|
|
5
|
+
import { toBackendLang } from '@plone/volto/helpers';
|
|
5
6
|
|
|
6
7
|
const DatetimeWidget = ({ value, children, className, format = 'lll' }) => {
|
|
7
8
|
const lang = useSelector((state) => state.intl.locale);
|
|
8
|
-
moment.locale(lang);
|
|
9
|
+
moment.locale(toBackendLang(lang));
|
|
9
10
|
return value ? (
|
|
10
11
|
<span className={cx(className, 'datetime', 'widget')}>
|
|
11
12
|
{children
|
|
@@ -5,17 +5,19 @@ import RelationWidget from './RelationWidget';
|
|
|
5
5
|
const RelationsWidget = ({ value, children, className }) =>
|
|
6
6
|
value ? (
|
|
7
7
|
<ul className={cx(className, 'relations', 'widget')}>
|
|
8
|
-
{value.map((item, key) =>
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
{value.map((item, key) => {
|
|
9
|
+
return item ? (
|
|
10
|
+
<li key={key}>
|
|
11
|
+
<RelationWidget
|
|
12
|
+
value={item || `relation target not found '${key}'`}
|
|
13
|
+
className={className}
|
|
14
|
+
key={item.token || item.title || item}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</RelationWidget>
|
|
18
|
+
</li>
|
|
19
|
+
) : null;
|
|
20
|
+
})}
|
|
19
21
|
</ul>
|
|
20
22
|
) : (
|
|
21
23
|
''
|
|
@@ -18,6 +18,7 @@ import settingsSVG from '@plone/volto/icons/settings.svg';
|
|
|
18
18
|
import rulesSVG from '@plone/volto/icons/content-existing.svg';
|
|
19
19
|
import undoControlPanelSVG from '@plone/volto/icons/undo-control-panel.svg';
|
|
20
20
|
import linkSVG from '@plone/volto/icons/link.svg';
|
|
21
|
+
import relationsSVG from '@plone/volto/icons/ahead.svg';
|
|
21
22
|
|
|
22
23
|
export const controlPanelsIcons = {
|
|
23
24
|
default: settingsSVG,
|
|
@@ -40,6 +41,7 @@ export const controlPanelsIcons = {
|
|
|
40
41
|
rules: rulesSVG,
|
|
41
42
|
undo: undoControlPanelSVG,
|
|
42
43
|
aliases: linkSVG,
|
|
44
|
+
relations: relationsSVG,
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
export const filterControlPanels = (controlpanels) => {
|
package/src/config/Widgets.jsx
CHANGED
|
@@ -98,6 +98,7 @@ export const widgetMapping = {
|
|
|
98
98
|
select_querystring_field: SelectMetadataWidget,
|
|
99
99
|
autocomplete: SelectAutoComplete,
|
|
100
100
|
color_picker: ColorPickerWidget,
|
|
101
|
+
select: SelectWidget,
|
|
101
102
|
},
|
|
102
103
|
vocabulary: {
|
|
103
104
|
'plone.app.vocabularies.Catalog': ObjectBrowserWidget,
|
package/src/config/index.js
CHANGED
|
@@ -36,6 +36,10 @@ export const GET_NAVIGATION = 'GET_NAVIGATION';
|
|
|
36
36
|
export const GET_PRINCIPALS = 'GET_PRINCIPALS';
|
|
37
37
|
export const GET_QUERYSTRING = 'GET_QUERYSTRING';
|
|
38
38
|
export const GET_QUERYSTRING_RESULTS = 'GET_QUERYSTRING_RESULTS';
|
|
39
|
+
export const CREATE_RELATIONS = 'CREATE_RELATIONS';
|
|
40
|
+
export const DELETE_RELATIONS = 'DELETE_RELATIONS';
|
|
41
|
+
export const LIST_RELATIONS = 'LIST_RELATIONS';
|
|
42
|
+
export const REBUILD_RELATIONS = 'REBUILD_RELATIONS';
|
|
39
43
|
export const GET_SCHEMA = 'GET_SCHEMA';
|
|
40
44
|
export const POST_SCHEMA = 'POST_SCHEMA';
|
|
41
45
|
export const PUT_SCHEMA = 'PUT_SCHEMA';
|
|
@@ -4,14 +4,18 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
|
-
|
|
7
|
+
ca: 'Català',
|
|
8
8
|
de: 'Deutsch',
|
|
9
|
+
en: 'English',
|
|
10
|
+
es: 'Español',
|
|
11
|
+
eu: 'Euskara',
|
|
12
|
+
fi: 'Suomi',
|
|
13
|
+
fr: 'Français',
|
|
14
|
+
it: 'Italiano',
|
|
9
15
|
nl: 'Nederlands',
|
|
10
16
|
ro: 'Română',
|
|
11
17
|
ja: '日本語',
|
|
12
18
|
pt: 'Português',
|
|
13
19
|
pt_BR: 'Português (Brasil)',
|
|
14
|
-
|
|
15
|
-
it: 'Italian',
|
|
16
|
-
eu: 'Euskara',
|
|
20
|
+
zh_CN: '中文',
|
|
17
21
|
};
|
|
@@ -1,12 +1,34 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
generateSitemap,
|
|
4
|
+
generateSitemapIndex,
|
|
5
|
+
SITEMAP_BATCH_SIZE,
|
|
6
|
+
} from '@plone/volto/helpers/Sitemap/Sitemap';
|
|
3
7
|
|
|
4
8
|
export const sitemap = function (req, res, next) {
|
|
5
|
-
|
|
9
|
+
let start = 0;
|
|
10
|
+
let size = undefined;
|
|
11
|
+
const { batch: batchStr } = req.params;
|
|
12
|
+
if (batchStr !== undefined) {
|
|
13
|
+
const batch = parseInt(batchStr);
|
|
14
|
+
if (isNaN(batch) || batch === 0 || '' + batch !== batchStr) {
|
|
15
|
+
res.status(404);
|
|
16
|
+
// Some data, such as the internal API address, may be sensitive to be published
|
|
17
|
+
res.send(
|
|
18
|
+
`Invalid sitemap name, use sitemap.xml.gz, or batched sitemapN.xml.gz where N is a positive integer.`,
|
|
19
|
+
);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
start = SITEMAP_BATCH_SIZE * (batch - 1);
|
|
23
|
+
size = SITEMAP_BATCH_SIZE;
|
|
24
|
+
}
|
|
25
|
+
generateSitemap(req, start, size).then((sitemap) => {
|
|
6
26
|
if (Buffer.isBuffer(sitemap)) {
|
|
7
27
|
res.set('Content-Type', 'application/x-gzip');
|
|
8
|
-
res.set(
|
|
9
|
-
|
|
28
|
+
res.set(
|
|
29
|
+
'Content-Disposition',
|
|
30
|
+
`attachment; filename="sitemap${batchStr || ''}.xml.gz"`,
|
|
31
|
+
);
|
|
10
32
|
res.send(sitemap);
|
|
11
33
|
} else {
|
|
12
34
|
// {"errno":-111, "code":"ECONNREFUSED", "host": ...}
|
|
@@ -17,10 +39,20 @@ export const sitemap = function (req, res, next) {
|
|
|
17
39
|
});
|
|
18
40
|
};
|
|
19
41
|
|
|
42
|
+
export const sitemapIndex = function (req, res, next) {
|
|
43
|
+
generateSitemapIndex(req).then((sitemapIndex) => {
|
|
44
|
+
res.set('Content-Type', 'application/xml');
|
|
45
|
+
res.set('Content-Disposition', 'attachment; filename="sitemap-index.xml"');
|
|
46
|
+
res.send(sitemapIndex);
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
20
50
|
export default function () {
|
|
21
51
|
const middleware = express.Router();
|
|
22
52
|
|
|
23
53
|
middleware.all('**/sitemap.xml.gz', sitemap);
|
|
54
|
+
middleware.all('**/sitemap:batch.xml.gz', sitemap);
|
|
55
|
+
middleware.all('**/sitemap-index.xml', sitemapIndex);
|
|
24
56
|
middleware.id = 'sitemap.xml.gz';
|
|
25
57
|
return middleware;
|
|
26
58
|
}
|
package/src/helpers/Api/Api.js
CHANGED
|
@@ -65,7 +65,16 @@ const widgetValidation = {
|
|
|
65
65
|
},
|
|
66
66
|
url: {
|
|
67
67
|
isValidURL: (urlValue, urlObj, intlFunc) => {
|
|
68
|
-
|
|
68
|
+
var urlRegex = new RegExp(
|
|
69
|
+
'^(https?:\\/\\/)?' + // validate protocol
|
|
70
|
+
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // validate domain name
|
|
71
|
+
'((\\d{1,3}\\.){3}\\d{1,3}))|' + // validate OR ip (v4) address
|
|
72
|
+
'(localhost)' + // validate OR localhost address
|
|
73
|
+
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // validate port and path
|
|
74
|
+
'(\\?[;&a-z\\d%_.~+=-]*)?' + // validate query string
|
|
75
|
+
'(\\#[-a-z\\d_]*)?$', // validate fragment locator
|
|
76
|
+
'i',
|
|
77
|
+
);
|
|
69
78
|
const isValid = urlRegex.test(urlValue);
|
|
70
79
|
return !isValid ? intlFunc(messages.isValidURL) : null;
|
|
71
80
|
},
|
|
@@ -194,7 +203,7 @@ const validateRequiredFields = (
|
|
|
194
203
|
const type = schema.properties[requiredField]?.type;
|
|
195
204
|
const widget = schema.properties[requiredField]?.widget;
|
|
196
205
|
|
|
197
|
-
let isEmpty = !formData[requiredField];
|
|
206
|
+
let isEmpty = !formData[requiredField] && formData[requiredField] !== 0;
|
|
198
207
|
if (!isEmpty) {
|
|
199
208
|
if (type === 'array') {
|
|
200
209
|
isEmpty = formData[requiredField]
|
|
@@ -5,6 +5,7 @@ const schema = {
|
|
|
5
5
|
properties: {
|
|
6
6
|
username: { title: 'Username', type: 'string', description: '' },
|
|
7
7
|
email: { title: 'Email', type: 'string', widget: 'email', description: '' },
|
|
8
|
+
url: { title: 'url', type: 'string', widget: 'url', description: '' },
|
|
8
9
|
},
|
|
9
10
|
fieldsets: [
|
|
10
11
|
{ id: 'default', title: 'FIXME: User Data', fields: ['username'] },
|
|
@@ -65,6 +66,38 @@ describe('FormValidation', () => {
|
|
|
65
66
|
});
|
|
66
67
|
});
|
|
67
68
|
|
|
69
|
+
it('do not treat 0 as missing required value', () => {
|
|
70
|
+
let newSchema = {
|
|
71
|
+
...schema,
|
|
72
|
+
properties: {
|
|
73
|
+
...schema.properties,
|
|
74
|
+
age: {
|
|
75
|
+
title: 'age',
|
|
76
|
+
type: 'integer',
|
|
77
|
+
widget: 'number',
|
|
78
|
+
description: '',
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ['age'],
|
|
82
|
+
};
|
|
83
|
+
expect(
|
|
84
|
+
FormValidation.validateFieldsPerFieldset({
|
|
85
|
+
schema: newSchema,
|
|
86
|
+
formData: { username: 'test username', age: null },
|
|
87
|
+
formatMessage,
|
|
88
|
+
}),
|
|
89
|
+
).toEqual({
|
|
90
|
+
age: [messages.required.defaultMessage],
|
|
91
|
+
});
|
|
92
|
+
expect(
|
|
93
|
+
FormValidation.validateFieldsPerFieldset({
|
|
94
|
+
schema: newSchema,
|
|
95
|
+
formData: { username: 'test username', age: 0 },
|
|
96
|
+
formatMessage,
|
|
97
|
+
}),
|
|
98
|
+
).toEqual({});
|
|
99
|
+
});
|
|
100
|
+
|
|
68
101
|
it('validates incorrect email', () => {
|
|
69
102
|
expect(
|
|
70
103
|
FormValidation.validateFieldsPerFieldset({
|
|
@@ -87,5 +120,45 @@ describe('FormValidation', () => {
|
|
|
87
120
|
}),
|
|
88
121
|
).toEqual({});
|
|
89
122
|
});
|
|
123
|
+
it('validates incorrect url', () => {
|
|
124
|
+
formData.url = 'foo';
|
|
125
|
+
expect(
|
|
126
|
+
FormValidation.validateFieldsPerFieldset({
|
|
127
|
+
schema,
|
|
128
|
+
formData,
|
|
129
|
+
formatMessage,
|
|
130
|
+
}),
|
|
131
|
+
).toEqual({ url: [messages.isValidURL.defaultMessage] });
|
|
132
|
+
});
|
|
133
|
+
it('validates url', () => {
|
|
134
|
+
formData.url = 'https://plone.org/';
|
|
135
|
+
expect(
|
|
136
|
+
FormValidation.validateFieldsPerFieldset({
|
|
137
|
+
schema,
|
|
138
|
+
formData,
|
|
139
|
+
formatMessage,
|
|
140
|
+
}),
|
|
141
|
+
).toEqual({});
|
|
142
|
+
});
|
|
143
|
+
it('validates url with ip', () => {
|
|
144
|
+
formData.url = 'http://127.0.0.1:8080/Plone';
|
|
145
|
+
expect(
|
|
146
|
+
FormValidation.validateFieldsPerFieldset({
|
|
147
|
+
schema,
|
|
148
|
+
formData,
|
|
149
|
+
formatMessage,
|
|
150
|
+
}),
|
|
151
|
+
).toEqual({});
|
|
152
|
+
});
|
|
153
|
+
it('validates url with localhost', () => {
|
|
154
|
+
formData.url = 'http://localhost:8080/Plone';
|
|
155
|
+
expect(
|
|
156
|
+
FormValidation.validateFieldsPerFieldset({
|
|
157
|
+
schema,
|
|
158
|
+
formData,
|
|
159
|
+
formatMessage,
|
|
160
|
+
}),
|
|
161
|
+
).toEqual({});
|
|
162
|
+
});
|
|
90
163
|
});
|
|
91
164
|
});
|
|
@@ -97,8 +97,10 @@ class Html extends Component {
|
|
|
97
97
|
} = this.props;
|
|
98
98
|
const head = Helmet.rewind();
|
|
99
99
|
const bodyClass = join(BodyClass.rewind(), ' ');
|
|
100
|
+
const htmlAttributes = head.htmlAttributes.toComponent();
|
|
101
|
+
|
|
100
102
|
return (
|
|
101
|
-
<html lang=
|
|
103
|
+
<html lang={htmlAttributes.lang}>
|
|
102
104
|
<head>
|
|
103
105
|
<meta charSet="utf-8" />
|
|
104
106
|
{head.base.toComponent()}
|
|
@@ -260,4 +260,76 @@ export const messages = defineMessages({
|
|
|
260
260
|
id: 'Show groups of users below',
|
|
261
261
|
defaultMessage: 'Show groups of users below',
|
|
262
262
|
},
|
|
263
|
+
inspectRelations: {
|
|
264
|
+
id: 'Inspect relations',
|
|
265
|
+
defaultMessage: 'Inspect relations',
|
|
266
|
+
},
|
|
267
|
+
relations: {
|
|
268
|
+
id: 'Relations',
|
|
269
|
+
defaultMessage: 'Relations',
|
|
270
|
+
},
|
|
271
|
+
fixRelations: {
|
|
272
|
+
id: 'Fix relations',
|
|
273
|
+
defaultMessage: 'Fix relations',
|
|
274
|
+
},
|
|
275
|
+
searchRelationSource: {
|
|
276
|
+
id: 'Search sources by title or path',
|
|
277
|
+
defaultMessage: 'Search sources by title or path',
|
|
278
|
+
},
|
|
279
|
+
searchRelationTarget: {
|
|
280
|
+
id: 'Search targets by title or path',
|
|
281
|
+
defaultMessage: 'Search targets by title or path',
|
|
282
|
+
},
|
|
283
|
+
createOrDeleteRelationsToTarget: {
|
|
284
|
+
id: 'Create or delete relations to target',
|
|
285
|
+
defaultMessage: 'Create or delete relations to target',
|
|
286
|
+
},
|
|
287
|
+
relationName: {
|
|
288
|
+
id: 'Relation name',
|
|
289
|
+
defaultMessage: 'relation',
|
|
290
|
+
},
|
|
291
|
+
selectRelation: {
|
|
292
|
+
id: 'Select relation',
|
|
293
|
+
defaultMessage: 'Select relation',
|
|
294
|
+
},
|
|
295
|
+
norelationfound: {
|
|
296
|
+
id: 'No relation found',
|
|
297
|
+
defaultMessage: 'No relation found',
|
|
298
|
+
},
|
|
299
|
+
toomanyrelationsfound: {
|
|
300
|
+
id: 'Many relations found. Please search.',
|
|
301
|
+
defaultMessage: 'Many relations found. Please search.',
|
|
302
|
+
},
|
|
303
|
+
rebuildRelations: {
|
|
304
|
+
id: 'rebuild relations',
|
|
305
|
+
defaultMessage: 'rebuild relations',
|
|
306
|
+
},
|
|
307
|
+
flushAndRebuildRelations: {
|
|
308
|
+
id: 'flush intIds and rebuild relations',
|
|
309
|
+
defaultMessage: 'flush intIds and rebuild relations',
|
|
310
|
+
},
|
|
311
|
+
addPotentialTargetsPath: {
|
|
312
|
+
id: 'target path',
|
|
313
|
+
defaultMessage: 'target path',
|
|
314
|
+
},
|
|
315
|
+
addPotentialSourcesPath: {
|
|
316
|
+
id: 'sources path',
|
|
317
|
+
defaultMessage: 'sources path',
|
|
318
|
+
},
|
|
319
|
+
relationsUpdated: {
|
|
320
|
+
id: 'Relations updated',
|
|
321
|
+
defaultMessage: 'Relations updated',
|
|
322
|
+
},
|
|
323
|
+
select: {
|
|
324
|
+
id: 'Select',
|
|
325
|
+
defaultMessage: 'Select',
|
|
326
|
+
},
|
|
327
|
+
selected: {
|
|
328
|
+
id: 'Selected',
|
|
329
|
+
defaultMessage: 'Selected',
|
|
330
|
+
},
|
|
331
|
+
filter: {
|
|
332
|
+
id: 'Filter',
|
|
333
|
+
defaultMessage: 'Filter',
|
|
334
|
+
},
|
|
263
335
|
});
|