@plone/volto 16.22.0 → 16.22.1
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 +15 -22
- package/.gitignore~ +71 -0
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +27 -1
- package/locales/ca/LC_MESSAGES/volto.po +37 -2
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +38 -3
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +37 -2
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +37 -2
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +37 -2
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +37 -2
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +37 -2
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +228 -193
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +37 -2
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +37 -2
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +37 -2
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +37 -2
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +37 -2
- package/locales/ro.json +1 -1
- package/locales/volto.pot +38 -3
- package/locales/volto.pot~ +4705 -0
- package/locales/zh_CN/LC_MESSAGES/volto.po +37 -2
- package/locales/zh_CN.json +1 -1
- package/news/4547.breaking~ +1 -0
- package/package.json +1 -1
- package/package.json~ +444 -0
- package/packages/volto-slate/package.json +1 -1
- package/src/components/manage/Blocks/Image/schema.js +5 -1
- package/src/components/manage/Blocks/Search/components/SearchInput.jsx +9 -2
- package/src/components/manage/Blocks/Search/hocs/withSearch.jsx +12 -1
- package/src/components/manage/Blocks/ToC/Schema.jsx +36 -7
- package/src/components/manage/Contents/ContentsPropertiesModal.jsx +1 -13
- package/src/components/manage/Controlpanels/Groups/RenderGroups.jsx +2 -2
- package/src/components/manage/Controlpanels/Users/RenderUsers.jsx +2 -2
- package/src/components/manage/Controlpanels/Users/UsersControlpanel.jsx +25 -10
- package/src/components/manage/Widgets/SelectUtils.js +1 -1
- package/src/components/theme/Error/ServerError.jsx +29 -0
- package/src/config/Views.jsx +2 -0
- package/src/config/index.js~ +223 -0
- package/src/express-middleware/files.js +8 -6
- package/src/express-middleware/images.js +7 -1
- package/src/middleware/api.js +14 -2
- package/src/reducers/actions/actions.js +7 -5
- package/src/reducers/actions/actions.test.js +70 -0
- package/src/server.jsx +9 -0
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +0 -90
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +0 -6
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +0 -6
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +0 -10
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +0 -30
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +0 -10
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +0 -6
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +0 -6
- package/pyvenv.cfg +0 -3
- package/share/man/man1/ttx.1 +0 -225
|
@@ -107,6 +107,7 @@ class UsersControlpanel extends Component {
|
|
|
107
107
|
isClient: false,
|
|
108
108
|
currentPage: 0,
|
|
109
109
|
pageSize: 10,
|
|
110
|
+
loginUsingEmail: false,
|
|
110
111
|
};
|
|
111
112
|
}
|
|
112
113
|
|
|
@@ -122,6 +123,14 @@ class UsersControlpanel extends Component {
|
|
|
122
123
|
}
|
|
123
124
|
};
|
|
124
125
|
|
|
126
|
+
// Because username field needs to be disabled if email login is enabled!
|
|
127
|
+
checkLoginUsingEmailStatus = async () => {
|
|
128
|
+
await this.props.getControlpanel('security');
|
|
129
|
+
this.setState({
|
|
130
|
+
loginUsingEmail: this.props.controlPanelData?.data.use_email_as_login,
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
125
134
|
/**
|
|
126
135
|
* Component did mount
|
|
127
136
|
* @method componentDidMount
|
|
@@ -132,6 +141,7 @@ class UsersControlpanel extends Component {
|
|
|
132
141
|
isClient: true,
|
|
133
142
|
});
|
|
134
143
|
this.fetchData();
|
|
144
|
+
this.checkLoginUsingEmailStatus();
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
@@ -425,7 +435,7 @@ class UsersControlpanel extends Component {
|
|
|
425
435
|
id: 'default',
|
|
426
436
|
title: 'FIXME: User Data',
|
|
427
437
|
fields: [
|
|
428
|
-
'username',
|
|
438
|
+
...(!this.state.loginUsingEmail ? ['username'] : []),
|
|
429
439
|
'fullname',
|
|
430
440
|
'email',
|
|
431
441
|
'password',
|
|
@@ -436,15 +446,19 @@ class UsersControlpanel extends Component {
|
|
|
436
446
|
},
|
|
437
447
|
],
|
|
438
448
|
properties: {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
449
|
+
...(!this.state.loginUsingEmail
|
|
450
|
+
? {
|
|
451
|
+
username: {
|
|
452
|
+
title: this.props.intl.formatMessage(
|
|
453
|
+
messages.addUserFormUsernameTitle,
|
|
454
|
+
),
|
|
455
|
+
type: 'string',
|
|
456
|
+
description: this.props.intl.formatMessage(
|
|
457
|
+
messages.addUserFormUsernameDescription,
|
|
458
|
+
),
|
|
459
|
+
},
|
|
460
|
+
}
|
|
461
|
+
: {}),
|
|
448
462
|
fullname: {
|
|
449
463
|
title: this.props.intl.formatMessage(
|
|
450
464
|
messages.addUserFormFullnameTitle,
|
|
@@ -670,6 +684,7 @@ export default compose(
|
|
|
670
684
|
createRequest: state.users.create,
|
|
671
685
|
loadRolesRequest: state.roles,
|
|
672
686
|
inheritedRole: state.authRole.authenticatedRole,
|
|
687
|
+
controlPanelData: state.controlpanels?.controlpanel,
|
|
673
688
|
}),
|
|
674
689
|
(dispatch) =>
|
|
675
690
|
bindActionCreators(
|
|
@@ -111,7 +111,7 @@ export function normalizeValue(choices, value, intl) {
|
|
|
111
111
|
|
|
112
112
|
if (Array.isArray(value)) {
|
|
113
113
|
// a list of values, like ['foo', 'bar'];
|
|
114
|
-
return value.map((v) => normalizeValue(choices, v));
|
|
114
|
+
return value.map((v) => normalizeValue(choices, v, intl));
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
if (isObject(value)) {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module components/theme/Error/ServerError
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { FormattedMessage } from 'react-intl';
|
|
7
|
+
import { Container } from 'semantic-ui-react';
|
|
8
|
+
import { withServerErrorCode } from '@plone/volto/helpers/Utils/Utils';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* server error
|
|
12
|
+
* @function ServerError
|
|
13
|
+
* @returns {string} Markup of the server error page.
|
|
14
|
+
*/
|
|
15
|
+
const ServerError = () => (
|
|
16
|
+
<Container className="view-wrapper">
|
|
17
|
+
<h1>
|
|
18
|
+
<FormattedMessage id="Server Error" defaultMessage="Server Error" />
|
|
19
|
+
</h1>
|
|
20
|
+
<p className="description">
|
|
21
|
+
<FormattedMessage
|
|
22
|
+
id="We apologize for the inconvenience, but there was an unexpected error on the server."
|
|
23
|
+
defaultMessage="We apologize for the inconvenience, but there was an unexpected error on the server."
|
|
24
|
+
/>
|
|
25
|
+
</p>
|
|
26
|
+
</Container>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default withServerErrorCode(500)(ServerError);
|
package/src/config/Views.jsx
CHANGED
|
@@ -16,6 +16,7 @@ import RequestTimeout from '@plone/volto/components/theme/RequestTimeout/Request
|
|
|
16
16
|
import AlbumView from '@plone/volto/components/theme/View/AlbumView';
|
|
17
17
|
import Unauthorized from '@plone/volto/components/theme/Unauthorized/Unauthorized';
|
|
18
18
|
import Forbidden from '@plone/volto/components/theme/Forbidden/Forbidden';
|
|
19
|
+
import ServerError from '@plone/volto/components/theme/Error/ServerError';
|
|
19
20
|
|
|
20
21
|
const EventView = loadable(() =>
|
|
21
22
|
import('@plone/volto/components/theme/View/EventView'),
|
|
@@ -114,6 +115,7 @@ export const errorViews = {
|
|
|
114
115
|
'401': Unauthorized,
|
|
115
116
|
'403': Forbidden,
|
|
116
117
|
'408': RequestTimeout,
|
|
118
|
+
'500': ServerError,
|
|
117
119
|
ECONNREFUSED: ConnectionRefused,
|
|
118
120
|
corsError: CorsError,
|
|
119
121
|
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config.
|
|
3
|
+
* @module config
|
|
4
|
+
*/
|
|
5
|
+
import { parse as parseUrl } from 'url';
|
|
6
|
+
import { defaultWidget, widgetMapping } from './Widgets';
|
|
7
|
+
import {
|
|
8
|
+
layoutViews,
|
|
9
|
+
contentTypesViews,
|
|
10
|
+
defaultView,
|
|
11
|
+
errorViews,
|
|
12
|
+
layoutViewsNamesMapping,
|
|
13
|
+
} from './Views';
|
|
14
|
+
import { nonContentRoutes } from './NonContentRoutes';
|
|
15
|
+
import {
|
|
16
|
+
groupBlocksOrder,
|
|
17
|
+
requiredBlocks,
|
|
18
|
+
blocksConfig,
|
|
19
|
+
initialBlocks,
|
|
20
|
+
initialBlocksFocus,
|
|
21
|
+
} from './Blocks';
|
|
22
|
+
import { components } from './Components';
|
|
23
|
+
import { loadables } from './Loadables';
|
|
24
|
+
import { workflowMapping } from './Workflows';
|
|
25
|
+
|
|
26
|
+
import { contentIcons } from './ContentIcons';
|
|
27
|
+
import { styleClassNameConverters, styleClassNameExtenders } from './Style';
|
|
28
|
+
import {
|
|
29
|
+
controlPanelsIcons,
|
|
30
|
+
filterControlPanels,
|
|
31
|
+
filterControlPanelsSchema,
|
|
32
|
+
} from './ControlPanels';
|
|
33
|
+
|
|
34
|
+
import { richtextEditorSettings, richtextViewSettings } from './RichTextEditor';
|
|
35
|
+
|
|
36
|
+
import applyAddonConfiguration, { addonsInfo } from 'load-volto-addons';
|
|
37
|
+
|
|
38
|
+
import ConfigRegistry from '@plone/volto/registry';
|
|
39
|
+
|
|
40
|
+
const host = process.env.HOST || 'localhost';
|
|
41
|
+
const port = process.env.PORT || '3000';
|
|
42
|
+
|
|
43
|
+
const apiPath =
|
|
44
|
+
process.env.RAZZLE_API_PATH ||
|
|
45
|
+
(__DEVELOPMENT__ ? `http://${host}:${port}` : '');
|
|
46
|
+
|
|
47
|
+
const getServerURL = (url) => {
|
|
48
|
+
if (!url) return;
|
|
49
|
+
const apiPathURL = parseUrl(url);
|
|
50
|
+
return `${apiPathURL.protocol}//${apiPathURL.hostname}${
|
|
51
|
+
apiPathURL.port ? `:${apiPathURL.port}` : ''
|
|
52
|
+
}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Sensible defaults for publicURL
|
|
56
|
+
// if RAZZLE_PUBLIC_URL is present, use it
|
|
57
|
+
// if in DEV, use the host/port combination by default
|
|
58
|
+
// if in PROD, assume it's RAZZLE_API_PATH server name (no /api or alikes) or fallback
|
|
59
|
+
// to DEV settings if RAZZLE_API_PATH is not present
|
|
60
|
+
const publicURL =
|
|
61
|
+
process.env.RAZZLE_PUBLIC_URL ||
|
|
62
|
+
(__DEVELOPMENT__
|
|
63
|
+
? `http://${host}:${port}`
|
|
64
|
+
: getServerURL(process.env.RAZZLE_API_PATH) || `http://${host}:${port}`);
|
|
65
|
+
|
|
66
|
+
const serverConfig =
|
|
67
|
+
typeof __SERVER__ !== 'undefined' && __SERVER__
|
|
68
|
+
? require('./server').default
|
|
69
|
+
: {};
|
|
70
|
+
|
|
71
|
+
let config = {
|
|
72
|
+
settings: {
|
|
73
|
+
host,
|
|
74
|
+
port,
|
|
75
|
+
// The URL Volto is going to be served (see sensible defaults above)
|
|
76
|
+
publicURL,
|
|
77
|
+
apiPath,
|
|
78
|
+
apiExpanders: [
|
|
79
|
+
// Add the following expanders for only issuing a single request.
|
|
80
|
+
// https://6.docs.plone.org/volto/configuration/settings-reference.html#term-apiExpanders
|
|
81
|
+
// {
|
|
82
|
+
// match: '',
|
|
83
|
+
// GET_CONTENT: ['breadcrumbs', 'navigation', 'actions', 'types'],
|
|
84
|
+
// },
|
|
85
|
+
],
|
|
86
|
+
// Internal proxy to bypass CORS *while developing*. NOT intended for production use.
|
|
87
|
+
// In production is recommended you use a Seamless mode deployment using a web server in
|
|
88
|
+
// front of both the frontend and the backend so you can bypass CORS safely.
|
|
89
|
+
// https://6.docs.plone.org/volto/deploying/seamless-mode.html
|
|
90
|
+
devProxyToApiPath:
|
|
91
|
+
process.env.RAZZLE_DEV_PROXY_API_PATH ||
|
|
92
|
+
process.env.RAZZLE_INTERNAL_API_PATH ||
|
|
93
|
+
process.env.RAZZLE_API_PATH ||
|
|
94
|
+
'http://localhost:8080/Plone', // Set it to '' for disabling the proxy
|
|
95
|
+
// proxyRewriteTarget Set it for set a custom target for the proxy or overide the internal VHM rewrite
|
|
96
|
+
// proxyRewriteTarget: '/VirtualHostBase/http/localhost:8080/Plone/VirtualHostRoot/_vh_api'
|
|
97
|
+
// proxyRewriteTarget: 'https://myvoltositeinproduction.com'
|
|
98
|
+
proxyRewriteTarget: process.env.RAZZLE_PROXY_REWRITE_TARGET || undefined,
|
|
99
|
+
// apiPath: process.env.RAZZLE_API_PATH || 'http://localhost:8000', // for Volto reference
|
|
100
|
+
// apiPath: process.env.RAZZLE_API_PATH || 'http://localhost:8081/db/web', // for guillotina
|
|
101
|
+
actions_raising_api_errors: ['GET_CONTENT', 'UPDATE_CONTENT'],
|
|
102
|
+
internalApiPath: process.env.RAZZLE_INTERNAL_API_PATH || undefined,
|
|
103
|
+
websockets: process.env.RAZZLE_WEBSOCKETS || false,
|
|
104
|
+
// TODO: legacyTraverse to be removed when the use of the legacy traverse is deprecated.
|
|
105
|
+
legacyTraverse: process.env.RAZZLE_LEGACY_TRAVERSE || false,
|
|
106
|
+
cookieExpires: 15552000, //in seconds. Default is 6 month (15552000)
|
|
107
|
+
nonContentRoutes,
|
|
108
|
+
richtextEditorSettings, // Part of draftjs support, to be removed
|
|
109
|
+
richtextViewSettings, // Part of draftjs support, to be removed
|
|
110
|
+
imageObjects: ['Image'],
|
|
111
|
+
reservedIds: ['login', 'layout', 'plone', 'zip', 'properties'],
|
|
112
|
+
downloadableObjects: ['File'], //list of content-types for which the direct download of the file will be carried out if the user is not authenticated
|
|
113
|
+
viewableInBrowserObjects: [], //ex: ['File']. List of content-types for which the file will be displayed in browser if the user is not authenticated
|
|
114
|
+
listingPreviewImageField: 'image', // deprecated from Volto 14 onwards
|
|
115
|
+
openExternalLinkInNewTab: false,
|
|
116
|
+
notSupportedBrowsers: ['ie'],
|
|
117
|
+
defaultPageSize: 25,
|
|
118
|
+
isMultilingual: false,
|
|
119
|
+
supportedLanguages: ['en'],
|
|
120
|
+
defaultLanguage: 'en',
|
|
121
|
+
navDepth: 1,
|
|
122
|
+
expressMiddleware: serverConfig.expressMiddleware, // BBB
|
|
123
|
+
defaultBlockType: 'slate',
|
|
124
|
+
verticalFormTabs: false,
|
|
125
|
+
useEmailAsLogin: false,
|
|
126
|
+
persistentReducers: ['blocksClipboard'],
|
|
127
|
+
initialReducersBlacklist: [], // reducers in this list won't be hydrated in windows.__data
|
|
128
|
+
asyncPropsExtenders: [], // per route asyncConnect customizers
|
|
129
|
+
contentIcons: contentIcons,
|
|
130
|
+
loadables,
|
|
131
|
+
lazyBundles: {
|
|
132
|
+
cms: [
|
|
133
|
+
'prettierStandalone',
|
|
134
|
+
'prettierParserHtml',
|
|
135
|
+
'prismCore',
|
|
136
|
+
'toastify',
|
|
137
|
+
'reactSelect',
|
|
138
|
+
'reactBeautifulDnd',
|
|
139
|
+
// 'diffLib',
|
|
140
|
+
],
|
|
141
|
+
draftEditor: [
|
|
142
|
+
'immutableLib',
|
|
143
|
+
'draftJs',
|
|
144
|
+
'draftJsLibIsSoftNewlineEvent',
|
|
145
|
+
'draftJsFilters',
|
|
146
|
+
'draftJsInlineToolbarPlugin',
|
|
147
|
+
'draftJsImportHtml',
|
|
148
|
+
'draftJsBlockBreakoutPlugin',
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
appExtras: [],
|
|
152
|
+
maxResponseSize: 2000000000, // This is superagent default (200 mb)
|
|
153
|
+
serverConfig,
|
|
154
|
+
storeExtenders: [],
|
|
155
|
+
showTags: true,
|
|
156
|
+
controlpanels: [],
|
|
157
|
+
controlPanelsIcons,
|
|
158
|
+
filterControlPanels,
|
|
159
|
+
filterControlPanelsSchema,
|
|
160
|
+
externalRoutes: [
|
|
161
|
+
// URL to be considered as external
|
|
162
|
+
// {
|
|
163
|
+
// match: {
|
|
164
|
+
// path: '/news',
|
|
165
|
+
// exact: false,
|
|
166
|
+
// strict: false,
|
|
167
|
+
// },
|
|
168
|
+
// url(payload) {
|
|
169
|
+
// return payload.location.pathname;
|
|
170
|
+
// },
|
|
171
|
+
// },
|
|
172
|
+
],
|
|
173
|
+
showSelfRegistration: false,
|
|
174
|
+
contentMetadataTagsImageField: 'image',
|
|
175
|
+
hasWorkingCopySupport: false,
|
|
176
|
+
maxUndoLevels: 200, // undo history size for the main form
|
|
177
|
+
addonsInfo: addonsInfo,
|
|
178
|
+
workflowMapping,
|
|
179
|
+
errorHandlers: [], // callables for unhandled errors
|
|
180
|
+
styleClassNameConverters,
|
|
181
|
+
hashLinkSmoothScroll: false,
|
|
182
|
+
styleClassNameExtenders,
|
|
183
|
+
querystringSearchGet: false,
|
|
184
|
+
},
|
|
185
|
+
experimental: {
|
|
186
|
+
addBlockButton: {
|
|
187
|
+
enabled: false,
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
widgets: {
|
|
191
|
+
...widgetMapping,
|
|
192
|
+
default: defaultWidget,
|
|
193
|
+
},
|
|
194
|
+
views: {
|
|
195
|
+
layoutViews,
|
|
196
|
+
contentTypesViews,
|
|
197
|
+
defaultView,
|
|
198
|
+
errorViews,
|
|
199
|
+
layoutViewsNamesMapping,
|
|
200
|
+
},
|
|
201
|
+
blocks: {
|
|
202
|
+
requiredBlocks,
|
|
203
|
+
blocksConfig,
|
|
204
|
+
groupBlocksOrder,
|
|
205
|
+
initialBlocks,
|
|
206
|
+
initialBlocksFocus,
|
|
207
|
+
showEditBlocksInBabelView: false,
|
|
208
|
+
},
|
|
209
|
+
addonRoutes: [],
|
|
210
|
+
addonReducers: {},
|
|
211
|
+
components,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
ConfigRegistry.settings = config.settings;
|
|
215
|
+
ConfigRegistry.experimental = config.experimental;
|
|
216
|
+
ConfigRegistry.blocks = config.blocks;
|
|
217
|
+
ConfigRegistry.views = config.views;
|
|
218
|
+
ConfigRegistry.widgets = config.widgets;
|
|
219
|
+
ConfigRegistry.addonRoutes = config.addonRoutes;
|
|
220
|
+
ConfigRegistry.addonReducers = config.addonReducers;
|
|
221
|
+
ConfigRegistry.components = config.components;
|
|
222
|
+
|
|
223
|
+
applyAddonConfiguration(ConfigRegistry);
|
|
@@ -2,11 +2,13 @@ import express from 'express';
|
|
|
2
2
|
import { getAPIResourceWithAuth } from '@plone/volto/helpers';
|
|
3
3
|
|
|
4
4
|
const HEADERS = [
|
|
5
|
-
'
|
|
6
|
-
'
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
5
|
+
'accept-ranges',
|
|
6
|
+
'cache-control',
|
|
7
|
+
'content-disposition',
|
|
8
|
+
'content-range',
|
|
9
|
+
'content-type',
|
|
10
|
+
'x-sendfile',
|
|
11
|
+
'x-accel-redirect',
|
|
10
12
|
];
|
|
11
13
|
|
|
12
14
|
function filesMiddlewareFn(req, res, next) {
|
|
@@ -14,7 +16,7 @@ function filesMiddlewareFn(req, res, next) {
|
|
|
14
16
|
.then((resource) => {
|
|
15
17
|
// Just forward the headers that we need
|
|
16
18
|
HEADERS.forEach((header) => {
|
|
17
|
-
if (resource.
|
|
19
|
+
if (resource.headers[header]) {
|
|
18
20
|
res.set(header, resource.get(header));
|
|
19
21
|
}
|
|
20
22
|
});
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import { getAPIResourceWithAuth } from '@plone/volto/helpers';
|
|
3
3
|
|
|
4
|
-
const HEADERS = [
|
|
4
|
+
const HEADERS = [
|
|
5
|
+
'content-type',
|
|
6
|
+
'content-disposition',
|
|
7
|
+
'cache-control',
|
|
8
|
+
'x-sendfile',
|
|
9
|
+
'x-accel-redirect',
|
|
10
|
+
];
|
|
5
11
|
|
|
6
12
|
function imageMiddlewareFn(req, res, next) {
|
|
7
13
|
getAPIResourceWithAuth(req)
|
package/src/middleware/api.js
CHANGED
|
@@ -250,10 +250,22 @@ const apiMiddlewareFactory = (api) => ({ dispatch, getState }) => (next) => (
|
|
|
250
250
|
};
|
|
251
251
|
});
|
|
252
252
|
}
|
|
253
|
-
|
|
253
|
+
try {
|
|
254
|
+
return next({ ...rest, result, type: `${type}_SUCCESS` });
|
|
255
|
+
} catch (error) {
|
|
256
|
+
// There was an exception while processing reducers or downstream middleware.
|
|
257
|
+
next({
|
|
258
|
+
...rest,
|
|
259
|
+
error: { status: 500, error },
|
|
260
|
+
type: `${type}_FAIL`,
|
|
261
|
+
});
|
|
262
|
+
// Rethrow the original exception on the client side only,
|
|
263
|
+
// so it doesn't fall through to express on the server.
|
|
264
|
+
if (__CLIENT__) throw error;
|
|
265
|
+
}
|
|
254
266
|
},
|
|
255
267
|
(error) => {
|
|
256
|
-
// Only
|
|
268
|
+
// Only SSR can set ECONNREFUSED
|
|
257
269
|
if (error.code === 'ECONNREFUSED') {
|
|
258
270
|
next({
|
|
259
271
|
...rest,
|
|
@@ -57,11 +57,13 @@ export default function actions(state = initialState, action = {}) {
|
|
|
57
57
|
}
|
|
58
58
|
return state;
|
|
59
59
|
case `${LIST_ACTIONS}_SUCCESS`:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
64
|
-
|
|
60
|
+
// Even if the expander is set or not, if the LIST_ACTIONS is
|
|
61
|
+
// called, we want it to store the data if the actions data is
|
|
62
|
+
// not set in the expander data (['@components']) but in the "normal"
|
|
63
|
+
// action result (we look for the object property returned by the endpoint)
|
|
64
|
+
// Unfortunately, this endpoint returns all the actions in a plain object
|
|
65
|
+
// with no structure :(
|
|
66
|
+
if (action.result.object) {
|
|
65
67
|
return {
|
|
66
68
|
...state,
|
|
67
69
|
error: null,
|
|
@@ -207,4 +207,74 @@ describe('Actions reducer - (ACTIONS)GET_CONTENT', () => {
|
|
|
207
207
|
loading: false,
|
|
208
208
|
});
|
|
209
209
|
});
|
|
210
|
+
|
|
211
|
+
it('should handle (ACTIONS)LIST_ACTIONS (standalone with apiExpander enabled)', () => {
|
|
212
|
+
expect(
|
|
213
|
+
actions(undefined, {
|
|
214
|
+
type: `${LIST_ACTIONS}_SUCCESS`,
|
|
215
|
+
result: {
|
|
216
|
+
object: [],
|
|
217
|
+
object_buttons: [],
|
|
218
|
+
site_actions: [],
|
|
219
|
+
user: [
|
|
220
|
+
{
|
|
221
|
+
icon: '',
|
|
222
|
+
id: 'preferences',
|
|
223
|
+
title: 'Preferences',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
icon: '',
|
|
227
|
+
id: 'dashboard',
|
|
228
|
+
title: 'Dashboard',
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
icon: '',
|
|
232
|
+
id: 'plone_setup',
|
|
233
|
+
title: 'Site Setup',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
icon: '',
|
|
237
|
+
id: 'logout',
|
|
238
|
+
title: 'Log out',
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
document_actions: [],
|
|
242
|
+
portal_tabs: [],
|
|
243
|
+
},
|
|
244
|
+
}),
|
|
245
|
+
).toEqual({
|
|
246
|
+
error: null,
|
|
247
|
+
actions: {
|
|
248
|
+
object: [],
|
|
249
|
+
object_buttons: [],
|
|
250
|
+
site_actions: [],
|
|
251
|
+
user: [
|
|
252
|
+
{
|
|
253
|
+
icon: '',
|
|
254
|
+
id: 'preferences',
|
|
255
|
+
title: 'Preferences',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
icon: '',
|
|
259
|
+
id: 'dashboard',
|
|
260
|
+
title: 'Dashboard',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
icon: '',
|
|
264
|
+
id: 'plone_setup',
|
|
265
|
+
title: 'Site Setup',
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
icon: '',
|
|
269
|
+
id: 'logout',
|
|
270
|
+
title: 'Log out',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
document_actions: [],
|
|
274
|
+
portal_tabs: [],
|
|
275
|
+
},
|
|
276
|
+
loaded: true,
|
|
277
|
+
loading: false,
|
|
278
|
+
});
|
|
279
|
+
});
|
|
210
280
|
});
|
package/src/server.jsx
CHANGED
|
@@ -263,6 +263,15 @@ server.get('/*', (req, res) => {
|
|
|
263
263
|
const readCriticalCss =
|
|
264
264
|
config.settings.serverConfig.readCriticalCss || defaultReadCriticalCss;
|
|
265
265
|
|
|
266
|
+
// If we are showing an "old browser" warning,
|
|
267
|
+
// make sure it doesn't get cached in a shared cache
|
|
268
|
+
const browserdetect = store.getState().browserdetect;
|
|
269
|
+
if (config.settings.notSupportedBrowsers.includes(browserdetect?.name)) {
|
|
270
|
+
res.set({
|
|
271
|
+
'Cache-Control': 'private',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
266
275
|
if (context.url) {
|
|
267
276
|
res.redirect(flattenToAppURL(context.url));
|
|
268
277
|
} else if (context.error_code) {
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"id": "Insert row before",
|
|
4
|
-
"defaultMessage": "Insert row before"
|
|
5
|
-
},
|
|
6
|
-
{
|
|
7
|
-
"id": "Insert row after",
|
|
8
|
-
"defaultMessage": "Insert row after"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"id": "Delete row",
|
|
12
|
-
"defaultMessage": "Delete row"
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"id": "Insert col before",
|
|
16
|
-
"defaultMessage": "Insert col before"
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
"id": "Insert col after",
|
|
20
|
-
"defaultMessage": "Insert col after"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"id": "Delete col",
|
|
24
|
-
"defaultMessage": "Delete col"
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"id": "Hide headers",
|
|
28
|
-
"defaultMessage": "Hide headers"
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"id": "Make the table sortable",
|
|
32
|
-
"defaultMessage": "Make the table sortable"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"id": "Visible only in view mode",
|
|
36
|
-
"defaultMessage": "Visible only in view mode"
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"id": "Fixed width table cells",
|
|
40
|
-
"defaultMessage": "Fixed width table cells"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"id": "Make the table compact",
|
|
44
|
-
"defaultMessage": "Make the table compact"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"id": "Reduce complexity",
|
|
48
|
-
"defaultMessage": "Reduce complexity"
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"id": "Divide each row into separate cells",
|
|
52
|
-
"defaultMessage": "Divide each row into separate cells"
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
"id": "Table color inverted",
|
|
56
|
-
"defaultMessage": "Table color inverted"
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"id": "Stripe alternate rows with color",
|
|
60
|
-
"defaultMessage": "Stripe alternate rows with color"
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"id": "Left",
|
|
64
|
-
"defaultMessage": "Left"
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"id": "Center",
|
|
68
|
-
"defaultMessage": "Center"
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"id": "Right",
|
|
72
|
-
"defaultMessage": "Right"
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
"id": "Bottom",
|
|
76
|
-
"defaultMessage": "Bottom"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"id": "Middle",
|
|
80
|
-
"defaultMessage": "Middle"
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
"id": "Top",
|
|
84
|
-
"defaultMessage": "Top"
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"id": "Table",
|
|
88
|
-
"defaultMessage": "Table"
|
|
89
|
-
}
|
|
90
|
-
]
|