@strapi/admin 4.11.0-beta.1 → 4.11.0-exp.0
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/admin/src/content-manager/components/ComponentIcon/ComponentIcon.js +16 -26
- package/admin/src/content-manager/components/ComponentIcon/constants.js +133 -0
- package/admin/src/content-manager/components/DynamicZone/components/AddComponentButton.js +32 -95
- package/admin/src/content-manager/components/DynamicZone/components/ComponentCard.js +10 -2
- package/admin/src/content-manager/components/DynamicZone/components/ComponentCategory.js +63 -15
- package/admin/src/content-manager/components/DynamicZone/components/ComponentPicker.js +50 -63
- package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +132 -58
- package/admin/src/content-manager/components/DynamicZone/components/DynamicZoneLabel.js +29 -37
- package/admin/src/content-manager/components/DynamicZone/index.js +131 -83
- package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +28 -6
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +18 -6
- package/admin/src/content-manager/pages/EditSettingsView/components/DynamicZoneList.js +7 -1
- package/admin/src/content-manager/pages/EditView/index.js +1 -1
- package/admin/src/hooks/useContentTypes/useContentTypes.js +0 -2
- package/admin/src/index.js +4 -3
- package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableCE.js +13 -0
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/index.js +3 -0
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +331 -0
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/Combobox.js +54 -4
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/index.js +12 -23
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/index.js +129 -116
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +62 -0
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js +59 -64
- package/admin/src/translations/en.json +6 -0
- package/build/1887.6f71e8b2.chunk.js +39 -0
- package/build/3081.7e9329cb.chunk.js +105 -0
- package/build/371.6e4e2c1f.chunk.js +71 -0
- package/build/5542.64b623c9.chunk.js +63 -0
- package/build/{5563.79950369.chunk.js → 5563.badbffde.chunk.js} +2 -2
- package/build/{6970.7ea35fbd.chunk.js → 6970.d456705f.chunk.js} +1 -1
- package/build/{7259.5cc67413.chunk.js → 7259.5d0de931.chunk.js} +1 -1
- package/build/8976.a85384ce.chunk.js +155 -0
- package/build/{1657.ca8562dd.chunk.js → 9932.5ef475c5.chunk.js} +54 -62
- package/build/{Admin-authenticatedApp.990df65d.chunk.js → Admin-authenticatedApp.c985d4a0.chunk.js} +2 -2
- package/build/{Admin_InternalErrorPage.96ceaae1.chunk.js → Admin_InternalErrorPage.f25f04f3.chunk.js} +1 -1
- package/build/Admin_homePage.05063e43.chunk.js +73 -0
- package/build/Admin_marketplace.23ea289f.chunk.js +55 -0
- package/build/Admin_pluginsPage.b1031a00.chunk.js +6 -0
- package/build/{Admin_profilePage.75bc083a.chunk.js → Admin_profilePage.e7ccee9f.chunk.js} +2 -2
- package/build/Admin_settingsPage.07a6a5f0.chunk.js +79 -0
- package/build/{Upload_ConfigureTheView.aa64ed9a.chunk.js → Upload_ConfigureTheView.121deffb.chunk.js} +1 -1
- package/build/admin-app.8644c322.chunk.js +63 -0
- package/build/{admin-edit-roles-page.0d12b741.chunk.js → admin-edit-roles-page.bfe3304d.chunk.js} +3 -3
- package/build/{admin-edit-users.f9ce7844.chunk.js → admin-edit-users.6efe0382.chunk.js} +2 -2
- package/build/admin-roles-list.b2577370.chunk.js +23 -0
- package/build/admin-users.4af49ccf.chunk.js +26 -0
- package/build/{api-tokens-create-page.973d2816.chunk.js → api-tokens-create-page.65411a36.chunk.js} +1 -1
- package/build/{api-tokens-edit-page.29725c5e.chunk.js → api-tokens-edit-page.60312cb6.chunk.js} +1 -1
- package/build/{api-tokens-list-page.66c4fbdd.chunk.js → api-tokens-list-page.01a4d5cd.chunk.js} +2 -2
- package/build/audit-logs-settings-page.09c75037.chunk.js +121 -0
- package/build/content-manager.04fa9c14.chunk.js +1094 -0
- package/build/content-type-builder-list-view.58f9ed20.chunk.js +211 -0
- package/build/{content-type-builder-translation-en-json.af293c9e.chunk.js → content-type-builder-translation-en-json.f592325b.chunk.js} +1 -1
- package/build/content-type-builder.baeb0413.chunk.js +132 -0
- package/build/email-settings-page.85b71afc.chunk.js +11 -0
- package/build/en-json.a8f34002.chunk.js +1 -0
- package/build/i18n-settings-page.c0da2362.chunk.js +114 -0
- package/build/index.html +1 -1
- package/build/main.8605d88e.js +2633 -0
- package/build/{review-workflows-settings.4b39b837.chunk.js → review-workflows-settings.3a7bae25.chunk.js} +1 -1
- package/build/{runtime~main.55d43bd7.js → runtime~main.36375726.js} +2 -2
- package/build/{sso-settings-page.265e3d72.chunk.js → sso-settings-page.4bb073e0.chunk.js} +1 -1
- package/build/{transfer-tokens-create-page.170acee6.chunk.js → transfer-tokens-create-page.9ec277d7.chunk.js} +1 -1
- package/build/{transfer-tokens-edit-page.6cf23295.chunk.js → transfer-tokens-edit-page.fa5ade14.chunk.js} +1 -1
- package/build/{transfer-tokens-list-page.c3fec4c1.chunk.js → transfer-tokens-list-page.5d68d590.chunk.js} +2 -2
- package/build/upload-settings.2c1565d6.chunk.js +14 -0
- package/build/upload.257b2aef.chunk.js +26 -0
- package/build/users-advanced-settings-page.dda58320.chunk.js +9 -0
- package/build/users-email-settings-page.a0c08594.chunk.js +24 -0
- package/build/users-providers-settings-page.14a82632.chunk.js +29 -0
- package/build/{users-roles-settings-page.c773086b.chunk.js → users-roles-settings-page.1f408276.chunk.js} +1 -1
- package/build/webhook-edit-page.b9a13be7.chunk.js +136 -0
- package/build/webhook-list-page.84e5abc9.chunk.js +63 -0
- package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableEE.js +23 -0
- package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/index.js +3 -0
- package/ee/server/services/review-workflows/review-workflows.js +4 -0
- package/package.json +19 -21
- package/server/controllers/webhooks.js +6 -6
- package/admin/src/content-manager/components/DynamicZone/utils/connect.js +0 -12
- package/admin/src/content-manager/components/DynamicZone/utils/select.js +0 -53
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/EventRow.js +0 -70
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +0 -174
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/keys.js +0 -39
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/utils/fieldsRegex.js +0 -4
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/utils/schema.js +0 -35
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/reducer.js +0 -100
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/utils/formatData.js +0 -20
- package/build/3081.c2cdfac8.chunk.js +0 -108
- package/build/456.9b85d4c6.chunk.js +0 -39
- package/build/462.a073ff1f.chunk.js +0 -71
- package/build/5542.002522eb.chunk.js +0 -71
- package/build/617.87b2fe96.chunk.js +0 -155
- package/build/Admin_homePage.107a9fe0.chunk.js +0 -73
- package/build/Admin_marketplace.1436fc2b.chunk.js +0 -55
- package/build/Admin_pluginsPage.e1afd5ed.chunk.js +0 -6
- package/build/Admin_settingsPage.bd715ed3.chunk.js +0 -79
- package/build/admin-app.8b102fe2.chunk.js +0 -63
- package/build/admin-roles-list.e8bf9685.chunk.js +0 -31
- package/build/admin-users.751b28b2.chunk.js +0 -34
- package/build/audit-logs-settings-page.3c6cea81.chunk.js +0 -129
- package/build/content-manager.89099707.chunk.js +0 -1123
- package/build/content-type-builder-list-view.1e821eb9.chunk.js +0 -215
- package/build/content-type-builder.b10576e7.chunk.js +0 -126
- package/build/email-settings-page.4368689f.chunk.js +0 -11
- package/build/en-json.0f5cc115.chunk.js +0 -1
- package/build/i18n-settings-page.7988d872.chunk.js +0 -114
- package/build/main.5a232c3d.js +0 -2630
- package/build/upload-settings.63d99bf5.chunk.js +0 -14
- package/build/upload.c50d8c7a.chunk.js +0 -34
- package/build/users-advanced-settings-page.2cfb5d24.chunk.js +0 -9
- package/build/users-email-settings-page.bd6c774a.chunk.js +0 -24
- package/build/users-providers-settings-page.528f0036.chunk.js +0 -29
- package/build/webhook-edit-page.ddd5963d.chunk.js +0 -128
- package/build/webhook-list-page.b0f5a02c.chunk.js +0 -71
|
@@ -8,6 +8,7 @@ import set from 'lodash/set';
|
|
|
8
8
|
import PropTypes from 'prop-types';
|
|
9
9
|
import { useIntl } from 'react-intl';
|
|
10
10
|
import { Prompt, Redirect } from 'react-router-dom';
|
|
11
|
+
import { flushSync } from 'react-dom';
|
|
11
12
|
import { useDispatch, useSelector } from 'react-redux';
|
|
12
13
|
|
|
13
14
|
import { Main } from '@strapi/design-system';
|
|
@@ -55,6 +56,7 @@ const EditViewDataManagerProvider = ({
|
|
|
55
56
|
status,
|
|
56
57
|
updateActionAllowedFields,
|
|
57
58
|
}) => {
|
|
59
|
+
const [isSaving, setIsSaving] = React.useState(false);
|
|
58
60
|
/**
|
|
59
61
|
* TODO: this should be moved into the global reducer
|
|
60
62
|
* to match ever other reducer in the CM.
|
|
@@ -194,14 +196,21 @@ const EditViewDataManagerProvider = ({
|
|
|
194
196
|
|
|
195
197
|
const dispatchAddComponent = useCallback(
|
|
196
198
|
(type) =>
|
|
197
|
-
(
|
|
199
|
+
(
|
|
200
|
+
keys,
|
|
201
|
+
componentLayoutData,
|
|
202
|
+
allComponents,
|
|
203
|
+
shouldCheckErrors = false,
|
|
204
|
+
position = undefined
|
|
205
|
+
) => {
|
|
198
206
|
trackUsageRef.current('didAddComponentToDynamicZone');
|
|
199
207
|
|
|
200
208
|
dispatch({
|
|
201
209
|
type,
|
|
202
210
|
keys: keys.split('.'),
|
|
211
|
+
position,
|
|
203
212
|
componentLayoutData,
|
|
204
|
-
allComponents
|
|
213
|
+
allComponents,
|
|
205
214
|
shouldCheckErrors,
|
|
206
215
|
});
|
|
207
216
|
},
|
|
@@ -376,14 +385,20 @@ const EditViewDataManagerProvider = ({
|
|
|
376
385
|
try {
|
|
377
386
|
if (isEmpty(errors)) {
|
|
378
387
|
const formData = createFormData(modifiedData, initialData);
|
|
388
|
+
flushSync(() => {
|
|
389
|
+
setIsSaving(true);
|
|
390
|
+
});
|
|
379
391
|
|
|
380
392
|
if (isCreatingEntry) {
|
|
381
393
|
await onPost(formData, trackerProperty);
|
|
382
394
|
} else {
|
|
383
395
|
await onPut(formData, trackerProperty);
|
|
384
396
|
}
|
|
397
|
+
|
|
398
|
+
setIsSaving(false);
|
|
385
399
|
}
|
|
386
400
|
} catch (err) {
|
|
401
|
+
setIsSaving(false);
|
|
387
402
|
errors = {
|
|
388
403
|
...errors,
|
|
389
404
|
...getAPIInnerErrors(err, { getTrad }),
|
|
@@ -445,9 +460,14 @@ const EditViewDataManagerProvider = ({
|
|
|
445
460
|
|
|
446
461
|
try {
|
|
447
462
|
if (isEmpty(errors)) {
|
|
463
|
+
flushSync(() => {
|
|
464
|
+
setIsSaving(true);
|
|
465
|
+
});
|
|
448
466
|
await onPublish();
|
|
467
|
+
setIsSaving(false);
|
|
449
468
|
}
|
|
450
469
|
} catch (err) {
|
|
470
|
+
setIsSaving(false);
|
|
451
471
|
errors = {
|
|
452
472
|
...errors,
|
|
453
473
|
...getAPIInnerErrors(err, { getTrad }),
|
|
@@ -639,10 +659,12 @@ const EditViewDataManagerProvider = ({
|
|
|
639
659
|
</Main>
|
|
640
660
|
) : (
|
|
641
661
|
<>
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
662
|
+
{!isSaving ? (
|
|
663
|
+
<Prompt
|
|
664
|
+
when={!isEqual(modifiedData, initialData)}
|
|
665
|
+
message={formatMessage({ id: 'global.prompt.unsaved' })}
|
|
666
|
+
/>
|
|
667
|
+
) : null}
|
|
646
668
|
<form noValidate onSubmit={handleSubmit}>
|
|
647
669
|
{children}
|
|
648
670
|
</form>
|
|
@@ -52,7 +52,13 @@ const reducer = (state, action) =>
|
|
|
52
52
|
}
|
|
53
53
|
case 'ADD_COMPONENT_TO_DYNAMIC_ZONE':
|
|
54
54
|
case 'ADD_REPEATABLE_COMPONENT_TO_FIELD': {
|
|
55
|
-
const {
|
|
55
|
+
const {
|
|
56
|
+
keys,
|
|
57
|
+
allComponents,
|
|
58
|
+
componentLayoutData,
|
|
59
|
+
shouldCheckErrors,
|
|
60
|
+
position = undefined,
|
|
61
|
+
} = action;
|
|
56
62
|
|
|
57
63
|
if (shouldCheckErrors) {
|
|
58
64
|
draftState.shouldCheckErrors = !state.shouldCheckErrors;
|
|
@@ -62,7 +68,15 @@ const reducer = (state, action) =>
|
|
|
62
68
|
draftState.modifiedDZName = keys[0];
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
const currentValue = get(state, ['modifiedData', ...keys], []);
|
|
71
|
+
const currentValue = [...get(state, ['modifiedData', ...keys], [])];
|
|
72
|
+
|
|
73
|
+
let actualPosition = position;
|
|
74
|
+
|
|
75
|
+
if (actualPosition === undefined) {
|
|
76
|
+
actualPosition = currentValue.length;
|
|
77
|
+
} else if (actualPosition < 0) {
|
|
78
|
+
actualPosition = 0;
|
|
79
|
+
}
|
|
66
80
|
|
|
67
81
|
const defaultDataStructure =
|
|
68
82
|
action.type === 'ADD_COMPONENT_TO_DYNAMIC_ZONE'
|
|
@@ -87,11 +101,9 @@ const reducer = (state, action) =>
|
|
|
87
101
|
componentLayoutData.attributes
|
|
88
102
|
);
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
? [...currentValue, componentDataStructure]
|
|
92
|
-
: [componentDataStructure];
|
|
104
|
+
currentValue.splice(actualPosition, 0, componentDataStructure);
|
|
93
105
|
|
|
94
|
-
set(draftState, ['modifiedData', ...keys],
|
|
106
|
+
set(draftState, ['modifiedData', ...keys], currentValue);
|
|
95
107
|
|
|
96
108
|
break;
|
|
97
109
|
}
|
|
@@ -25,6 +25,12 @@ const CustomLink = styled(Flex)`
|
|
|
25
25
|
> div:first-child {
|
|
26
26
|
background: ${({ theme }) => theme.colors.primary200};
|
|
27
27
|
color: ${({ theme }) => theme.colors.primary600};
|
|
28
|
+
|
|
29
|
+
svg {
|
|
30
|
+
path {
|
|
31
|
+
fill: ${({ theme }) => theme.colors.primary600};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
28
34
|
}
|
|
29
35
|
}
|
|
30
36
|
`;
|
|
@@ -49,7 +55,7 @@ const DynamicZoneList = ({ components }) => {
|
|
|
49
55
|
as={Link}
|
|
50
56
|
to={`/content-manager/components/${componentUid}/configurations/edit`}
|
|
51
57
|
>
|
|
52
|
-
<ComponentIcon />
|
|
58
|
+
<ComponentIcon icon={componentLayouts?.[componentUid]?.info?.icon} />
|
|
53
59
|
|
|
54
60
|
<Box paddingTop={1}>
|
|
55
61
|
<Typography fontSize={1} textColor="neutral600" fontWeight="bold">
|
|
@@ -13,7 +13,7 @@ import { Pencil, Layer } from '@strapi/icons';
|
|
|
13
13
|
import InformationBox from 'ee_else_ce/content-manager/pages/EditView/InformationBox';
|
|
14
14
|
import { InjectionZone } from '../../../shared/components';
|
|
15
15
|
import permissions from '../../../permissions';
|
|
16
|
-
import DynamicZone from '../../components/DynamicZone';
|
|
16
|
+
import { DynamicZone } from '../../components/DynamicZone';
|
|
17
17
|
import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
|
|
18
18
|
import EditViewDataManagerProvider from '../../components/EditViewDataManagerProvider';
|
|
19
19
|
import SingleTypeFormWrapper from '../../components/SingleTypeFormWrapper';
|
|
@@ -2,8 +2,6 @@ import { useAPIErrorHandler, useFetchClient, useNotification } from '@strapi/hel
|
|
|
2
2
|
import { useQueries } from 'react-query';
|
|
3
3
|
|
|
4
4
|
export function useContentTypes() {
|
|
5
|
-
console.log('----> read');
|
|
6
|
-
|
|
7
5
|
const { get } = useFetchClient();
|
|
8
6
|
const { formatAPIError } = useAPIErrorHandler();
|
|
9
7
|
const toggleNotification = useNotification();
|
package/admin/src/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import ReactDOM from 'react-dom';
|
|
2
1
|
import { getFetchClient } from '@strapi/helper-plugin';
|
|
3
|
-
import {
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
4
3
|
import appCustomisations from './app';
|
|
4
|
+
import { Components, Fields, Middlewares, Reducers } from './core/apis';
|
|
5
5
|
// eslint-disable-next-line import/extensions
|
|
6
6
|
import plugins from './plugins';
|
|
7
7
|
import appReducers from './reducers';
|
|
@@ -68,7 +68,8 @@ const run = async () => {
|
|
|
68
68
|
|
|
69
69
|
await app.loadTrads();
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
const root = createRoot(MOUNT_NODE);
|
|
72
|
+
root.render(app.render());
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
run();
|
package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableCE.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import EventTable from '../Events';
|
|
4
|
+
|
|
5
|
+
// This component is overwritten by the EE counterpart
|
|
6
|
+
export function EventTableCE() {
|
|
7
|
+
return (
|
|
8
|
+
<EventTable.Root>
|
|
9
|
+
<EventTable.Headers />
|
|
10
|
+
<EventTable.Body />
|
|
11
|
+
</EventTable.Root>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import { useFormikContext } from 'formik';
|
|
5
|
+
import { useIntl } from 'react-intl';
|
|
6
|
+
import styled from 'styled-components';
|
|
7
|
+
import {
|
|
8
|
+
FieldLabel,
|
|
9
|
+
Flex,
|
|
10
|
+
Typography,
|
|
11
|
+
BaseCheckbox,
|
|
12
|
+
Checkbox,
|
|
13
|
+
Loader,
|
|
14
|
+
RawTable as Table,
|
|
15
|
+
RawTh as Th,
|
|
16
|
+
RawTd as Td,
|
|
17
|
+
RawTr as Tr,
|
|
18
|
+
RawThead as Thead,
|
|
19
|
+
RawTbody as Tbody,
|
|
20
|
+
VisuallyHidden,
|
|
21
|
+
} from '@strapi/design-system';
|
|
22
|
+
|
|
23
|
+
import { useContentTypes } from '../../../../../../../hooks/useContentTypes';
|
|
24
|
+
|
|
25
|
+
export const formatValue = (value) =>
|
|
26
|
+
value.reduce((acc, curr) => {
|
|
27
|
+
const key = curr.split('.')[0];
|
|
28
|
+
|
|
29
|
+
if (!acc[key]) {
|
|
30
|
+
acc[key] = [];
|
|
31
|
+
}
|
|
32
|
+
acc[key].push(curr);
|
|
33
|
+
|
|
34
|
+
return acc;
|
|
35
|
+
}, {});
|
|
36
|
+
|
|
37
|
+
// TODO check whether we want to move alternating background colour tables to the design system
|
|
38
|
+
const StyledTable = styled(Table)`
|
|
39
|
+
tbody tr:nth-child(odd) {
|
|
40
|
+
background: ${({ theme }) => theme.colors.neutral100};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
thead th span {
|
|
44
|
+
color: ${({ theme }) => theme.colors.neutral500};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
td,
|
|
48
|
+
th {
|
|
49
|
+
padding-block-start: ${({ theme }) => theme.spaces[3]};
|
|
50
|
+
padding-block-end: ${({ theme }) => theme.spaces[3]};
|
|
51
|
+
width: 10%;
|
|
52
|
+
vertical-align: middle;
|
|
53
|
+
text-align: center;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
tbody tr td:first-child {
|
|
57
|
+
// Add padding to the start of the first column to avoid the checkbox appearing
|
|
58
|
+
// too close to the edge of the table
|
|
59
|
+
padding-inline-start: ${({ theme }) => theme.spaces[2]};
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const getCEHeaders = (isDraftAndPublish) => {
|
|
64
|
+
const headers = [
|
|
65
|
+
{ id: 'Settings.webhooks.events.create', defaultMessage: 'Create' },
|
|
66
|
+
{ id: 'Settings.webhooks.events.update', defaultMessage: 'Update' },
|
|
67
|
+
{ id: 'app.utils.delete', defaultMessage: 'Delete' },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
if (isDraftAndPublish) {
|
|
71
|
+
headers.push({ id: 'app.utils.publish', defaultMessage: 'Publish' });
|
|
72
|
+
headers.push({ id: 'app.utils.unpublish', defaultMessage: 'Unpublish' });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return headers;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const getCEEvents = (isDraftAndPublish) => {
|
|
79
|
+
const entryEvents = ['entry.create', 'entry.update', 'entry.delete'];
|
|
80
|
+
|
|
81
|
+
if (isDraftAndPublish) {
|
|
82
|
+
entryEvents.push('entry.publish', 'entry.unpublish');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
entry: entryEvents,
|
|
87
|
+
media: ['media.create', 'media.update', 'media.delete'],
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const WebhookEventContext = React.createContext();
|
|
92
|
+
|
|
93
|
+
const Root = ({ children }) => {
|
|
94
|
+
const { formatMessage } = useIntl();
|
|
95
|
+
const { collectionTypes, isLoading } = useContentTypes();
|
|
96
|
+
|
|
97
|
+
const isDraftAndPublish = React.useMemo(
|
|
98
|
+
() => collectionTypes.some((ct) => ct.options.draftAndPublish === true),
|
|
99
|
+
[collectionTypes]
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const label = formatMessage({
|
|
103
|
+
id: 'Settings.webhooks.form.events',
|
|
104
|
+
defaultMessage: 'Events',
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<WebhookEventContext.Provider value={{ isDraftAndPublish }}>
|
|
109
|
+
<Flex direction="column" alignItems="stretch" gap={1}>
|
|
110
|
+
<FieldLabel aria-hidden>{label}</FieldLabel>
|
|
111
|
+
{isLoading && (
|
|
112
|
+
<Loader>
|
|
113
|
+
{formatMessage({
|
|
114
|
+
id: 'Settings.webhooks.events.isLoading',
|
|
115
|
+
defaultMessage: 'Events loading',
|
|
116
|
+
})}
|
|
117
|
+
</Loader>
|
|
118
|
+
)}
|
|
119
|
+
<StyledTable aria-label={label}>{children}</StyledTable>
|
|
120
|
+
</Flex>
|
|
121
|
+
</WebhookEventContext.Provider>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
Root.propTypes = {
|
|
126
|
+
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const Headers = ({ getHeaders = getCEHeaders }) => {
|
|
130
|
+
const { isDraftAndPublish } = React.useContext(WebhookEventContext);
|
|
131
|
+
|
|
132
|
+
const { formatMessage } = useIntl();
|
|
133
|
+
const headers = getHeaders(isDraftAndPublish);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<Thead>
|
|
137
|
+
<Tr>
|
|
138
|
+
<Th>
|
|
139
|
+
<VisuallyHidden>
|
|
140
|
+
{formatMessage({
|
|
141
|
+
id: 'Settings.webhooks.event.select',
|
|
142
|
+
defaultMessage: 'Select event',
|
|
143
|
+
})}
|
|
144
|
+
</VisuallyHidden>
|
|
145
|
+
</Th>
|
|
146
|
+
{headers.map((header) => {
|
|
147
|
+
if (['app.utils.publish', 'app.utils.unpublish'].includes(header.id)) {
|
|
148
|
+
return (
|
|
149
|
+
<Th
|
|
150
|
+
key={header.id}
|
|
151
|
+
title={formatMessage({
|
|
152
|
+
id: 'Settings.webhooks.event.publish-tooltip',
|
|
153
|
+
defaultMessage: 'This event only exists for content with draft & publish enabled',
|
|
154
|
+
})}
|
|
155
|
+
>
|
|
156
|
+
<Typography variant="sigma" textColor="neutral600">
|
|
157
|
+
{formatMessage(header)}
|
|
158
|
+
</Typography>
|
|
159
|
+
</Th>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<Th key={header.id}>
|
|
165
|
+
<Typography variant="sigma" textColor="neutral600">
|
|
166
|
+
{formatMessage(header)}
|
|
167
|
+
</Typography>
|
|
168
|
+
</Th>
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
171
|
+
</Tr>
|
|
172
|
+
</Thead>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
Headers.defaultProps = {
|
|
177
|
+
getHeaders: getCEHeaders,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
Headers.propTypes = {
|
|
181
|
+
getHeaders: PropTypes.func,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const Body = ({ providedEvents }) => {
|
|
185
|
+
const { isDraftAndPublish } = React.useContext(WebhookEventContext);
|
|
186
|
+
|
|
187
|
+
const events = providedEvents || getCEEvents(isDraftAndPublish);
|
|
188
|
+
const { values, handleChange: onChange } = useFormikContext();
|
|
189
|
+
|
|
190
|
+
const inputName = 'events';
|
|
191
|
+
const inputValue = values.events;
|
|
192
|
+
const disabledEvents = [];
|
|
193
|
+
|
|
194
|
+
const formattedValue = formatValue(inputValue);
|
|
195
|
+
|
|
196
|
+
const handleSelect = ({ target: { name, value } }) => {
|
|
197
|
+
let set = new Set(inputValue);
|
|
198
|
+
|
|
199
|
+
if (value) {
|
|
200
|
+
set.add(name);
|
|
201
|
+
} else {
|
|
202
|
+
set.delete(name);
|
|
203
|
+
}
|
|
204
|
+
onChange({ target: { name: inputName, value: Array.from(set) } });
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const handleSelectAll = ({ target: { name, value } }) => {
|
|
208
|
+
let set = new Set(inputValue);
|
|
209
|
+
|
|
210
|
+
if (value) {
|
|
211
|
+
events[name].forEach((event) => {
|
|
212
|
+
if (!disabledEvents.includes(event)) {
|
|
213
|
+
set.add(event);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
} else {
|
|
217
|
+
events[name].forEach((event) => set.delete(event));
|
|
218
|
+
}
|
|
219
|
+
onChange({ target: { name: inputName, value: Array.from(set) } });
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<Tbody>
|
|
224
|
+
{Object.entries(events).map(([event, value]) => {
|
|
225
|
+
return (
|
|
226
|
+
<EventRow
|
|
227
|
+
disabledEvents={disabledEvents}
|
|
228
|
+
key={event}
|
|
229
|
+
name={event}
|
|
230
|
+
events={value}
|
|
231
|
+
inputValue={formattedValue[event]}
|
|
232
|
+
handleSelect={handleSelect}
|
|
233
|
+
handleSelectAll={handleSelectAll}
|
|
234
|
+
/>
|
|
235
|
+
);
|
|
236
|
+
})}
|
|
237
|
+
</Tbody>
|
|
238
|
+
);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
Body.defaultProps = {
|
|
242
|
+
providedEvents: null,
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
Body.propTypes = {
|
|
246
|
+
providedEvents: PropTypes.object,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Converts a string to title case and removes hyphens.
|
|
251
|
+
*
|
|
252
|
+
* @param {string} str - The string to convert.
|
|
253
|
+
* @returns {string} The converted string.
|
|
254
|
+
*/
|
|
255
|
+
const removeHyphensAndTitleCase = (str) =>
|
|
256
|
+
str
|
|
257
|
+
.replace(/-/g, ' ')
|
|
258
|
+
.split(' ')
|
|
259
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
260
|
+
.join(' ');
|
|
261
|
+
|
|
262
|
+
const EventRow = ({ disabledEvents, name, events, inputValue, handleSelect, handleSelectAll }) => {
|
|
263
|
+
const { formatMessage } = useIntl();
|
|
264
|
+
const enabledCheckboxes = events.filter((event) => !disabledEvents.includes(event));
|
|
265
|
+
|
|
266
|
+
const hasSomeCheckboxSelected = inputValue.length > 0;
|
|
267
|
+
const areAllCheckboxesSelected = inputValue.length === enabledCheckboxes.length;
|
|
268
|
+
|
|
269
|
+
const onChangeAll = ({ target: { name } }) => {
|
|
270
|
+
const valueToSet = !areAllCheckboxesSelected;
|
|
271
|
+
|
|
272
|
+
handleSelectAll({
|
|
273
|
+
target: { name, value: valueToSet },
|
|
274
|
+
});
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
const targetColumns = 5;
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<Tr>
|
|
281
|
+
<Td>
|
|
282
|
+
<Checkbox
|
|
283
|
+
indeterminate={hasSomeCheckboxSelected && !areAllCheckboxesSelected}
|
|
284
|
+
aria-label={formatMessage({
|
|
285
|
+
id: 'global.select-all-entries',
|
|
286
|
+
defaultMessage: 'Select all entries',
|
|
287
|
+
})}
|
|
288
|
+
name={name}
|
|
289
|
+
onChange={onChangeAll}
|
|
290
|
+
value={areAllCheckboxesSelected}
|
|
291
|
+
>
|
|
292
|
+
{removeHyphensAndTitleCase(name)}
|
|
293
|
+
</Checkbox>
|
|
294
|
+
</Td>
|
|
295
|
+
|
|
296
|
+
{events.map((event) => {
|
|
297
|
+
return (
|
|
298
|
+
<Td key={event}>
|
|
299
|
+
<BaseCheckbox
|
|
300
|
+
disabled={disabledEvents.includes(event)}
|
|
301
|
+
aria-label={event}
|
|
302
|
+
name={event}
|
|
303
|
+
value={inputValue.includes(event)}
|
|
304
|
+
onValueChange={(value) => handleSelect({ target: { name: event, value } })}
|
|
305
|
+
/>
|
|
306
|
+
</Td>
|
|
307
|
+
);
|
|
308
|
+
})}
|
|
309
|
+
{events.length < targetColumns && <Td colSpan={`${targetColumns - events.length}`} />}
|
|
310
|
+
</Tr>
|
|
311
|
+
);
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
EventRow.defaultProps = {
|
|
315
|
+
disabledEvents: [],
|
|
316
|
+
events: [],
|
|
317
|
+
inputValue: [],
|
|
318
|
+
handleSelect() {},
|
|
319
|
+
handleSelectAll() {},
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
EventRow.propTypes = {
|
|
323
|
+
disabledEvents: PropTypes.array,
|
|
324
|
+
events: PropTypes.array,
|
|
325
|
+
inputValue: PropTypes.array,
|
|
326
|
+
handleSelect: PropTypes.func,
|
|
327
|
+
handleSelectAll: PropTypes.func,
|
|
328
|
+
name: PropTypes.string.isRequired,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export default { Root, Headers, Body, EventRow };
|
package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/Combobox.js
CHANGED
|
@@ -1,10 +1,59 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import { useFormikContext } from 'formik';
|
|
3
4
|
import { ComboboxOption, CreatableCombobox } from '@strapi/design-system';
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
const HTTP_HEADERS = [
|
|
7
|
+
'A-IM',
|
|
8
|
+
'Accept',
|
|
9
|
+
'Accept-Charset',
|
|
10
|
+
'Accept-Encoding',
|
|
11
|
+
'Accept-Language',
|
|
12
|
+
'Accept-Datetime',
|
|
13
|
+
'Access-Control-Request-Method',
|
|
14
|
+
'Access-Control-Request-Headers',
|
|
15
|
+
'Authorization',
|
|
16
|
+
'Cache-Control',
|
|
17
|
+
'Connection',
|
|
18
|
+
'Content-Length',
|
|
19
|
+
'Content-Type',
|
|
20
|
+
'Cookie',
|
|
21
|
+
'Date',
|
|
22
|
+
'Expect',
|
|
23
|
+
'Forwarded',
|
|
24
|
+
'From',
|
|
25
|
+
'Host',
|
|
26
|
+
'If-Match',
|
|
27
|
+
'If-Modified-Since',
|
|
28
|
+
'If-None-Match',
|
|
29
|
+
'If-Range',
|
|
30
|
+
'If-Unmodified-Since',
|
|
31
|
+
'Max-Forwards',
|
|
32
|
+
'Origin',
|
|
33
|
+
'Pragma',
|
|
34
|
+
'Proxy-Authorization',
|
|
35
|
+
'Range',
|
|
36
|
+
'Referer',
|
|
37
|
+
'TE',
|
|
38
|
+
'User-Agent',
|
|
39
|
+
'Upgrade',
|
|
40
|
+
'Via',
|
|
41
|
+
'Warning',
|
|
42
|
+
];
|
|
5
43
|
|
|
6
44
|
const Combobox = ({ name, onChange, value, ...props }) => {
|
|
7
|
-
const
|
|
45
|
+
const {
|
|
46
|
+
values: { headers },
|
|
47
|
+
} = useFormikContext();
|
|
48
|
+
const [options, setOptions] = useState(HTTP_HEADERS);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setOptions(
|
|
52
|
+
HTTP_HEADERS.filter(
|
|
53
|
+
(key) => !headers?.some((header) => header.key !== value && header.key === key)
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
}, [headers, value]);
|
|
8
57
|
|
|
9
58
|
const handleChange = (value) => {
|
|
10
59
|
onChange({ target: { name, value } });
|
|
@@ -13,12 +62,13 @@ const Combobox = ({ name, onChange, value, ...props }) => {
|
|
|
13
62
|
const handleCreateOption = (value) => {
|
|
14
63
|
setOptions((prev) => [...prev, value]);
|
|
15
64
|
|
|
16
|
-
|
|
65
|
+
handleChange(value);
|
|
17
66
|
};
|
|
18
67
|
|
|
19
68
|
return (
|
|
20
69
|
<CreatableCombobox
|
|
21
70
|
{...props}
|
|
71
|
+
onClear={() => handleChange('')}
|
|
22
72
|
onChange={handleChange}
|
|
23
73
|
onCreateOption={handleCreateOption}
|
|
24
74
|
placeholder=""
|