@plone/volto 17.0.0-alpha.24 → 17.0.0-alpha.26

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.
Files changed (130) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +92 -4
  3. package/CONTRIBUTING.md +5 -1
  4. package/README.md +9 -7
  5. package/cypress/support/commands.js +12 -9
  6. package/cypress.config.js +1 -0
  7. package/locales/ca/LC_MESSAGES/volto.po +41 -15
  8. package/locales/ca.json +1 -1
  9. package/locales/de/LC_MESSAGES/volto.po +41 -15
  10. package/locales/de.json +1 -1
  11. package/locales/en/LC_MESSAGES/volto.po +40 -14
  12. package/locales/en.json +1 -1
  13. package/locales/es/LC_MESSAGES/volto.po +69 -43
  14. package/locales/es.json +1 -1
  15. package/locales/eu/LC_MESSAGES/volto.po +40 -14
  16. package/locales/eu.json +1 -1
  17. package/locales/fi/LC_MESSAGES/volto.po +40 -14
  18. package/locales/fi.json +1 -1
  19. package/locales/fr/LC_MESSAGES/volto.po +41 -15
  20. package/locales/fr.json +1 -1
  21. package/locales/it/LC_MESSAGES/volto.po +40 -14
  22. package/locales/it.json +1 -1
  23. package/locales/ja/LC_MESSAGES/volto.po +40 -14
  24. package/locales/ja.json +1 -1
  25. package/locales/nl/LC_MESSAGES/volto.po +41 -15
  26. package/locales/nl.json +1 -1
  27. package/locales/pt/LC_MESSAGES/volto.po +41 -15
  28. package/locales/pt.json +1 -1
  29. package/locales/pt_BR/LC_MESSAGES/volto.po +40 -14
  30. package/locales/pt_BR.json +1 -1
  31. package/locales/ro/LC_MESSAGES/volto.po +41 -15
  32. package/locales/ro.json +1 -1
  33. package/locales/volto.pot +41 -15
  34. package/locales/zh_CN/LC_MESSAGES/volto.po +41 -15
  35. package/locales/zh_CN.json +1 -1
  36. package/package.json +4 -4
  37. package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +90 -0
  38. package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +6 -0
  39. package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +6 -0
  40. package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +6 -0
  41. package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +10 -0
  42. package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +10 -0
  43. package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +30 -0
  44. package/packages/volto-slate/build/messages/src/elementEditor/messages.json +10 -0
  45. package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +6 -0
  46. package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +6 -0
  47. package/packages/volto-slate/package.json +1 -1
  48. package/packages/volto-slate/src/editor/render.jsx +2 -3
  49. package/src/actions/index.js +4 -0
  50. package/src/actions/navroot/navroot.js +16 -0
  51. package/src/actions/navroot/navroot.test.js +15 -0
  52. package/src/actions/relations/relations.js +17 -0
  53. package/src/actions/site/site.js +16 -0
  54. package/src/actions/site/site.test.js +15 -0
  55. package/src/actions/userSession/userSession.js +17 -1
  56. package/src/components/manage/Blocks/Block/Settings.jsx +2 -0
  57. package/src/components/manage/Blocks/Block/Settings.test.jsx +90 -0
  58. package/src/components/manage/Blocks/Image/schema.js +5 -1
  59. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +18 -11
  60. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +42 -25
  61. package/src/components/manage/Blocks/ToC/View.jsx +75 -13
  62. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +4 -13
  63. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.test.jsx +44 -0
  64. package/src/components/manage/Contents/Contents.jsx +27 -0
  65. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
  66. package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +11 -9
  67. package/src/components/manage/Controlpanels/Relations/Relations.jsx +3 -3
  68. package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +8 -7
  69. package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +15 -9
  70. package/src/components/manage/Controlpanels/Rules/AddRule.jsx +1 -1
  71. package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
  72. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +95 -5
  73. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +127 -99
  74. package/src/components/manage/Diff/DiffField.jsx +25 -1
  75. package/src/components/manage/Form/BlockDataForm.jsx +3 -2
  76. package/src/components/manage/Form/BlockDataForm.test.jsx +34 -2
  77. package/src/components/manage/LinksToItem/LinksToItem.jsx +1 -1
  78. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +5 -2
  79. package/src/components/manage/Messages/Messages.jsx +32 -99
  80. package/src/components/manage/Messages/Messages.test.jsx +0 -1
  81. package/src/components/manage/Sharing/Sharing.jsx +50 -21
  82. package/src/components/manage/UniversalLink/UniversalLink.jsx +4 -6
  83. package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
  84. package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
  85. package/src/components/manage/Widgets/FormFieldWrapper.jsx +1 -1
  86. package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
  87. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
  88. package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
  89. package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
  90. package/src/components/theme/Comments/Comment.stories.jsx +84 -0
  91. package/src/components/theme/Comments/Comments.jsx +273 -378
  92. package/src/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +37 -3
  93. package/src/components/theme/Login/Login.jsx +159 -241
  94. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
  95. package/src/components/theme/Logo/Logo.jsx +35 -29
  96. package/src/components/theme/Logo/Logo.test.jsx +135 -1
  97. package/src/components/theme/Logout/Logout.jsx +36 -83
  98. package/src/components/theme/Navigation/Navigation.jsx +86 -171
  99. package/src/components/theme/Search/SearchTags.jsx +30 -60
  100. package/src/components/theme/SearchWidget/SearchWidget.jsx +15 -3
  101. package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
  102. package/src/components/theme/Sitemap/Sitemap.jsx +24 -13
  103. package/src/components/theme/Sitemap/Sitemap.test.jsx +23 -2
  104. package/src/components/theme/View/View.jsx +2 -0
  105. package/src/config/ControlPanels.js +0 -1
  106. package/src/config/Widgets.jsx +2 -0
  107. package/src/config/index.js +15 -3
  108. package/src/constants/ActionTypes.js +4 -0
  109. package/src/express-middleware/images.js +1 -0
  110. package/src/helpers/MessageLabels/MessageLabels.js +26 -4
  111. package/src/helpers/Site/index.js +21 -0
  112. package/src/helpers/index.js +1 -0
  113. package/src/reducers/index.js +4 -0
  114. package/src/reducers/navroot/navroot.js +79 -0
  115. package/src/reducers/navroot/navroot.test.js +110 -0
  116. package/src/reducers/relations/relations.js +74 -46
  117. package/src/reducers/site/site.js +51 -0
  118. package/src/reducers/site/site.test.js +67 -0
  119. package/src/reducers/userSession/userSession.js +15 -1
  120. package/src/server.jsx +9 -0
  121. package/test-setup-config.js +1 -0
  122. package/theme/themes/pastanaga/collections/form.overrides +46 -0
  123. package/theme/themes/pastanaga/elements/input.overrides +10 -0
  124. package/theme/themes/pastanaga/elements/label.overrides +10 -0
  125. package/theme/themes/pastanaga/extras/login.less +3 -0
  126. package/webpack-plugins/webpack-less-plugin.js +19 -0
  127. package/.gitignore~ +0 -71
  128. package/news/4547.breaking~ +0 -1
  129. package/package.json~ +0 -444
  130. package/src/config/index.js~ +0 -223
@@ -1,71 +1,41 @@
1
- /**
2
- * Search tags components.
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
- * Search tags container class.
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
- * Render method.
41
- * @method render
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
- export default connect(
64
- (state) => ({
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
- { getVocabulary },
71
- )(SearchTags);
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;
@@ -1,8 +1,11 @@
1
- import { useState } from 'react';
1
+ import { useState, useEffect } from 'react';
2
2
  import { useHistory } from 'react-router-dom';
3
3
  import { Form, Input } from 'semantic-ui-react';
4
4
  import { defineMessages, useIntl } from 'react-intl';
5
+ import { useDispatch, useSelector } from 'react-redux';
5
6
 
7
+ import { getNavroot } from '@plone/volto/actions';
8
+ import { hasApiExpander, getBaseUrl } from '@plone/volto/helpers';
6
9
  import { Icon } from '@plone/volto/components';
7
10
  import zoomSVG from '@plone/volto/icons/zoom.svg';
8
11
 
@@ -19,6 +22,8 @@ const messages = defineMessages({
19
22
 
20
23
  const SearchWidget = (props) => {
21
24
  const intl = useIntl();
25
+ const dispatch = useDispatch();
26
+
22
27
  const [text, setText] = useState('');
23
28
  const history = useHistory();
24
29
  const onChangeText = (event, { value }) => {
@@ -29,14 +34,21 @@ const SearchWidget = (props) => {
29
34
  const path =
30
35
  pathname?.length > 0 ? `&path=${encodeURIComponent(pathname)}` : '';
31
36
 
32
- history.push(`/search?SearchableText=${encodeURIComponent(text)}${path}`);
37
+ history.push(`./search?SearchableText=${encodeURIComponent(text)}${path}`);
33
38
  // reset input value
34
39
  setText('');
35
40
  event.preventDefault();
36
41
  };
37
42
 
43
+ const navroot = useSelector((state) => state.navroot?.data);
44
+ useEffect(() => {
45
+ if (!hasApiExpander('navroot', getBaseUrl(pathname))) {
46
+ dispatch(getNavroot(getBaseUrl(pathname)));
47
+ }
48
+ }, [dispatch, pathname]);
49
+
38
50
  return (
39
- <Form action="/search" onSubmit={onSubmit}>
51
+ <Form action={`${navroot?.navroot?.['@id']}/search`} onSubmit={onSubmit}>
40
52
  <Form.Field className="searchbox">
41
53
  <Input
42
54
  aria-label={intl.formatMessage(messages.search)}
@@ -15,6 +15,14 @@ describe('SearchWidget', () => {
15
15
  locale: 'en',
16
16
  messages: {},
17
17
  },
18
+ navroot: {
19
+ data: {
20
+ '@id': 'http://localhost:3000/@navroot',
21
+ navroot: {
22
+ '@id': 'http://localhost:3000',
23
+ },
24
+ },
25
+ },
18
26
  });
19
27
  const component = renderer.create(
20
28
  <Provider store={store}>
@@ -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
- if (settings.isMultilingual) {
43
- this.props.getNavigation(`${toBackendLang(this.props.lang)}`, 4);
44
- } else {
45
- this.props.getNavigation('', 4);
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
- const lang = getState().intl.locale;
110
- if (settings.isMultilingual) {
111
- return (
112
- __SERVER__ && dispatch(getNavigation(`${toBackendLang(lang)}`, 4))
113
- );
114
- } else {
115
- return __SERVER__ && dispatch(getNavigation('', 4));
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
+ });
@@ -123,6 +123,7 @@ class View extends Component {
123
123
  if (!hasApiExpander('actions', getBaseUrl(this.props.pathname))) {
124
124
  this.props.listActions(getBaseUrl(this.props.pathname));
125
125
  }
126
+
126
127
  this.props.getContent(
127
128
  getBaseUrl(this.props.pathname),
128
129
  this.props.versionId,
@@ -142,6 +143,7 @@ class View extends Component {
142
143
  if (!hasApiExpander('actions', getBaseUrl(nextProps.pathname))) {
143
144
  this.props.listActions(getBaseUrl(nextProps.pathname));
144
145
  }
146
+
145
147
  this.props.getContent(
146
148
  getBaseUrl(nextProps.pathname),
147
149
  this.props.versionId,
@@ -75,7 +75,6 @@ export const filterControlPanelsSchema = (controlpanel) => {
75
75
  'toolbar_position',
76
76
  'toolbar_logo',
77
77
  'default_page',
78
- 'site_logo',
79
78
  'site_favicon',
80
79
  'site_favicon_mimetype',
81
80
  'exposeDCMetaTags',
@@ -24,6 +24,7 @@ import InternalUrlWidget from '@plone/volto/components/manage/Widgets/InternalUr
24
24
  import EmailWidget from '@plone/volto/components/manage/Widgets/EmailWidget';
25
25
  import NumberWidget from '@plone/volto/components/manage/Widgets/NumberWidget';
26
26
  import ImageSizeWidget from '@plone/volto/components/manage/Widgets/ImageSizeWidget';
27
+ import RegistryImageWidget from '@plone/volto/components/manage/Widgets/RegistryImageWidget';
27
28
 
28
29
  import ReferenceWidget from '@plone/volto/components/manage/Widgets/ReferenceWidget';
29
30
  import ObjectBrowserWidget from '@plone/volto/components/manage/Widgets/ObjectBrowserWidget';
@@ -72,6 +73,7 @@ export const widgetMapping = {
72
73
  recurrence: RecurrenceWidget,
73
74
  remoteUrl: UrlWidget,
74
75
  id: IdWidget,
76
+ site_logo: RegistryImageWidget,
75
77
  },
76
78
  widget: {
77
79
  richtext: WysiwygWidget,
@@ -37,6 +37,8 @@ import applyAddonConfiguration, { addonsInfo } from 'load-volto-addons';
37
37
 
38
38
  import ConfigRegistry from '@plone/volto/registry';
39
39
 
40
+ import { getSiteAsyncPropExtender } from '@plone/volto/helpers';
41
+
40
42
  const host = process.env.HOST || 'localhost';
41
43
  const port = process.env.PORT || '3000';
42
44
 
@@ -83,7 +85,13 @@ let config = {
83
85
  // https://6.docs.plone.org/volto/configuration/settings-reference.html#term-apiExpanders
84
86
  // {
85
87
  // match: '',
86
- // GET_CONTENT: ['breadcrumbs', 'navigation', 'actions', 'types'],
88
+ // GET_CONTENT: [
89
+ // 'breadcrumbs',
90
+ // 'navigation',
91
+ // 'actions',
92
+ // 'types',
93
+ // 'navroot',
94
+ // ],
87
95
  // },
88
96
  ],
89
97
  // Internal proxy to bypass CORS *while developing*. NOT intended for production use.
@@ -128,7 +136,7 @@ let config = {
128
136
  useEmailAsLogin: false,
129
137
  persistentReducers: ['blocksClipboard'],
130
138
  initialReducersBlacklist: [], // reducers in this list won't be hydrated in windows.__data
131
- asyncPropsExtenders: [], // per route asyncConnect customizers
139
+ asyncPropsExtenders: [getSiteAsyncPropExtender], // per route asyncConnect customizers
132
140
  contentIcons: contentIcons,
133
141
  loadables,
134
142
  lazyBundles: {
@@ -188,6 +196,10 @@ let config = {
188
196
  blockSettingsTabFieldsetsInitialStateOpen: true,
189
197
  excludeLinksAndReferencesMenuItem: false,
190
198
  containerBlockTypes: ['gridBlock'],
199
+ siteTitleFormat: {
200
+ includeSiteTitle: false,
201
+ titleAndSiteTitleSeparator: '-',
202
+ },
191
203
  },
192
204
  experimental: {
193
205
  addBlockButton: {
@@ -223,7 +235,7 @@ config.settings.apiExpanders = [
223
235
  ...config.settings.apiExpanders,
224
236
  {
225
237
  match: '',
226
- GET_CONTENT: ['breadcrumbs', 'actions', 'types'],
238
+ GET_CONTENT: ['breadcrumbs', 'actions', 'types', 'navroot'],
227
239
  },
228
240
  {
229
241
  match: '',
@@ -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';
@@ -137,3 +138,6 @@ export const REMOVE_ALIASES = 'REMOVE_ALIASES';
137
138
  export const GET_USERSCHEMA = 'GET_USERSCHEMA';
138
139
  export const GET_UPGRADE = 'GET_UPGRADE';
139
140
  export const POST_UPGRADE = 'POST_UPGRADE';
141
+ export const RESET_LOGIN_REQUEST = 'RESET_LOGIN_REQUEST';
142
+ export const GET_SITE = 'GET_SITE';
143
+ export const GET_NAVROOT = 'GET_NAVROOT';
@@ -28,6 +28,7 @@ export default function imagesMiddleware() {
28
28
 
29
29
  middleware.all(['**/@@images/*'], imageMiddlewareFn);
30
30
  middleware.all(['/@portrait/*'], imageMiddlewareFn);
31
+ middleware.all(['/@@site-logo/*'], imageMiddlewareFn);
31
32
  middleware.id = 'imageResourcesProcessor';
32
33
  return middleware;
33
34
  }
@@ -172,6 +172,28 @@ export const messages = defineMessages({
172
172
  id: 'Roles',
173
173
  defaultMessage: 'Roles',
174
174
  },
175
+ addUserFormPasswordAndSendPasswordTogetherNotAllowed: {
176
+ id:
177
+ 'It is not allowed to define both the password and to request sending the password reset message by e-mail. You need to select one of them.',
178
+ defaultMessage:
179
+ 'It is not allowed to define both the password and to request sending the password reset message by e-mail. You need to select one of them.',
180
+ },
181
+ userSearchNoResults: {
182
+ id: 'There are no users with the searched criteria',
183
+ defaultMessage: 'There are no users with the searched criteria',
184
+ },
185
+ groupSearchNoResults: {
186
+ id: 'There are no groups with the searched criteria',
187
+ defaultMessage: 'There are no groups with the searched criteria',
188
+ },
189
+ updateUserFormTitle: {
190
+ id: 'Update User',
191
+ defaultMessage: 'Update User',
192
+ },
193
+ updateUserSuccess: {
194
+ id: 'User updated successfuly',
195
+ defaultMessage: 'User updated successfuly',
196
+ },
175
197
  updateRoles: {
176
198
  id: 'User roles updated',
177
199
  defaultMessage: 'User roles updated',
@@ -234,19 +256,19 @@ export const messages = defineMessages({
234
256
  },
235
257
  copyBlocks: {
236
258
  id: 'Copy blocks',
237
- defaultMesages: 'Copy blocks',
259
+ defaultMessage: 'Copy blocks',
238
260
  },
239
261
  cutBlocks: {
240
262
  id: 'Cut blocks',
241
- defaultMesages: 'Cut blocks',
263
+ defaultMessage: 'Cut blocks',
242
264
  },
243
265
  pasteBlocks: {
244
266
  id: 'Paste blocks',
245
- defaultMesages: 'Paste blocks',
267
+ defaultMessage: 'Paste blocks',
246
268
  },
247
269
  deleteBlocks: {
248
270
  id: 'Delete blocks',
249
- defaultMesages: 'Delete blocks',
271
+ defaultMessage: 'Delete blocks',
250
272
  },
251
273
  showAllUserButton: {
252
274
  id: 'Show All',
@@ -0,0 +1,21 @@
1
+ import { GET_SITE } from '@plone/volto/constants/ActionTypes';
2
+ import { getSite } from '@plone/volto/actions';
3
+
4
+ const getSiteAsyncPropExtender = {
5
+ path: '/',
6
+ extend: (dispatchActions) => {
7
+ if (
8
+ dispatchActions.filter((asyncAction) => asyncAction.key === GET_SITE)
9
+ .length === 0
10
+ ) {
11
+ dispatchActions.push({
12
+ key: GET_SITE,
13
+ promise: ({ location, store: { dispatch } }) =>
14
+ __SERVER__ && dispatch(getSite()),
15
+ });
16
+ }
17
+ return dispatchActions;
18
+ },
19
+ };
20
+
21
+ export { getSiteAsyncPropExtender };
@@ -121,3 +121,4 @@ export {
121
121
  getCurrentStateMapping,
122
122
  getWorkflowOptions,
123
123
  } from './Workflows/Workflows';
124
+ export { getSiteAsyncPropExtender } from './Site';
@@ -50,6 +50,8 @@ import workingCopy from './workingcopy/workingcopy';
50
50
  import transactions from './transactions/transactions';
51
51
  import upgrade from './upgrade/upgrade';
52
52
  import userschema from './userschema/userschema';
53
+ import site from './site/site';
54
+ import navroot from './navroot/navroot';
53
55
 
54
56
  /**
55
57
  * Root reducer.
@@ -105,6 +107,8 @@ const reducers = {
105
107
  workingCopy,
106
108
  transactions,
107
109
  userschema,
110
+ site,
111
+ navroot,
108
112
  };
109
113
 
110
114
  export default reducers;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Navroot reducer.
3
+ * @module reducers/navroot/navroot
4
+ */
5
+ import {
6
+ flattenToAppURL,
7
+ getBaseUrl,
8
+ hasApiExpander,
9
+ } from '@plone/volto/helpers';
10
+
11
+ import { GET_NAVROOT, GET_CONTENT } from '@plone/volto/constants/ActionTypes';
12
+
13
+ const initialState = {
14
+ error: null,
15
+ loaded: false,
16
+ loading: false,
17
+ data: {},
18
+ };
19
+
20
+ /**
21
+ * navroot reducer.
22
+ * @function navroot
23
+ * @param {Object} state Current state.
24
+ * @param {Object} action Action to be handled.
25
+ * @returns {Object} New state.
26
+ */
27
+ export default function navroot(state = initialState, action = {}) {
28
+ let hasExpander;
29
+ switch (action.type) {
30
+ case `${GET_NAVROOT}_PENDING`:
31
+ return {
32
+ ...state,
33
+ error: null,
34
+ loaded: false,
35
+ loading: true,
36
+ data: {},
37
+ };
38
+ case `${GET_CONTENT}_SUCCESS`:
39
+ hasExpander = hasApiExpander(
40
+ 'navroot',
41
+ getBaseUrl(flattenToAppURL(action.result['@id'])),
42
+ );
43
+ if (hasExpander && !action.subrequest) {
44
+ return {
45
+ ...state,
46
+ error: null,
47
+ data: action.result['@components'].navroot,
48
+ loaded: true,
49
+ loading: false,
50
+ };
51
+ }
52
+ return state;
53
+ case `${GET_NAVROOT}_SUCCESS`:
54
+ hasExpander = hasApiExpander(
55
+ 'navroot',
56
+ getBaseUrl(flattenToAppURL(action.result['@id'])),
57
+ );
58
+ if (!hasExpander) {
59
+ return {
60
+ ...state,
61
+ error: null,
62
+ loaded: true,
63
+ loading: false,
64
+ data: action.result,
65
+ };
66
+ }
67
+ return state;
68
+ case `${GET_NAVROOT}_FAIL`:
69
+ return {
70
+ ...state,
71
+ error: action.result,
72
+ loaded: false,
73
+ loading: false,
74
+ data: {},
75
+ };
76
+ default:
77
+ return state;
78
+ }
79
+ }
@@ -0,0 +1,110 @@
1
+ import { GET_CONTENT, GET_NAVROOT } from '@plone/volto/constants/ActionTypes';
2
+ import config from '@plone/volto/registry';
3
+ import navroot from './navroot';
4
+
5
+ const { settings } = config;
6
+
7
+ describe('Navroot reducer', () => {
8
+ it('should return the initial state', () => {
9
+ expect(navroot()).toEqual({
10
+ error: null,
11
+ data: {},
12
+ loaded: false,
13
+ loading: false,
14
+ });
15
+ });
16
+
17
+ it('should handle GET_NAVROOT_PENDING', () => {
18
+ expect(
19
+ navroot(undefined, {
20
+ type: `${GET_NAVROOT}_PENDING`,
21
+ }),
22
+ ).toEqual({
23
+ error: null,
24
+ data: {},
25
+ loaded: false,
26
+ loading: true,
27
+ });
28
+ });
29
+
30
+ it('should handle GET_NAVROOT_SUCCESS', () => {
31
+ expect(
32
+ navroot(undefined, {
33
+ type: `${GET_NAVROOT}_SUCCESS`,
34
+ result: {
35
+ title: 'Welcome to Plone!',
36
+ description:
37
+ 'Congratulations! You have successfully installed Plone.',
38
+ '@id': `${settings.apiPath}/front-page`,
39
+ },
40
+ }),
41
+ ).toEqual({
42
+ error: null,
43
+ data: {
44
+ '@id': `${settings.apiPath}/front-page`,
45
+ title: 'Welcome to Plone!',
46
+ description: 'Congratulations! You have successfully installed Plone.',
47
+ },
48
+
49
+ loaded: true,
50
+ loading: false,
51
+ });
52
+ });
53
+
54
+ it('should handle GET_NAVROOT_FAIL', () => {
55
+ expect(
56
+ navroot(undefined, {
57
+ type: `${GET_NAVROOT}_FAIL`,
58
+ error: 'failed',
59
+ }),
60
+ ).toEqual({
61
+ error: undefined,
62
+ data: {},
63
+ loaded: false,
64
+ loading: false,
65
+ });
66
+ });
67
+ });
68
+
69
+ describe('Navroot reducer (NAVROOT)GET_CONTENT', () => {
70
+ beforeEach(() => {
71
+ config.settings.apiExpanders = [
72
+ {
73
+ match: '',
74
+ GET_CONTENT: ['navroot'],
75
+ },
76
+ ];
77
+ });
78
+
79
+ it('should handle (NAVROOT)GET_CONTENT_SUCCESS', () => {
80
+ expect(
81
+ navroot(undefined, {
82
+ type: `${GET_CONTENT}_SUCCESS`,
83
+ result: {
84
+ '@components': {
85
+ navroot: {
86
+ navroot: {
87
+ title: 'Welcome to Plone!',
88
+ description:
89
+ 'Congratulations! You have successfully installed Plone.',
90
+ '@id': `${settings.apiPath}/front-page`,
91
+ },
92
+ },
93
+ },
94
+ },
95
+ }),
96
+ ).toEqual({
97
+ error: null,
98
+ data: {
99
+ navroot: {
100
+ '@id': `${settings.apiPath}/front-page`,
101
+ title: 'Welcome to Plone!',
102
+ description:
103
+ 'Congratulations! You have successfully installed Plone.',
104
+ },
105
+ },
106
+ loaded: true,
107
+ loading: false,
108
+ });
109
+ });
110
+ });