@plone/volto 17.0.0-alpha.25 → 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 (95) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/CHANGELOG.md +52 -5
  3. package/README.md +8 -7
  4. package/cypress/support/commands.js +12 -9
  5. package/cypress.config.js +1 -0
  6. package/locales/ca/LC_MESSAGES/volto.po +36 -15
  7. package/locales/ca.json +1 -1
  8. package/locales/de/LC_MESSAGES/volto.po +36 -15
  9. package/locales/de.json +1 -1
  10. package/locales/en/LC_MESSAGES/volto.po +35 -14
  11. package/locales/en.json +1 -1
  12. package/locales/es/LC_MESSAGES/volto.po +65 -44
  13. package/locales/es.json +1 -1
  14. package/locales/eu/LC_MESSAGES/volto.po +35 -14
  15. package/locales/eu.json +1 -1
  16. package/locales/fi/LC_MESSAGES/volto.po +35 -14
  17. package/locales/fi.json +1 -1
  18. package/locales/fr/LC_MESSAGES/volto.po +36 -15
  19. package/locales/fr.json +1 -1
  20. package/locales/it/LC_MESSAGES/volto.po +35 -14
  21. package/locales/it.json +1 -1
  22. package/locales/ja/LC_MESSAGES/volto.po +35 -14
  23. package/locales/ja.json +1 -1
  24. package/locales/nl/LC_MESSAGES/volto.po +36 -15
  25. package/locales/nl.json +1 -1
  26. package/locales/pt/LC_MESSAGES/volto.po +36 -15
  27. package/locales/pt.json +1 -1
  28. package/locales/pt_BR/LC_MESSAGES/volto.po +35 -14
  29. package/locales/pt_BR.json +1 -1
  30. package/locales/ro/LC_MESSAGES/volto.po +36 -15
  31. package/locales/ro.json +1 -1
  32. package/locales/volto.pot +35 -14
  33. package/locales/zh_CN/LC_MESSAGES/volto.po +36 -15
  34. package/locales/zh_CN.json +1 -1
  35. package/package.json +4 -4
  36. package/packages/volto-slate/package.json +1 -1
  37. package/packages/volto-slate/src/editor/render.jsx +2 -3
  38. package/src/actions/index.js +3 -0
  39. package/src/actions/navroot/navroot.js +16 -0
  40. package/src/actions/navroot/navroot.test.js +15 -0
  41. package/src/actions/site/site.js +16 -0
  42. package/src/actions/site/site.test.js +15 -0
  43. package/src/actions/userSession/userSession.js +17 -1
  44. package/src/components/manage/Blocks/Block/Settings.jsx +2 -0
  45. package/src/components/manage/Blocks/Block/Settings.test.jsx +90 -0
  46. package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +1 -1
  47. package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +42 -25
  48. package/src/components/manage/Blocks/ToC/View.jsx +75 -13
  49. package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +2 -12
  50. package/src/components/manage/Controlpanels/Groups/GroupsControlpanel.jsx +65 -38
  51. package/src/components/manage/Controlpanels/Rules/AddRule.jsx +1 -1
  52. package/src/components/manage/Controlpanels/Rules/EditRule.jsx +1 -1
  53. package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +95 -5
  54. package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +116 -103
  55. package/src/components/manage/Form/BlockDataForm.jsx +3 -2
  56. package/src/components/manage/Form/BlockDataForm.test.jsx +34 -2
  57. package/src/components/manage/LinksToItem/LinksToItem.test.jsx +4 -1
  58. package/src/components/manage/Messages/Messages.jsx +32 -99
  59. package/src/components/manage/Messages/Messages.test.jsx +0 -1
  60. package/src/components/manage/Sharing/Sharing.jsx +39 -16
  61. package/src/components/manage/UniversalLink/UniversalLink.jsx +4 -6
  62. package/src/components/manage/Widgets/ArrayWidget.jsx +3 -1
  63. package/src/components/manage/Widgets/ArrayWidget.test.jsx +45 -1
  64. package/src/components/manage/Widgets/RegistryImageWidget.jsx +210 -0
  65. package/src/components/manage/Widgets/RegistryImageWidget.test.jsx +91 -0
  66. package/src/components/manage/Widgets/SelectWidget.jsx +15 -1
  67. package/src/components/manage/Widgets/SelectWidget.test.jsx +45 -1
  68. package/src/components/theme/ContentMetadataTags/ContentMetadataTags.jsx +37 -3
  69. package/src/components/theme/Login/Login.jsx +159 -241
  70. package/src/components/theme/Logo/Logo.Multilingual.test.jsx +131 -1
  71. package/src/components/theme/Logo/Logo.jsx +35 -29
  72. package/src/components/theme/Logo/Logo.test.jsx +135 -1
  73. package/src/components/theme/Logout/Logout.jsx +1 -1
  74. package/src/components/theme/Navigation/Navigation.jsx +86 -171
  75. package/src/components/theme/SearchWidget/SearchWidget.jsx +15 -3
  76. package/src/components/theme/SearchWidget/SearchWidget.test.jsx +8 -0
  77. package/src/components/theme/View/View.jsx +2 -0
  78. package/src/config/ControlPanels.js +0 -1
  79. package/src/config/Widgets.jsx +2 -0
  80. package/src/config/index.js +15 -3
  81. package/src/constants/ActionTypes.js +3 -0
  82. package/src/express-middleware/images.js +1 -0
  83. package/src/helpers/MessageLabels/MessageLabels.js +26 -4
  84. package/src/helpers/Site/index.js +21 -0
  85. package/src/helpers/index.js +1 -0
  86. package/src/reducers/index.js +4 -0
  87. package/src/reducers/navroot/navroot.js +79 -0
  88. package/src/reducers/navroot/navroot.test.js +110 -0
  89. package/src/reducers/site/site.js +51 -0
  90. package/src/reducers/site/site.test.js +67 -0
  91. package/src/reducers/userSession/userSession.js +15 -1
  92. package/test-setup-config.js +1 -0
  93. package/theme/themes/pastanaga/elements/input.overrides +5 -1
  94. package/theme/themes/pastanaga/extras/login.less +3 -0
  95. package/webpack-plugins/webpack-less-plugin.js +19 -0
@@ -2,25 +2,18 @@
2
2
  * Logo component.
3
3
  * @module components/theme/Logo/Logo
4
4
  */
5
-
6
- import { defineMessages, useIntl } from 'react-intl';
5
+ import { useEffect } from 'react';
7
6
  import { Image } from 'semantic-ui-react';
8
- import { useSelector } from 'react-redux';
9
- import config from '@plone/volto/registry';
10
- import { UniversalLink } from '@plone/volto/components';
11
- import { toBackendLang } from '@plone/volto/helpers';
7
+ import { ConditionalLink } from '@plone/volto/components';
12
8
  import LogoImage from '@plone/volto/components/theme/Logo/Logo.svg';
13
-
14
- const messages = defineMessages({
15
- site: {
16
- id: 'Site',
17
- defaultMessage: 'Site',
18
- },
19
- plonesite: {
20
- id: 'Plone Site',
21
- defaultMessage: 'Plone Site',
22
- },
23
- });
9
+ import { useSelector, useDispatch } from 'react-redux';
10
+ import { getNavroot } from '@plone/volto/actions';
11
+ import {
12
+ flattenToAppURL,
13
+ hasApiExpander,
14
+ getBaseUrl,
15
+ toPublicURL,
16
+ } from '@plone/volto/helpers';
24
17
 
25
18
  /**
26
19
  * Logo component class.
@@ -29,23 +22,36 @@ const messages = defineMessages({
29
22
  * @returns {string} Markup of the component.
30
23
  */
31
24
  const Logo = () => {
32
- const { settings } = config;
33
- const lang = useSelector((state) => state.intl.locale);
34
- const intl = useIntl();
25
+ const pathname = useSelector((state) => state.router.location.pathname);
26
+ const site = useSelector((state) => state.site.data);
27
+ const navroot = useSelector((state) => state.navroot.data);
28
+ const dispatch = useDispatch();
29
+
30
+ useEffect(() => {
31
+ if (pathname && !hasApiExpander('navroot', getBaseUrl(pathname))) {
32
+ dispatch(getNavroot(getBaseUrl(pathname)));
33
+ }
34
+ }, [dispatch, pathname]);
35
+
36
+ // remove trailing slash
37
+ const currentURL = toPublicURL(pathname).replace(/\/$/, '');
35
38
 
36
39
  return (
37
- <UniversalLink
38
- href={settings.isMultilingual ? `/${toBackendLang(lang)}` : '/'}
39
- title={intl.formatMessage(messages.site)}
40
+ <ConditionalLink
41
+ href={navroot?.navroot?.['@id']}
42
+ title={navroot?.navroot?.title}
43
+ condition={currentURL !== navroot?.navroot?.['@id']}
40
44
  >
41
45
  <Image
42
- src={LogoImage}
43
- alt={intl.formatMessage(messages.plonesite)}
44
- title={intl.formatMessage(messages.plonesite)}
45
- width="158.2"
46
- height="40.7"
46
+ src={
47
+ site['plone.site_logo']
48
+ ? flattenToAppURL(site['plone.site_logo'])
49
+ : LogoImage
50
+ }
51
+ alt={navroot?.navroot?.title}
52
+ title={navroot?.navroot?.title}
47
53
  />
48
- </UniversalLink>
54
+ </ConditionalLink>
49
55
  );
50
56
  };
51
57
 
@@ -4,17 +4,151 @@ 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 config from '@plone/volto/registry';
8
+
7
9
  import Logo from './Logo';
8
10
 
9
11
  const mockStore = configureStore();
10
12
 
13
+ beforeAll(() => {
14
+ config.settings.publicURL = 'http://localhost:3000';
15
+ });
16
+
11
17
  describe('Logo', () => {
12
- it('renders a logo component', () => {
18
+ it('renders a logo component with default config', () => {
19
+ const store = mockStore({
20
+ intl: {
21
+ locale: 'en',
22
+ messages: {},
23
+ },
24
+ navroot: {
25
+ data: {
26
+ id: 'http://localhost:3000/@navroot',
27
+ navroot: {
28
+ '@id': 'http://localhost:3000',
29
+ title: 'Plone Site',
30
+ },
31
+ },
32
+ },
33
+ router: {
34
+ location: {
35
+ pathname: '/',
36
+ },
37
+ },
38
+ site: {
39
+ data: {},
40
+ },
41
+ });
42
+ const component = renderer.create(
43
+ <Provider store={store}>
44
+ <MemoryRouter>
45
+ <Logo />
46
+ </MemoryRouter>
47
+ </Provider>,
48
+ );
49
+ const json = component.toJSON();
50
+ expect(json).toMatchSnapshot();
51
+ });
52
+ it('renders a logo component with a custom logo', () => {
13
53
  const store = mockStore({
14
54
  intl: {
15
55
  locale: 'en',
16
56
  messages: {},
17
57
  },
58
+ navroot: {
59
+ data: {
60
+ id: 'http://localhost:3000/@navroot',
61
+ navroot: {
62
+ '@id': 'http://localhost:3000',
63
+ title: 'Plone Site',
64
+ },
65
+ },
66
+ },
67
+ router: {
68
+ location: {
69
+ pathname: '/',
70
+ },
71
+ },
72
+ site: {
73
+ data: {
74
+ 'plone.site_logo':
75
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
76
+ },
77
+ },
78
+ });
79
+ const component = renderer.create(
80
+ <Provider store={store}>
81
+ <MemoryRouter>
82
+ <Logo />
83
+ </MemoryRouter>
84
+ </Provider>,
85
+ );
86
+ const json = component.toJSON();
87
+ expect(json).toMatchSnapshot();
88
+ });
89
+ it('renders a logo component with default config in a non-root url', () => {
90
+ const store = mockStore({
91
+ intl: {
92
+ locale: 'en',
93
+ messages: {},
94
+ },
95
+ navroot: {
96
+ data: {
97
+ id: 'http://localhost:3000/@navroot',
98
+ navroot: {
99
+ '@id': 'http://localhost:3000',
100
+ title: 'Plone Site',
101
+ },
102
+ },
103
+ },
104
+ router: {
105
+ location: {
106
+ pathname: '/some-page',
107
+ },
108
+ },
109
+ site: {
110
+ data: {
111
+ 'plone.site_logo':
112
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
113
+ },
114
+ },
115
+ });
116
+ const component = renderer.create(
117
+ <Provider store={store}>
118
+ <MemoryRouter>
119
+ <Logo />
120
+ </MemoryRouter>
121
+ </Provider>,
122
+ );
123
+ const json = component.toJSON();
124
+ expect(json).toMatchSnapshot();
125
+ });
126
+ it('renders a logo component with a custom logo in a non-root url', () => {
127
+ const store = mockStore({
128
+ intl: {
129
+ locale: 'en',
130
+ messages: {},
131
+ },
132
+ navroot: {
133
+ data: {
134
+ id: 'http://localhost:3000/@navroot',
135
+ navroot: {
136
+ '@id': 'http://localhost:3000',
137
+ title: 'Plone Site',
138
+ },
139
+ },
140
+ },
141
+ router: {
142
+ location: {
143
+ pathname: '/some-page',
144
+ },
145
+ },
146
+ site: {
147
+ data: {
148
+ 'plone.site_logo':
149
+ 'http://localhost:3000/@@site-logo/logo.cab945d8.svg',
150
+ },
151
+ },
18
152
  });
19
153
  const component = renderer.create(
20
154
  <Provider store={store}>
@@ -55,7 +55,7 @@ const Logout = ({ location }) => {
55
55
  }
56
56
  }, [history, returnUrl, intl, token]);
57
57
 
58
- return <Login location={{ query: location.query }} />;
58
+ return <Login location={{ query: location.query }} isLogout={true} />;
59
59
  };
60
60
 
61
61
  export default Logout;
@@ -1,14 +1,9 @@
1
- /**
2
- * Navigation components.
3
- * @module components/theme/Navigation/Navigation
4
- */
5
-
6
- import React, { Component } from 'react';
1
+ import { useEffect, useState } from 'react';
7
2
  import PropTypes from 'prop-types';
8
- import { connect } from 'react-redux';
9
- import { compose } from 'redux';
10
- import { defineMessages, injectIntl } from 'react-intl';
3
+ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
4
+ import { defineMessages, useIntl } from 'react-intl';
11
5
  import { Menu } from 'semantic-ui-react';
6
+
12
7
  import cx from 'classnames';
13
8
  import { BodyClass, getBaseUrl, hasApiExpander } from '@plone/volto/helpers';
14
9
  import config from '@plone/volto/registry';
@@ -27,176 +22,96 @@ const messages = defineMessages({
27
22
  },
28
23
  });
29
24
 
30
- /**
31
- * Navigation container class.
32
- * @class Navigation
33
- * @extends Component
34
- */
35
- class Navigation extends Component {
36
- /**
37
- * Property types.
38
- * @property {Object} propTypes Property types.
39
- * @static
40
- */
41
- static propTypes = {
42
- getNavigation: PropTypes.func.isRequired,
43
- pathname: PropTypes.string.isRequired,
44
- items: PropTypes.arrayOf(
45
- PropTypes.shape({
46
- title: PropTypes.string,
47
- url: PropTypes.string,
48
- }),
49
- ).isRequired,
50
- lang: PropTypes.string.isRequired,
51
- };
52
-
53
- static defaultProps = {
54
- token: null,
55
- };
56
-
57
- /**
58
- * Constructor
59
- * @method constructor
60
- * @param {Object} props Component properties
61
- * @constructs Navigation
62
- */
63
- constructor(props) {
64
- super(props);
65
- this.toggleMobileMenu = this.toggleMobileMenu.bind(this);
66
- this.closeMobileMenu = this.closeMobileMenu.bind(this);
67
- this.state = {
68
- isMobileMenuOpen: false,
69
- };
70
- }
25
+ const Navigation = (props) => {
26
+ const intl = useIntl();
27
+ const dispatch = useDispatch();
28
+ const { pathname, type } = props;
29
+ const [isMobileMenuOpen, setisMobileMenuOpen] = useState(false);
30
+ const token = useSelector((state) => state.userSession.token, shallowEqual);
31
+ const items = useSelector((state) => state.navigation.items, shallowEqual);
32
+ const lang = useSelector((state) => state.intl.locale);
71
33
 
72
- componentDidMount() {
34
+ useEffect(() => {
73
35
  const { settings } = config;
74
- if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
75
- this.props.getNavigation(
76
- getBaseUrl(this.props.pathname),
77
- settings.navDepth,
78
- );
36
+ if (!hasApiExpander('navigation', getBaseUrl(pathname))) {
37
+ dispatch(getNavigation(getBaseUrl(pathname), settings.navDepth));
79
38
  }
80
- }
39
+ }, [pathname, token, dispatch]);
81
40
 
82
- /**
83
- * Component will receive props
84
- * @method componentWillReceiveProps
85
- * @param {Object} nextProps Next properties
86
- * @returns {undefined}
87
- */
88
- UNSAFE_componentWillReceiveProps(nextProps) {
89
- const { settings } = config;
90
- if (
91
- nextProps.pathname !== this.props.pathname ||
92
- nextProps.token !== this.props.token
93
- ) {
94
- if (!hasApiExpander('navigation', getBaseUrl(this.props.pathname))) {
95
- this.props.getNavigation(
96
- getBaseUrl(nextProps.pathname),
97
- settings.navDepth,
98
- );
99
- }
100
- }
101
- }
102
-
103
- /**
104
- * Toggle mobile menu's open state
105
- * @method toggleMobileMenu
106
- * @returns {undefined}
107
- */
108
- toggleMobileMenu() {
109
- this.setState({ isMobileMenuOpen: !this.state.isMobileMenuOpen });
110
- }
41
+ const toggleMobileMenu = () => {
42
+ setisMobileMenuOpen(!isMobileMenuOpen);
43
+ };
111
44
 
112
- /**
113
- * Close mobile menu
114
- * @method closeMobileMenu
115
- * @returns {undefined}
116
- */
117
- closeMobileMenu() {
118
- if (!this.state.isMobileMenuOpen) {
45
+ const closeMobileMenu = () => {
46
+ if (!isMobileMenuOpen) {
119
47
  return;
120
48
  }
121
- this.setState({ isMobileMenuOpen: false });
122
- }
49
+ setisMobileMenuOpen(false);
50
+ };
123
51
 
124
- /**
125
- * Render method.
126
- * @method render
127
- * @returns {string} Markup for the component.
128
- */
129
- render() {
130
- return (
131
- <nav className="navigation" id="navigation" aria-label="navigation">
132
- <div className="hamburger-wrapper mobile tablet only">
133
- <button
134
- className={cx('hamburger hamburger--spin', {
135
- 'is-active': this.state.isMobileMenuOpen,
136
- })}
137
- aria-label={
138
- this.state.isMobileMenuOpen
139
- ? this.props.intl.formatMessage(messages.closeMobileMenu, {
140
- type: this.props.type,
141
- })
142
- : this.props.intl.formatMessage(messages.openMobileMenu, {
143
- type: this.props.type,
144
- })
145
- }
146
- title={
147
- this.state.isMobileMenuOpen
148
- ? this.props.intl.formatMessage(messages.closeMobileMenu, {
149
- type: this.props.type,
150
- })
151
- : this.props.intl.formatMessage(messages.openMobileMenu, {
152
- type: this.props.type,
153
- })
154
- }
155
- type="button"
156
- onClick={this.toggleMobileMenu}
157
- >
158
- <span className="hamburger-box">
159
- <span className="hamburger-inner" />
160
- </span>
161
- </button>
162
- </div>
163
- <Menu
164
- stackable
165
- pointing
166
- secondary
167
- className="computer large screen widescreen only"
168
- onClick={this.closeMobileMenu}
52
+ return (
53
+ <nav className="navigation" id="navigation" aria-label="navigation">
54
+ <div className="hamburger-wrapper mobile tablet only">
55
+ <button
56
+ className={cx('hamburger hamburger--spin', {
57
+ 'is-active': isMobileMenuOpen,
58
+ })}
59
+ aria-label={
60
+ isMobileMenuOpen
61
+ ? intl.formatMessage(messages.closeMobileMenu, {
62
+ type: type,
63
+ })
64
+ : intl.formatMessage(messages.openMobileMenu, {
65
+ type: type,
66
+ })
67
+ }
68
+ title={
69
+ isMobileMenuOpen
70
+ ? intl.formatMessage(messages.closeMobileMenu, {
71
+ type: type,
72
+ })
73
+ : intl.formatMessage(messages.openMobileMenu, {
74
+ type: type,
75
+ })
76
+ }
77
+ type="button"
78
+ onClick={toggleMobileMenu}
169
79
  >
170
- <NavItems items={this.props.items} lang={this.props.lang} />
171
- </Menu>
172
- <CSSTransition
173
- in={this.state.isMobileMenuOpen}
174
- timeout={500}
175
- classNames="mobile-menu"
176
- unmountOnExit
177
- >
178
- <div key="mobile-menu-key" className="mobile-menu">
179
- <BodyClass className="has-mobile-menu-open" />
180
- <div className="mobile-menu-nav">
181
- <Menu stackable pointing secondary onClick={this.closeMobileMenu}>
182
- <NavItems items={this.props.items} lang={this.props.lang} />
183
- </Menu>
184
- </div>
80
+ <span className="hamburger-box">
81
+ <span className="hamburger-inner" />
82
+ </span>
83
+ </button>
84
+ </div>
85
+ <Menu
86
+ stackable
87
+ pointing
88
+ secondary
89
+ className="computer large screen widescreen only"
90
+ onClick={closeMobileMenu}
91
+ >
92
+ <NavItems items={items} lang={lang} />
93
+ </Menu>
94
+ <CSSTransition
95
+ in={isMobileMenuOpen}
96
+ timeout={500}
97
+ classNames="mobile-menu"
98
+ unmountOnExit
99
+ >
100
+ <div key="mobile-menu-key" className="mobile-menu">
101
+ <BodyClass className="has-mobile-menu-open" />
102
+ <div className="mobile-menu-nav">
103
+ <Menu stackable pointing secondary onClick={closeMobileMenu}>
104
+ <NavItems items={items} lang={lang} />
105
+ </Menu>
185
106
  </div>
186
- </CSSTransition>
187
- </nav>
188
- );
189
- }
190
- }
107
+ </div>
108
+ </CSSTransition>
109
+ </nav>
110
+ );
111
+ };
112
+
113
+ Navigation.propTypes = {
114
+ pathname: PropTypes.string.isRequired,
115
+ };
191
116
 
192
- export default compose(
193
- injectIntl,
194
- connect(
195
- (state) => ({
196
- token: state.userSession.token,
197
- items: state.navigation.items,
198
- lang: state.intl.locale,
199
- }),
200
- { getNavigation },
201
- ),
202
- )(Navigation);
117
+ export default Navigation;
@@ -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}>
@@ -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: '',