@strapi/admin 4.11.0-exp.9xg4-3qfm-9w8f.1 → 4.11.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.
Files changed (112) hide show
  1. package/admin/src/components/Providers/index.js +32 -32
  2. package/admin/src/components/Theme/index.js +5 -3
  3. package/admin/src/content-manager/components/ComponentIcon/ComponentIcon.js +16 -26
  4. package/admin/src/content-manager/components/ComponentIcon/constants.js +133 -0
  5. package/admin/src/content-manager/components/DynamicTable/BulkActionsBar/index.js +307 -0
  6. package/admin/src/content-manager/components/DynamicTable/index.js +20 -4
  7. package/admin/src/content-manager/components/DynamicZone/components/AddComponentButton.js +32 -95
  8. package/admin/src/content-manager/components/DynamicZone/components/ComponentCard.js +10 -2
  9. package/admin/src/content-manager/components/DynamicZone/components/ComponentCategory.js +63 -15
  10. package/admin/src/content-manager/components/DynamicZone/components/ComponentPicker.js +50 -63
  11. package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +132 -58
  12. package/admin/src/content-manager/components/DynamicZone/components/DynamicZoneLabel.js +29 -37
  13. package/admin/src/content-manager/components/DynamicZone/index.js +131 -83
  14. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +12 -4
  15. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +18 -6
  16. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +0 -1
  17. package/admin/src/content-manager/components/Inputs/index.js +18 -11
  18. package/admin/src/content-manager/components/Inputs/utils/index.js +0 -1
  19. package/admin/src/content-manager/pages/EditSettingsView/components/DynamicZoneList.js +7 -1
  20. package/admin/src/content-manager/pages/EditView/index.js +1 -1
  21. package/admin/src/content-manager/pages/ListView/index.js +118 -2
  22. package/admin/src/content-manager/utils/index.js +2 -0
  23. package/admin/src/content-manager/{components/EditViewDataManagerProvider/utils → utils}/schema.js +1 -1
  24. package/admin/src/injectionZones.js +6 -1
  25. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableCE.js +13 -0
  26. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/index.js +3 -0
  27. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +331 -0
  28. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/Combobox.js +54 -4
  29. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/index.js +12 -23
  30. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/index.js +129 -116
  31. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +62 -0
  32. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/index.js +59 -64
  33. package/admin/src/translations/en.json +11 -1
  34. package/build/3562.e0b1a0b3.chunk.js +50 -0
  35. package/build/371.6e4e2c1f.chunk.js +71 -0
  36. package/build/5297.31c9ffdc.chunk.js +39 -0
  37. package/build/{5563.79950369.chunk.js → 5563.badbffde.chunk.js} +2 -2
  38. package/build/{3081.7e9329cb.chunk.js → 6691.f7a3b5ac.chunk.js} +2 -2
  39. package/build/6970.d456705f.chunk.js +1 -0
  40. package/build/{7259.5cc67413.chunk.js → 7259.5d0de931.chunk.js} +1 -1
  41. package/build/8976.0022f5a3.chunk.js +50 -0
  42. package/build/{1657.3f2b2c11.chunk.js → 9932.5ef475c5.chunk.js} +54 -54
  43. package/build/Admin-authenticatedApp.ab2b5910.chunk.js +79 -0
  44. package/build/{Admin_InternalErrorPage.96ceaae1.chunk.js → Admin_InternalErrorPage.f25f04f3.chunk.js} +1 -1
  45. package/build/{Admin_homePage.94dc81b1.chunk.js → Admin_homePage.05063e43.chunk.js} +16 -16
  46. package/build/{Admin_marketplace.1b0c3d3b.chunk.js → Admin_marketplace.005d2d5b.chunk.js} +11 -11
  47. package/build/{Admin_pluginsPage.a28b96d5.chunk.js → Admin_pluginsPage.5d9d4060.chunk.js} +1 -1
  48. package/build/{Admin_profilePage.a8fa3a56.chunk.js → Admin_profilePage.ab7b94d7.chunk.js} +2 -2
  49. package/build/{Admin_settingsPage.ee76d19e.chunk.js → Admin_settingsPage.07a6a5f0.chunk.js} +2 -2
  50. package/build/{Upload_ConfigureTheView.aa64ed9a.chunk.js → Upload_ConfigureTheView.121deffb.chunk.js} +1 -1
  51. package/build/{admin-app.bd209f08.chunk.js → admin-app.7cc667be.chunk.js} +10 -10
  52. package/build/{admin-edit-roles-page.0d12b741.chunk.js → admin-edit-roles-page.bfe3304d.chunk.js} +3 -3
  53. package/build/{admin-edit-users.f9ce7844.chunk.js → admin-edit-users.6efe0382.chunk.js} +2 -2
  54. package/build/{admin-roles-list.af53b372.chunk.js → admin-roles-list.b2577370.chunk.js} +1 -1
  55. package/build/{admin-users.0fc77b35.chunk.js → admin-users.4af49ccf.chunk.js} +2 -2
  56. package/build/{api-tokens-create-page.973d2816.chunk.js → api-tokens-create-page.65411a36.chunk.js} +1 -1
  57. package/build/{api-tokens-edit-page.29725c5e.chunk.js → api-tokens-edit-page.60312cb6.chunk.js} +1 -1
  58. package/build/{api-tokens-list-page.66c4fbdd.chunk.js → api-tokens-list-page.01a4d5cd.chunk.js} +2 -2
  59. package/build/audit-logs-settings-page.b165679b.chunk.js +16 -0
  60. package/build/content-manager.8cc6c3f9.chunk.js +1094 -0
  61. package/build/content-type-builder-list-view.58f9ed20.chunk.js +211 -0
  62. package/build/{content-type-builder-translation-en-json.af293c9e.chunk.js → content-type-builder-translation-en-json.f592325b.chunk.js} +1 -1
  63. package/build/content-type-builder.baeb0413.chunk.js +132 -0
  64. package/build/{email-settings-page.63f269ff.chunk.js → email-settings-page.8caad83f.chunk.js} +1 -1
  65. package/build/en-json.a8f34002.chunk.js +1 -0
  66. package/build/i18n-settings-page.579d5eab.chunk.js +9 -0
  67. package/build/i18n-translation-en-json.1ec7becf.chunk.js +1 -0
  68. package/build/index.html +1 -1
  69. package/build/main.1d678f7b.js +2926 -0
  70. package/build/{review-workflows-settings.56cab253.chunk.js → review-workflows-settings.3a7bae25.chunk.js} +2 -2
  71. package/build/{runtime~main.0dfc909e.js → runtime~main.9dbd4553.js} +2 -2
  72. package/build/{sso-settings-page.265e3d72.chunk.js → sso-settings-page.4bb073e0.chunk.js} +1 -1
  73. package/build/{transfer-tokens-create-page.170acee6.chunk.js → transfer-tokens-create-page.9ec277d7.chunk.js} +1 -1
  74. package/build/{transfer-tokens-edit-page.6cf23295.chunk.js → transfer-tokens-edit-page.fa5ade14.chunk.js} +1 -1
  75. package/build/{transfer-tokens-list-page.c3fec4c1.chunk.js → transfer-tokens-list-page.5d68d590.chunk.js} +2 -2
  76. package/build/{upload-settings.1d187578.chunk.js → upload-settings.2c1565d6.chunk.js} +1 -1
  77. package/build/{upload.bc340679.chunk.js → upload.257b2aef.chunk.js} +1 -1
  78. package/build/{users-advanced-settings-page.7b4bf63a.chunk.js → users-advanced-settings-page.ddd29040.chunk.js} +1 -1
  79. package/build/{users-email-settings-page.035a026c.chunk.js → users-email-settings-page.717e2a51.chunk.js} +1 -1
  80. package/build/{users-providers-settings-page.6873dce9.chunk.js → users-providers-settings-page.c7eae829.chunk.js} +1 -1
  81. package/build/{users-roles-settings-page.2549794b.chunk.js → users-roles-settings-page.63cf2838.chunk.js} +1 -1
  82. package/build/webhook-edit-page.8576742e.chunk.js +31 -0
  83. package/build/{webhook-list-page.0861d3e9.chunk.js → webhook-list-page.abf5747c.chunk.js} +1 -1
  84. package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableEE.js +23 -0
  85. package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/index.js +3 -0
  86. package/package.json +13 -13
  87. package/admin/src/content-manager/components/DynamicTable/ConfirmDialogDeleteAll/index.js +0 -73
  88. package/admin/src/content-manager/components/DynamicZone/utils/connect.js +0 -12
  89. package/admin/src/content-manager/components/DynamicZone/utils/select.js +0 -53
  90. package/admin/src/content-manager/components/Inputs/utils/getStep.js +0 -13
  91. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/EventRow.js +0 -70
  92. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/EventInput/index.js +0 -174
  93. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/HeadersInput/keys.js +0 -39
  94. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/utils/fieldsRegex.js +0 -4
  95. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/utils/schema.js +0 -35
  96. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/reducer.js +0 -100
  97. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/utils/formatData.js +0 -20
  98. package/build/462.6f8cbd19.chunk.js +0 -71
  99. package/build/617.0518c0ba.chunk.js +0 -155
  100. package/build/6858.85d76858.chunk.js +0 -50
  101. package/build/6970.6a329e15.chunk.js +0 -1
  102. package/build/9036.f7ce35cc.chunk.js +0 -211
  103. package/build/Admin-authenticatedApp.e7ca2959.chunk.js +0 -79
  104. package/build/audit-logs-settings-page.6bc76e7d.chunk.js +0 -121
  105. package/build/content-manager.8bfce7f0.chunk.js +0 -1123
  106. package/build/content-type-builder-list-view.26aab6f3.chunk.js +0 -215
  107. package/build/content-type-builder.b10576e7.chunk.js +0 -126
  108. package/build/en-json.ba3290b8.chunk.js +0 -1
  109. package/build/i18n-settings-page.2ac4ca58.chunk.js +0 -114
  110. package/build/i18n-translation-en-json.60af6722.chunk.js +0 -1
  111. package/build/main.aca47de6.js +0 -2633
  112. package/build/webhook-edit-page.0bc97587.chunk.js +0 -128
@@ -1,145 +1,159 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
+ import { Field, FormikProvider, useFormik } from 'formik';
4
+ import { useIntl } from 'react-intl';
3
5
  import { Form, Link } from '@strapi/helper-plugin';
4
6
  import { ArrowLeft, Check, Play as Publish } from '@strapi/icons';
5
7
  import {
6
- ContentLayout,
7
- HeaderLayout,
8
- Box,
8
+ Grid,
9
+ GridItem,
9
10
  Button,
10
11
  Flex,
11
12
  TextInput,
12
- Grid,
13
- GridItem,
13
+ HeaderLayout,
14
+ ContentLayout,
15
+ Box,
14
16
  } from '@strapi/design-system';
15
- import { Field, Formik } from 'formik';
16
17
 
17
- import { useIntl } from 'react-intl';
18
- import EventInput from '../EventInput';
18
+ import EventTable from 'ee_else_ce/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable';
19
+ import { makeWebhookValidationSchema } from './utils/makeWebhookValidationSchema';
19
20
  import HeadersInput from '../HeadersInput';
20
21
  import TriggerContainer from '../TriggerContainer';
21
- import schema from '../utils/schema';
22
22
 
23
23
  const WebhookForm = ({
24
24
  handleSubmit,
25
- data,
26
25
  triggerWebhook,
27
26
  isCreating,
28
27
  isTriggering,
29
28
  triggerResponse,
30
- isDraftAndPublishEvents,
29
+ data,
31
30
  }) => {
32
31
  const { formatMessage } = useIntl();
33
32
  const [showTriggerResponse, setShowTriggerResponse] = useState(false);
34
33
 
34
+ /**
35
+ * Map the headers into a form that can be used within the formik form
36
+ * @param {Object} headers
37
+ * @returns {Array}
38
+ */
39
+ const mapHeaders = (headers) => {
40
+ if (!Object.keys(headers).length) {
41
+ return [{ key: '', value: '' }];
42
+ }
43
+
44
+ return Object.entries(headers).map(([key, value]) => ({ key, value }));
45
+ };
46
+
47
+ const formik = useFormik({
48
+ initialValues: {
49
+ name: data?.name || '',
50
+ url: data?.url || '',
51
+ headers: mapHeaders(data?.headers || {}),
52
+ events: data?.events || [],
53
+ },
54
+ onSubmit: handleSubmit,
55
+ validationSchema: makeWebhookValidationSchema({ formatMessage }),
56
+ validateOnChange: false,
57
+ validateOnBlur: false,
58
+ });
59
+
35
60
  return (
36
- <Formik
37
- onSubmit={handleSubmit}
38
- initialValues={{
39
- name: data?.name || '',
40
- url: data?.url || '',
41
- headers: Object.keys(data?.headers || []).length
42
- ? Object.entries(data.headers).map(([key, value]) => ({ key, value }))
43
- : [{ key: '', value: '' }],
44
- events: data?.events || [],
45
- }}
46
- validationSchema={schema}
47
- validateOnChange={false}
48
- validateOnBlur={false}
49
- >
50
- {({ handleSubmit, errors }) => (
51
- <Form noValidate>
52
- <HeaderLayout
53
- primaryAction={
54
- <Flex gap={2}>
55
- <Button
56
- onClick={() => {
57
- triggerWebhook();
58
- setShowTriggerResponse(true);
59
- }}
60
- variant="tertiary"
61
- startIcon={<Publish />}
62
- disabled={isCreating || isTriggering}
63
- size="L"
64
- >
65
- {formatMessage({
66
- id: 'Settings.webhooks.trigger',
67
- defaultMessage: 'Trigger',
68
- })}
69
- </Button>
70
- <Button startIcon={<Check />} onClick={handleSubmit} type="submit" size="L">
71
- {formatMessage({
72
- id: 'global.save',
73
- defaultMessage: 'Save',
74
- })}
75
- </Button>
76
- </Flex>
77
- }
78
- title={
79
- isCreating
80
- ? formatMessage({
81
- id: 'Settings.webhooks.create',
82
- defaultMessage: 'Create a webhook',
83
- })
84
- : data?.name
85
- }
86
- navigationAction={
87
- <Link startIcon={<ArrowLeft />} to="/settings/webhooks">
61
+ <FormikProvider value={formik}>
62
+ <Form onSubmit={formik.handleSubmit}>
63
+ <HeaderLayout
64
+ primaryAction={
65
+ <Flex gap={2}>
66
+ <Button
67
+ onClick={() => {
68
+ triggerWebhook();
69
+ setShowTriggerResponse(true);
70
+ }}
71
+ variant="tertiary"
72
+ startIcon={<Publish />}
73
+ disabled={isCreating || isTriggering}
74
+ size="L"
75
+ >
88
76
  {formatMessage({
89
- id: 'global.back',
90
- defaultMessage: 'Back',
77
+ id: 'Settings.webhooks.trigger',
78
+ defaultMessage: 'Trigger',
91
79
  })}
92
- </Link>
93
- }
94
- />
95
- <ContentLayout>
96
- <Flex direction="column" alignItems="stretch" gap={4}>
97
- {showTriggerResponse && (
98
- <div className="trigger-wrapper">
99
- <TriggerContainer
100
- isPending={isTriggering}
101
- response={triggerResponse}
102
- onCancel={() => setShowTriggerResponse(false)}
103
- />
104
- </div>
105
- )}
106
- <Box background="neutral0" padding={8} shadow="filterShadow" hasRadius>
107
- <Flex direction="column" alignItems="stretch" gap={6}>
108
- <Grid gap={6}>
109
- <GridItem col={6}>
110
- <Field
111
- as={TextInput}
112
- name="name"
113
- error={errors.name && formatMessage({ id: errors.name })}
114
- label={formatMessage({
115
- id: 'global.name',
116
- defaultMessage: 'Name',
117
- })}
118
- required
119
- />
120
- </GridItem>
121
- <GridItem col={12}>
122
- <Field
123
- as={TextInput}
124
- name="url"
125
- error={errors.url && formatMessage({ id: errors.url })}
126
- label={formatMessage({
127
- id: 'Settings.roles.form.input.url',
128
- defaultMessage: 'Url',
129
- })}
130
- required
131
- />
132
- </GridItem>
133
- </Grid>
134
- <HeadersInput />
135
- <EventInput isDraftAndPublish={isDraftAndPublishEvents} />
136
- </Flex>
137
- </Box>
80
+ </Button>
81
+ <Button
82
+ startIcon={<Check />}
83
+ type="submit"
84
+ size="L"
85
+ disabled={!formik.dirty}
86
+ loading={formik.isSubmitting}
87
+ >
88
+ {formatMessage({
89
+ id: 'global.save',
90
+ defaultMessage: 'Save',
91
+ })}
92
+ </Button>
138
93
  </Flex>
139
- </ContentLayout>
140
- </Form>
141
- )}
142
- </Formik>
94
+ }
95
+ title={
96
+ isCreating
97
+ ? formatMessage({
98
+ id: 'Settings.webhooks.create',
99
+ defaultMessage: 'Create a webhook',
100
+ })
101
+ : data?.name
102
+ }
103
+ navigationAction={
104
+ <Link startIcon={<ArrowLeft />} to="/settings/webhooks">
105
+ {formatMessage({
106
+ id: 'global.back',
107
+ defaultMessage: 'Back',
108
+ })}
109
+ </Link>
110
+ }
111
+ />
112
+ <ContentLayout>
113
+ <Flex direction="column" alignItems="stretch" gap={4}>
114
+ {showTriggerResponse && (
115
+ <TriggerContainer
116
+ isPending={isTriggering}
117
+ response={triggerResponse}
118
+ onCancel={() => setShowTriggerResponse(false)}
119
+ />
120
+ )}
121
+ <Box background="neutral0" padding={8} shadow="filterShadow" hasRadius>
122
+ <Flex direction="column" alignItems="stretch" gap={6}>
123
+ <Grid gap={6}>
124
+ <GridItem col={6}>
125
+ <Field
126
+ as={TextInput}
127
+ name="name"
128
+ error={formik?.errors?.name && formik.errors.name}
129
+ label={formatMessage({
130
+ id: 'global.name',
131
+ defaultMessage: 'Name',
132
+ })}
133
+ required
134
+ />
135
+ </GridItem>
136
+ <GridItem col={12}>
137
+ <Field
138
+ as={TextInput}
139
+ name="url"
140
+ error={formik?.errors?.url && formik.errors.url}
141
+ label={formatMessage({
142
+ id: 'Settings.roles.form.input.url',
143
+ defaultMessage: 'Url',
144
+ })}
145
+ required
146
+ />
147
+ </GridItem>
148
+ </Grid>
149
+ <HeadersInput />
150
+ <EventTable />
151
+ </Flex>
152
+ </Box>
153
+ </Flex>
154
+ </ContentLayout>
155
+ </Form>
156
+ </FormikProvider>
143
157
  );
144
158
  };
145
159
 
@@ -148,7 +162,6 @@ WebhookForm.propTypes = {
148
162
  handleSubmit: PropTypes.func.isRequired,
149
163
  triggerWebhook: PropTypes.func.isRequired,
150
164
  isCreating: PropTypes.bool.isRequired,
151
- isDraftAndPublishEvents: PropTypes.bool.isRequired,
152
165
  isTriggering: PropTypes.bool.isRequired,
153
166
  triggerResponse: PropTypes.object,
154
167
  };
@@ -0,0 +1,62 @@
1
+ import * as yup from 'yup';
2
+ import { translatedErrors } from '@strapi/helper-plugin';
3
+
4
+ const NAME_REGEX = /(^$)|(^[A-Za-z][_0-9A-Za-z ]*$)/;
5
+ const URL_REGEX = /(^$)|((https?:\/\/.*)(d*)\/?(.*))/;
6
+
7
+ export const makeWebhookValidationSchema = ({ formatMessage }) =>
8
+ yup.object().shape({
9
+ name: yup
10
+ .string()
11
+ .required(
12
+ formatMessage({
13
+ id: 'Settings.webhooks.validation.name',
14
+ defaultMessage: 'Name is required',
15
+ })
16
+ )
17
+ .matches(NAME_REGEX, translatedErrors.regex),
18
+ url: yup
19
+ .string()
20
+ .required(
21
+ formatMessage({
22
+ id: 'Settings.webhooks.validation.url.required',
23
+ defaultMessage: 'Url is required',
24
+ })
25
+ )
26
+ .matches(
27
+ URL_REGEX,
28
+ formatMessage({
29
+ id: translatedErrors.regex,
30
+ defaultMessage: 'The value does not match the regex',
31
+ })
32
+ ),
33
+ headers: yup.lazy((array) => {
34
+ let baseSchema = yup.array();
35
+
36
+ if (array.length === 1) {
37
+ const { key, value } = array[0];
38
+
39
+ if (!key && !value) {
40
+ return baseSchema;
41
+ }
42
+ }
43
+
44
+ return baseSchema.of(
45
+ yup.object().shape({
46
+ key: yup.string().required(
47
+ formatMessage({
48
+ id: 'Settings.webhooks.validation.key',
49
+ defaultMessage: 'Key is required',
50
+ })
51
+ ),
52
+ value: yup.string().required(
53
+ formatMessage({
54
+ id: 'Settings.webhooks.validation.value',
55
+ defaultMessage: 'Value is required',
56
+ })
57
+ ),
58
+ })
59
+ );
60
+ }),
61
+ events: yup.array(),
62
+ });
@@ -1,60 +1,68 @@
1
- /**
2
- *
3
- * EditView
4
- *
5
- */
6
1
  import * as React from 'react';
7
2
  import {
8
3
  LoadingIndicatorPage,
9
4
  SettingsPageTitle,
10
5
  useNotification,
11
- useOverlayBlocker,
12
6
  useFetchClient,
7
+ useAPIErrorHandler,
13
8
  } from '@strapi/helper-plugin';
14
9
  import { Main } from '@strapi/design-system';
15
10
  import { useMutation, useQuery, useQueryClient } from 'react-query';
16
11
  import { useHistory, useRouteMatch } from 'react-router-dom';
17
12
  import { useContentTypes } from '../../../../../hooks/useContentTypes';
18
13
  import WebhookForm from './components/WebhookForm';
19
- import cleanData from './utils/formatData';
14
+
15
+ const cleanData = (data) => ({
16
+ ...data,
17
+ headers: data.headers.reduce((acc, { key, value }) => {
18
+ if (key !== '') {
19
+ acc[key] = value;
20
+ }
21
+
22
+ return acc;
23
+ }, {}),
24
+ });
20
25
 
21
26
  const EditView = () => {
22
27
  const {
23
28
  params: { id },
24
29
  } = useRouteMatch('/settings/webhooks/:id');
30
+ const isCreating = id === 'create';
25
31
 
26
32
  const { replace } = useHistory();
27
- const { lockApp, unlockApp } = useOverlayBlocker();
28
33
  const toggleNotification = useNotification();
34
+ const { formatAPIError } = useAPIErrorHandler();
29
35
  const queryClient = useQueryClient();
30
- const { isLoading: isLoadingForModels, collectionTypes } = useContentTypes();
36
+ const { isLoading: isLoadingForModels } = useContentTypes();
31
37
  const { put, get, post } = useFetchClient();
32
38
 
33
- const isCreating = id === 'create';
34
-
35
- const { isLoading, data } = useQuery(
36
- ['get-webhook', id],
39
+ const {
40
+ isLoading,
41
+ data: webhookData,
42
+ error: webhookError,
43
+ } = useQuery(
44
+ ['webhooks', id],
37
45
  async () => {
38
- try {
39
- const {
40
- data: { data },
41
- } = await get(`/admin/webhooks/${id}`);
46
+ const {
47
+ data: { data },
48
+ } = await get(`/admin/webhooks/${id}`);
42
49
 
43
- return data;
44
- } catch (err) {
45
- toggleNotification({
46
- type: 'warning',
47
- message: { id: 'notification.error' },
48
- });
49
-
50
- return null;
51
- }
50
+ return data;
52
51
  },
53
52
  {
54
53
  enabled: !isCreating,
55
54
  }
56
55
  );
57
56
 
57
+ React.useEffect(() => {
58
+ if (webhookError) {
59
+ toggleNotification({
60
+ type: 'warning',
61
+ message: formatAPIError(webhookError),
62
+ });
63
+ }
64
+ }, [webhookError, toggleNotification, formatAPIError]);
65
+
58
66
  const {
59
67
  isLoading: isTriggering,
60
68
  data: triggerResponse,
@@ -64,10 +72,10 @@ const EditView = () => {
64
72
 
65
73
  const triggerWebhook = () =>
66
74
  mutate(null, {
67
- onError() {
75
+ onError(error) {
68
76
  toggleNotification({
69
77
  type: 'warning',
70
- message: { id: 'notification.error' },
78
+ message: formatAPIError(error),
71
79
  });
72
80
  },
73
81
  });
@@ -78,7 +86,6 @@ const EditView = () => {
78
86
 
79
87
  const handleSubmit = async (data) => {
80
88
  if (isCreating) {
81
- lockApp();
82
89
  createWebhookMutation.mutate(cleanData(data), {
83
90
  onSuccess({ data: result }) {
84
91
  toggleNotification({
@@ -86,48 +93,37 @@ const EditView = () => {
86
93
  message: { id: 'Settings.webhooks.created' },
87
94
  });
88
95
  replace(`/settings/webhooks/${result.data.id}`);
89
- unlockApp();
90
96
  },
91
- onError(e) {
97
+ onError(error) {
92
98
  toggleNotification({
93
99
  type: 'warning',
94
- message: { id: 'notification.error' },
100
+ message: formatAPIError(error),
95
101
  });
96
- console.log(e);
97
- unlockApp();
98
102
  },
99
103
  });
100
- } else {
101
- lockApp();
102
- updateWebhookMutation.mutate(
103
- { id, body: cleanData(data) },
104
- {
105
- onSuccess() {
106
- queryClient.invalidateQueries(['get-webhook', id]);
107
- toggleNotification({
108
- type: 'success',
109
- message: { id: 'notification.form.success.fields' },
110
- });
111
- unlockApp();
112
- },
113
- onError(e) {
114
- toggleNotification({
115
- type: 'warning',
116
- message: { id: 'notification.error' },
117
- });
118
- console.log(e);
119
- unlockApp();
120
- },
121
- }
122
- );
104
+
105
+ return;
123
106
  }
107
+ updateWebhookMutation.mutate(
108
+ { id, body: cleanData(data) },
109
+ {
110
+ onSuccess() {
111
+ queryClient.invalidateQueries(['webhooks', id]);
112
+ toggleNotification({
113
+ type: 'success',
114
+ message: { id: 'notification.form.success.fields' },
115
+ });
116
+ },
117
+ onError(error) {
118
+ toggleNotification({
119
+ type: 'warning',
120
+ message: formatAPIError(error),
121
+ });
122
+ },
123
+ }
124
+ );
124
125
  };
125
126
 
126
- const isDraftAndPublishEvents = React.useMemo(
127
- () => collectionTypes.some((ct) => ct.options.draftAndPublish === true),
128
- [collectionTypes]
129
- );
130
-
131
127
  if (isLoading || isLoadingForModels) {
132
128
  return <LoadingIndicatorPage />;
133
129
  }
@@ -137,14 +133,13 @@ const EditView = () => {
137
133
  <SettingsPageTitle name="Webhooks" />
138
134
  <WebhookForm
139
135
  {...{
136
+ data: webhookData,
140
137
  handleSubmit,
141
- data,
142
138
  triggerWebhook,
143
139
  isCreating,
144
140
  isTriggering,
145
141
  isTriggerIdle,
146
142
  triggerResponse: triggerResponse?.data.data,
147
- isDraftAndPublishEvents,
148
143
  }}
149
144
  />
150
145
  </Main>
@@ -285,6 +285,8 @@
285
285
  "Settings.webhooks.create.header": "Create new header",
286
286
  "Settings.webhooks.created": "Webhook created",
287
287
  "Settings.webhooks.event.publish-tooltip": "This event only exists for contents with Draft/Publish system enabled",
288
+ "Settings.webhooks.event.select": "Select event",
289
+ "Settings.webhooks.events.isLoading": "Events loading",
288
290
  "Settings.webhooks.events.create": "Create",
289
291
  "Settings.webhooks.events.update": "Update",
290
292
  "Settings.webhooks.events.delete": "Delete webhook",
@@ -313,6 +315,10 @@
313
315
  "Settings.webhooks.trigger.test": "Test-trigger",
314
316
  "Settings.webhooks.trigger.title": "Save before Trigger",
315
317
  "Settings.webhooks.value": "Value",
318
+ "Settings.webhooks.validation.name": "Name is required",
319
+ "Settings.webhooks.validation.url.required": "Url is required",
320
+ "Settings.webhooks.validation.key": "Key is required",
321
+ "Settings.webhooks.validation.value": "Value is required",
316
322
  "Usecase.back-end": "Back-end developer",
317
323
  "Usecase.button.skip": "Skip this question",
318
324
  "Usecase.content-creator": "Content Creator",
@@ -795,7 +801,9 @@
795
801
  "content-manager.plugin.description.long": "Quick way to see, edit and delete the data in your database.",
796
802
  "content-manager.plugin.description.short": "Quick way to see, edit and delete the data in your database.",
797
803
  "content-manager.popUpWarning.bodyMessage.contentType.delete": "Are you sure to delete Content-Type?",
798
- "content-manager.popUpWarning.bodyMessage.contentType.delete.all": "Are you sure to delete all Content-Types?",
804
+ "content-manager.popUpWarning.bodyMessage.contentType.delete.all": "Are you sure you want to delete these entries?",
805
+ "content-manager.popUpWarning.bodyMessage.contentType.publish.all": "Are you sure you want to publish these entries?",
806
+ "content-manager.popUpWarning.bodyMessage.contentType.unpublish.all": "Are you sure you want to unpublish these entries?",
799
807
  "content-manager.popUpWarning.warning.has-draft-relations.title": "Confirmation",
800
808
  "content-manager.popUpWarning.warning.publish-question": "Do you still want to publish?",
801
809
  "content-manager.popUpWarning.warning.unpublish": "If you don't publish this content, it will automatically turn into a Draft.",
@@ -818,6 +826,8 @@
818
826
  "content-manager.success.record.save": "Saved",
819
827
  "content-manager.success.record.unpublish": "Unpublished",
820
828
  "content-manager.utils.data-loaded": "The {number, plural, =1 {entry has} other {entries have}} successfully been loaded",
829
+ "content-manager.listView.validation.errors.title": "Action required",
830
+ "content-manager.listView.validation.errors.message": "Please make sure all fields are valid before publishing (required field, min/max character limit, etc.)",
821
831
  "dark": "Dark",
822
832
  "form.button.continue": "Continue",
823
833
  "form.button.done": "Done",
@@ -0,0 +1,50 @@
1
+ (self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[3562],{51355:function(E,m,r){var n=r(94318),u=r(3387),s="[object Boolean]";function x(v){return v===!0||v===!1||u(v)&&n(v)==s}E.exports=x},95919:function(E,m,r){var n=r(80022);function u(s){return n(s)&&s!=+s}E.exports=u},80022:function(E,m,r){var n=r(94318),u=r(3387),s="[object Number]";function x(v){return typeof v=="number"||u(v)&&n(v)==s}E.exports=x},59578:function(E,m,r){var n=r(41119);function u(s){return n(s).toLowerCase()}E.exports=u},98178:function(E,m,r){"use strict";r.d(m,{P1:function(){return j}});var n="NOT_FOUND";function u(l){var a;return{get:function(t){return a&&l(a.key,t)?a.value:n},put:function(t,o){a={key:t,value:o}},getEntries:function(){return a?[a]:[]},clear:function(){a=void 0}}}function s(l,a){var e=[];function t(p){var f=e.findIndex(function(g){return a(p,g.key)});if(f>-1){var h=e[f];return f>0&&(e.splice(f,1),e.unshift(h)),h.value}return n}function o(p,f){t(p)===n&&(e.unshift({key:p,value:f}),e.length>l&&e.pop())}function i(){return e}function c(){e=[]}return{get:t,put:o,getEntries:i,clear:c}}var x=function(a,e){return a===e};function v(l){return function(e,t){if(e===null||t===null||e.length!==t.length)return!1;for(var o=e.length,i=0;i<o;i++)if(!l(e[i],t[i]))return!1;return!0}}function M(l,a){var e=typeof a=="object"?a:{equalityCheck:a},t=e.equalityCheck,o=t===void 0?x:t,i=e.maxSize,c=i===void 0?1:i,p=e.resultEqualityCheck,f=v(o),h=c===1?u(f):s(c,f);function g(){var d=h.get(arguments);if(d===n){if(d=l.apply(null,arguments),p){var _=h.getEntries(),y=_.find(function(O){return p(O.value,d)});y&&(d=y.value)}h.put(arguments,d)}return d}return g.clearCache=function(){return h.clear()},g}function P(l){var a=Array.isArray(l[0])?l[0]:l;if(!a.every(function(t){return typeof t=="function"})){var e=a.map(function(t){return typeof t=="function"?"function "+(t.name||"unnamed")+"()":typeof t}).join(", ");throw new Error("createSelector expects all input-selectors to be functions, but received the following types: ["+e+"]")}return a}function b(l){for(var a=arguments.length,e=new Array(a>1?a-1:0),t=1;t<a;t++)e[t-1]=arguments[t];var o=function(){for(var c=arguments.length,p=new Array(c),f=0;f<c;f++)p[f]=arguments[f];var h=0,g,d={memoizeOptions:void 0},_=p.pop();if(typeof _=="object"&&(d=_,_=p.pop()),typeof _!="function")throw new Error("createSelector expects an output function after the inputs, but received: ["+typeof _+"]");var y=d,O=y.memoizeOptions,C=O===void 0?e:O,Z=Array.isArray(C)?C:[C],D=P(p),R=l.apply(void 0,[function(){return h++,_.apply(null,arguments)}].concat(Z)),A=l(function(){for(var B=[],S=D.length,T=0;T<S;T++)B.push(D[T].apply(null,arguments));return g=R.apply(null,B),g});return Object.assign(A,{resultFunc:_,memoizedResultFunc:R,dependencies:D,lastResult:function(){return g},recomputations:function(){return h},resetRecomputations:function(){return h=0}}),A};return o}var j=b(M),w=function(a,e){if(e===void 0&&(e=j),typeof a!="object")throw new Error("createStructuredSelector expects first argument to be an object "+("where each property is a selector, instead received a "+typeof a));var t=Object.keys(a),o=e(t.map(function(i){return a[i]}),function(){for(var i=arguments.length,c=new Array(i),p=0;p<i;p++)c[p]=arguments[p];return c.reduce(function(f,h,g){return f[t[g]]=h,f},{})});return o}},83828:function(E,m,r){"use strict";r.d(m,{U:function(){return a},y:function(){return w}});var n=r(74512),u=r(32735),s=r(8471),x=r(91045),v=r(74971),M=r(49372),P=r(87933),b=r(72850);const j=({theme:e,expanded:t,variant:o,disabled:i,error:c})=>c?`1px solid ${e.colors.danger600} !important`:i?`1px solid ${e.colors.neutral150}`:t?`1px solid ${e.colors.primary600}`:o==="primary"?`1px solid ${e.colors.neutral0}`:`1px solid ${e.colors.neutral100}`,w=(0,s.ZP)(M.Z)``,l=(0,s.ZP)(b.x)`
2
+ border: ${j};
3
+
4
+ &:hover:not([aria-disabled='true']) {
5
+ border: 1px solid ${({theme:e})=>e.colors.primary600};
6
+
7
+ ${w} {
8
+ color: ${({theme:e,expanded:t})=>t?void 0:e.colors.primary700};
9
+ }
10
+
11
+ ${M.Z} {
12
+ color: ${({theme:e,expanded:t})=>t?void 0:e.colors.primary600};
13
+ }
14
+
15
+ & > ${P.k} {
16
+ background: ${({theme:e})=>e.colors.primary100};
17
+ }
18
+
19
+ [data-strapi-dropdown='true'] {
20
+ background: ${({theme:e})=>e.colors.primary200};
21
+ }
22
+ }
23
+ `,a=({children:e,disabled:t=!1,error:o,expanded:i=!1,hasErrorMessage:c=!0,id:p,onToggle:f,toggle:h,size:g="M",variant:d="primary",shadow:_})=>{const y=(0,v.M)(p),O=u.useMemo(()=>({expanded:i,onToggle:f,toggle:h,id:y,size:g,variant:d,disabled:t}),[t,i,y,f,g,h,d]);return(0,n.jsxs)(x.S.Provider,{value:O,children:[(0,n.jsx)(l,{"data-strapi-expanded":i,disabled:t,"aria-disabled":t,expanded:i,hasRadius:!0,variant:d,error:o,shadow:_,children:e}),o&&c&&(0,n.jsx)(b.x,{paddingTop:1,children:(0,n.jsx)(M.Z,{variant:"pi",textColor:"danger600",children:o})})]})}},89966:function(E,m,r){"use strict";r.d(m,{v:function(){return x}});var n=r(74512),u=r(91045),s=r(72850);const x=({children:v,...M})=>{const{expanded:P,id:b}=(0,u.A)();if(!P)return null;const j=`accordion-content-${b}`,w=`accordion-label-${b}`,l=`accordion-desc-${b}`;return(0,n.jsx)(s.x,{role:"region",id:j,"aria-labelledby":w,"aria-describedby":l,...M,children:v})}},91045:function(E,m,r){"use strict";r.d(m,{A:function(){return s},S:function(){return u}});var n=r(32735);const u=(0,n.createContext)({disabled:!1,expanded:!1,id:"",size:"M",variant:"primary"}),s=()=>(0,n.useContext)(u)},61762:function(E,m,r){"use strict";r.d(m,{B:function(){return e}});var n=r(74512),u=r(16899),s=r(8471),x=r(83828),v=r(91045);const M=({expanded:t,disabled:o,variant:i})=>{let c="neutral100";return t?c="primary100":o?c="neutral150":i==="primary"&&(c="neutral0"),c};var P=r(7563),b=r(99140),j=r(87933),w=r(49372);const l=(0,s.ZP)(P.A)`
24
+ text-align: left;
25
+
26
+ // necessary to make the ellipsis prop work on the title
27
+ > span {
28
+ max-width: 100%;
29
+ }
30
+
31
+ svg {
32
+ width: ${14/16}rem;
33
+ height: ${14/16}rem;
34
+
35
+ path {
36
+ fill: ${({theme:t,expanded:o})=>o?t.colors.primary600:t.colors.neutral500};
37
+ }
38
+ }
39
+ `,a=(0,s.ZP)(j.k)`
40
+ min-height: ${({theme:t,size:o})=>t.sizes.accordions[o]};
41
+ border-radius: ${({theme:t,expanded:o})=>o?`${t.borderRadius} ${t.borderRadius} 0 0`:t.borderRadius};
42
+
43
+ &:hover {
44
+ svg {
45
+ path {
46
+ fill: ${({theme:t})=>t.colors.primary600};
47
+ }
48
+ }
49
+ }
50
+ `,e=({title:t,description:o,as:i="span",togglePosition:c="right",action:p,...f})=>{const{onToggle:h,toggle:g,expanded:d,id:_,size:y,variant:O,disabled:C}=(0,v.A)(),Z=`accordion-content-${_}`,D=`accordion-label-${_}`,R=`accordion-desc-${_}`,A=y==="M"?6:4,$=y==="M"?A:A-2,B=M({expanded:d,disabled:C,variant:O}),S={as:i,fontWeight:y==="S"?"bold":void 0,id:D,textColor:d?"primary600":"neutral700",ellipsis:!0,variant:y==="M"?"delta":void 0},T=d?"primary600":"neutral600",W=d?"primary200":"neutral200",L=y==="M"?`${32/16}rem`:`${24/16}rem`,I=()=>{C||(g&&!h?(console.warn('Deprecation warning: Usage of "toggle" prop in Accordion component is deprecated. This is discouraged and will be removed in the next major release. Please use "onToggle" instead'),g()):h&&h())},U=(0,n.jsx)(j.k,{justifyContent:"center",borderRadius:"50%",height:L,width:L,transform:d?"rotate(180deg)":void 0,"data-strapi-dropdown":!0,"aria-hidden":!0,as:"span",background:W,cursor:C?"not-allowed":"pointer",onClick:I,shrink:0,children:(0,n.jsx)(b.J,{as:u.Z,width:y==="M"?`${11/16}rem`:`${8/16}rem`,color:d?"primary600":"neutral600"})});return(0,n.jsx)(a,{paddingBottom:$,paddingLeft:A,paddingRight:A,paddingTop:$,background:B,expanded:d,size:y,justifyContent:"space-between",cursor:C?"not-allowed":"",children:(0,n.jsxs)(j.k,{gap:3,flex:1,maxWidth:"100%",children:[c==="left"&&U,(0,n.jsx)(l,{onClick:I,"aria-disabled":C,"aria-expanded":d,"aria-controls":Z,"aria-labelledby":D,"data-strapi-accordion-toggle":!0,expanded:d,type:"button",flex:1,minWidth:0,...f,children:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(x.y,{...S,children:t}),o&&(0,n.jsx)(w.Z,{as:"p",id:R,textColor:T,children:o})]})}),c==="right"&&(0,n.jsxs)(j.k,{gap:3,children:[U,p]}),c==="left"&&p]})})}},47081:function(E,m,r){"use strict";r.d(m,{Z:function(){return s}});var n=r(74512);const u=x=>(0,n.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"1rem",height:"1rem",fill:"none",viewBox:"0 0 24 24",...x,children:[(0,n.jsx)("path",{fill:"#212134",d:"M16.563 5.587a2.503 2.503 0 1 0 0-5.007 2.503 2.503 0 0 0 0 5.007Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M18.487 3.083c-.012.788-.487 1.513-1.229 1.797a1.954 1.954 0 0 1-2.184-.574A1.943 1.943 0 0 1 14.9 2.11c.4-.684 1.2-1.066 1.981-.927a1.954 1.954 0 0 1 1.606 1.9c.011.748 1.17.748 1.158 0A3.138 3.138 0 0 0 17.565.17c-1.176-.423-2.567-.03-3.36.933-.83 1.002-.968 2.45-.284 3.575.678 1.124 1.993 1.674 3.273 1.431 1.432-.272 2.428-1.593 2.451-3.019.012-.753-1.147-.753-1.158-.006ZM16.563 14.372a2.503 2.503 0 1 0 0-5.007 2.503 2.503 0 0 0 0 5.007Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M18.487 11.867c-.012.789-.487 1.513-1.229 1.797a1.954 1.954 0 0 1-2.184-.574 1.943 1.943 0 0 1-.174-2.196c.4-.684 1.2-1.066 1.981-.927.928.156 1.588.968 1.606 1.9.011.748 1.17.748 1.158 0a3.138 3.138 0 0 0-2.08-2.914c-1.176-.423-2.567-.029-3.36.933-.83 1.002-.968 2.45-.284 3.575.678 1.124 1.993 1.675 3.273 1.431 1.432-.272 2.428-1.593 2.451-3.019.012-.753-1.147-.753-1.158-.005ZM16.563 23.392a2.503 2.503 0 1 0 0-5.006 2.503 2.503 0 0 0 0 5.006Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M18.487 20.89c-.012.787-.487 1.512-1.229 1.796a1.954 1.954 0 0 1-2.184-.574 1.943 1.943 0 0 1-.174-2.196c.4-.684 1.2-1.066 1.981-.927.928.156 1.588.967 1.606 1.9.011.748 1.17.748 1.158 0a3.138 3.138 0 0 0-2.08-2.914c-1.176-.423-2.567-.03-3.36.933-.83 1.002-.968 2.45-.284 3.575.678 1.124 1.993 1.674 3.273 1.431 1.432-.272 2.428-1.593 2.451-3.019.012-.753-1.147-.753-1.158-.006ZM7.378 5.622a2.503 2.503 0 1 0 0-5.007 2.503 2.503 0 0 0 0 5.007Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M9.302 3.119c-.011.788-.486 1.512-1.228 1.796a1.954 1.954 0 0 1-2.185-.574 1.943 1.943 0 0 1-.173-2.196c.4-.684 1.199-1.066 1.981-.927a1.943 1.943 0 0 1 1.605 1.9c.012.748 1.17.748 1.16 0A3.138 3.138 0 0 0 8.38.205c-1.176-.423-2.567-.029-3.36.933-.83 1.002-.968 2.45-.285 3.575.678 1.124 1.994 1.675 3.274 1.431 1.431-.272 2.428-1.593 2.451-3.019.012-.753-1.147-.753-1.159-.005ZM7.378 14.406a2.503 2.503 0 1 0 0-5.006 2.503 2.503 0 0 0 0 5.006Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M9.302 11.902c-.011.788-.486 1.513-1.228 1.797a1.954 1.954 0 0 1-2.185-.574 1.943 1.943 0 0 1-.173-2.196c.4-.684 1.199-1.066 1.981-.927a1.943 1.943 0 0 1 1.605 1.9c.012.748 1.17.748 1.16 0A3.138 3.138 0 0 0 8.38 8.988c-1.176-.423-2.567-.03-3.36.933-.83 1.002-.968 2.45-.285 3.575.678 1.124 1.994 1.674 3.274 1.431 1.431-.272 2.428-1.593 2.451-3.019.012-.753-1.147-.753-1.159-.006ZM7.378 23.427a2.503 2.503 0 1 0 0-5.007 2.503 2.503 0 0 0 0 5.007Z"}),(0,n.jsx)("path",{fill:"#212134",d:"M9.302 20.924c-.011.788-.486 1.513-1.228 1.797a1.954 1.954 0 0 1-2.185-.574 1.943 1.943 0 0 1-.173-2.196c.4-.684 1.199-1.066 1.981-.927.933.156 1.594.967 1.605 1.9.012.748 1.17.748 1.16 0A3.139 3.139 0 0 0 8.38 18.01c-1.176-.423-2.567-.03-3.36.933-.83 1.002-.968 2.45-.285 3.569.678 1.124 1.994 1.675 3.274 1.431 1.431-.272 2.428-1.593 2.451-3.019.012-.747-1.147-.747-1.159 0Z"})]}),s=u},86308:function(E,m,r){"use strict";r.d(m,{Z:function(){return s}});var n=r(74512);const u=x=>(0,n.jsxs)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"1rem",height:"1rem",fill:"none",viewBox:"0 0 24 24",...x,children:[(0,n.jsx)("circle",{cx:12,cy:12,r:12,fill:"#212134"}),(0,n.jsx)("path",{fill:"#F6F6F9",d:"M17 12.569c0 .124-.1.224-.225.224h-3.981v3.982c0 .124-.101.225-.226.225h-1.136a.225.225 0 0 1-.226-.225v-3.981H7.226A.225.225 0 0 1 7 12.567v-1.136c0-.125.1-.226.225-.226h3.982V7.226c0-.124.1-.225.224-.225h1.138c.124 0 .224.1.224.225v3.982h3.982c.124 0 .225.1.225.224v1.138Z"})]}),s=u}}]);