@plone/volto 17.0.0-alpha.4 → 17.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.changelog.draft +20 -20
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +98 -13
- package/CONTRIBUTING.md +1 -1
- package/README.md +9 -12
- package/locales/de/LC_MESSAGES/volto.po +17 -17
- package/locales/de.json +1 -1
- package/package.json +3 -2
- package/packages/volto-slate/package.json +1 -1
- package/src/components/manage/Blocks/Listing/Edit.jsx +0 -14
- package/src/components/manage/Blocks/Listing/ListingBody.test.jsx +0 -20
- package/src/components/manage/Blocks/Listing/getAsyncData.js +10 -2
- package/src/components/manage/Blocks/Listing/withQuerystringResults.jsx +20 -14
- 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/hocs/withSearch.jsx +28 -19
- package/src/components/manage/Contents/Contents.jsx +29 -24
- package/src/components/manage/Controlpanels/Controlpanels.jsx +190 -224
- package/src/components/manage/Controlpanels/Controlpanels.test.jsx +46 -7
- package/src/components/manage/Form/InlineForm.jsx +39 -9
- package/src/components/manage/Form/InlineFormState.js +8 -0
- package/src/components/manage/Widgets/ObjectListWidget.jsx +3 -8
- package/src/components/theme/Icon/Icon.jsx +2 -2
- package/src/components/theme/Login/Login.jsx +1 -0
- package/src/config/index.js +1 -0
- package/src/express-middleware/sitemap.js +36 -3
- package/src/helpers/Robots/Robots.js +24 -6
- package/src/helpers/Sitemap/Sitemap.js +44 -2
- package/src/helpers/Url/Url.js +8 -3
- package/src/helpers/Url/Url.test.js +14 -0
- package/src/helpers/Utils/Utils.js +17 -4
- package/src/helpers/Utils/usePagination.js +14 -48
- package/src/helpers/index.js +2 -0
- package/src/middleware/Api.test.js +54 -0
- package/src/middleware/api.js +1 -1
- package/test-setup-config.js +1 -0
- package/theme/themes/pastanaga/extras/sidebar.less +4 -0
- package/src/helpers/Utils/usePagination.test.js +0 -115
|
@@ -114,15 +114,19 @@ function normalizeState({
|
|
|
114
114
|
block: id,
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
);
|
|
117
|
+
// Note Ideally the searchtext functionality should be restructured as being just
|
|
118
|
+
// another facet. But right now it's the same. This means that if a searchText
|
|
119
|
+
// is provided, it will override the SearchableText facet.
|
|
120
|
+
// If there is no searchText, the SearchableText in the query remains in effect.
|
|
121
|
+
// TODO eventually the searchText should be a distinct facet from SearchableText, and
|
|
122
|
+
// the two conditions could be combined, in comparison to the current state, when
|
|
123
|
+
// one overrides the other.
|
|
125
124
|
if (searchText) {
|
|
125
|
+
params.query = params.query.reduce(
|
|
126
|
+
// Remove SearchableText from query
|
|
127
|
+
(acc, kvp) => (kvp.i === 'SearchableText' ? acc : [...acc, kvp]),
|
|
128
|
+
[],
|
|
129
|
+
);
|
|
126
130
|
params.query.push({
|
|
127
131
|
i: 'SearchableText',
|
|
128
132
|
o: 'plone.app.querystring.operation.string.contains',
|
|
@@ -144,16 +148,12 @@ const getSearchFields = (searchData) => {
|
|
|
144
148
|
};
|
|
145
149
|
|
|
146
150
|
/**
|
|
147
|
-
* A
|
|
151
|
+
* A HOC that will mirror the search block state to a hash location
|
|
148
152
|
*/
|
|
149
153
|
const useHashState = () => {
|
|
150
154
|
const location = useLocation();
|
|
151
155
|
const history = useHistory();
|
|
152
156
|
|
|
153
|
-
/**
|
|
154
|
-
* Required to maintain parameter compatibility.
|
|
155
|
-
With this we will maintain support for receiving hash (#) and search (?) type parameters.
|
|
156
|
-
*/
|
|
157
157
|
const oldState = React.useMemo(() => {
|
|
158
158
|
return {
|
|
159
159
|
...qs.parse(location.search),
|
|
@@ -169,7 +169,7 @@ const useHashState = () => {
|
|
|
169
169
|
|
|
170
170
|
const setSearchData = React.useCallback(
|
|
171
171
|
(searchData) => {
|
|
172
|
-
const newParams = qs.parse(location.
|
|
172
|
+
const newParams = qs.parse(location.hash);
|
|
173
173
|
|
|
174
174
|
let changed = false;
|
|
175
175
|
|
|
@@ -186,11 +186,11 @@ const useHashState = () => {
|
|
|
186
186
|
|
|
187
187
|
if (changed) {
|
|
188
188
|
history.push({
|
|
189
|
-
|
|
189
|
+
hash: qs.stringify(newParams),
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
},
|
|
193
|
-
[history, oldState, location.
|
|
193
|
+
[history, oldState, location.hash],
|
|
194
194
|
);
|
|
195
195
|
|
|
196
196
|
return [current, setSearchData];
|
|
@@ -282,8 +282,14 @@ const withSearch = (options) => (WrappedComponent) => {
|
|
|
282
282
|
const timeoutRef = React.useRef();
|
|
283
283
|
const facetSettings = data?.facets;
|
|
284
284
|
|
|
285
|
+
const deepQuery = JSON.stringify(data.query);
|
|
285
286
|
const onTriggerSearch = React.useCallback(
|
|
286
|
-
(
|
|
287
|
+
(
|
|
288
|
+
toSearchText = undefined,
|
|
289
|
+
toSearchFacets = undefined,
|
|
290
|
+
toSortOn = undefined,
|
|
291
|
+
toSortOrder = undefined,
|
|
292
|
+
) => {
|
|
287
293
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
288
294
|
timeoutRef.current = setTimeout(
|
|
289
295
|
() => {
|
|
@@ -291,7 +297,7 @@ const withSearch = (options) => (WrappedComponent) => {
|
|
|
291
297
|
id,
|
|
292
298
|
query: data.query || {},
|
|
293
299
|
facets: toSearchFacets || facets,
|
|
294
|
-
searchText: toSearchText,
|
|
300
|
+
searchText: toSearchText || searchText,
|
|
295
301
|
sortOn: toSortOn || sortOn,
|
|
296
302
|
sortOrder: toSortOrder || sortOrder,
|
|
297
303
|
facetSettings,
|
|
@@ -305,11 +311,14 @@ const withSearch = (options) => (WrappedComponent) => {
|
|
|
305
311
|
toSearchFacets ? inputDelay / 3 : inputDelay,
|
|
306
312
|
);
|
|
307
313
|
},
|
|
314
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
308
315
|
[
|
|
309
|
-
data.query
|
|
316
|
+
// Use deep comparison of data.query
|
|
317
|
+
deepQuery,
|
|
310
318
|
facets,
|
|
311
319
|
id,
|
|
312
320
|
setLocationSearchData,
|
|
321
|
+
searchText,
|
|
313
322
|
sortOn,
|
|
314
323
|
sortOrder,
|
|
315
324
|
facetSettings,
|
|
@@ -796,18 +796,20 @@ class Contents extends Component {
|
|
|
796
796
|
*/
|
|
797
797
|
onMoveToTop(event, { value }) {
|
|
798
798
|
const id = this.state.items[value]['@id'];
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
799
|
+
this.props
|
|
800
|
+
.orderContent(
|
|
801
|
+
getBaseUrl(this.props.pathname),
|
|
802
|
+
id.replace(/^.*\//, ''),
|
|
803
|
+
'top',
|
|
804
|
+
)
|
|
805
|
+
.then(() => {
|
|
806
|
+
this.setState(
|
|
807
|
+
{
|
|
808
|
+
currentPage: 0,
|
|
809
|
+
},
|
|
810
|
+
() => this.fetchContents(),
|
|
811
|
+
);
|
|
812
|
+
});
|
|
811
813
|
}
|
|
812
814
|
|
|
813
815
|
/**
|
|
@@ -818,18 +820,21 @@ class Contents extends Component {
|
|
|
818
820
|
* @returns {undefined}
|
|
819
821
|
*/
|
|
820
822
|
onMoveToBottom(event, { value }) {
|
|
821
|
-
this.
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
823
|
+
const id = this.state.items[value]['@id'];
|
|
824
|
+
this.props
|
|
825
|
+
.orderContent(
|
|
826
|
+
getBaseUrl(this.props.pathname),
|
|
827
|
+
id.replace(/^.*\//, ''),
|
|
828
|
+
'bottom',
|
|
829
|
+
)
|
|
830
|
+
.then(() => {
|
|
831
|
+
this.setState(
|
|
832
|
+
{
|
|
833
|
+
currentPage: 0,
|
|
834
|
+
},
|
|
835
|
+
() => this.fetchContents(),
|
|
836
|
+
);
|
|
837
|
+
});
|
|
833
838
|
}
|
|
834
839
|
|
|
835
840
|
/**
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
* @module components/manage/Controlpanels/Controlpanels
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import React, { Component } from 'react';
|
|
7
6
|
import PropTypes from 'prop-types';
|
|
7
|
+
import { useState, useEffect } from 'react';
|
|
8
8
|
import { connect } from 'react-redux';
|
|
9
9
|
import { compose } from 'redux';
|
|
10
10
|
import { Link } from 'react-router-dom';
|
|
11
11
|
import { concat, filter, last, map, uniqBy } from 'lodash';
|
|
12
12
|
import { Portal } from 'react-portal';
|
|
13
|
-
import { Helmet } from '@plone/volto/helpers';
|
|
13
|
+
import { asyncConnect, Helmet } from '@plone/volto/helpers';
|
|
14
14
|
import { Container, Grid, Header, Message, Segment } from 'semantic-ui-react';
|
|
15
|
-
import { FormattedMessage, defineMessages,
|
|
15
|
+
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
16
16
|
|
|
17
17
|
import { listControlpanels, getSystemInformation } from '@plone/volto/actions';
|
|
18
18
|
import { Error, Icon, Toolbar, VersionOverview } from '@plone/volto/components';
|
|
@@ -94,185 +94,126 @@ const messages = defineMessages({
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Controlpanels container class.
|
|
97
|
-
* @class Controlpanels
|
|
98
|
-
* @extends Component
|
|
99
97
|
*/
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
controlpanels: PropTypes.arrayOf(
|
|
109
|
-
PropTypes.shape({
|
|
110
|
-
'@id': PropTypes.string,
|
|
111
|
-
group: PropTypes.string,
|
|
112
|
-
title: PropTypes.string,
|
|
113
|
-
}),
|
|
114
|
-
).isRequired,
|
|
115
|
-
pathname: PropTypes.string.isRequired,
|
|
116
|
-
};
|
|
98
|
+
function Controlpanels({
|
|
99
|
+
controlpanels,
|
|
100
|
+
controlpanelsRequest,
|
|
101
|
+
systemInformation,
|
|
102
|
+
pathname,
|
|
103
|
+
}) {
|
|
104
|
+
const intl = useIntl();
|
|
105
|
+
const [isClient, setIsClient] = useState(false);
|
|
117
106
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
* @param {Object} props Component properties
|
|
122
|
-
* @constructs EditComponent
|
|
123
|
-
*/
|
|
124
|
-
constructor(props) {
|
|
125
|
-
super(props);
|
|
126
|
-
this.state = {
|
|
127
|
-
error: null,
|
|
128
|
-
isClient: false,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
setIsClient(true);
|
|
109
|
+
}, []);
|
|
131
110
|
|
|
132
|
-
|
|
133
|
-
* Component did mount
|
|
134
|
-
* @method componentDidMount
|
|
135
|
-
* @returns {undefined}
|
|
136
|
-
*/
|
|
137
|
-
componentDidMount() {
|
|
138
|
-
this.props.listControlpanels();
|
|
139
|
-
this.props.getSystemInformation();
|
|
140
|
-
this.setState({ isClient: true });
|
|
141
|
-
}
|
|
111
|
+
const error = controlpanelsRequest?.error;
|
|
142
112
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
this.props.controlpanelsRequest.loading &&
|
|
147
|
-
nextProps.controlpanelsRequest.error
|
|
148
|
-
) {
|
|
149
|
-
this.setState({
|
|
150
|
-
error: nextProps.controlpanelsRequest.error,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
113
|
+
if (error) {
|
|
114
|
+
return <Error error={error} />;
|
|
153
115
|
}
|
|
154
116
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
117
|
+
let customcontrolpanels = config.settings.controlpanels
|
|
118
|
+
? config.settings.controlpanels.map((el) => {
|
|
119
|
+
el.group =
|
|
120
|
+
intl.formatMessage({
|
|
121
|
+
id: el.group,
|
|
122
|
+
defaultMessage: el.group,
|
|
123
|
+
}) || el.group;
|
|
124
|
+
return el;
|
|
125
|
+
})
|
|
126
|
+
: [];
|
|
127
|
+
const { filterControlPanels } = config.settings;
|
|
165
128
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
group: this.props.intl.formatMessage(
|
|
222
|
-
messages.usersControlPanelCategory,
|
|
223
|
-
),
|
|
224
|
-
title: this.props.intl.formatMessage(
|
|
225
|
-
messages.usergroupmemberbership,
|
|
226
|
-
),
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
'@id': '/groups',
|
|
230
|
-
group: this.props.intl.formatMessage(
|
|
231
|
-
messages.usersControlPanelCategory,
|
|
232
|
-
),
|
|
233
|
-
title: this.props.intl.formatMessage(messages.groups),
|
|
234
|
-
},
|
|
235
|
-
],
|
|
236
|
-
),
|
|
237
|
-
(controlpanel) => ({
|
|
238
|
-
...controlpanel,
|
|
239
|
-
id: last(controlpanel['@id'].split('/')),
|
|
240
|
-
}),
|
|
241
|
-
);
|
|
242
|
-
const groups = map(uniqBy(controlpanels, 'group'), 'group');
|
|
243
|
-
const { controlPanelsIcons: icons } = config.settings;
|
|
129
|
+
const filteredControlPanels = map(
|
|
130
|
+
concat(filterControlPanels(controlpanels), customcontrolpanels, [
|
|
131
|
+
{
|
|
132
|
+
'@id': '/addons',
|
|
133
|
+
group: intl.formatMessage(messages.general),
|
|
134
|
+
title: intl.formatMessage(messages.addons),
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
'@id': '/database',
|
|
138
|
+
group: intl.formatMessage(messages.general),
|
|
139
|
+
title: intl.formatMessage(messages.database),
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
'@id': '/rules',
|
|
143
|
+
group: intl.formatMessage(messages.content),
|
|
144
|
+
title: intl.formatMessage(messages.contentRules),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
'@id': '/undo',
|
|
148
|
+
group: intl.formatMessage(messages.general),
|
|
149
|
+
title: intl.formatMessage(messages.undo),
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
'@id': '/aliases',
|
|
153
|
+
group: intl.formatMessage(messages.general),
|
|
154
|
+
title: intl.formatMessage(messages.urlmanagement),
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
'@id': '/moderate-comments',
|
|
158
|
+
group: intl.formatMessage(messages.content),
|
|
159
|
+
title: intl.formatMessage(messages.moderatecomments),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
'@id': '/users',
|
|
163
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
164
|
+
title: intl.formatMessage(messages.users),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
'@id': '/usergroupmembership',
|
|
168
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
169
|
+
title: intl.formatMessage(messages.usergroupmemberbership),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
'@id': '/groups',
|
|
173
|
+
group: intl.formatMessage(messages.usersControlPanelCategory),
|
|
174
|
+
title: intl.formatMessage(messages.groups),
|
|
175
|
+
},
|
|
176
|
+
]),
|
|
177
|
+
(controlpanel) => ({
|
|
178
|
+
...controlpanel,
|
|
179
|
+
id: last(controlpanel['@id'].split('/')),
|
|
180
|
+
}),
|
|
181
|
+
);
|
|
182
|
+
const groups = map(uniqBy(filteredControlPanels, 'group'), 'group');
|
|
183
|
+
const { controlPanelsIcons: icons } = config.settings;
|
|
244
184
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
{
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
<Grid
|
|
274
|
-
|
|
275
|
-
|
|
185
|
+
return (
|
|
186
|
+
<div className="view-wrapper">
|
|
187
|
+
<Helmet title={intl.formatMessage(messages.sitesetup)} />
|
|
188
|
+
<Container className="controlpanel">
|
|
189
|
+
<Segment.Group raised>
|
|
190
|
+
<Segment className="primary">
|
|
191
|
+
<FormattedMessage id="Site Setup" defaultMessage="Site Setup" />
|
|
192
|
+
</Segment>
|
|
193
|
+
{systemInformation && systemInformation.upgrade && (
|
|
194
|
+
<Message attached warning>
|
|
195
|
+
<FormattedMessage
|
|
196
|
+
id="The site configuration is outdated and needs to be upgraded."
|
|
197
|
+
defaultMessage="The site configuration is outdated and needs to be upgraded."
|
|
198
|
+
/>{' '}
|
|
199
|
+
<Link to={`/controlpanel/plone-upgrade`}>
|
|
200
|
+
<FormattedMessage
|
|
201
|
+
id="Please continue with the upgrade."
|
|
202
|
+
defaultMessage="Please continue with the upgrade."
|
|
203
|
+
/>
|
|
204
|
+
</Link>
|
|
205
|
+
</Message>
|
|
206
|
+
)}
|
|
207
|
+
{map(groups, (group) => [
|
|
208
|
+
<Segment key={`header-${group}`} secondary>
|
|
209
|
+
{group}
|
|
210
|
+
</Segment>,
|
|
211
|
+
<Segment key={`body-${group}`} attached>
|
|
212
|
+
<Grid doubling columns={6}>
|
|
213
|
+
<Grid.Row>
|
|
214
|
+
{map(
|
|
215
|
+
filter(filteredControlPanels, { group }),
|
|
216
|
+
(controlpanel) => (
|
|
276
217
|
<Grid.Column key={controlpanel.id}>
|
|
277
218
|
<Link to={`/controlpanel/${controlpanel.id}`}>
|
|
278
219
|
<Header as="h3" icon textAlign="center">
|
|
@@ -286,58 +227,83 @@ class Controlpanels extends Component {
|
|
|
286
227
|
</Header>
|
|
287
228
|
</Link>
|
|
288
229
|
</Grid.Column>
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
</Grid>
|
|
292
|
-
</
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
</Segment>
|
|
302
|
-
<Segment attached>
|
|
303
|
-
{this.props.systemInformation ? (
|
|
304
|
-
<VersionOverview {...this.props.systemInformation} />
|
|
305
|
-
) : null}
|
|
306
|
-
</Segment>
|
|
307
|
-
</Segment.Group>
|
|
308
|
-
</Container>
|
|
309
|
-
{this.state.isClient && (
|
|
310
|
-
<Portal node={document.getElementById('toolbar')}>
|
|
311
|
-
<Toolbar
|
|
312
|
-
pathname={this.props.pathname}
|
|
313
|
-
hideDefaultViewButtons
|
|
314
|
-
inner={
|
|
315
|
-
<Link to="/" className="item">
|
|
316
|
-
<Icon
|
|
317
|
-
name={backSVG}
|
|
318
|
-
className="contents circled"
|
|
319
|
-
size="30px"
|
|
320
|
-
title={this.props.intl.formatMessage(messages.back)}
|
|
321
|
-
/>
|
|
322
|
-
</Link>
|
|
323
|
-
}
|
|
230
|
+
),
|
|
231
|
+
)}
|
|
232
|
+
</Grid.Row>
|
|
233
|
+
</Grid>
|
|
234
|
+
</Segment>,
|
|
235
|
+
])}
|
|
236
|
+
</Segment.Group>
|
|
237
|
+
<Segment.Group raised>
|
|
238
|
+
<Segment className="primary">
|
|
239
|
+
<FormattedMessage
|
|
240
|
+
id="Version Overview"
|
|
241
|
+
defaultMessage="Version Overview"
|
|
324
242
|
/>
|
|
325
|
-
</
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
243
|
+
</Segment>
|
|
244
|
+
<Segment attached>
|
|
245
|
+
{systemInformation ? (
|
|
246
|
+
<VersionOverview {...systemInformation} />
|
|
247
|
+
) : null}
|
|
248
|
+
</Segment>
|
|
249
|
+
</Segment.Group>
|
|
250
|
+
</Container>
|
|
251
|
+
{isClient && (
|
|
252
|
+
<Portal node={document.getElementById('toolbar')}>
|
|
253
|
+
<Toolbar
|
|
254
|
+
pathname={pathname}
|
|
255
|
+
hideDefaultViewButtons
|
|
256
|
+
inner={
|
|
257
|
+
<Link to="/" className="item">
|
|
258
|
+
<Icon
|
|
259
|
+
name={backSVG}
|
|
260
|
+
className="contents circled"
|
|
261
|
+
size="30px"
|
|
262
|
+
title={intl.formatMessage(messages.back)}
|
|
263
|
+
/>
|
|
264
|
+
</Link>
|
|
265
|
+
}
|
|
266
|
+
/>
|
|
267
|
+
</Portal>
|
|
268
|
+
)}
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
330
271
|
}
|
|
331
272
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Property types.
|
|
275
|
+
* @property {Object} propTypes Property types.
|
|
276
|
+
* @static
|
|
277
|
+
*/
|
|
278
|
+
Controlpanels.propTypes = {
|
|
279
|
+
controlpanels: PropTypes.arrayOf(
|
|
280
|
+
PropTypes.shape({
|
|
281
|
+
'@id': PropTypes.string,
|
|
282
|
+
group: PropTypes.string,
|
|
283
|
+
title: PropTypes.string,
|
|
340
284
|
}),
|
|
341
|
-
|
|
342
|
-
|
|
285
|
+
).isRequired,
|
|
286
|
+
pathname: PropTypes.string.isRequired,
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
export default compose(
|
|
290
|
+
connect((state, props) => ({
|
|
291
|
+
controlpanels: state.controlpanels.controlpanels,
|
|
292
|
+
controlpanelsRequest: state.controlpanels.list,
|
|
293
|
+
pathname: props.location.pathname,
|
|
294
|
+
systemInformation: state.controlpanels.systeminformation,
|
|
295
|
+
})),
|
|
296
|
+
|
|
297
|
+
asyncConnect([
|
|
298
|
+
{
|
|
299
|
+
key: 'controlpanels',
|
|
300
|
+
promise: async ({ location, store: { dispatch } }) =>
|
|
301
|
+
await dispatch(listControlpanels()),
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
key: 'systemInformation',
|
|
305
|
+
promise: async ({ location, store: { dispatch } }) =>
|
|
306
|
+
await dispatch(getSystemInformation()),
|
|
307
|
+
},
|
|
308
|
+
]),
|
|
343
309
|
)(Controlpanels);
|