payload 0.15.1 → 0.15.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +6 -0
- package/CHANGELOG.md +35 -0
- package/dist/admin/components/elements/WhereBuilder/field-types.d.ts +2 -2
- package/dist/admin/components/elements/WhereBuilder/field-types.js +11 -7
- package/dist/admin/components/elements/elements.spec.d.ts +1 -0
- package/dist/admin/components/elements/elements.spec.js +12 -0
- package/dist/admin/components/forms/DraggableSection/index.js +2 -3
- package/dist/admin/components/forms/Form/buildStateFromSchema.d.ts +10 -1
- package/dist/admin/components/forms/Form/buildStateFromSchema.js +14 -6
- package/dist/admin/components/forms/Form/getDataByPath.js +6 -11
- package/dist/admin/components/forms/Form/getSiblingData.js +12 -14
- package/dist/admin/components/forms/Form/index.js +23 -6
- package/dist/admin/components/forms/Form/reduceFieldsToValues.d.ts +1 -1
- package/dist/admin/components/forms/Form/reduceFieldsToValues.js +1 -2
- package/dist/admin/components/forms/Form/types.d.ts +3 -2
- package/dist/admin/components/forms/RenderFields/index.d.ts +1 -2
- package/dist/admin/components/forms/RenderFields/index.js +6 -16
- package/dist/admin/components/forms/RenderFields/types.d.ts +0 -5
- package/dist/admin/components/forms/field-types/Array/Array.js +18 -9
- package/dist/admin/components/forms/field-types/Blocks/Blocks.js +21 -15
- package/dist/admin/components/forms/field-types/Checkbox/index.js +3 -4
- package/dist/admin/components/forms/field-types/Code/Code.js +4 -5
- package/dist/admin/components/forms/field-types/DateTime/index.js +2 -3
- package/dist/admin/components/forms/field-types/Email/index.js +2 -3
- package/dist/admin/components/forms/field-types/Number/index.js +3 -4
- package/dist/admin/components/forms/field-types/Password/index.js +2 -2
- package/dist/admin/components/forms/field-types/Point/index.js +2 -3
- package/dist/admin/components/forms/field-types/RadioGroup/index.js +3 -4
- package/dist/admin/components/forms/field-types/Relationship/index.js +49 -17
- package/dist/admin/components/forms/field-types/RichText/RichText.js +3 -4
- package/dist/admin/components/forms/field-types/RichText/elements/upload/Element/EditModal/index.js +4 -2
- package/dist/admin/components/forms/field-types/Row/index.js +7 -2
- package/dist/admin/components/forms/field-types/Select/index.js +4 -5
- package/dist/admin/components/forms/field-types/Text/index.js +6 -3
- package/dist/admin/components/forms/field-types/Textarea/index.js +4 -5
- package/dist/admin/components/forms/field-types/Upload/Add/index.js +1 -1
- package/dist/admin/components/forms/field-types/Upload/Input.d.ts +2 -1
- package/dist/admin/components/forms/field-types/Upload/Input.js +3 -1
- package/dist/admin/components/forms/field-types/Upload/SelectExisting/index.js +27 -4
- package/dist/admin/components/forms/field-types/Upload/SelectExisting/types.d.ts +3 -0
- package/dist/admin/components/forms/field-types/Upload/index.js +4 -5
- package/dist/admin/components/forms/field-types/getFilterOptionsQuery.d.ts +5 -0
- package/dist/admin/components/forms/field-types/getFilterOptionsQuery.js +11 -0
- package/dist/admin/components/forms/useField/index.js +39 -8
- package/dist/admin/components/utilities/OperationProvider/index.d.ts +4 -0
- package/dist/admin/components/utilities/OperationProvider/index.js +3 -0
- package/dist/admin/components/views/Account/Default.js +41 -39
- package/dist/admin/components/views/Account/index.js +4 -2
- package/dist/admin/components/views/CreateFirstUser/index.js +1 -1
- package/dist/admin/components/views/Global/Default.js +45 -43
- package/dist/admin/components/views/Global/index.js +5 -5
- package/dist/admin/components/views/collections/Edit/Auth/APIKey.js +1 -1
- package/dist/admin/components/views/collections/Edit/Default.js +55 -53
- package/dist/admin/components/views/collections/Edit/index.js +5 -5
- package/dist/auth/auth.spec.d.ts +1 -0
- package/dist/auth/auth.spec.js +198 -0
- package/dist/collections/graphql/resolvers/resolvers.spec.d.ts +1 -0
- package/dist/collections/graphql/resolvers/resolvers.spec.js +360 -0
- package/dist/collections/operations/local/local.spec.d.ts +1 -0
- package/dist/collections/operations/local/local.spec.js +175 -0
- package/dist/collections/tests/collections.spec.d.ts +1 -0
- package/dist/collections/tests/collections.spec.js +725 -0
- package/dist/collections/tests/hooks.spec.d.ts +1 -0
- package/dist/collections/tests/hooks.spec.js +152 -0
- package/dist/collections/tests/pointField.spec.d.ts +1 -0
- package/dist/collections/tests/pointField.spec.js +219 -0
- package/dist/collections/tests/relationships.spec.d.ts +1 -0
- package/dist/collections/tests/relationships.spec.js +194 -0
- package/dist/collections/tests/uploads.spec.d.ts +1 -0
- package/dist/collections/tests/uploads.spec.js +328 -0
- package/dist/config/load.d.ts +3 -1
- package/dist/config/load.js +5 -3
- package/dist/config/types.d.ts +3 -0
- package/dist/config/types.js +1 -1
- package/dist/config/validate.d.ts +2 -1
- package/dist/config/validate.js +2 -4
- package/dist/email/build.d.ts +2 -1
- package/dist/email/build.js +7 -9
- package/dist/errors/errors.spec.d.ts +1 -0
- package/dist/errors/errors.spec.js +29 -0
- package/dist/express/middleware/errorHandler.spec.d.ts +1 -0
- package/dist/express/middleware/errorHandler.spec.js +91 -0
- package/dist/fields/config/sanitize.js +2 -2
- package/dist/fields/config/schema.js +3 -1
- package/dist/fields/config/types.d.ts +25 -1
- package/dist/fields/config/types.js +1 -1
- package/dist/fields/performFieldOperations.js +3 -3
- package/dist/fields/traverseFields.js +15 -5
- package/dist/fields/validationPromise.d.ts +10 -3
- package/dist/fields/validationPromise.js +16 -5
- package/dist/fields/validations.d.ts +33 -35
- package/dist/fields/validations.js +130 -76
- package/dist/fields/validations.spec.js +115 -43
- package/dist/globals/requestHandlers/globals.spec.d.ts +4 -0
- package/dist/globals/requestHandlers/globals.spec.js +161 -0
- package/dist/graphql/schema/buildMutationInputType.js +2 -2
- package/dist/graphql/schema/fieldToSchemaMap.js +7 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/mongoose/buildQuery.js +2 -2
- package/dist/mongoose/connect.d.ts +2 -1
- package/dist/mongoose/connect.js +2 -4
- package/dist/mongoose/sanitizeFormattedValue.js +12 -3
- package/dist/preferences/graphql/resolvers.spec.d.ts +1 -0
- package/dist/preferences/graphql/resolvers.spec.js +115 -0
- package/dist/utilities/logger.d.ts +1 -1
- package/dist/utilities/logger.js +10 -6
- package/dist/versions/drafts/appendVersionToQueryKey.js +8 -5
- package/dist/webpack/getBaseConfig.js +2 -1
- package/docs/fields/overview.mdx +39 -3
- package/docs/fields/relationship.mdx +45 -0
- package/docs/fields/upload.mdx +1 -0
- package/docs/getting-started/installation.mdx +14 -10
- package/docs/queries/overview.mdx +2 -1
- package/package.json +1 -1
|
@@ -8,11 +8,10 @@ import FieldDescription from '../../FieldDescription';
|
|
|
8
8
|
import './index.scss';
|
|
9
9
|
const baseClass = 'checkbox';
|
|
10
10
|
const Checkbox = (props) => {
|
|
11
|
-
const { name, path: pathFromProps,
|
|
11
|
+
const { name, path: pathFromProps, validate = checkbox, label, onChange, disableFormData, required, admin: { readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
12
12
|
const path = pathFromProps || name;
|
|
13
|
-
const memoizedValidate = useCallback((value) => {
|
|
14
|
-
|
|
15
|
-
return validationResult;
|
|
13
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
14
|
+
return validate(value, { ...options, required });
|
|
16
15
|
}, [validate, required]);
|
|
17
16
|
const { value, showError, errorMessage, setValue, } = useField({
|
|
18
17
|
path,
|
|
@@ -11,7 +11,7 @@ import FieldDescription from '../../FieldDescription';
|
|
|
11
11
|
import { code } from '../../../../../fields/validations';
|
|
12
12
|
import './index.scss';
|
|
13
13
|
const Code = (props) => {
|
|
14
|
-
const { path: pathFromProps, name, required, validate = code, admin: { readOnly, style, className, width, language, description, condition, } = {}, label,
|
|
14
|
+
const { path: pathFromProps, name, required, validate = code, admin: { readOnly, style, className, width, language, description, condition, } = {}, label, } = props;
|
|
15
15
|
const [highlighter] = useState(() => {
|
|
16
16
|
if (languages[language]) {
|
|
17
17
|
return (content) => highlight(content, languages[language]);
|
|
@@ -19,10 +19,9 @@ const Code = (props) => {
|
|
|
19
19
|
return (content) => content;
|
|
20
20
|
});
|
|
21
21
|
const path = pathFromProps || name;
|
|
22
|
-
const memoizedValidate = useCallback((value) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, [validate, maxLength, minLength, required]);
|
|
22
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
23
|
+
return validate(value, { ...options, required });
|
|
24
|
+
}, [validate, required]);
|
|
26
25
|
const { value, showError, setValue, errorMessage, } = useField({
|
|
27
26
|
path,
|
|
28
27
|
validate: memoizedValidate,
|
|
@@ -11,9 +11,8 @@ const baseClass = 'date-time-field';
|
|
|
11
11
|
const DateTime = (props) => {
|
|
12
12
|
const { path: pathFromProps, name, required, validate = dateValidation, label, admin: { placeholder, readOnly, style, className, width, date, description, condition, } = {}, } = props;
|
|
13
13
|
const path = pathFromProps || name;
|
|
14
|
-
const memoizedValidate = useCallback((value) => {
|
|
15
|
-
|
|
16
|
-
return validationResult;
|
|
14
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
15
|
+
return validate(value, { ...options, required });
|
|
17
16
|
}, [validate, required]);
|
|
18
17
|
const { value, showError, errorMessage, setValue, } = useField({
|
|
19
18
|
path,
|
|
@@ -9,9 +9,8 @@ import './index.scss';
|
|
|
9
9
|
const Email = (props) => {
|
|
10
10
|
const { name, path: pathFromProps, required, validate = email, admin: { readOnly, style, className, width, placeholder, autoComplete, description, condition, } = {}, label, } = props;
|
|
11
11
|
const path = pathFromProps || name;
|
|
12
|
-
const memoizedValidate = useCallback((value) => {
|
|
13
|
-
|
|
14
|
-
return validationResult;
|
|
12
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
13
|
+
return validate(value, { ...options, required });
|
|
15
14
|
}, [validate, required]);
|
|
16
15
|
const fieldType = useField({
|
|
17
16
|
path,
|
|
@@ -9,10 +9,9 @@ import './index.scss';
|
|
|
9
9
|
const NumberField = (props) => {
|
|
10
10
|
const { name, path: pathFromProps, required, validate = number, label, max, min, admin: { readOnly, style, className, width, step, placeholder, description, condition, } = {}, } = props;
|
|
11
11
|
const path = pathFromProps || name;
|
|
12
|
-
const memoizedValidate = useCallback((value) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}, [validate, max, min, required]);
|
|
12
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
13
|
+
return validate(value, { ...options, min, max, required });
|
|
14
|
+
}, [validate, min, max, required]);
|
|
16
15
|
const { value, showError, setValue, errorMessage, } = useField({
|
|
17
16
|
path,
|
|
18
17
|
validate: memoizedValidate,
|
|
@@ -8,8 +8,8 @@ import './index.scss';
|
|
|
8
8
|
const Password = (props) => {
|
|
9
9
|
const { path: pathFromProps, name, required, validate = password, style, className, width, autoComplete, label, } = props;
|
|
10
10
|
const path = pathFromProps || name;
|
|
11
|
-
const memoizedValidate = useCallback((value) => {
|
|
12
|
-
const validationResult = validate(value, { required });
|
|
11
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
12
|
+
const validationResult = validate(value, { ...options, required });
|
|
13
13
|
return validationResult;
|
|
14
14
|
}, [validate, required]);
|
|
15
15
|
const { value, showError, formProcessing, setValue, errorMessage, } = useField({
|
|
@@ -10,9 +10,8 @@ const baseClass = 'point';
|
|
|
10
10
|
const PointField = (props) => {
|
|
11
11
|
const { name, path: pathFromProps, required, validate = point, label, admin: { readOnly, style, className, width, step, placeholder, description, condition, } = {}, } = props;
|
|
12
12
|
const path = pathFromProps || name;
|
|
13
|
-
const memoizedValidate = useCallback((value) => {
|
|
14
|
-
|
|
15
|
-
return validationResult;
|
|
13
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
14
|
+
return validate(value, { ...options, required });
|
|
16
15
|
}, [validate, required]);
|
|
17
16
|
const { value = [null, null], showError, setValue, errorMessage, } = useField({
|
|
18
17
|
path,
|
|
@@ -12,10 +12,9 @@ const baseClass = 'radio-group';
|
|
|
12
12
|
const RadioGroup = (props) => {
|
|
13
13
|
const { name, path: pathFromProps, required, validate = radio, label, admin: { readOnly, layout = 'horizontal', style, className, width, description, condition, } = {}, options, } = props;
|
|
14
14
|
const path = pathFromProps || name;
|
|
15
|
-
const memoizedValidate = useCallback((value) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}, [validate, required, options]);
|
|
15
|
+
const memoizedValidate = useCallback((value, validationOptions) => {
|
|
16
|
+
return validate(value, { ...validationOptions, options, required });
|
|
17
|
+
}, [validate, options, required]);
|
|
19
18
|
const { value, showError, errorMessage, setValue, } = useField({
|
|
20
19
|
path,
|
|
21
20
|
validate: memoizedValidate,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState, useReducer, } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import equal from 'deep-equal';
|
|
3
|
+
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
|
3
4
|
import qs from 'qs';
|
|
4
5
|
import withCondition from '../../withCondition';
|
|
5
6
|
import ReactSelect from '../../../elements/ReactSelect';
|
|
@@ -8,27 +9,32 @@ import Label from '../../Label';
|
|
|
8
9
|
import Error from '../../Error';
|
|
9
10
|
import FieldDescription from '../../FieldDescription';
|
|
10
11
|
import { relationship } from '../../../../../fields/validations';
|
|
11
|
-
import { useFormProcessing } from '../../Form/context';
|
|
12
|
+
import { useFormProcessing, useWatchForm } from '../../Form/context';
|
|
12
13
|
import optionsReducer from './optionsReducer';
|
|
13
14
|
import { createRelationMap } from './createRelationMap';
|
|
14
15
|
import { useDebouncedCallback } from '../../../../hooks/useDebouncedCallback';
|
|
16
|
+
import { useDocumentInfo } from '../../../utilities/DocumentInfo';
|
|
17
|
+
import { getFilterOptionsQuery } from '../getFilterOptionsQuery';
|
|
15
18
|
import './index.scss';
|
|
16
19
|
const maxResultsPerRequest = 10;
|
|
17
20
|
const baseClass = 'relationship';
|
|
18
21
|
const Relationship = (props) => {
|
|
19
|
-
const { relationTo, validate = relationship, path, name, required, label, hasMany, admin: { readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
22
|
+
const { relationTo, validate = relationship, path, name, required, label, hasMany, filterOptions, admin: { readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
20
23
|
const { serverURL, routes: { api, }, collections, } = useConfig();
|
|
24
|
+
const { id } = useDocumentInfo();
|
|
25
|
+
const { user } = useAuth();
|
|
26
|
+
const { getData, getSiblingData } = useWatchForm();
|
|
21
27
|
const formProcessing = useFormProcessing();
|
|
22
28
|
const hasMultipleRelations = Array.isArray(relationTo);
|
|
23
29
|
const [options, dispatchOptions] = useReducer(optionsReducer, required || hasMany ? [] : [{ value: 'null', label: 'None' }]);
|
|
24
30
|
const [lastFullyLoadedRelation, setLastFullyLoadedRelation] = useState(-1);
|
|
25
31
|
const [lastLoadedPage, setLastLoadedPage] = useState(1);
|
|
26
32
|
const [errorLoading, setErrorLoading] = useState('');
|
|
33
|
+
const [optionFilters, setOptionFilters] = useState();
|
|
27
34
|
const [hasLoadedValueOptions, setHasLoadedValueOptions] = useState(false);
|
|
28
35
|
const [search, setSearch] = useState('');
|
|
29
|
-
const memoizedValidate = useCallback((value) => {
|
|
30
|
-
|
|
31
|
-
return validationResult;
|
|
36
|
+
const memoizedValidate = useCallback((value, validationOptions) => {
|
|
37
|
+
return validate(value, { ...validationOptions, required });
|
|
32
38
|
}, [validate, required]);
|
|
33
39
|
const { value, showError, errorMessage, setValue, initialValue, } = useField({
|
|
34
40
|
path: path || name,
|
|
@@ -51,9 +57,13 @@ const Relationship = (props) => {
|
|
|
51
57
|
const fieldToSearch = ((_a = collection === null || collection === void 0 ? void 0 : collection.admin) === null || _a === void 0 ? void 0 : _a.useAsTitle) || 'id';
|
|
52
58
|
const query = {
|
|
53
59
|
where: {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
and: [
|
|
61
|
+
{
|
|
62
|
+
id: {
|
|
63
|
+
not_in: relationMap[relation],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
],
|
|
57
67
|
},
|
|
58
68
|
limit: maxResultsPerRequest,
|
|
59
69
|
page: lastLoadedPageToUse,
|
|
@@ -61,9 +71,14 @@ const Relationship = (props) => {
|
|
|
61
71
|
depth: 0,
|
|
62
72
|
};
|
|
63
73
|
if (searchArg) {
|
|
64
|
-
query.where
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
query.where.and.push({
|
|
75
|
+
[fieldToSearch]: {
|
|
76
|
+
like: searchArg,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (optionFilters[relation]) {
|
|
81
|
+
query.where.and.push(optionFilters[relation]);
|
|
67
82
|
}
|
|
68
83
|
const response = await fetch(`${serverURL}${api}/${relation}?${qs.stringify(query)}`);
|
|
69
84
|
if (response.ok) {
|
|
@@ -88,7 +103,7 @@ const Relationship = (props) => {
|
|
|
88
103
|
}
|
|
89
104
|
}, Promise.resolve());
|
|
90
105
|
}
|
|
91
|
-
}, [
|
|
106
|
+
}, [relationTo, hasMany, errorLoading, collections, optionFilters, serverURL, api, hasMultipleRelations]);
|
|
92
107
|
const findOptionsByValue = useCallback(() => {
|
|
93
108
|
if (value) {
|
|
94
109
|
if (hasMany) {
|
|
@@ -182,11 +197,28 @@ const Relationship = (props) => {
|
|
|
182
197
|
}
|
|
183
198
|
}, [hasMany, hasMultipleRelations, relationTo, initialValue, hasLoadedValueOptions, errorLoading, collections, api, serverURL]);
|
|
184
199
|
useEffect(() => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
200
|
+
if (!filterOptions) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const newOptionFilters = getFilterOptionsQuery(filterOptions, {
|
|
204
|
+
id,
|
|
205
|
+
data: getData(),
|
|
206
|
+
relationTo,
|
|
207
|
+
siblingData: getSiblingData(path),
|
|
208
|
+
user,
|
|
188
209
|
});
|
|
189
|
-
|
|
210
|
+
if (!equal(newOptionFilters, optionFilters)) {
|
|
211
|
+
setOptionFilters(newOptionFilters);
|
|
212
|
+
}
|
|
213
|
+
}, [relationTo, filterOptions, optionFilters, id, getData, getSiblingData, path, user]);
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
if (optionFilters) {
|
|
216
|
+
setHasLoadedValueOptions(false);
|
|
217
|
+
getResults({
|
|
218
|
+
value: initialValue,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}, [initialValue, getResults, optionFilters]);
|
|
190
222
|
const classes = [
|
|
191
223
|
'field-type',
|
|
192
224
|
baseClass,
|
|
@@ -51,9 +51,8 @@ const RichText = (props) => {
|
|
|
51
51
|
}
|
|
52
52
|
return (React.createElement("span", { ...attributes }, children));
|
|
53
53
|
}, [enabledLeaves, path, props]);
|
|
54
|
-
const memoizedValidate = useCallback((value) => {
|
|
55
|
-
|
|
56
|
-
return validationResult;
|
|
54
|
+
const memoizedValidate = useCallback((value, validationOptions) => {
|
|
55
|
+
return validate(value, { ...validationOptions, required });
|
|
57
56
|
}, [validate, required]);
|
|
58
57
|
const fieldType = useField({
|
|
59
58
|
path,
|
|
@@ -147,7 +146,7 @@ const RichText = (props) => {
|
|
|
147
146
|
return null;
|
|
148
147
|
})),
|
|
149
148
|
React.createElement("div", { className: `${baseClass}__editor`, ref: editorRef },
|
|
150
|
-
React.createElement(Editable, {
|
|
149
|
+
React.createElement(Editable, { renderElement: renderElement, renderLeaf: renderLeaf, placeholder: placeholder, spellCheck: true, readOnly: readOnly, onBlur: onBlur, onKeyDown: (event) => {
|
|
151
150
|
if (event.key === 'Enter') {
|
|
152
151
|
if (event.shiftKey) {
|
|
153
152
|
event.preventDefault();
|
package/dist/admin/components/forms/field-types/RichText/elements/upload/Element/EditModal/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
|
2
2
|
import { Transforms } from 'slate';
|
|
3
3
|
import { ReactEditor, useSlateStatic } from 'slate-react';
|
|
4
4
|
import { Modal } from '@faceless-ui/modal';
|
|
5
|
+
import { useAuth } from '@payloadcms/config-provider';
|
|
5
6
|
import buildStateFromSchema from '../../../../../../Form/buildStateFromSchema';
|
|
6
7
|
import MinimalTemplate from '../../../../../../../templates/Minimal';
|
|
7
8
|
import Button from '../../../../../../../elements/Button';
|
|
@@ -15,6 +16,7 @@ const baseClass = 'edit-upload-modal';
|
|
|
15
16
|
export const EditModal = ({ slug, closeModal, relatedCollectionConfig, fieldSchema, element }) => {
|
|
16
17
|
const editor = useSlateStatic();
|
|
17
18
|
const [initialState, setInitialState] = useState({});
|
|
19
|
+
const { user } = useAuth();
|
|
18
20
|
const handleUpdateEditData = useCallback((fields) => {
|
|
19
21
|
const newNode = {
|
|
20
22
|
fields: reduceFieldsToValues(fields, true),
|
|
@@ -25,11 +27,11 @@ export const EditModal = ({ slug, closeModal, relatedCollectionConfig, fieldSche
|
|
|
25
27
|
}, [closeModal, editor, element]);
|
|
26
28
|
useEffect(() => {
|
|
27
29
|
const awaitInitialState = async () => {
|
|
28
|
-
const state = await buildStateFromSchema(fieldSchema, element === null || element === void 0 ? void 0 : element.fields);
|
|
30
|
+
const state = await buildStateFromSchema({ fieldSchema, data: element === null || element === void 0 ? void 0 : element.fields, user, operation: 'update' });
|
|
29
31
|
setInitialState(state);
|
|
30
32
|
};
|
|
31
33
|
awaitInitialState();
|
|
32
|
-
}, [fieldSchema, element.fields]);
|
|
34
|
+
}, [fieldSchema, element.fields, user]);
|
|
33
35
|
return (React.createElement(Modal, { slug: slug, className: baseClass },
|
|
34
36
|
React.createElement(MinimalTemplate, { width: "normal" },
|
|
35
37
|
React.createElement("header", { className: `${baseClass}__header` },
|
|
@@ -4,8 +4,13 @@ import withCondition from '../../withCondition';
|
|
|
4
4
|
import { fieldAffectsData } from '../../../../../fields/config/types';
|
|
5
5
|
import './index.scss';
|
|
6
6
|
const Row = (props) => {
|
|
7
|
-
const { fields, fieldTypes, path, permissions, admin: { readOnly, }, } = props;
|
|
8
|
-
|
|
7
|
+
const { fields, fieldTypes, path, permissions, admin: { readOnly, className, }, } = props;
|
|
8
|
+
const classes = [
|
|
9
|
+
'field-type',
|
|
10
|
+
'row',
|
|
11
|
+
className,
|
|
12
|
+
].filter(Boolean).join(' ');
|
|
13
|
+
return (React.createElement(RenderFields, { readOnly: readOnly, className: classes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: fields.map((field) => ({
|
|
9
14
|
...field,
|
|
10
15
|
path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
|
|
11
16
|
})) }));
|
|
@@ -13,16 +13,15 @@ const formatOptions = (options) => options.map((option) => {
|
|
|
13
13
|
};
|
|
14
14
|
});
|
|
15
15
|
const Select = (props) => {
|
|
16
|
-
const { path: pathFromProps, name,
|
|
16
|
+
const { path: pathFromProps, name, validate = select, label, options: optionsFromProps, hasMany, required, admin: { readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
17
17
|
const path = pathFromProps || name;
|
|
18
18
|
const [options, setOptions] = useState(formatOptions(optionsFromProps));
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
setOptions(formatOptions(optionsFromProps));
|
|
21
21
|
}, [optionsFromProps]);
|
|
22
|
-
const memoizedValidate = useCallback((value) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, [validate, required, options]);
|
|
22
|
+
const memoizedValidate = useCallback((value, validationOptions) => {
|
|
23
|
+
return validate(value, { ...validationOptions, options, hasMany, required });
|
|
24
|
+
}, [validate, required, hasMany, options]);
|
|
26
25
|
const { value, showError, setValue, errorMessage, } = useField({
|
|
27
26
|
path,
|
|
28
27
|
validate: memoizedValidate,
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
2
|
import useField from '../../useField';
|
|
3
3
|
import withCondition from '../../withCondition';
|
|
4
4
|
import { text } from '../../../../../fields/validations';
|
|
5
5
|
import TextInput from './Input';
|
|
6
6
|
const Text = (props) => {
|
|
7
|
-
const { path: pathFromProps, name, required, validate = text, label, admin: { placeholder, readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
7
|
+
const { path: pathFromProps, name, required, validate = text, label, minLength, maxLength, admin: { placeholder, readOnly, style, className, width, description, condition, } = {}, } = props;
|
|
8
8
|
const path = pathFromProps || name;
|
|
9
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
10
|
+
return validate(value, { ...options, minLength, maxLength, required });
|
|
11
|
+
}, [validate, minLength, maxLength, required]);
|
|
9
12
|
const field = useField({
|
|
10
13
|
path,
|
|
11
|
-
validate,
|
|
14
|
+
validate: memoizedValidate,
|
|
12
15
|
enableDebouncedValue: true,
|
|
13
16
|
condition,
|
|
14
17
|
});
|
|
@@ -5,12 +5,11 @@ import { textarea } from '../../../../../fields/validations';
|
|
|
5
5
|
import TextareaInput from './Input';
|
|
6
6
|
import './index.scss';
|
|
7
7
|
const Textarea = (props) => {
|
|
8
|
-
const { path: pathFromProps, name, required, validate = textarea, admin: { readOnly, style, className, width, placeholder, rows, description, condition, } = {}, label,
|
|
8
|
+
const { path: pathFromProps, name, required, validate = textarea, maxLength, minLength, admin: { readOnly, style, className, width, placeholder, rows, description, condition, } = {}, label, } = props;
|
|
9
9
|
const path = pathFromProps || name;
|
|
10
|
-
const memoizedValidate = useCallback((value) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}, [validate, maxLength, minLength, required]);
|
|
10
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
11
|
+
return validate(value, { ...options, required, maxLength, minLength });
|
|
12
|
+
}, [validate, required, maxLength, minLength]);
|
|
14
13
|
const { value, showError, setValue, errorMessage, } = useField({
|
|
15
14
|
path,
|
|
16
15
|
validate: memoizedValidate,
|
|
@@ -26,7 +26,7 @@ const AddUploadModal = (props) => {
|
|
|
26
26
|
const collectionPermissions = (_b = (_a = permissions === null || permissions === void 0 ? void 0 : permissions.collections) === null || _a === void 0 ? void 0 : _a[collection.slug]) === null || _b === void 0 ? void 0 : _b.fields;
|
|
27
27
|
return (React.createElement(Modal, { className: classes, slug: slug },
|
|
28
28
|
React.createElement(MinimalTemplate, { width: "wide" },
|
|
29
|
-
React.createElement(Form, { method: "post", action: `${serverURL}${api}/${collection.slug}`, onSuccess: onSuccess, disableSuccessStatus: true },
|
|
29
|
+
React.createElement(Form, { method: "post", action: `${serverURL}${api}/${collection.slug}`, onSuccess: onSuccess, disableSuccessStatus: true, validationOperation: "create" },
|
|
30
30
|
React.createElement("header", { className: `${baseClass}__header` },
|
|
31
31
|
React.createElement("div", null,
|
|
32
32
|
React.createElement("h1", null,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { UploadField } from '../../../../../fields/config/types';
|
|
2
|
+
import { FilterOptions, UploadField } from '../../../../../fields/config/types';
|
|
3
3
|
import { Description } from '../../FieldDescription/types';
|
|
4
4
|
import { FieldTypes } from '..';
|
|
5
5
|
import { SanitizedCollectionConfig } from '../../../../../collections/config/types';
|
|
@@ -21,6 +21,7 @@ export declare type UploadInputProps = Omit<UploadField, 'type'> & {
|
|
|
21
21
|
collection?: SanitizedCollectionConfig;
|
|
22
22
|
serverURL?: string;
|
|
23
23
|
api?: string;
|
|
24
|
+
filterOptions: FilterOptions;
|
|
24
25
|
};
|
|
25
26
|
declare const UploadInput: React.FC<UploadInputProps>;
|
|
26
27
|
export default UploadInput;
|
|
@@ -10,7 +10,7 @@ import SelectExistingModal from './SelectExisting';
|
|
|
10
10
|
import './index.scss';
|
|
11
11
|
const baseClass = 'upload';
|
|
12
12
|
const UploadInput = (props) => {
|
|
13
|
-
const { path, required, readOnly, style, className, width, description, label, relationTo, fieldTypes, value, onChange, showError, serverURL = 'http://localhost:3000', api = '/api', collection, errorMessage, } = props;
|
|
13
|
+
const { path, required, readOnly, style, className, width, description, label, relationTo, fieldTypes, value, onChange, showError, serverURL = 'http://localhost:3000', api = '/api', collection, errorMessage, filterOptions, } = props;
|
|
14
14
|
const { toggle } = useModal();
|
|
15
15
|
const addModalSlug = `${path}-add`;
|
|
16
16
|
const selectExistingModalSlug = `${path}-select-existing`;
|
|
@@ -78,6 +78,8 @@ const UploadInput = (props) => {
|
|
|
78
78
|
slug: selectExistingModalSlug,
|
|
79
79
|
setValue: onChange,
|
|
80
80
|
addModalSlug,
|
|
81
|
+
filterOptions,
|
|
82
|
+
path,
|
|
81
83
|
} }),
|
|
82
84
|
React.createElement(FieldDescription, { value: file, description: description })))));
|
|
83
85
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { Fragment, useState, useEffect } from 'react';
|
|
2
|
+
import equal from 'deep-equal';
|
|
2
3
|
import { Modal, useModal } from '@faceless-ui/modal';
|
|
3
|
-
import { useConfig } from '@payloadcms/config-provider';
|
|
4
|
+
import { useAuth, useConfig } from '@payloadcms/config-provider';
|
|
4
5
|
import MinimalTemplate from '../../../../templates/Minimal';
|
|
5
6
|
import Button from '../../../../elements/Button';
|
|
6
7
|
import usePayloadAPI from '../../../../../hooks/usePayloadAPI';
|
|
@@ -10,17 +11,24 @@ import UploadGallery from '../../../../elements/UploadGallery';
|
|
|
10
11
|
import PerPage from '../../../../elements/PerPage';
|
|
11
12
|
import formatFields from '../../../../views/collections/List/formatFields';
|
|
12
13
|
import './index.scss';
|
|
14
|
+
import { getFilterOptionsQuery } from '../../getFilterOptionsQuery';
|
|
15
|
+
import { useDocumentInfo } from '../../../../utilities/DocumentInfo';
|
|
16
|
+
import { useWatchForm } from '../../../Form/context';
|
|
13
17
|
const baseClass = 'select-existing-upload-modal';
|
|
14
18
|
const SelectExistingUploadModal = (props) => {
|
|
15
19
|
var _a, _b;
|
|
16
|
-
const { setValue, collection, collection: { slug: collectionSlug, admin: { description, pagination: { defaultLimit, }, } = {}, } = {}, slug: modalSlug, } = props;
|
|
20
|
+
const { setValue, collection, collection: { slug: collectionSlug, admin: { description, pagination: { defaultLimit, }, } = {}, } = {}, slug: modalSlug, path, filterOptions, } = props;
|
|
17
21
|
const { serverURL, routes: { api } } = useConfig();
|
|
22
|
+
const { id } = useDocumentInfo();
|
|
23
|
+
const { user } = useAuth();
|
|
24
|
+
const { getData, getSiblingData } = useWatchForm();
|
|
18
25
|
const { closeAll, currentModal } = useModal();
|
|
19
26
|
const [fields] = useState(() => formatFields(collection));
|
|
20
27
|
const [limit, setLimit] = useState(defaultLimit);
|
|
21
28
|
const [sort, setSort] = useState(null);
|
|
22
29
|
const [where, setWhere] = useState(null);
|
|
23
30
|
const [page, setPage] = useState(null);
|
|
31
|
+
const [optionFilters, setOptionFilters] = useState();
|
|
24
32
|
const classes = [
|
|
25
33
|
baseClass,
|
|
26
34
|
].filter(Boolean).join(' ');
|
|
@@ -32,13 +40,28 @@ const SelectExistingUploadModal = (props) => {
|
|
|
32
40
|
if (page)
|
|
33
41
|
params.page = page;
|
|
34
42
|
if (where)
|
|
35
|
-
params.where = where;
|
|
43
|
+
params.where = { and: [where, optionFilters] };
|
|
36
44
|
if (sort)
|
|
37
45
|
params.sort = sort;
|
|
38
46
|
if (limit)
|
|
39
47
|
params.limit = limit;
|
|
40
48
|
setParams(params);
|
|
41
|
-
}, [setParams, page, sort, where, limit]);
|
|
49
|
+
}, [setParams, page, sort, where, limit, optionFilters]);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!filterOptions || !isOpen) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const newOptionFilters = getFilterOptionsQuery(filterOptions, {
|
|
55
|
+
id,
|
|
56
|
+
relationTo: collectionSlug,
|
|
57
|
+
data: getData(),
|
|
58
|
+
siblingData: getSiblingData(path),
|
|
59
|
+
user,
|
|
60
|
+
})[collectionSlug];
|
|
61
|
+
if (!equal(newOptionFilters, optionFilters)) {
|
|
62
|
+
setOptionFilters(newOptionFilters);
|
|
63
|
+
}
|
|
64
|
+
}, [collectionSlug, filterOptions, optionFilters, id, getData, getSiblingData, path, user, isOpen]);
|
|
42
65
|
return (React.createElement(Modal, { className: classes, slug: modalSlug }, isOpen && (React.createElement(MinimalTemplate, { width: "wide" },
|
|
43
66
|
React.createElement("header", { className: `${baseClass}__header` },
|
|
44
67
|
React.createElement("div", null,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { SanitizedCollectionConfig } from '../../../../../../collections/config/types';
|
|
2
|
+
import { FilterOptions } from '../../../../../../fields/config/types';
|
|
2
3
|
export declare type Props = {
|
|
3
4
|
setValue: (val: {
|
|
4
5
|
id: string;
|
|
5
6
|
} | null) => void;
|
|
6
7
|
collection: SanitizedCollectionConfig;
|
|
7
8
|
slug: string;
|
|
9
|
+
path: any;
|
|
10
|
+
filterOptions: FilterOptions;
|
|
8
11
|
};
|
|
@@ -7,11 +7,10 @@ import UploadInput from './Input';
|
|
|
7
7
|
import './index.scss';
|
|
8
8
|
const Upload = (props) => {
|
|
9
9
|
const { collections, serverURL, routes: { api, }, } = useConfig();
|
|
10
|
-
const { path, name, required, admin: { readOnly, style, className, width, description, condition, } = {}, label, validate = upload, relationTo, fieldTypes, } = props;
|
|
10
|
+
const { path, name, required, admin: { readOnly, style, className, width, description, condition, } = {}, label, validate = upload, relationTo, fieldTypes, filterOptions, } = props;
|
|
11
11
|
const collection = collections.find((coll) => coll.slug === relationTo);
|
|
12
|
-
const memoizedValidate = useCallback((value) => {
|
|
13
|
-
|
|
14
|
-
return validationResult;
|
|
12
|
+
const memoizedValidate = useCallback((value, options) => {
|
|
13
|
+
return validate(value, { ...options, required });
|
|
15
14
|
}, [validate, required]);
|
|
16
15
|
const field = useField({
|
|
17
16
|
path,
|
|
@@ -26,7 +25,7 @@ const Upload = (props) => {
|
|
|
26
25
|
setValue,
|
|
27
26
|
]);
|
|
28
27
|
if (collection.upload) {
|
|
29
|
-
return (React.createElement(UploadInput, { path: path, value: value, onChange: onChange, description: description, label: label, required: required, showError: showError, serverURL: serverURL, api: api, errorMessage: errorMessage, readOnly: readOnly, style: style, className: className, width: width, collection: collection, fieldTypes: fieldTypes, name: name, relationTo: relationTo }));
|
|
28
|
+
return (React.createElement(UploadInput, { path: path, value: value, onChange: onChange, description: description, label: label, required: required, showError: showError, serverURL: serverURL, api: api, errorMessage: errorMessage, readOnly: readOnly, style: style, className: className, width: width, collection: collection, fieldTypes: fieldTypes, name: name, relationTo: relationTo, filterOptions: filterOptions }));
|
|
30
29
|
}
|
|
31
30
|
return null;
|
|
32
31
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Where } from '../../../../types';
|
|
2
|
+
import { FilterOptions, FilterOptionsProps } from '../../../../fields/config/types';
|
|
3
|
+
export declare const getFilterOptionsQuery: (filterOptions: FilterOptions, options: FilterOptionsProps) => {
|
|
4
|
+
[collection: string]: Where;
|
|
5
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const getFilterOptionsQuery = (filterOptions, options) => {
|
|
2
|
+
const { relationTo } = options;
|
|
3
|
+
const relations = Array.isArray(relationTo) ? relationTo : [relationTo];
|
|
4
|
+
const query = {};
|
|
5
|
+
if (typeof filterOptions !== 'undefined') {
|
|
6
|
+
relations.forEach((relation) => {
|
|
7
|
+
query[relation] = typeof filterOptions === 'function' ? filterOptions(options) : filterOptions;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
return query;
|
|
11
|
+
};
|