@strapi/admin 4.1.6-alpha.1 → 4.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +17 -3
- package/admin/src/content-manager/components/DynamicTable/CellContent/utils/hasContent.js +33 -2
- package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +42 -42
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/getAPIInnerError.js +18 -0
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/handleAPIError.js +15 -0
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/index.js +0 -1
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/schema.js +21 -19
- package/admin/src/content-manager/components/InputUID/index.js +1 -5
- package/admin/src/content-manager/components/Inputs/index.js +8 -10
- package/admin/src/content-manager/components/RepeatableComponent/index.js +1 -4
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +15 -3
- package/admin/src/content-manager/components/Wysiwyg/index.js +3 -4
- package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +6 -1
- package/admin/src/content-manager/pages/EditSettingsView/utils/layout.js +7 -1
- package/admin/src/content-manager/pages/EditView/DeleteLink/index.js +1 -4
- package/admin/src/content-manager/pages/EditView/DraftAndPublishBadge/index.js +1 -4
- package/admin/src/content-manager/pages/ListView/selectors.js +3 -6
- package/admin/src/content-manager/testUtils/data.js +5 -1
- package/admin/src/content-manager/utils/isFieldTypeNumber.js +3 -0
- package/admin/src/translations/en.json +2 -0
- package/build/{Admin-authenticatedApp.cf7104f9.chunk.js → Admin-authenticatedApp.c0239c26.chunk.js} +1 -1
- package/build/content-manager.abde723b.chunk.js +1 -0
- package/build/{en-json.c55e5344.chunk.js → en-json.94e6ed8a.chunk.js} +1 -1
- package/build/index.html +1 -1
- package/build/{main.06e1a4bf.js → main.82ea2ad5.js} +2 -2
- package/build/{main.06e1a4bf.js.LICENSE.txt → main.82ea2ad5.js.LICENSE.txt} +0 -0
- package/build/{runtime~main.b090a1bb.js → runtime~main.0634180a.js} +1 -1
- package/package.json +5 -5
- package/server/validation/permission.js +5 -1
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/getYupInnerErrors.js +0 -17
- package/build/content-manager.2f6a2082.chunk.js +0 -1
|
@@ -203,8 +203,6 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
203
203
|
const displayErrors = useCallback(
|
|
204
204
|
err => {
|
|
205
205
|
const errorPayload = err.response.data;
|
|
206
|
-
console.error(errorPayload);
|
|
207
|
-
|
|
208
206
|
let errorMessage = get(errorPayload, ['error', 'message'], 'Bad Request');
|
|
209
207
|
|
|
210
208
|
// TODO handle errors correctly when back-end ready
|
|
@@ -272,10 +270,14 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
272
270
|
dispatch(setStatus('resolved'));
|
|
273
271
|
|
|
274
272
|
replace(`/content-manager/collectionType/${slug}/${data.id}${rawQuery}`);
|
|
273
|
+
|
|
274
|
+
return Promise.resolve(data);
|
|
275
275
|
} catch (err) {
|
|
276
|
-
trackUsageRef.current('didNotCreateEntry', { error: err, trackerProperty });
|
|
277
276
|
displayErrors(err);
|
|
277
|
+
trackUsageRef.current('didNotCreateEntry', { error: err, trackerProperty });
|
|
278
278
|
dispatch(setStatus('resolved'));
|
|
279
|
+
|
|
280
|
+
return Promise.reject(err);
|
|
279
281
|
}
|
|
280
282
|
},
|
|
281
283
|
[
|
|
@@ -308,9 +310,13 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
308
310
|
type: 'success',
|
|
309
311
|
message: { id: getTrad('success.record.publish') },
|
|
310
312
|
});
|
|
313
|
+
|
|
314
|
+
return Promise.resolve(data);
|
|
311
315
|
} catch (err) {
|
|
312
316
|
displayErrors(err);
|
|
313
317
|
dispatch(setStatus('resolved'));
|
|
318
|
+
|
|
319
|
+
return Promise.reject(err);
|
|
314
320
|
}
|
|
315
321
|
}, [cleanReceivedData, displayErrors, id, slug, dispatch, toggleNotification]);
|
|
316
322
|
|
|
@@ -334,11 +340,15 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
334
340
|
dispatch(submitSucceeded(cleanReceivedData(data)));
|
|
335
341
|
|
|
336
342
|
dispatch(setStatus('resolved'));
|
|
343
|
+
|
|
344
|
+
return Promise.resolve(data);
|
|
337
345
|
} catch (err) {
|
|
338
346
|
trackUsageRef.current('didNotEditEntry', { error: err, trackerProperty });
|
|
339
347
|
displayErrors(err);
|
|
340
348
|
|
|
341
349
|
dispatch(setStatus('resolved'));
|
|
350
|
+
|
|
351
|
+
return Promise.reject(err);
|
|
342
352
|
}
|
|
343
353
|
},
|
|
344
354
|
[cleanReceivedData, displayErrors, slug, id, dispatch, toggleNotification]
|
|
@@ -362,9 +372,13 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
|
|
|
362
372
|
|
|
363
373
|
dispatch(submitSucceeded(cleanReceivedData(data)));
|
|
364
374
|
dispatch(setStatus('resolved'));
|
|
375
|
+
|
|
376
|
+
return Promise.resolve(data);
|
|
365
377
|
} catch (err) {
|
|
366
378
|
dispatch(setStatus('resolved'));
|
|
367
379
|
displayErrors(err);
|
|
380
|
+
|
|
381
|
+
return Promise.reject(err);
|
|
368
382
|
}
|
|
369
383
|
}, [cleanReceivedData, displayErrors, id, slug, dispatch, toggleNotification]);
|
|
370
384
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import isEmpty from 'lodash/isEmpty';
|
|
2
|
+
import isNumber from 'lodash/isNumber';
|
|
2
3
|
|
|
3
4
|
import isSingleRelation from './isSingleRelation';
|
|
5
|
+
import isFieldTypeNumber from '../../../../utils/isFieldTypeNumber';
|
|
4
6
|
|
|
5
7
|
export default function hasContent(type, content, metadatas, fieldSchema) {
|
|
6
8
|
if (type === 'component') {
|
|
7
9
|
const {
|
|
8
|
-
mainField: { name: mainFieldName },
|
|
10
|
+
mainField: { name: mainFieldName, type: mainFieldType },
|
|
9
11
|
} = metadatas;
|
|
10
12
|
|
|
11
13
|
// Repeatable fields show the ID as fallback, in case the mainField
|
|
@@ -14,7 +16,28 @@ export default function hasContent(type, content, metadatas, fieldSchema) {
|
|
|
14
16
|
return content.length > 0;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
const value = content?.[mainFieldName];
|
|
20
|
+
|
|
21
|
+
// relations, media ... show the id as fallback
|
|
22
|
+
if (mainFieldName === 'id' && ![undefined, null].includes(value)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* The ID field reports itself as type `integer`, which makes it
|
|
27
|
+
impossible to distinguish it from other number fields.
|
|
28
|
+
|
|
29
|
+
Biginteger fields need to be treated as strings, as `isNumber`
|
|
30
|
+
doesn't deal with them.
|
|
31
|
+
*/
|
|
32
|
+
if (
|
|
33
|
+
isFieldTypeNumber(mainFieldType) &&
|
|
34
|
+
mainFieldType !== 'biginteger' &&
|
|
35
|
+
mainFieldName !== 'id'
|
|
36
|
+
) {
|
|
37
|
+
return isNumber(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return !isEmpty(value);
|
|
18
41
|
}
|
|
19
42
|
|
|
20
43
|
if (type === 'relation') {
|
|
@@ -25,5 +48,13 @@ export default function hasContent(type, content, metadatas, fieldSchema) {
|
|
|
25
48
|
return content.count > 0;
|
|
26
49
|
}
|
|
27
50
|
|
|
51
|
+
/*
|
|
52
|
+
Biginteger fields need to be treated as strings, as `isNumber`
|
|
53
|
+
doesn't deal with them.
|
|
54
|
+
*/
|
|
55
|
+
if (isFieldTypeNumber(type) && type !== 'biginteger') {
|
|
56
|
+
return isNumber(content);
|
|
57
|
+
}
|
|
58
|
+
|
|
28
59
|
return !isEmpty(content);
|
|
29
60
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useMemo, useRef, useReducer } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
4
|
+
import get from 'lodash/get';
|
|
5
|
+
import isEqual from 'lodash/isEqual';
|
|
6
|
+
import set from 'lodash/set';
|
|
3
7
|
import PropTypes from 'prop-types';
|
|
4
8
|
import { useIntl } from 'react-intl';
|
|
5
9
|
import { Prompt, Redirect } from 'react-router-dom';
|
|
@@ -10,10 +14,13 @@ import {
|
|
|
10
14
|
useNotification,
|
|
11
15
|
useOverlayBlocker,
|
|
12
16
|
useTracking,
|
|
17
|
+
getYupInnerErrors,
|
|
13
18
|
} from '@strapi/helper-plugin';
|
|
19
|
+
|
|
14
20
|
import { getTrad, removeKeyInObject } from '../../utils';
|
|
15
21
|
import reducer, { initialState } from './reducer';
|
|
16
|
-
import { cleanData, createYupSchema
|
|
22
|
+
import { cleanData, createYupSchema } from './utils';
|
|
23
|
+
import { getAPIInnerError } from './utils/getAPIInnerError';
|
|
17
24
|
|
|
18
25
|
const EditViewDataManagerProvider = ({
|
|
19
26
|
allLayoutData,
|
|
@@ -262,7 +269,7 @@ const EditViewDataManagerProvider = ({
|
|
|
262
269
|
);
|
|
263
270
|
|
|
264
271
|
const createFormData = useCallback(
|
|
265
|
-
data => {
|
|
272
|
+
(data) => {
|
|
266
273
|
// First we need to remove the added keys needed for the dnd
|
|
267
274
|
const preparedData = removeKeyInObject(cloneDeep(data), '__temp_key__');
|
|
268
275
|
// Then we need to apply our helper
|
|
@@ -286,34 +293,31 @@ const EditViewDataManagerProvider = ({
|
|
|
286
293
|
}, [hasDraftAndPublish, shouldNotRunValidations]);
|
|
287
294
|
|
|
288
295
|
const handleSubmit = useCallback(
|
|
289
|
-
async e => {
|
|
296
|
+
async (e) => {
|
|
290
297
|
e.preventDefault();
|
|
291
298
|
let errors = {};
|
|
292
299
|
|
|
293
|
-
// First validate the form
|
|
294
300
|
try {
|
|
295
301
|
await yupSchema.validate(modifiedData, { abortEarly: false });
|
|
296
|
-
|
|
297
|
-
const formData = createFormData(modifiedData);
|
|
298
|
-
|
|
299
|
-
if (isCreatingEntry) {
|
|
300
|
-
onPost(formData, trackerProperty);
|
|
301
|
-
} else {
|
|
302
|
-
onPut(formData, trackerProperty);
|
|
303
|
-
}
|
|
304
302
|
} catch (err) {
|
|
305
|
-
console.log('ValidationError');
|
|
306
|
-
console.log(err);
|
|
307
|
-
|
|
308
303
|
errors = getYupInnerErrors(err);
|
|
304
|
+
}
|
|
309
305
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
306
|
+
try {
|
|
307
|
+
if (isEmpty(errors)) {
|
|
308
|
+
const formData = createFormData(modifiedData);
|
|
309
|
+
|
|
310
|
+
if (isCreatingEntry) {
|
|
311
|
+
await onPost(formData, trackerProperty);
|
|
312
|
+
} else {
|
|
313
|
+
await onPut(formData, trackerProperty);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (err) {
|
|
317
|
+
errors = {
|
|
318
|
+
...errors,
|
|
319
|
+
...getAPIInnerError(err),
|
|
320
|
+
};
|
|
317
321
|
}
|
|
318
322
|
|
|
319
323
|
dispatch({
|
|
@@ -321,16 +325,7 @@ const EditViewDataManagerProvider = ({
|
|
|
321
325
|
errors,
|
|
322
326
|
});
|
|
323
327
|
},
|
|
324
|
-
[
|
|
325
|
-
createFormData,
|
|
326
|
-
isCreatingEntry,
|
|
327
|
-
modifiedData,
|
|
328
|
-
onPost,
|
|
329
|
-
onPut,
|
|
330
|
-
toggleNotification,
|
|
331
|
-
trackerProperty,
|
|
332
|
-
yupSchema,
|
|
333
|
-
]
|
|
328
|
+
[createFormData, isCreatingEntry, modifiedData, onPost, onPut, trackerProperty, yupSchema]
|
|
334
329
|
);
|
|
335
330
|
|
|
336
331
|
const handlePublish = useCallback(async () => {
|
|
@@ -345,17 +340,22 @@ const EditViewDataManagerProvider = ({
|
|
|
345
340
|
let errors = {};
|
|
346
341
|
|
|
347
342
|
try {
|
|
348
|
-
// Validate the form using yup
|
|
349
343
|
await schema.validate(modifiedData, { abortEarly: false });
|
|
350
|
-
|
|
351
|
-
onPublish();
|
|
352
344
|
} catch (err) {
|
|
353
|
-
console.error('ValidationError');
|
|
354
|
-
console.error(err);
|
|
355
|
-
|
|
356
345
|
errors = getYupInnerErrors(err);
|
|
357
346
|
}
|
|
358
347
|
|
|
348
|
+
try {
|
|
349
|
+
if (isEmpty(errors)) {
|
|
350
|
+
await onPublish();
|
|
351
|
+
}
|
|
352
|
+
} catch (err) {
|
|
353
|
+
errors = {
|
|
354
|
+
...errors,
|
|
355
|
+
...getAPIInnerError(err),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
359
|
dispatch({
|
|
360
360
|
type: 'SET_FORM_ERRORS',
|
|
361
361
|
errors,
|
|
@@ -363,8 +363,8 @@ const EditViewDataManagerProvider = ({
|
|
|
363
363
|
}, [allLayoutData, currentContentTypeLayout, isCreatingEntry, modifiedData, onPublish]);
|
|
364
364
|
|
|
365
365
|
const shouldCheckDZErrors = useCallback(
|
|
366
|
-
dzName => {
|
|
367
|
-
const doesDZHaveError = Object.keys(formErrors).some(key => key.split('.')[0] === dzName);
|
|
366
|
+
(dzName) => {
|
|
367
|
+
const doesDZHaveError = Object.keys(formErrors).some((key) => key.split('.')[0] === dzName);
|
|
368
368
|
const shouldCheckErrors = !isEmpty(formErrors) && doesDZHaveError;
|
|
369
369
|
|
|
370
370
|
return shouldCheckErrors;
|
|
@@ -418,7 +418,7 @@ const EditViewDataManagerProvider = ({
|
|
|
418
418
|
});
|
|
419
419
|
}, []);
|
|
420
420
|
|
|
421
|
-
const onRemoveRelation = useCallback(keys => {
|
|
421
|
+
const onRemoveRelation = useCallback((keys) => {
|
|
422
422
|
dispatch({
|
|
423
423
|
type: 'REMOVE_RELATION',
|
|
424
424
|
keys,
|
package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/getAPIInnerError.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getTrad } from '../../../utils';
|
|
2
|
+
|
|
3
|
+
export function getAPIInnerError(error) {
|
|
4
|
+
const errorPayload = error.response.data.error.details.errors;
|
|
5
|
+
const validationErrors = errorPayload.reduce((acc, err) => {
|
|
6
|
+
acc[err.path.join('.')] = {
|
|
7
|
+
id: getTrad(`apiError.${err.message}`),
|
|
8
|
+
defaultMessage: err.message,
|
|
9
|
+
values: {
|
|
10
|
+
field: err.path[err.path.length - 1],
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
return acc;
|
|
15
|
+
}, {});
|
|
16
|
+
|
|
17
|
+
return validationErrors;
|
|
18
|
+
}
|
package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/handleAPIError.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getTrad } from '../../../utils';
|
|
2
|
+
|
|
3
|
+
export function handleAPIError(error) {
|
|
4
|
+
const errorPayload = error.response.data.error.details.errors;
|
|
5
|
+
const validationErrors = errorPayload.reduce((acc, err) => {
|
|
6
|
+
acc[err.path.join('.')] = {
|
|
7
|
+
id: getTrad(`apiError.${err.message}`),
|
|
8
|
+
defaultMessage: err.message,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
return acc;
|
|
12
|
+
}, {});
|
|
13
|
+
|
|
14
|
+
return validationErrors;
|
|
15
|
+
}
|
|
@@ -7,12 +7,14 @@ import toNumber from 'lodash/toNumber';
|
|
|
7
7
|
import * as yup from 'yup';
|
|
8
8
|
import { translatedErrors as errorsTrads } from '@strapi/helper-plugin';
|
|
9
9
|
|
|
10
|
+
import isFieldTypeNumber from '../../../utils/isFieldTypeNumber';
|
|
11
|
+
|
|
10
12
|
yup.addMethod(yup.mixed, 'defined', function() {
|
|
11
|
-
return this.test('defined', errorsTrads.required, value => value !== undefined);
|
|
13
|
+
return this.test('defined', errorsTrads.required, (value) => value !== undefined);
|
|
12
14
|
});
|
|
13
15
|
|
|
14
16
|
yup.addMethod(yup.array, 'notEmptyMin', function(min) {
|
|
15
|
-
return this.test('notEmptyMin', errorsTrads.min, value => {
|
|
17
|
+
return this.test('notEmptyMin', errorsTrads.min, (value) => {
|
|
16
18
|
if (isEmpty(value)) {
|
|
17
19
|
return true;
|
|
18
20
|
}
|
|
@@ -49,7 +51,7 @@ yup.addMethod(yup.string, 'isSuperior', function(message, min) {
|
|
|
49
51
|
});
|
|
50
52
|
});
|
|
51
53
|
|
|
52
|
-
const getAttributes = data => get(data, ['attributes'], {});
|
|
54
|
+
const getAttributes = (data) => get(data, ['attributes'], {});
|
|
53
55
|
|
|
54
56
|
const createYupSchema = (
|
|
55
57
|
model,
|
|
@@ -95,7 +97,7 @@ const createYupSchema = (
|
|
|
95
97
|
if (attribute.repeatable === true) {
|
|
96
98
|
const { min, max, required } = attribute;
|
|
97
99
|
|
|
98
|
-
let componentSchema = yup.lazy(value => {
|
|
100
|
+
let componentSchema = yup.lazy((value) => {
|
|
99
101
|
let baseSchema = yup.array().of(componentFieldSchema);
|
|
100
102
|
|
|
101
103
|
if (min) {
|
|
@@ -121,7 +123,7 @@ const createYupSchema = (
|
|
|
121
123
|
|
|
122
124
|
return acc;
|
|
123
125
|
}
|
|
124
|
-
const componentSchema = yup.lazy(obj => {
|
|
126
|
+
const componentSchema = yup.lazy((obj) => {
|
|
125
127
|
if (obj !== undefined) {
|
|
126
128
|
return attribute.required === true && !options.isDraft
|
|
127
129
|
? componentFieldSchema.defined()
|
|
@@ -152,7 +154,7 @@ const createYupSchema = (
|
|
|
152
154
|
if (min) {
|
|
153
155
|
if (attribute.required) {
|
|
154
156
|
dynamicZoneSchema = dynamicZoneSchema
|
|
155
|
-
.test('min', errorsTrads.min, value => {
|
|
157
|
+
.test('min', errorsTrads.min, (value) => {
|
|
156
158
|
if (options.isCreatingEntry) {
|
|
157
159
|
return value && value.length >= min;
|
|
158
160
|
}
|
|
@@ -163,7 +165,7 @@ const createYupSchema = (
|
|
|
163
165
|
|
|
164
166
|
return value !== null && value.length >= min;
|
|
165
167
|
})
|
|
166
|
-
.test('required', errorsTrads.required, value => {
|
|
168
|
+
.test('required', errorsTrads.required, (value) => {
|
|
167
169
|
if (options.isCreatingEntry) {
|
|
168
170
|
return value !== null || value !== undefined;
|
|
169
171
|
}
|
|
@@ -178,7 +180,7 @@ const createYupSchema = (
|
|
|
178
180
|
dynamicZoneSchema = dynamicZoneSchema.notEmptyMin(min);
|
|
179
181
|
}
|
|
180
182
|
} else if (attribute.required && !options.isDraft) {
|
|
181
|
-
dynamicZoneSchema = dynamicZoneSchema.test('required', errorsTrads.required, value => {
|
|
183
|
+
dynamicZoneSchema = dynamicZoneSchema.test('required', errorsTrads.required, (value) => {
|
|
182
184
|
if (options.isCreatingEntry) {
|
|
183
185
|
return value !== null || value !== undefined;
|
|
184
186
|
}
|
|
@@ -213,7 +215,7 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
213
215
|
if (type === 'json') {
|
|
214
216
|
schema = yup
|
|
215
217
|
.mixed(errorsTrads.json)
|
|
216
|
-
.test('isJSON', errorsTrads.json, value => {
|
|
218
|
+
.test('isJSON', errorsTrads.json, (value) => {
|
|
217
219
|
if (value === undefined) {
|
|
218
220
|
return true;
|
|
219
221
|
}
|
|
@@ -236,19 +238,19 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
236
238
|
if (['number', 'integer', 'float', 'decimal'].includes(type)) {
|
|
237
239
|
schema = yup
|
|
238
240
|
.number()
|
|
239
|
-
.transform(cv => (isNaN(cv) ? undefined : cv))
|
|
241
|
+
.transform((cv) => (isNaN(cv) ? undefined : cv))
|
|
240
242
|
.typeError();
|
|
241
243
|
}
|
|
242
244
|
|
|
243
|
-
if (['date', 'datetime'].includes(type)) {
|
|
244
|
-
schema = yup.date();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
245
|
if (type === 'biginteger') {
|
|
248
246
|
schema = yup.string().matches(/^-?\d*$/);
|
|
249
247
|
}
|
|
250
248
|
|
|
251
|
-
|
|
249
|
+
if (['date', 'datetime'].includes(type)) {
|
|
250
|
+
schema = yup.date();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Object.keys(validations).forEach((validation) => {
|
|
252
254
|
const validationValue = validations[validation];
|
|
253
255
|
|
|
254
256
|
if (
|
|
@@ -267,13 +269,13 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
267
269
|
if (options.isCreatingEntry) {
|
|
268
270
|
schema = schema.required(errorsTrads.required);
|
|
269
271
|
} else {
|
|
270
|
-
schema = schema.test('required', errorsTrads.required, value => {
|
|
272
|
+
schema = schema.test('required', errorsTrads.required, (value) => {
|
|
271
273
|
// Field is not touched and the user is editing the entry
|
|
272
274
|
if (value === undefined && !options.isFromComponent) {
|
|
273
275
|
return true;
|
|
274
276
|
}
|
|
275
277
|
|
|
276
|
-
if (
|
|
278
|
+
if (isFieldTypeNumber(type)) {
|
|
277
279
|
if (value === 0) {
|
|
278
280
|
return true;
|
|
279
281
|
}
|
|
@@ -344,12 +346,12 @@ const createYupSchemaAttribute = (type, validations, options) => {
|
|
|
344
346
|
}
|
|
345
347
|
break;
|
|
346
348
|
case 'positive':
|
|
347
|
-
if (
|
|
349
|
+
if (isFieldTypeNumber(type)) {
|
|
348
350
|
schema = schema.positive();
|
|
349
351
|
}
|
|
350
352
|
break;
|
|
351
353
|
case 'negative':
|
|
352
|
-
if (
|
|
354
|
+
if (isFieldTypeNumber(type)) {
|
|
353
355
|
schema = schema.negative();
|
|
354
356
|
}
|
|
355
357
|
break;
|
|
@@ -82,7 +82,6 @@ const InputUID = ({
|
|
|
82
82
|
onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
|
|
83
83
|
setIsLoading(false);
|
|
84
84
|
} catch (err) {
|
|
85
|
-
console.error({ err });
|
|
86
85
|
setIsLoading(false);
|
|
87
86
|
}
|
|
88
87
|
};
|
|
@@ -107,7 +106,6 @@ const InputUID = ({
|
|
|
107
106
|
|
|
108
107
|
setIsLoading(false);
|
|
109
108
|
} catch (err) {
|
|
110
|
-
console.error({ err });
|
|
111
109
|
setIsLoading(false);
|
|
112
110
|
}
|
|
113
111
|
};
|
|
@@ -184,12 +182,10 @@ const InputUID = ({
|
|
|
184
182
|
onChange(e);
|
|
185
183
|
};
|
|
186
184
|
|
|
187
|
-
const formattedError = error ? formatMessage({ id: error, defaultMessage: error }) : undefined;
|
|
188
|
-
|
|
189
185
|
return (
|
|
190
186
|
<TextInput
|
|
191
187
|
disabled={disabled}
|
|
192
|
-
error={
|
|
188
|
+
error={error}
|
|
193
189
|
endAction={
|
|
194
190
|
<EndActionWrapper>
|
|
195
191
|
{availability && availability.isAvailable && !regenerateLabel && (
|
|
@@ -42,10 +42,7 @@ function Inputs({
|
|
|
42
42
|
|
|
43
43
|
const disabled = useMemo(() => !get(metadatas, 'editable', true), [metadatas]);
|
|
44
44
|
const type = fieldSchema.type;
|
|
45
|
-
|
|
46
|
-
const errorId = useMemo(() => {
|
|
47
|
-
return get(formErrors, [keys, 'id'], null);
|
|
48
|
-
}, [formErrors, keys]);
|
|
45
|
+
const error = get(formErrors, [keys], null);
|
|
49
46
|
|
|
50
47
|
const fieldName = useMemo(() => {
|
|
51
48
|
return getFieldName(keys);
|
|
@@ -160,10 +157,10 @@ function Inputs({
|
|
|
160
157
|
return disabled;
|
|
161
158
|
}, [disabled, isCreatingEntry, isUserAllowedToEditField, isUserAllowedToReadField]);
|
|
162
159
|
|
|
163
|
-
const options = useMemo(
|
|
164
|
-
fieldSchema,
|
|
165
|
-
isRequired
|
|
166
|
-
|
|
160
|
+
const options = useMemo(
|
|
161
|
+
() => generateOptions(fieldSchema.enum || [], isRequired),
|
|
162
|
+
[fieldSchema, isRequired]
|
|
163
|
+
);
|
|
167
164
|
|
|
168
165
|
const { label, description, placeholder, visible } = metadatas;
|
|
169
166
|
|
|
@@ -177,7 +174,7 @@ function Inputs({
|
|
|
177
174
|
description={description ? { id: description, defaultMessage: description } : null}
|
|
178
175
|
intlLabel={{ id: label, defaultMessage: label }}
|
|
179
176
|
labelAction={labelAction}
|
|
180
|
-
error={
|
|
177
|
+
error={error && formatMessage(error)}
|
|
181
178
|
name={keys}
|
|
182
179
|
required={isRequired}
|
|
183
180
|
/>
|
|
@@ -215,6 +212,7 @@ function Inputs({
|
|
|
215
212
|
}
|
|
216
213
|
queryInfos={queryInfos}
|
|
217
214
|
value={value}
|
|
215
|
+
error={error && formatMessage(error)}
|
|
218
216
|
/>
|
|
219
217
|
);
|
|
220
218
|
}
|
|
@@ -228,7 +226,7 @@ function Inputs({
|
|
|
228
226
|
isNullable={inputType === 'bool' && [null, undefined].includes(fieldSchema.default)}
|
|
229
227
|
description={description ? { id: description, defaultMessage: description } : null}
|
|
230
228
|
disabled={shouldDisableField}
|
|
231
|
-
error={
|
|
229
|
+
error={error}
|
|
232
230
|
labelAction={labelAction}
|
|
233
231
|
contentTypeUID={currentContentTypeLayout.uid}
|
|
234
232
|
customInputs={{
|
|
@@ -144,8 +144,6 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
144
144
|
const displayErrors = useCallback(
|
|
145
145
|
err => {
|
|
146
146
|
const errorPayload = err.response.payload;
|
|
147
|
-
console.error(errorPayload);
|
|
148
|
-
|
|
149
147
|
let errorMessage = get(errorPayload, ['message'], 'Bad Request');
|
|
150
148
|
|
|
151
149
|
// TODO handle errors correctly when back-end ready
|
|
@@ -178,10 +176,12 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
178
176
|
} catch (err) {
|
|
179
177
|
trackUsageRef.current('didNotDeleteEntry', { error: err, ...trackerProperty });
|
|
180
178
|
|
|
179
|
+
displayErrors(err);
|
|
180
|
+
|
|
181
181
|
return Promise.reject(err);
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
|
-
[slug, toggleNotification, searchToSend]
|
|
184
|
+
[slug, displayErrors, toggleNotification, searchToSend]
|
|
185
185
|
);
|
|
186
186
|
|
|
187
187
|
const onDeleteSucceeded = useCallback(() => {
|
|
@@ -211,12 +211,16 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
211
211
|
setIsCreatingEntry(false);
|
|
212
212
|
|
|
213
213
|
dispatch(setStatus('resolved'));
|
|
214
|
+
|
|
215
|
+
return Promise.resolve(data);
|
|
214
216
|
} catch (err) {
|
|
215
217
|
trackUsageRef.current('didNotCreateEntry', { error: err, trackerProperty });
|
|
216
218
|
|
|
217
219
|
displayErrors(err);
|
|
218
220
|
|
|
219
221
|
dispatch(setStatus('resolved'));
|
|
222
|
+
|
|
223
|
+
return Promise.reject(err);
|
|
220
224
|
}
|
|
221
225
|
},
|
|
222
226
|
[cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification, setCurrentStep]
|
|
@@ -239,10 +243,14 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
239
243
|
dispatch(submitSucceeded(cleanReceivedData(data)));
|
|
240
244
|
|
|
241
245
|
dispatch(setStatus('resolved'));
|
|
246
|
+
|
|
247
|
+
return Promise.resolve(data);
|
|
242
248
|
} catch (err) {
|
|
243
249
|
displayErrors(err);
|
|
244
250
|
|
|
245
251
|
dispatch(setStatus('resolved'));
|
|
252
|
+
|
|
253
|
+
return Promise.reject(err);
|
|
246
254
|
}
|
|
247
255
|
}, [cleanReceivedData, displayErrors, slug, searchToSend, dispatch, toggleNotification]);
|
|
248
256
|
|
|
@@ -267,12 +275,16 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
|
|
|
267
275
|
dispatch(submitSucceeded(cleanReceivedData(data)));
|
|
268
276
|
|
|
269
277
|
dispatch(setStatus('resolved'));
|
|
278
|
+
|
|
279
|
+
return Promise.resolve(data);
|
|
270
280
|
} catch (err) {
|
|
271
281
|
displayErrors(err);
|
|
272
282
|
|
|
273
283
|
trackUsageRef.current('didNotEditEntry', { error: err, trackerProperty });
|
|
274
284
|
|
|
275
285
|
dispatch(setStatus('resolved'));
|
|
286
|
+
|
|
287
|
+
return Promise.reject(err);
|
|
276
288
|
}
|
|
277
289
|
},
|
|
278
290
|
[cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification]
|
|
@@ -118,7 +118,6 @@ const Wysiwyg = ({
|
|
|
118
118
|
)
|
|
119
119
|
: '';
|
|
120
120
|
|
|
121
|
-
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
|
|
122
121
|
const label = intlLabel.id
|
|
123
122
|
? formatMessage(
|
|
124
123
|
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
|
|
@@ -157,7 +156,7 @@ const Wysiwyg = ({
|
|
|
157
156
|
disabled={disabled}
|
|
158
157
|
isExpandMode={isExpandMode}
|
|
159
158
|
editorRef={editorRef}
|
|
160
|
-
error={
|
|
159
|
+
error={error}
|
|
161
160
|
isPreviewMode={isPreviewMode}
|
|
162
161
|
name={name}
|
|
163
162
|
onChange={onChange}
|
|
@@ -171,10 +170,10 @@ const Wysiwyg = ({
|
|
|
171
170
|
<Hint description={description} name={name} error={error} />
|
|
172
171
|
</Stack>
|
|
173
172
|
|
|
174
|
-
{
|
|
173
|
+
{error && (
|
|
175
174
|
<Box paddingTop={1}>
|
|
176
175
|
<Typography variant="pi" textColor="danger600" data-strapi-field-error>
|
|
177
|
-
{
|
|
176
|
+
{error}
|
|
178
177
|
</Typography>
|
|
179
178
|
</Box>
|
|
180
179
|
)}
|
|
@@ -11,7 +11,12 @@ import { makeSelectModelAndComponentSchemas } from '../../App/selectors';
|
|
|
11
11
|
import getTrad from '../../../utils/getTrad';
|
|
12
12
|
import GenericInput from './GenericInput';
|
|
13
13
|
|
|
14
|
-
const FIELD_SIZES = [
|
|
14
|
+
const FIELD_SIZES = [
|
|
15
|
+
[4, '33%'],
|
|
16
|
+
[6, '50%'],
|
|
17
|
+
[8, '66%'],
|
|
18
|
+
[12, '100%'],
|
|
19
|
+
];
|
|
15
20
|
|
|
16
21
|
const NON_RESIZABLE_FIELD_TYPES = ['dynamiczone', 'component', 'json', 'richtext'];
|
|
17
22
|
|
|
@@ -28,7 +28,13 @@ const formatLayout = arr => {
|
|
|
28
28
|
|
|
29
29
|
return acc2;
|
|
30
30
|
}, []);
|
|
31
|
-
const rowId =
|
|
31
|
+
const rowId =
|
|
32
|
+
acc.length === 0
|
|
33
|
+
? 0
|
|
34
|
+
: Math.max.apply(
|
|
35
|
+
Math,
|
|
36
|
+
acc.map(o => o.rowId)
|
|
37
|
+
) + 1;
|
|
32
38
|
|
|
33
39
|
const currentRowSize = getRowSize(currentRow);
|
|
34
40
|
|