@plone/volto 18.0.0-alpha.46 → 18.0.0-alpha.48
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/.eslintrc +0 -1
- package/CHANGELOG.md +64 -0
- package/locales/ca/LC_MESSAGES/volto.po +82 -15
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +87 -20
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +82 -15
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +82 -15
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +82 -15
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +82 -15
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +82 -15
- package/locales/fr.json +1 -1
- package/locales/hi/LC_MESSAGES/volto.po +82 -15
- package/locales/hi.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +82 -15
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +82 -15
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +82 -15
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +82 -15
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +82 -15
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +82 -15
- package/locales/ro.json +1 -1
- package/locales/volto.pot +83 -16
- package/locales/zh_CN/LC_MESSAGES/volto.po +82 -15
- package/locales/zh_CN.json +1 -1
- package/package.json +11 -9
- package/razzle.config.js +8 -5
- package/src/actions/aliases/aliases.js +27 -7
- package/src/actions/aliases/aliases.test.js +1 -1
- package/src/components/manage/Blocks/Block/Edit.jsx +1 -2
- package/src/components/manage/Blocks/Block/EditBlockWrapper.jsx +5 -2
- package/src/components/manage/Blocks/Block/StyleWrapper.jsx +1 -1
- package/src/components/manage/Blocks/Listing/getAsyncData.js +8 -0
- package/src/components/manage/Blocks/ToC/View.jsx +18 -7
- package/src/components/manage/Blocks/ToC/variations/DefaultTocRenderer.jsx +2 -20
- package/src/components/manage/Blocks/ToC/variations/HorizontalMenu.jsx +2 -19
- package/src/components/manage/Controlpanels/Aliases.jsx +499 -412
- package/src/components/manage/Controlpanels/Aliases.test.jsx +7 -0
- package/src/components/manage/Edit/Edit.jsx +7 -3
- package/src/components/manage/Form/ModalForm.jsx +3 -1
- package/src/components/manage/Toolbar/PersonalTools.jsx +7 -7
- package/src/components/manage/Toolbar/PersonalTools.test.jsx +71 -0
- package/src/components/manage/Widgets/IdWidget.jsx +6 -7
- package/src/components/theme/App/App.jsx +2 -0
- package/src/components/theme/App/App.test.jsx +4 -3
- package/src/components/theme/Login/Login.jsx +1 -2
- package/src/components/theme/RouteAnnouncer/RouteAnnouncer.jsx +64 -0
- package/src/constants/ActionTypes.js +1 -0
- package/src/express-middleware/static.js +2 -2
- package/src/helpers/Api/Api.js +12 -1
- package/src/helpers/Blocks/Blocks.js +73 -33
- package/src/helpers/Blocks/Blocks.test.js +204 -27
- package/src/middleware/api.js +3 -0
- package/src/reducers/content/content.js +12 -0
- package/src/start-server.js +2 -5
- package/types/actions/aliases/aliases.d.ts +8 -1
- package/types/components/manage/Blocks/ToC/View.d.ts +1 -4
- package/types/components/manage/Blocks/ToC/variations/DefaultTocRenderer.d.ts +10 -5
- package/types/components/manage/Blocks/ToC/variations/HorizontalMenu.d.ts +10 -5
- package/types/components/manage/Blocks/ToC/variations/index.d.ts +16 -4
- package/types/components/manage/Contents/__mocks__/index.d.ts +0 -1
- package/types/components/manage/Controlpanels/Relations/RelationsMatrix.d.ts +1 -1
- package/types/components/manage/Controlpanels/index.d.ts +0 -1
- package/types/components/manage/Form/__mocks__/index.d.ts +0 -1
- package/types/components/manage/Form/index.d.ts +0 -1
- package/types/components/manage/Multilingual/ManageTranslations.d.ts +1 -1
- package/types/components/manage/Sidebar/ObjectBrowser.d.ts +1 -1
- package/types/components/manage/Widgets/InternalUrlWidget.d.ts +1 -1
- package/types/components/manage/Widgets/UrlWidget.d.ts +1 -1
- package/types/components/manage/Widgets/__mocks__/index.d.ts +0 -1
- package/types/components/manage/Widgets/index.d.ts +2 -3
- package/types/components/theme/RouteAnnouncer/RouteAnnouncer.d.ts +2 -0
- package/types/config/slots.d.ts +1 -1
- package/types/constants/ActionTypes.d.ts +1 -0
- package/types/helpers/Blocks/Blocks.d.ts +10 -1
- package/types/helpers/Helmet/Helmet.d.ts +1 -1
|
@@ -1,34 +1,38 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo } from 'react';
|
|
2
2
|
import { useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { Link, useHistory, useLocation } from 'react-router-dom';
|
|
4
|
+
import { getBaseUrl, getParentUrl, Helmet } from '@plone/volto/helpers';
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from '@plone/volto/
|
|
10
|
-
import { removeAliases, addAliases, getAliases } from '@plone/volto/actions';
|
|
6
|
+
removeAliases,
|
|
7
|
+
addAliases,
|
|
8
|
+
getAliases,
|
|
9
|
+
uploadAliases,
|
|
10
|
+
} from '@plone/volto/actions/aliases/aliases';
|
|
11
11
|
import { createPortal } from 'react-dom';
|
|
12
12
|
import {
|
|
13
|
-
Container,
|
|
14
13
|
Button,
|
|
15
|
-
Segment,
|
|
16
|
-
Form,
|
|
17
14
|
Checkbox,
|
|
15
|
+
Container,
|
|
16
|
+
Form,
|
|
18
17
|
Header,
|
|
19
18
|
Input,
|
|
19
|
+
Loader,
|
|
20
|
+
Menu,
|
|
21
|
+
Pagination,
|
|
20
22
|
Radio,
|
|
21
|
-
|
|
23
|
+
Segment,
|
|
22
24
|
Table,
|
|
23
|
-
Pagination,
|
|
24
|
-
Menu,
|
|
25
25
|
} from 'semantic-ui-react';
|
|
26
26
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
|
27
27
|
import DatetimeWidget from '@plone/volto/components/manage/Widgets/DatetimeWidget';
|
|
28
|
+
import FormFieldWrapper from '@plone/volto/components/manage/Widgets/FormFieldWrapper';
|
|
29
|
+
import { ModalForm } from '@plone/volto/components/manage/Form';
|
|
28
30
|
import { Icon, Toolbar } from '@plone/volto/components';
|
|
31
|
+
import FormattedDate from '@plone/volto/components/theme/FormattedDate/FormattedDate';
|
|
29
32
|
import { useClient } from '@plone/volto/hooks';
|
|
30
33
|
|
|
31
34
|
import backSVG from '@plone/volto/icons/back.svg';
|
|
35
|
+
import editingSVG from '@plone/volto/icons/editing.svg';
|
|
32
36
|
import { map } from 'lodash';
|
|
33
37
|
import { toast } from 'react-toastify';
|
|
34
38
|
import { Toast } from '@plone/volto/components';
|
|
@@ -42,6 +46,14 @@ const messages = defineMessages({
|
|
|
42
46
|
id: 'URL Management',
|
|
43
47
|
defaultMessage: 'URL Management',
|
|
44
48
|
},
|
|
49
|
+
AddUrl: {
|
|
50
|
+
id: 'Add Alternative URL',
|
|
51
|
+
defaultMessage: 'Add Alternative URL',
|
|
52
|
+
},
|
|
53
|
+
EditUrl: {
|
|
54
|
+
id: 'Edit Alternative URL',
|
|
55
|
+
defaultMessage: 'Edit Alternative URL',
|
|
56
|
+
},
|
|
45
57
|
success: {
|
|
46
58
|
id: 'Success',
|
|
47
59
|
defaultMessage: 'Success',
|
|
@@ -50,6 +62,66 @@ const messages = defineMessages({
|
|
|
50
62
|
id: 'Alias has been added',
|
|
51
63
|
defaultMessage: 'Alias has been added',
|
|
52
64
|
},
|
|
65
|
+
successUpload: {
|
|
66
|
+
id: 'Aliases have been uploaded.',
|
|
67
|
+
defaultMessage: 'Aliases have been uploaded.',
|
|
68
|
+
},
|
|
69
|
+
successRemove: {
|
|
70
|
+
id: 'Aliases have been removed.',
|
|
71
|
+
defaultMessage: 'Aliases have been removed.',
|
|
72
|
+
},
|
|
73
|
+
filterByPrefix: {
|
|
74
|
+
id: 'Filter by prefix',
|
|
75
|
+
defaultMessage: 'Filter by path',
|
|
76
|
+
},
|
|
77
|
+
manualOrAuto: {
|
|
78
|
+
id: 'Manually or automatically added?',
|
|
79
|
+
defaultMessage: 'Manually or automatically added?',
|
|
80
|
+
},
|
|
81
|
+
createdAfter: {
|
|
82
|
+
id: 'Created after',
|
|
83
|
+
defaultMessage: 'Created after',
|
|
84
|
+
},
|
|
85
|
+
createdBefore: {
|
|
86
|
+
id: 'Created before',
|
|
87
|
+
defaultMessage: 'Created before',
|
|
88
|
+
},
|
|
89
|
+
altUrlPathTitle: {
|
|
90
|
+
id: 'Alternative url path (Required)',
|
|
91
|
+
defaultMessage: 'Alternative URL path (Required)',
|
|
92
|
+
},
|
|
93
|
+
altUrlError: {
|
|
94
|
+
id: 'Alternative url path must start with a slash.',
|
|
95
|
+
defaultMessage: 'Alternative URL path must start with a slash.',
|
|
96
|
+
},
|
|
97
|
+
targetUrlPathTitle: {
|
|
98
|
+
id: 'Target Path (Required)',
|
|
99
|
+
defaultMessage: 'Target Path (Required)',
|
|
100
|
+
},
|
|
101
|
+
BulkUploadAltUrls: {
|
|
102
|
+
id: 'BulkUploadAltUrls',
|
|
103
|
+
defaultMessage: 'Bulk upload CSV',
|
|
104
|
+
},
|
|
105
|
+
CSVFile: {
|
|
106
|
+
id: 'CSVFile',
|
|
107
|
+
defaultMessage: 'CSV file',
|
|
108
|
+
},
|
|
109
|
+
Both: {
|
|
110
|
+
id: 'Both',
|
|
111
|
+
defaultMessage: 'Both',
|
|
112
|
+
},
|
|
113
|
+
Automatically: {
|
|
114
|
+
id: 'Automatically',
|
|
115
|
+
defaultMessage: 'Automatically',
|
|
116
|
+
},
|
|
117
|
+
Manually: {
|
|
118
|
+
id: 'Manually',
|
|
119
|
+
defaultMessage: 'Manually',
|
|
120
|
+
},
|
|
121
|
+
examplePath: {
|
|
122
|
+
id: 'examplePath',
|
|
123
|
+
defaultMessage: '/example',
|
|
124
|
+
},
|
|
53
125
|
});
|
|
54
126
|
|
|
55
127
|
const filterChoices = [
|
|
@@ -67,215 +139,153 @@ const Aliases = (props) => {
|
|
|
67
139
|
const { pathname } = useLocation();
|
|
68
140
|
const history = useHistory();
|
|
69
141
|
|
|
142
|
+
const hasAdvancedFiltering = useSelector(
|
|
143
|
+
(state) => state.site.data?.features?.filter_aliases_by_date,
|
|
144
|
+
);
|
|
145
|
+
const hasBulkUpload = hasAdvancedFiltering !== undefined;
|
|
70
146
|
const aliases = useSelector((state) => state.aliases);
|
|
71
147
|
const [filterType, setFilterType] = useState(filterChoices[0]);
|
|
72
148
|
const [createdBefore, setCreatedBefore] = useState(null);
|
|
73
|
-
const [
|
|
74
|
-
const [isAltUrlCorrect, setIsAltUrlCorrect] = useState(false);
|
|
75
|
-
const [targetUrlPath, setTargetUrlPath] = useState('');
|
|
149
|
+
const [createdAfter, setCreatedAfter] = useState(null);
|
|
76
150
|
const [aliasesToRemove, setAliasesToRemove] = useState([]);
|
|
77
|
-
const [errorMessageAdd, setErrorMessageAdd] = useState('');
|
|
78
151
|
const [filterQuery, setFilterQuery] = useState('');
|
|
79
152
|
const [activePage, setActivePage] = useState(1);
|
|
80
|
-
const [pages, setPages] = useState('');
|
|
81
153
|
const [itemsPerPage, setItemsPerPage] = useState(10);
|
|
154
|
+
const [addModalOpen, setAddModalOpen] = useState(false);
|
|
155
|
+
const [addError, setAddError] = useState(null);
|
|
156
|
+
const [editingData, setEditingData] = useState(null);
|
|
157
|
+
const [uploadModalOpen, setUploadModalOpen] = useState(false);
|
|
158
|
+
const [uploadError, setUploadError] = useState(null);
|
|
82
159
|
const isClient = useClient();
|
|
83
160
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
) {
|
|
97
|
-
const pages = Math.ceil(aliases.items_total / itemsPerPage);
|
|
98
|
-
|
|
99
|
-
if (pages === 0 || isNaN(pages)) {
|
|
100
|
-
setPages('');
|
|
101
|
-
} else {
|
|
102
|
-
setPages(pages);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (prevactivePage !== activePage || previtemsPerPage !== itemsPerPage) {
|
|
106
|
-
dispatch(
|
|
107
|
-
getAliases(getBaseUrl(pathname), {
|
|
108
|
-
query: filterQuery,
|
|
109
|
-
manual: filterType.value,
|
|
110
|
-
datetime: createdBefore,
|
|
111
|
-
batchSize: itemsPerPage === 'All' ? 999999999999 : itemsPerPage,
|
|
112
|
-
batchStart: (activePage - 1) * itemsPerPage,
|
|
113
|
-
}),
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
if (prevalturlpath !== altUrlPath) {
|
|
117
|
-
if (altUrlPath.charAt(0) === '/') {
|
|
118
|
-
setIsAltUrlCorrect(true);
|
|
119
|
-
} else {
|
|
120
|
-
setIsAltUrlCorrect(false);
|
|
121
|
-
}
|
|
161
|
+
const updateResults = useCallback(() => {
|
|
162
|
+
const options = {
|
|
163
|
+
query: filterQuery,
|
|
164
|
+
manual: filterType.value,
|
|
165
|
+
batchStart: (activePage - 1) * itemsPerPage,
|
|
166
|
+
batchSize: itemsPerPage === 'All' ? 999999999999 : itemsPerPage,
|
|
167
|
+
};
|
|
168
|
+
if (hasAdvancedFiltering) {
|
|
169
|
+
options.start = createdAfter || '';
|
|
170
|
+
options.end = createdBefore || '';
|
|
171
|
+
} else {
|
|
172
|
+
options.datetime = createdBefore || '';
|
|
122
173
|
}
|
|
174
|
+
dispatch(getAliases(getBaseUrl(pathname), options));
|
|
123
175
|
}, [
|
|
124
|
-
itemsPerPage,
|
|
125
|
-
pathname,
|
|
126
|
-
prevaliasesitemstotal,
|
|
127
|
-
aliases.items_total,
|
|
128
|
-
previtemsPerPage,
|
|
129
|
-
prevactivePage,
|
|
130
176
|
activePage,
|
|
131
|
-
|
|
132
|
-
altUrlPath,
|
|
133
|
-
prevtargetUrlPath,
|
|
134
|
-
targetUrlPath,
|
|
135
|
-
dispatch,
|
|
136
|
-
filterQuery,
|
|
137
|
-
filterType.value,
|
|
177
|
+
createdAfter,
|
|
138
178
|
createdBefore,
|
|
139
|
-
]);
|
|
140
|
-
|
|
141
|
-
useEffect(() => {
|
|
142
|
-
if (prevaliasesaddloading && !aliases.add.loaded) {
|
|
143
|
-
if (aliases.add.error) {
|
|
144
|
-
setErrorMessageAdd(aliases.add.error.response.body.message);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (prevaliasesaddloading && aliases.add.loaded) {
|
|
148
|
-
dispatch(
|
|
149
|
-
getAliases(getBaseUrl(pathname), {
|
|
150
|
-
query: filterQuery,
|
|
151
|
-
manual: filterType.value,
|
|
152
|
-
datetime: createdBefore,
|
|
153
|
-
batchSize: itemsPerPage,
|
|
154
|
-
}),
|
|
155
|
-
);
|
|
156
|
-
toast.success(
|
|
157
|
-
<Toast
|
|
158
|
-
success
|
|
159
|
-
title={intl.formatMessage(messages.success)}
|
|
160
|
-
content={intl.formatMessage(messages.successAdd)}
|
|
161
|
-
/>,
|
|
162
|
-
);
|
|
163
|
-
if (!aliases.add.error) {
|
|
164
|
-
setErrorMessageAdd('');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
if (prevaliasesremoveloading && aliases.remove.loaded) {
|
|
168
|
-
dispatch(
|
|
169
|
-
getAliases(getBaseUrl(pathname), {
|
|
170
|
-
query: filterQuery,
|
|
171
|
-
manual: filterType.value,
|
|
172
|
-
datetime: createdBefore,
|
|
173
|
-
batchSize: itemsPerPage,
|
|
174
|
-
}),
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
}, [
|
|
178
|
-
prevaliasesaddloading,
|
|
179
|
-
aliases.add.loaded,
|
|
180
|
-
aliases.add.error,
|
|
181
|
-
aliases.remove.loaded,
|
|
182
|
-
prevaliasesremoveloading,
|
|
183
179
|
dispatch,
|
|
184
|
-
pathname,
|
|
185
180
|
filterQuery,
|
|
186
181
|
filterType.value,
|
|
187
|
-
|
|
182
|
+
hasAdvancedFiltering,
|
|
188
183
|
itemsPerPage,
|
|
189
|
-
|
|
184
|
+
pathname,
|
|
190
185
|
]);
|
|
191
186
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const handleSelectFilterType = (type) => {
|
|
197
|
-
setFilterType(type);
|
|
198
|
-
};
|
|
187
|
+
// Update results after changing the page.
|
|
188
|
+
// (We intentionally leave updateResults out of the deps.)
|
|
189
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
190
|
+
useEffect(() => updateResults(), [activePage, itemsPerPage]);
|
|
199
191
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const handleSubmitFilter = () => {
|
|
209
|
-
dispatch(
|
|
210
|
-
getAliases(getBaseUrl(pathname), {
|
|
211
|
-
query: filterQuery,
|
|
212
|
-
manual: filterType.value,
|
|
213
|
-
datetime: createdBefore,
|
|
214
|
-
batchSize: itemsPerPage,
|
|
215
|
-
}),
|
|
216
|
-
);
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const handleAltUrlChange = (url) => {
|
|
220
|
-
setAltUrlPath(url);
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
const handleTargetUrlChange = (url) => {
|
|
224
|
-
setTargetUrlPath(url);
|
|
225
|
-
};
|
|
192
|
+
// Calculate page count from results
|
|
193
|
+
const pages = useMemo(() => {
|
|
194
|
+
let pages = Math.ceil(aliases.items_total / itemsPerPage);
|
|
195
|
+
if (pages === 0 || isNaN(pages)) {
|
|
196
|
+
pages = '';
|
|
197
|
+
}
|
|
198
|
+
return pages;
|
|
199
|
+
}, [aliases.items_total, itemsPerPage]);
|
|
226
200
|
|
|
227
|
-
|
|
228
|
-
|
|
201
|
+
// Add new alias
|
|
202
|
+
const handleAdd = (formData) => {
|
|
203
|
+
const { altUrlPath, targetUrlPath } = formData;
|
|
204
|
+
// Validate altUrlPath starts with a slash
|
|
205
|
+
if (!altUrlPath || altUrlPath.charAt(0) !== '/') {
|
|
206
|
+
setAddError(intl.formatMessage(messages.altUrlError));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
// Remove existing alias first if we're editing it.
|
|
210
|
+
const precondition = editingData
|
|
211
|
+
? dispatch(
|
|
212
|
+
removeAliases('', { items: [{ path: editingData.altUrlPath }] }),
|
|
213
|
+
)
|
|
214
|
+
: Promise.resolve();
|
|
215
|
+
precondition.then(() => {
|
|
229
216
|
dispatch(
|
|
230
217
|
addAliases('', {
|
|
231
|
-
items: [
|
|
232
|
-
{
|
|
233
|
-
path: altUrlPath,
|
|
234
|
-
'redirect-to': targetUrlPath,
|
|
235
|
-
},
|
|
236
|
-
],
|
|
218
|
+
items: [{ path: altUrlPath, 'redirect-to': targetUrlPath }],
|
|
237
219
|
}),
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
220
|
+
)
|
|
221
|
+
.then(() => {
|
|
222
|
+
updateResults();
|
|
223
|
+
setAddModalOpen(false);
|
|
224
|
+
setEditingData(null);
|
|
225
|
+
toast.success(
|
|
226
|
+
<Toast
|
|
227
|
+
success
|
|
228
|
+
title={intl.formatMessage(messages.success)}
|
|
229
|
+
content={intl.formatMessage(messages.successAdd)}
|
|
230
|
+
/>,
|
|
231
|
+
);
|
|
232
|
+
})
|
|
233
|
+
.catch((error) => {
|
|
234
|
+
setAddError(error.response?.body?.message);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
};
|
|
243
238
|
|
|
239
|
+
// Check/uncheck an alias
|
|
244
240
|
const handleCheckAlias = (alias) => {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const index = aliasess.indexOf(alias);
|
|
248
|
-
if (index > -1) {
|
|
249
|
-
let newAliasesArr = aliasess;
|
|
250
|
-
newAliasesArr.splice(index, 1);
|
|
251
|
-
setAliasesToRemove(newAliasesArr);
|
|
252
|
-
}
|
|
241
|
+
if (aliasesToRemove.includes(alias)) {
|
|
242
|
+
setAliasesToRemove(aliasesToRemove.filter((x) => x !== alias));
|
|
253
243
|
} else {
|
|
254
244
|
setAliasesToRemove([...aliasesToRemove, alias]);
|
|
255
245
|
}
|
|
256
246
|
};
|
|
257
|
-
const handleRemoveAliases = () => {
|
|
258
|
-
const items = aliasesToRemove.map((a) => {
|
|
259
|
-
return {
|
|
260
|
-
path: a,
|
|
261
|
-
};
|
|
262
|
-
});
|
|
263
247
|
|
|
248
|
+
// Remove selected aliases
|
|
249
|
+
const handleRemoveAliases = () => {
|
|
264
250
|
dispatch(
|
|
265
251
|
removeAliases('', {
|
|
266
|
-
items,
|
|
252
|
+
items: aliasesToRemove.map((a) => ({ path: a })),
|
|
267
253
|
}),
|
|
268
|
-
)
|
|
254
|
+
).then(() => {
|
|
255
|
+
updateResults();
|
|
256
|
+
toast.success(
|
|
257
|
+
<Toast
|
|
258
|
+
success
|
|
259
|
+
title={intl.formatMessage(messages.success)}
|
|
260
|
+
content={intl.formatMessage(messages.successRemove)}
|
|
261
|
+
/>,
|
|
262
|
+
);
|
|
263
|
+
});
|
|
269
264
|
setAliasesToRemove([]);
|
|
270
265
|
};
|
|
271
266
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
267
|
+
// Upload CSV
|
|
268
|
+
const handleBulkUpload = (formData) => {
|
|
269
|
+
fetch(`data:${formData.file['content-type']};base64,${formData.file.data}`)
|
|
270
|
+
.then((res) => res.blob())
|
|
271
|
+
.then((blob) => {
|
|
272
|
+
dispatch(uploadAliases(blob))
|
|
273
|
+
.then(() => {
|
|
274
|
+
updateResults();
|
|
275
|
+
setUploadError(null);
|
|
276
|
+
setUploadModalOpen(false);
|
|
277
|
+
toast.success(
|
|
278
|
+
<Toast
|
|
279
|
+
success
|
|
280
|
+
title={intl.formatMessage(messages.success)}
|
|
281
|
+
content={intl.formatMessage(messages.successUpload)}
|
|
282
|
+
/>,
|
|
283
|
+
);
|
|
284
|
+
})
|
|
285
|
+
.catch((error) => {
|
|
286
|
+
setUploadError(error.response?.body?.message);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
279
289
|
};
|
|
280
290
|
|
|
281
291
|
return (
|
|
@@ -291,246 +301,319 @@ const Aliases = (props) => {
|
|
|
291
301
|
values={{ title: <q>{title}</q> }}
|
|
292
302
|
/>
|
|
293
303
|
</Segment>
|
|
294
|
-
<
|
|
295
|
-
<
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
name="alternative-url-path"
|
|
312
|
-
placeholder="/example"
|
|
313
|
-
value={altUrlPath}
|
|
314
|
-
onChange={(e) => handleAltUrlChange(e.target.value)}
|
|
315
|
-
/>
|
|
316
|
-
{!isAltUrlCorrect && altUrlPath !== '' && (
|
|
317
|
-
<p style={{ color: 'red' }}>
|
|
318
|
-
<FormattedMessage
|
|
319
|
-
id="Alternative url path must start with a slash."
|
|
320
|
-
defaultMessage="Alternative url path must start with a slash."
|
|
321
|
-
/>
|
|
322
|
-
</p>
|
|
323
|
-
)}
|
|
324
|
-
</Form.Field>
|
|
325
|
-
<Header size="medium">
|
|
326
|
-
<FormattedMessage
|
|
327
|
-
id="Target Path (Required)"
|
|
328
|
-
defaultMessage="Target Path (Required)"
|
|
329
|
-
/>
|
|
330
|
-
</Header>
|
|
331
|
-
<p className="help">
|
|
332
|
-
<FormattedMessage
|
|
333
|
-
id="Enter the absolute path of the target. Target must exist or be an existing alternative url path to the target."
|
|
334
|
-
defaultMessage="Enter the absolute path of the target. Target must exist or be an existing alternative url path to the target."
|
|
335
|
-
/>
|
|
336
|
-
</p>
|
|
337
|
-
<Form.Field>
|
|
338
|
-
<Input
|
|
339
|
-
id="target-url-input"
|
|
340
|
-
name="target-url-path"
|
|
341
|
-
placeholder="/example"
|
|
342
|
-
value={targetUrlPath}
|
|
343
|
-
onChange={(e) => handleTargetUrlChange(e.target.value)}
|
|
344
|
-
/>
|
|
345
|
-
</Form.Field>
|
|
346
|
-
<Button
|
|
347
|
-
id="submit-alias"
|
|
348
|
-
primary
|
|
349
|
-
onClick={() => handleSubmitAlias()}
|
|
350
|
-
disabled={
|
|
351
|
-
!isAltUrlCorrect ||
|
|
352
|
-
altUrlPath === '' ||
|
|
353
|
-
targetUrlPath === ''
|
|
304
|
+
<Segment>
|
|
305
|
+
<Button
|
|
306
|
+
primary
|
|
307
|
+
id="add-alt-url"
|
|
308
|
+
onClick={() => setAddModalOpen(true)}
|
|
309
|
+
>
|
|
310
|
+
{intl.formatMessage(messages.AddUrl)}…
|
|
311
|
+
</Button>
|
|
312
|
+
{addModalOpen && (
|
|
313
|
+
<ModalForm
|
|
314
|
+
open={true}
|
|
315
|
+
onSubmit={handleAdd}
|
|
316
|
+
onCancel={() => setAddModalOpen(false)}
|
|
317
|
+
title={
|
|
318
|
+
editingData
|
|
319
|
+
? intl.formatMessage(messages.EditUrl)
|
|
320
|
+
: intl.formatMessage(messages.AddUrl)
|
|
354
321
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
322
|
+
submitError={addError}
|
|
323
|
+
schema={{
|
|
324
|
+
fieldsets: [
|
|
325
|
+
{
|
|
326
|
+
id: 'default',
|
|
327
|
+
fields: ['altUrlPath', 'targetUrlPath'],
|
|
328
|
+
},
|
|
329
|
+
],
|
|
330
|
+
properties: {
|
|
331
|
+
altUrlPath: {
|
|
332
|
+
title: intl.formatMessage(messages.altUrlPathTitle),
|
|
333
|
+
description: (
|
|
334
|
+
<FormattedMessage
|
|
335
|
+
id="Enter the absolute path where the alternative url should exist. The path must start with '/'. Only URLs that result in a 404 not found page will result in a redirect occurring."
|
|
336
|
+
defaultMessage="Enter the absolute path where the alternative URL should exist. The path must start with '/'. Only URLs that result in a 404 not found page will result in a redirect occurring."
|
|
337
|
+
/>
|
|
338
|
+
),
|
|
339
|
+
placeholder: intl.formatMessage(messages.examplePath),
|
|
340
|
+
},
|
|
341
|
+
targetUrlPath: {
|
|
342
|
+
title: intl.formatMessage(messages.targetUrlPathTitle),
|
|
343
|
+
description: (
|
|
344
|
+
<FormattedMessage
|
|
345
|
+
id="Enter the absolute path of the target. Target must exist or be an existing alternative url path to the target."
|
|
346
|
+
defaultMessage="Enter the absolute path of the target. Target must exist or be an existing alternative URL path to the target."
|
|
347
|
+
/>
|
|
348
|
+
),
|
|
349
|
+
placeholder: intl.formatMessage(messages.examplePath),
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
required: ['altUrlPath', 'targetUrlPath'],
|
|
353
|
+
}}
|
|
354
|
+
formData={editingData || {}}
|
|
355
|
+
/>
|
|
356
|
+
)}
|
|
357
|
+
{hasBulkUpload && (
|
|
358
|
+
<>
|
|
359
|
+
<Button onClick={() => setUploadModalOpen(true)}>
|
|
360
|
+
{intl.formatMessage(messages.BulkUploadAltUrls)}…
|
|
361
|
+
</Button>
|
|
362
|
+
{uploadModalOpen && (
|
|
363
|
+
<ModalForm
|
|
364
|
+
open={true}
|
|
365
|
+
onSubmit={handleBulkUpload}
|
|
366
|
+
onCancel={() => setUploadModalOpen(false)}
|
|
367
|
+
title={intl.formatMessage(messages.BulkUploadAltUrls)}
|
|
368
|
+
submitError={uploadError}
|
|
369
|
+
description={
|
|
370
|
+
<>
|
|
371
|
+
<p>
|
|
372
|
+
<FormattedMessage
|
|
373
|
+
id="bulkUploadUrlsHelp"
|
|
374
|
+
defaultMessage="Add many alternative URLs at once by uploading a CSV file. The first column should be the path to redirect from; the second, the path to redirect to. Both paths must be Plone-site-relative, starting with a slash (/). An optional third column can contain a date and time. An optional fourth column can contain a boolean to mark as a manual redirect (default true)."
|
|
375
|
+
/>
|
|
376
|
+
</p>
|
|
377
|
+
<p>
|
|
378
|
+
<FormattedMessage
|
|
379
|
+
id="Example"
|
|
380
|
+
defaultMessage="Example"
|
|
381
|
+
/>
|
|
382
|
+
:
|
|
383
|
+
<br />
|
|
384
|
+
<code>
|
|
385
|
+
/old-home-page.asp,/front-page,2019/01/27 10:42:59
|
|
386
|
+
GMT+1,true
|
|
387
|
+
<br />
|
|
388
|
+
/people/JoeT,/Users/joe-thurston,2018-12-31,false
|
|
389
|
+
</code>
|
|
390
|
+
</p>
|
|
391
|
+
</>
|
|
392
|
+
}
|
|
393
|
+
schema={{
|
|
394
|
+
fieldsets: [
|
|
395
|
+
{
|
|
396
|
+
id: 'default',
|
|
397
|
+
fields: ['file'],
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
properties: {
|
|
401
|
+
file: {
|
|
402
|
+
title: intl.formatMessage(messages.CSVFile),
|
|
403
|
+
type: 'object',
|
|
404
|
+
factory: 'File Upload',
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
required: ['file'],
|
|
408
|
+
}}
|
|
409
|
+
/>
|
|
410
|
+
)}
|
|
411
|
+
</>
|
|
412
|
+
)}
|
|
413
|
+
</Segment>
|
|
414
|
+
<Segment>
|
|
415
|
+
<Form>
|
|
373
416
|
<Header size="medium">
|
|
374
417
|
<FormattedMessage
|
|
375
418
|
id="All existing alternative urls for this site"
|
|
376
|
-
defaultMessage="
|
|
419
|
+
defaultMessage="Existing alternative URLs for this site"
|
|
377
420
|
/>
|
|
378
421
|
</Header>
|
|
379
|
-
<
|
|
380
|
-
<
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
422
|
+
<Segment>
|
|
423
|
+
<Form.Field>
|
|
424
|
+
<FormFieldWrapper
|
|
425
|
+
id="filterQuery"
|
|
426
|
+
title={intl.formatMessage(messages.filterByPrefix)}
|
|
427
|
+
>
|
|
428
|
+
<Input
|
|
429
|
+
name="filter"
|
|
430
|
+
placeholder={intl.formatMessage(messages.examplePath)}
|
|
431
|
+
value={filterQuery}
|
|
432
|
+
onChange={(e) => setFilterQuery(e.target.value)}
|
|
433
|
+
/>
|
|
434
|
+
</FormFieldWrapper>
|
|
435
|
+
</Form.Field>
|
|
436
|
+
<Form.Field>
|
|
437
|
+
<FormFieldWrapper
|
|
438
|
+
id="filterType"
|
|
439
|
+
title={intl.formatMessage(messages.manualOrAuto)}
|
|
440
|
+
>
|
|
441
|
+
<Form.Group inline>
|
|
442
|
+
{filterChoices.map((o, i) => (
|
|
443
|
+
<Form.Field key={i}>
|
|
444
|
+
<Radio
|
|
445
|
+
label={intl.formatMessage({ id: o.label })}
|
|
446
|
+
name="radioGroup"
|
|
447
|
+
value={o.value}
|
|
448
|
+
checked={filterType === o}
|
|
449
|
+
onChange={() => setFilterType(o)}
|
|
450
|
+
/>
|
|
451
|
+
</Form.Field>
|
|
452
|
+
))}
|
|
453
|
+
</Form.Group>
|
|
454
|
+
</FormFieldWrapper>
|
|
455
|
+
</Form.Field>
|
|
456
|
+
<Form.Field>
|
|
457
|
+
<DatetimeWidget
|
|
458
|
+
id="created-before-date"
|
|
459
|
+
title={intl.formatMessage(messages.createdBefore)}
|
|
460
|
+
dateOnly={true}
|
|
461
|
+
value={createdBefore}
|
|
462
|
+
onChange={(id, value) => {
|
|
463
|
+
setCreatedBefore(value);
|
|
464
|
+
}}
|
|
407
465
|
/>
|
|
408
466
|
</Form.Field>
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
467
|
+
{hasAdvancedFiltering && (
|
|
468
|
+
<Form.Field>
|
|
469
|
+
<DatetimeWidget
|
|
470
|
+
id="created-after-date"
|
|
471
|
+
title={intl.formatMessage(messages.createdAfter)}
|
|
472
|
+
dateOnly={true}
|
|
473
|
+
value={createdAfter}
|
|
474
|
+
onChange={(id, value) => {
|
|
475
|
+
setCreatedAfter(value);
|
|
476
|
+
}}
|
|
477
|
+
/>
|
|
478
|
+
</Form.Field>
|
|
479
|
+
)}
|
|
480
|
+
<Button onClick={() => updateResults()} primary>
|
|
481
|
+
<FormattedMessage id="Filter" defaultMessage="Filter" />
|
|
482
|
+
</Button>
|
|
483
|
+
</Segment>
|
|
484
|
+
</Form>
|
|
485
|
+
</Segment>
|
|
486
|
+
<Segment>
|
|
487
|
+
<Header size="small">
|
|
488
|
+
<FormattedMessage
|
|
489
|
+
id="Alternative url path → target url path (date and time of creation, manually created yes/no)"
|
|
490
|
+
defaultMessage="Alternative URL path → target URL path (date and time of creation, manually created yes/no)"
|
|
491
|
+
/>
|
|
492
|
+
</Header>
|
|
430
493
|
|
|
431
|
-
|
|
432
|
-
|
|
494
|
+
<Table celled compact>
|
|
495
|
+
<Table.Header>
|
|
496
|
+
<Table.Row>
|
|
497
|
+
<Table.HeaderCell width="1">
|
|
498
|
+
<FormattedMessage id="Select" defaultMessage="Select" />
|
|
499
|
+
</Table.HeaderCell>
|
|
500
|
+
<Table.HeaderCell width="10">
|
|
501
|
+
<FormattedMessage id="Alias" defaultMessage="Alias" />
|
|
502
|
+
</Table.HeaderCell>
|
|
503
|
+
<Table.HeaderCell width="1">
|
|
504
|
+
<FormattedMessage id="Date" defaultMessage="Date" />
|
|
505
|
+
</Table.HeaderCell>
|
|
506
|
+
<Table.HeaderCell width="1">
|
|
507
|
+
<FormattedMessage id="Manual" defaultMessage="Manual" />
|
|
508
|
+
</Table.HeaderCell>
|
|
509
|
+
</Table.Row>
|
|
510
|
+
</Table.Header>
|
|
511
|
+
<Table.Body>
|
|
512
|
+
{aliases.get.loading && (
|
|
433
513
|
<Table.Row>
|
|
434
|
-
<Table.
|
|
435
|
-
<
|
|
436
|
-
</Table.
|
|
437
|
-
<Table.HeaderCell>
|
|
438
|
-
<FormattedMessage id="Alias" defaultMessage="Alias" />
|
|
439
|
-
</Table.HeaderCell>
|
|
440
|
-
<Table.HeaderCell>
|
|
441
|
-
<FormattedMessage id="Target" defaultMessage="Target" />
|
|
442
|
-
</Table.HeaderCell>
|
|
443
|
-
<Table.HeaderCell>
|
|
444
|
-
<FormattedMessage id="Date" defaultMessage="Date" />
|
|
445
|
-
</Table.HeaderCell>
|
|
446
|
-
<Table.HeaderCell>
|
|
447
|
-
<FormattedMessage id="Manual" defaultMessage="Manual" />
|
|
448
|
-
</Table.HeaderCell>
|
|
514
|
+
<Table.Cell colSpan="4">
|
|
515
|
+
<Loader active inline="centered" />
|
|
516
|
+
</Table.Cell>
|
|
449
517
|
</Table.Row>
|
|
450
|
-
{aliases.items.length > 0 &&
|
|
451
|
-
aliases.items.map((alias, i) => (
|
|
452
|
-
<Table.Row key={i}>
|
|
453
|
-
<Table.Cell>
|
|
454
|
-
<Checkbox
|
|
455
|
-
onChange={(e, { value }) =>
|
|
456
|
-
handleCheckAlias(value)
|
|
457
|
-
}
|
|
458
|
-
checked={aliasesToRemove.includes(alias.path)}
|
|
459
|
-
value={alias.path}
|
|
460
|
-
/>
|
|
461
|
-
</Table.Cell>
|
|
462
|
-
<Table.Cell>
|
|
463
|
-
<p>{alias.path}</p>
|
|
464
|
-
</Table.Cell>
|
|
465
|
-
<Table.Cell>
|
|
466
|
-
<p>{alias['redirect-to']}</p>
|
|
467
|
-
</Table.Cell>
|
|
468
|
-
<Table.Cell>
|
|
469
|
-
<p>{alias.datetime}</p>
|
|
470
|
-
</Table.Cell>
|
|
471
|
-
<Table.Cell>
|
|
472
|
-
<p>{`${alias.manual}`}</p>
|
|
473
|
-
</Table.Cell>
|
|
474
|
-
</Table.Row>
|
|
475
|
-
))}
|
|
476
|
-
</Table.Body>
|
|
477
|
-
</Table>
|
|
478
|
-
<div
|
|
479
|
-
style={{
|
|
480
|
-
display: 'flex',
|
|
481
|
-
flexWrap: 'wrap',
|
|
482
|
-
alignItems: 'center',
|
|
483
|
-
marginBottom: '20px',
|
|
484
|
-
}}
|
|
485
|
-
>
|
|
486
|
-
{pages && (
|
|
487
|
-
<Pagination
|
|
488
|
-
boundaryRange={0}
|
|
489
|
-
activePage={activePage}
|
|
490
|
-
ellipsisItem={null}
|
|
491
|
-
firstItem={null}
|
|
492
|
-
lastItem={null}
|
|
493
|
-
siblingRange={1}
|
|
494
|
-
totalPages={pages}
|
|
495
|
-
onPageChange={(e, o) => handlePageChange(e, o)}
|
|
496
|
-
/>
|
|
497
518
|
)}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
+
{aliases.items.length > 0 &&
|
|
520
|
+
aliases.items.map((alias, i) => (
|
|
521
|
+
<Table.Row key={i} verticalAlign="top">
|
|
522
|
+
<Table.Cell>
|
|
523
|
+
<Checkbox
|
|
524
|
+
onChange={(e, { value }) => handleCheckAlias(value)}
|
|
525
|
+
checked={aliasesToRemove.includes(alias.path)}
|
|
526
|
+
value={alias.path}
|
|
527
|
+
/>
|
|
528
|
+
</Table.Cell>
|
|
529
|
+
<Table.Cell>
|
|
530
|
+
{alias.path}
|
|
531
|
+
<br />
|
|
532
|
+
→ {alias['redirect-to']}{' '}
|
|
533
|
+
<Button
|
|
534
|
+
basic
|
|
535
|
+
style={{ verticalAlign: 'middle' }}
|
|
536
|
+
aria-label={intl.formatMessage(messages.EditUrl)}
|
|
537
|
+
onClick={() => {
|
|
538
|
+
setEditingData({
|
|
539
|
+
altUrlPath: alias.path,
|
|
540
|
+
targetUrlPath: alias['redirect-to'],
|
|
541
|
+
});
|
|
542
|
+
setAddModalOpen(true);
|
|
543
|
+
}}
|
|
544
|
+
>
|
|
545
|
+
<Icon name={editingSVG} size="18px" />
|
|
546
|
+
</Button>
|
|
547
|
+
</Table.Cell>
|
|
548
|
+
<Table.Cell>
|
|
549
|
+
<FormattedDate date={alias.datetime} />
|
|
550
|
+
</Table.Cell>
|
|
551
|
+
<Table.Cell>{`${alias.manual}`}</Table.Cell>
|
|
552
|
+
</Table.Row>
|
|
519
553
|
))}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
554
|
+
</Table.Body>
|
|
555
|
+
</Table>
|
|
556
|
+
<div
|
|
557
|
+
style={{
|
|
558
|
+
display: 'flex',
|
|
559
|
+
flexWrap: 'wrap',
|
|
560
|
+
alignItems: 'center',
|
|
561
|
+
marginBottom: '20px',
|
|
562
|
+
}}
|
|
563
|
+
>
|
|
564
|
+
{pages && (
|
|
565
|
+
<Pagination
|
|
566
|
+
boundaryRange={0}
|
|
567
|
+
activePage={activePage}
|
|
568
|
+
ellipsisItem={null}
|
|
569
|
+
firstItem={null}
|
|
570
|
+
lastItem={null}
|
|
571
|
+
siblingRange={1}
|
|
572
|
+
totalPages={pages}
|
|
573
|
+
onPageChange={(e, { activePage }) =>
|
|
574
|
+
setActivePage(activePage)
|
|
575
|
+
}
|
|
530
576
|
/>
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
577
|
+
)}
|
|
578
|
+
<Menu.Menu
|
|
579
|
+
position="right"
|
|
580
|
+
style={{ display: 'flex', marginLeft: 'auto' }}
|
|
581
|
+
>
|
|
582
|
+
<Menu.Item style={{ color: 'grey' }}>
|
|
583
|
+
<FormattedMessage id="Show" defaultMessage="Show" />:
|
|
584
|
+
</Menu.Item>
|
|
585
|
+
{map(itemsPerPageChoices, (size) => (
|
|
586
|
+
<Menu.Item
|
|
587
|
+
style={{
|
|
588
|
+
padding: '0 0.4em',
|
|
589
|
+
margin: '0em 0.357em',
|
|
590
|
+
cursor: 'pointer',
|
|
591
|
+
}}
|
|
592
|
+
key={size}
|
|
593
|
+
value={size}
|
|
594
|
+
active={size === itemsPerPage}
|
|
595
|
+
onClick={(e, { value }) => {
|
|
596
|
+
setItemsPerPage(value);
|
|
597
|
+
setActivePage(1);
|
|
598
|
+
}}
|
|
599
|
+
>
|
|
600
|
+
{size}
|
|
601
|
+
</Menu.Item>
|
|
602
|
+
))}
|
|
603
|
+
</Menu.Menu>
|
|
604
|
+
</div>
|
|
605
|
+
<Button
|
|
606
|
+
id="remove-alt-urls"
|
|
607
|
+
disabled={aliasesToRemove.length === 0}
|
|
608
|
+
onClick={handleRemoveAliases}
|
|
609
|
+
primary
|
|
610
|
+
>
|
|
611
|
+
<FormattedMessage
|
|
612
|
+
id="Remove selected"
|
|
613
|
+
defaultMessage="Remove selected"
|
|
614
|
+
/>
|
|
615
|
+
</Button>
|
|
616
|
+
</Segment>
|
|
534
617
|
</Segment.Group>
|
|
535
618
|
</article>
|
|
536
619
|
</Container>
|
|
@@ -540,7 +623,11 @@ const Aliases = (props) => {
|
|
|
540
623
|
pathname={pathname}
|
|
541
624
|
hideDefaultViewButtons
|
|
542
625
|
inner={
|
|
543
|
-
<Link
|
|
626
|
+
<Link
|
|
627
|
+
className="item"
|
|
628
|
+
to="#"
|
|
629
|
+
onClick={() => history.push(getParentUrl(pathname))}
|
|
630
|
+
>
|
|
544
631
|
<Icon
|
|
545
632
|
name={backSVG}
|
|
546
633
|
className="contents circled"
|