payload 0.15.3 → 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.
Files changed (89) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/admin/components/elements/WhereBuilder/field-types.d.ts +2 -2
  3. package/dist/admin/components/elements/WhereBuilder/field-types.js +11 -7
  4. package/dist/admin/components/forms/DraggableSection/index.js +2 -3
  5. package/dist/admin/components/forms/Form/buildStateFromSchema.d.ts +10 -1
  6. package/dist/admin/components/forms/Form/buildStateFromSchema.js +14 -6
  7. package/dist/admin/components/forms/Form/getDataByPath.js +6 -11
  8. package/dist/admin/components/forms/Form/getSiblingData.js +12 -14
  9. package/dist/admin/components/forms/Form/index.js +23 -6
  10. package/dist/admin/components/forms/Form/reduceFieldsToValues.d.ts +1 -1
  11. package/dist/admin/components/forms/Form/reduceFieldsToValues.js +1 -2
  12. package/dist/admin/components/forms/Form/types.d.ts +3 -2
  13. package/dist/admin/components/forms/RenderFields/index.d.ts +1 -2
  14. package/dist/admin/components/forms/RenderFields/index.js +6 -16
  15. package/dist/admin/components/forms/RenderFields/types.d.ts +0 -5
  16. package/dist/admin/components/forms/field-types/Array/Array.js +18 -9
  17. package/dist/admin/components/forms/field-types/Blocks/Blocks.js +21 -15
  18. package/dist/admin/components/forms/field-types/Checkbox/index.js +3 -4
  19. package/dist/admin/components/forms/field-types/Code/Code.js +4 -5
  20. package/dist/admin/components/forms/field-types/DateTime/index.js +2 -3
  21. package/dist/admin/components/forms/field-types/Email/index.js +2 -3
  22. package/dist/admin/components/forms/field-types/Number/index.js +3 -4
  23. package/dist/admin/components/forms/field-types/Password/index.js +2 -2
  24. package/dist/admin/components/forms/field-types/Point/index.js +2 -3
  25. package/dist/admin/components/forms/field-types/RadioGroup/index.js +3 -4
  26. package/dist/admin/components/forms/field-types/Relationship/index.js +49 -17
  27. package/dist/admin/components/forms/field-types/RichText/RichText.js +3 -4
  28. package/dist/admin/components/forms/field-types/RichText/elements/upload/Element/EditModal/index.js +4 -2
  29. package/dist/admin/components/forms/field-types/Row/index.js +7 -2
  30. package/dist/admin/components/forms/field-types/Select/index.js +4 -5
  31. package/dist/admin/components/forms/field-types/Text/index.js +6 -3
  32. package/dist/admin/components/forms/field-types/Textarea/index.js +4 -5
  33. package/dist/admin/components/forms/field-types/Upload/Add/index.js +1 -1
  34. package/dist/admin/components/forms/field-types/Upload/Input.d.ts +2 -1
  35. package/dist/admin/components/forms/field-types/Upload/Input.js +3 -1
  36. package/dist/admin/components/forms/field-types/Upload/SelectExisting/index.js +27 -4
  37. package/dist/admin/components/forms/field-types/Upload/SelectExisting/types.d.ts +3 -0
  38. package/dist/admin/components/forms/field-types/Upload/index.js +4 -5
  39. package/dist/admin/components/forms/field-types/getFilterOptionsQuery.d.ts +5 -0
  40. package/dist/admin/components/forms/field-types/getFilterOptionsQuery.js +11 -0
  41. package/dist/admin/components/forms/useField/index.js +39 -8
  42. package/dist/admin/components/utilities/OperationProvider/index.d.ts +4 -0
  43. package/dist/admin/components/utilities/OperationProvider/index.js +3 -0
  44. package/dist/admin/components/views/Account/Default.js +41 -39
  45. package/dist/admin/components/views/Account/index.js +4 -2
  46. package/dist/admin/components/views/CreateFirstUser/index.js +1 -1
  47. package/dist/admin/components/views/Global/Default.js +45 -43
  48. package/dist/admin/components/views/Global/index.js +5 -5
  49. package/dist/admin/components/views/collections/Edit/Auth/APIKey.js +1 -1
  50. package/dist/admin/components/views/collections/Edit/Default.js +55 -53
  51. package/dist/admin/components/views/collections/Edit/index.js +5 -5
  52. package/dist/collections/tests/pointField.spec.js +26 -15
  53. package/dist/collections/tests/relationships.spec.js +21 -1
  54. package/dist/config/load.d.ts +3 -1
  55. package/dist/config/load.js +5 -3
  56. package/dist/config/types.d.ts +3 -0
  57. package/dist/config/types.js +1 -1
  58. package/dist/config/validate.d.ts +2 -1
  59. package/dist/config/validate.js +2 -4
  60. package/dist/email/build.d.ts +2 -1
  61. package/dist/email/build.js +7 -9
  62. package/dist/express/middleware/errorHandler.spec.js +2 -2
  63. package/dist/fields/config/sanitize.js +2 -2
  64. package/dist/fields/config/schema.js +3 -1
  65. package/dist/fields/config/types.d.ts +25 -1
  66. package/dist/fields/config/types.js +1 -1
  67. package/dist/fields/performFieldOperations.js +3 -3
  68. package/dist/fields/traverseFields.js +15 -5
  69. package/dist/fields/validationPromise.d.ts +10 -3
  70. package/dist/fields/validationPromise.js +16 -5
  71. package/dist/fields/validations.d.ts +33 -35
  72. package/dist/fields/validations.js +130 -76
  73. package/dist/fields/validations.spec.js +115 -43
  74. package/dist/graphql/schema/fieldToSchemaMap.js +7 -7
  75. package/dist/index.d.ts +2 -2
  76. package/dist/index.js +5 -5
  77. package/dist/mongoose/buildQuery.js +2 -2
  78. package/dist/mongoose/connect.d.ts +2 -1
  79. package/dist/mongoose/connect.js +2 -4
  80. package/dist/mongoose/sanitizeFormattedValue.js +12 -3
  81. package/dist/utilities/logger.d.ts +1 -1
  82. package/dist/utilities/logger.js +10 -6
  83. package/dist/webpack/getBaseConfig.js +2 -1
  84. package/docs/fields/overview.mdx +39 -3
  85. package/docs/fields/relationship.mdx +45 -0
  86. package/docs/fields/upload.mdx +1 -0
  87. package/docs/getting-started/installation.mdx +14 -10
  88. package/docs/queries/overview.mdx +2 -1
  89. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## [0.15.4](https://github.com/payloadcms/payload/compare/v0.15.3...v0.15.4) (2022-04-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * [#495](https://github.com/payloadcms/payload/issues/495), avoids appending version to id queries ([ab432a4](https://github.com/payloadcms/payload/commit/ab432a43dc568da0b7e65e275aed335d729600fa))
7
+ * default point validation allows not required and some edge cases ([29405bb](https://github.com/payloadcms/payload/commit/29405bbc0e3a5c3c1f3dadb2386a68e1fe159c42))
8
+ * maintains field validation internally for speed ([b99f6b1](https://github.com/payloadcms/payload/commit/b99f6b16af1573185bb8de07c6e54ac02caf6de8))
9
+
10
+
11
+ ### Features
12
+
13
+ * allows like to search by many words, adds contain to match exact strings ([ec91757](https://github.com/payloadcms/payload/commit/ec91757257ed062c7743fca3d07d1b6af21cacb4))
14
+ * extended validation function arguments ([#494](https://github.com/payloadcms/payload/issues/494)) ([1b4b570](https://github.com/payloadcms/payload/commit/1b4b5707bfa731bedc5d9ca49ac9f425932b999c)), closes [#495](https://github.com/payloadcms/payload/issues/495)
15
+ * filter relationship options in admin ui using filterOptions ([485991b](https://github.com/payloadcms/payload/commit/485991bd48c3512acca8dd94b3ab6c160bf1f153))
16
+ * **logging:** allow pino logger options to be passed into init ([6620a4f](https://github.com/payloadcms/payload/commit/6620a4f682f0a3169218dd83e1de315f95726287))
17
+ * support className config for row, block and array fields ([#504](https://github.com/payloadcms/payload/issues/504)) ([0461c21](https://github.com/payloadcms/payload/commit/0461c2109bea76742f94ae6f830c655ec67d1428))
18
+ * upload field implements filterOptions ([1482fde](https://github.com/payloadcms/payload/commit/1482fded9a2e700416e7d0b0c753a05f56f4aee1))
19
+ * WIP extended validation function arguments ([647cac3](https://github.com/payloadcms/payload/commit/647cac3612c02dc164254e050ef589a88077b55f))
20
+ * working PoC for reusing relationship filters in validate ([df934df](https://github.com/payloadcms/payload/commit/df934dfeff8b12857d133b2da9f441bc0285dee4))
21
+
1
22
  ## [0.15.3](https://github.com/payloadcms/payload/compare/v0.15.2...v0.15.3) (2022-04-04)
2
23
 
3
24
 
@@ -20,14 +20,14 @@ declare const fieldTypeConditions: {
20
20
  value: string;
21
21
  }[];
22
22
  };
23
- wysiwyg: {
23
+ code: {
24
24
  component: string;
25
25
  operators: {
26
26
  label: string;
27
27
  value: string;
28
28
  }[];
29
29
  };
30
- code: {
30
+ richText: {
31
31
  component: string;
32
32
  operators: {
33
33
  label: string;
@@ -57,26 +57,30 @@ const like = {
57
57
  label: 'is like',
58
58
  value: 'like',
59
59
  };
60
+ const contains = {
61
+ label: 'contains',
62
+ value: 'contains',
63
+ };
60
64
  const fieldTypeConditions = {
61
65
  text: {
62
66
  component: 'Text',
63
- operators: [...base, like],
67
+ operators: [...base, like, contains],
64
68
  },
65
69
  email: {
66
70
  component: 'Text',
67
- operators: [...base, like],
71
+ operators: [...base, contains],
68
72
  },
69
73
  textarea: {
70
74
  component: 'Text',
71
- operators: [...base, like],
75
+ operators: [...base, like, contains],
72
76
  },
73
- wysiwyg: {
77
+ code: {
74
78
  component: 'Text',
75
- operators: [...base, like],
79
+ operators: [...base, like, contains],
76
80
  },
77
- code: {
81
+ richText: {
78
82
  component: 'Text',
79
- operators: [...base, like],
83
+ operators: [...base, like, contains],
80
84
  },
81
85
  number: {
82
86
  component: 'Number',
@@ -7,7 +7,7 @@ import PositionPanel from './PositionPanel';
7
7
  import Button from '../../elements/Button';
8
8
  import { NegativeFieldGutterProvider } from '../FieldTypeGutter/context';
9
9
  import FieldTypeGutter from '../FieldTypeGutter';
10
- import RenderFields, { useRenderedFields } from '../RenderFields';
10
+ import RenderFields from '../RenderFields';
11
11
  import HiddenInput from '../field-types/HiddenInput';
12
12
  import './index.scss';
13
13
  import { fieldAffectsData } from '../../../../fields/config/types';
@@ -15,7 +15,6 @@ const baseClass = 'draggable-section';
15
15
  const DraggableSection = (props) => {
16
16
  const { moveRow, addRow, removeRow, rowIndex, rowCount, parentPath, fieldSchema, label, blockType, fieldTypes, id, setRowCollapse, isCollapsed, permissions, readOnly, hasMaxRows, } = props;
17
17
  const [isHovered, setIsHovered] = useState(false);
18
- const { operation } = useRenderedFields();
19
18
  const classes = [
20
19
  baseClass,
21
20
  isCollapsed ? 'is-collapsed' : 'is-open',
@@ -32,7 +31,7 @@ const DraggableSection = (props) => {
32
31
  React.createElement(Button, { icon: "chevron", onClick: () => setRowCollapse(id, !isCollapsed), buttonStyle: "icon-label", className: `toggle-collapse toggle-collapse--is-${isCollapsed ? 'collapsed' : 'open'}`, round: true }))),
33
32
  React.createElement(AnimateHeight, { height: isCollapsed ? 0 : 'auto', duration: 200 },
34
33
  React.createElement(NegativeFieldGutterProvider, { allow: false },
35
- React.createElement(RenderFields, { operation: operation, readOnly: readOnly, fieldTypes: fieldTypes, key: rowIndex, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: fieldSchema.map((field) => ({
34
+ React.createElement(RenderFields, { readOnly: readOnly, fieldTypes: fieldTypes, key: rowIndex, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: fieldSchema.map((field) => ({
36
35
  ...field,
37
36
  path: `${parentPath}.${rowIndex}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
38
37
  })) })))),
@@ -1,4 +1,13 @@
1
+ import { User } from '../../../../auth';
1
2
  import { Field as FieldSchema } from '../../../../fields/config/types';
2
3
  import { Fields, Data } from './types';
3
- declare const buildStateFromSchema: (fieldSchema: FieldSchema[], fullData?: Data) => Promise<Fields>;
4
+ declare type Args = {
5
+ fieldSchema: FieldSchema[];
6
+ data?: Data;
7
+ siblingData?: Data;
8
+ user?: User;
9
+ id?: string | number;
10
+ operation?: 'create' | 'update';
11
+ };
12
+ declare const buildStateFromSchema: (args: Args) => Promise<Fields>;
4
13
  export default buildStateFromSchema;
@@ -1,10 +1,10 @@
1
1
  import ObjectID from 'bson-objectid';
2
- import { fieldAffectsData, fieldIsPresentationalOnly } from '../../../../fields/config/types';
3
- const buildValidationPromise = async (fieldState, field) => {
2
+ import { fieldAffectsData, fieldIsPresentationalOnly, } from '../../../../fields/config/types';
3
+ const buildValidationPromise = async (fieldState, options) => {
4
4
  const validatedFieldState = fieldState;
5
5
  let validationResult = true;
6
- if (typeof field.validate === 'function') {
7
- validationResult = await field.validate(fieldState.value, field);
6
+ if (typeof fieldState.validate === 'function') {
7
+ validationResult = await fieldState.validate(fieldState.value, options);
8
8
  }
9
9
  if (typeof validationResult === 'string') {
10
10
  validatedFieldState.errorMessage = validationResult;
@@ -14,7 +14,8 @@ const buildValidationPromise = async (fieldState, field) => {
14
14
  validatedFieldState.valid = true;
15
15
  }
16
16
  };
17
- const buildStateFromSchema = async (fieldSchema, fullData = {}) => {
17
+ const buildStateFromSchema = async (args) => {
18
+ const { fieldSchema, data: fullData = {}, user, id, operation, } = args;
18
19
  if (fieldSchema) {
19
20
  const validationPromises = [];
20
21
  const structureFieldState = (field, passesCondition, data = {}) => {
@@ -28,7 +29,14 @@ const buildStateFromSchema = async (fieldSchema, fullData = {}) => {
28
29
  condition: (_a = field.admin) === null || _a === void 0 ? void 0 : _a.condition,
29
30
  passesCondition,
30
31
  };
31
- validationPromises.push(buildValidationPromise(fieldState, field));
32
+ validationPromises.push(buildValidationPromise(fieldState, {
33
+ ...field,
34
+ fullData,
35
+ user,
36
+ siblingData: data,
37
+ id,
38
+ operation,
39
+ }));
32
40
  return fieldState;
33
41
  };
34
42
  const iterateFields = (fields, data, parentPassesCondition, path = '') => fields.reduce((state, field) => {
@@ -1,19 +1,14 @@
1
1
  import { unflatten } from 'flatley';
2
- import reduceFieldsToValues from './reduceFieldsToValues';
3
2
  const getDataByPath = (fields, path) => {
4
3
  const pathPrefixToRemove = path.substring(0, path.lastIndexOf('.') + 1);
5
4
  const name = path.split('.').pop();
6
- const data = Object.keys(fields).reduce((matchedData, key) => {
7
- if (key.indexOf(`${path}.`) === 0 || key === path) {
8
- return {
9
- ...matchedData,
10
- [key.replace(pathPrefixToRemove, '')]: fields[key],
11
- };
5
+ const data = {};
6
+ Object.keys(fields).forEach((key) => {
7
+ if (!fields[key].disableFormData && (key.indexOf(`${path}.`) === 0 || key === path)) {
8
+ data[key.replace(pathPrefixToRemove, '')] = fields[key].value;
12
9
  }
13
- return matchedData;
14
- }, {});
15
- const values = reduceFieldsToValues(data, true);
16
- const unflattenedData = unflatten(values);
10
+ });
11
+ const unflattenedData = unflatten(data);
17
12
  return unflattenedData === null || unflattenedData === void 0 ? void 0 : unflattenedData[name];
18
13
  };
19
14
  export default getDataByPath;
@@ -1,20 +1,18 @@
1
+ import { unflatten } from 'flatley';
1
2
  import reduceFieldsToValues from './reduceFieldsToValues';
2
3
  const getSiblingData = (fields, path) => {
3
- let siblingFields = fields;
4
+ if (path.indexOf('.') === -1) {
5
+ return reduceFieldsToValues(fields, true);
6
+ }
7
+ const siblingFields = {};
4
8
  // If this field is nested
5
9
  // We can provide a list of sibling fields
6
- if (path.indexOf('.') > 0) {
7
- const parentFieldPath = path.substring(0, path.lastIndexOf('.') + 1);
8
- siblingFields = Object.keys(fields).reduce((siblings, fieldKey) => {
9
- if (fieldKey.indexOf(parentFieldPath) === 0) {
10
- return {
11
- ...siblings,
12
- [fieldKey.replace(parentFieldPath, '')]: fields[fieldKey],
13
- };
14
- }
15
- return siblings;
16
- }, {});
17
- }
18
- return reduceFieldsToValues(siblingFields, true);
10
+ const parentFieldPath = path.substring(0, path.lastIndexOf('.') + 1);
11
+ Object.keys(fields).forEach((fieldKey) => {
12
+ if (!fields[fieldKey].disableFormData && fieldKey.indexOf(parentFieldPath) === 0) {
13
+ siblingFields[fieldKey.replace(parentFieldPath, '')] = fields[fieldKey].value;
14
+ }
15
+ });
16
+ return unflatten(siblingFields, { safe: true });
19
17
  };
20
18
  export default getSiblingData;
@@ -1,10 +1,12 @@
1
1
  /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
2
2
  import React, { useReducer, useEffect, useRef, useState, useCallback, } from 'react';
3
+ import isDeepEqual from 'deep-equal';
3
4
  import { serialize } from 'object-to-formdata';
4
5
  import { useHistory } from 'react-router-dom';
5
6
  import { toast } from 'react-toastify';
6
7
  import { useAuth } from '@payloadcms/config-provider';
7
8
  import { useLocale } from '../../utilities/Locale';
9
+ import { useDocumentInfo } from '../../utilities/DocumentInfo';
8
10
  import { requests } from '../../../api';
9
11
  import useThrottledEffect from '../../../hooks/useThrottledEffect';
10
12
  import fieldReducer from './fieldReducer';
@@ -17,6 +19,7 @@ import buildInitialState from './buildInitialState';
17
19
  import errorMessages from './errorMessages';
18
20
  import { SubmittedContext, ProcessingContext, ModifiedContext, FormContext, FormWatchContext } from './context';
19
21
  import buildStateFromSchema from './buildStateFromSchema';
22
+ import { useOperation } from '../../utilities/OperationProvider';
20
23
  const baseClass = 'form';
21
24
  const Form = (props) => {
22
25
  const { disabled, onSubmit, method, action, handleResponse, onSuccess, children, className, redirect, disableSuccessStatus, initialState, // fully formed initial field state
@@ -24,7 +27,9 @@ const Form = (props) => {
24
27
  waitForAutocomplete, log, } = props;
25
28
  const history = useHistory();
26
29
  const locale = useLocale();
27
- const { refreshCookie } = useAuth();
30
+ const { refreshCookie, user } = useAuth();
31
+ const { id } = useDocumentInfo();
32
+ const operation = useOperation();
28
33
  const [modified, setModified] = useState(false);
29
34
  const [processing, setProcessing] = useState(false);
30
35
  const [submitted, setSubmitted] = useState(false);
@@ -43,6 +48,7 @@ const Form = (props) => {
43
48
  const validateForm = useCallback(async () => {
44
49
  const validatedFieldState = {};
45
50
  let isValid = true;
51
+ const data = contextRef.current.getData();
46
52
  const validationPromises = Object.entries(contextRef.current.fields).map(async ([path, field]) => {
47
53
  const validatedField = {
48
54
  ...field,
@@ -51,7 +57,13 @@ const Form = (props) => {
51
57
  if (field.passesCondition !== false) {
52
58
  let validationResult = true;
53
59
  if (typeof field.validate === 'function') {
54
- validationResult = await field.validate(field.value);
60
+ validationResult = await field.validate(field.value, {
61
+ data,
62
+ siblingData: contextRef.current.getSiblingData(path),
63
+ user,
64
+ id,
65
+ operation,
66
+ });
55
67
  }
56
68
  if (typeof validationResult === 'string') {
57
69
  validatedField.errorMessage = validationResult;
@@ -62,9 +74,11 @@ const Form = (props) => {
62
74
  validatedFieldState[path] = validatedField;
63
75
  });
64
76
  await Promise.all(validationPromises);
65
- dispatchFields({ type: 'REPLACE_STATE', state: validatedFieldState });
77
+ if (!isDeepEqual(contextRef.current.fields, validatedFieldState)) {
78
+ dispatchFields({ type: 'REPLACE_STATE', state: validatedFieldState });
79
+ }
66
80
  return isValid;
67
- }, [contextRef]);
81
+ }, [contextRef, id, user, operation]);
68
82
  const submit = useCallback(async (options = {}, e) => {
69
83
  const { overrides = {}, action: actionToUse = action, method: methodToUse = method, skipValidation, } = options;
70
84
  if (disabled) {
@@ -233,10 +247,10 @@ const Form = (props) => {
233
247
  return formData;
234
248
  }, [contextRef]);
235
249
  const reset = useCallback(async (fieldSchema, data) => {
236
- const state = await buildStateFromSchema(fieldSchema, data);
250
+ const state = await buildStateFromSchema({ fieldSchema, data, user, id, operation });
237
251
  contextRef.current = { ...initContextState };
238
252
  dispatchFields({ type: 'REPLACE_STATE', state });
239
- }, []);
253
+ }, [id, user, operation]);
240
254
  contextRef.current.dispatchFields = dispatchFields;
241
255
  contextRef.current.submit = submit;
242
256
  contextRef.current.getFields = getFields;
@@ -270,6 +284,9 @@ const Form = (props) => {
270
284
  useThrottledEffect(() => {
271
285
  refreshCookie();
272
286
  }, 15000, [fields]);
287
+ useThrottledEffect(() => {
288
+ validateForm();
289
+ }, 1000, [validateForm, fields]);
273
290
  useEffect(() => {
274
291
  contextRef.current = { ...contextRef.current }; // triggers rerender of all components that subscribe to form
275
292
  setModified(false);
@@ -1,3 +1,3 @@
1
- import { Fields, Data } from './types';
1
+ import { Data, Fields } from './types';
2
2
  declare const reduceFieldsToValues: (fields: Fields, unflatten?: boolean) => Data;
3
3
  export default reduceFieldsToValues;
@@ -7,8 +7,7 @@ const reduceFieldsToValues = (fields, unflatten) => {
7
7
  }
8
8
  });
9
9
  if (unflatten) {
10
- const unflattened = flatleyUnflatten(data, { safe: true });
11
- return unflattened;
10
+ return flatleyUnflatten(data, { safe: true });
12
11
  }
13
12
  return data;
14
13
  };
@@ -1,11 +1,11 @@
1
1
  /// <reference types="react" />
2
- import { Field as FieldConfig, Condition } from '../../../../fields/config/types';
2
+ import { Field as FieldConfig, Condition, Validate } from '../../../../fields/config/types';
3
3
  export declare type Field = {
4
4
  value: unknown;
5
5
  initialValue: unknown;
6
6
  errorMessage?: string;
7
7
  valid: boolean;
8
- validate?: (val: unknown) => Promise<boolean | string> | boolean | string;
8
+ validate?: Validate;
9
9
  disableFormData?: boolean;
10
10
  ignoreWhileFlattening?: boolean;
11
11
  condition?: Condition;
@@ -34,6 +34,7 @@ export declare type Props = {
34
34
  initialData?: Data;
35
35
  waitForAutocomplete?: boolean;
36
36
  log?: boolean;
37
+ validationOperation?: 'create' | 'update';
37
38
  };
38
39
  export declare type SubmitOptions = {
39
40
  action?: string;
@@ -1,5 +1,4 @@
1
1
  import React from 'react';
2
- import { Props, Context } from './types';
3
- export declare const useRenderedFields: () => Context;
2
+ import { Props } from './types';
4
3
  declare const RenderFields: React.FC<Props>;
5
4
  export default RenderFields;
@@ -1,31 +1,21 @@
1
- import React, { createContext, useEffect, useContext, useState } from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import RenderCustomComponent from '../../utilities/RenderCustomComponent';
3
3
  import useIntersect from '../../../hooks/useIntersect';
4
4
  import { fieldAffectsData, fieldIsPresentationalOnly } from '../../../../fields/config/types';
5
+ import { useOperation } from '../../utilities/OperationProvider';
5
6
  const baseClass = 'render-fields';
6
7
  const intersectionObserverOptions = {
7
8
  rootMargin: '1000px',
8
9
  };
9
- const RenderedFieldContext = createContext({});
10
- export const useRenderedFields = () => useContext(RenderedFieldContext);
11
10
  const RenderFields = (props) => {
12
11
  var _a;
13
- const { fieldSchema, fieldTypes, filter, permissions, readOnly: readOnlyOverride, operation: operationFromProps, className, } = props;
12
+ const { fieldSchema, fieldTypes, filter, permissions, readOnly: readOnlyOverride, className, } = props;
14
13
  const [hasRendered, setHasRendered] = useState(false);
15
14
  const [intersectionRef, entry] = useIntersect(intersectionObserverOptions);
15
+ const operation = useOperation();
16
16
  const isIntersecting = Boolean(entry === null || entry === void 0 ? void 0 : entry.isIntersecting);
17
17
  const isAboveViewport = ((_a = entry === null || entry === void 0 ? void 0 : entry.boundingClientRect) === null || _a === void 0 ? void 0 : _a.top) < 0;
18
18
  const shouldRender = isIntersecting || isAboveViewport;
19
- const { operation: operationFromContext } = useRenderedFields();
20
- const operation = operationFromProps || operationFromContext;
21
- const [contextValue, setContextValue] = useState({
22
- operation,
23
- });
24
- useEffect(() => {
25
- setContextValue({
26
- operation,
27
- });
28
- }, [operation]);
29
19
  useEffect(() => {
30
20
  if (shouldRender && !hasRendered) {
31
21
  setHasRendered(true);
@@ -36,7 +26,7 @@ const RenderFields = (props) => {
36
26
  className,
37
27
  ].filter(Boolean).join(' ');
38
28
  if (fieldSchema) {
39
- return (React.createElement("div", { ref: intersectionRef, className: classes }, hasRendered && (React.createElement(RenderedFieldContext.Provider, { value: contextValue }, fieldSchema.map((field, i) => {
29
+ return (React.createElement("div", { ref: intersectionRef, className: classes }, hasRendered && (fieldSchema.map((field, i) => {
40
30
  var _a, _b, _c, _d, _e, _f, _g, _h;
41
31
  const fieldIsPresentational = fieldIsPresentationalOnly(field);
42
32
  let FieldComponent = fieldTypes[field.type];
@@ -80,7 +70,7 @@ const RenderFields = (props) => {
80
70
  return null;
81
71
  }
82
72
  return null;
83
- })))));
73
+ }))));
84
74
  }
85
75
  return null;
86
76
  };
@@ -1,13 +1,8 @@
1
1
  import { FieldPermissions } from '../../../../auth/types';
2
2
  import { FieldWithPath, Field } from '../../../../fields/config/types';
3
3
  import { FieldTypes } from '../field-types';
4
- export declare type Operation = 'create' | 'update';
5
- export declare type Context = {
6
- operation: Operation;
7
- };
8
4
  export declare type Props = {
9
5
  className?: string;
10
- operation?: Operation;
11
6
  readOnly?: boolean;
12
7
  permissions?: {
13
8
  [field: string]: FieldPermissions;
@@ -1,5 +1,6 @@
1
- import React, { useEffect, useReducer, useCallback, useState } from 'react';
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
2
  import { DragDropContext, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '@payloadcms/config-provider';
3
4
  import withCondition from '../../withCondition';
4
5
  import Button from '../../../elements/Button';
5
6
  import DraggableSection from '../../DraggableSection';
@@ -11,11 +12,13 @@ import Error from '../../Error';
11
12
  import { array } from '../../../../../fields/validations';
12
13
  import Banner from '../../../elements/Banner';
13
14
  import FieldDescription from '../../FieldDescription';
15
+ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
16
+ import { useOperation } from '../../../utilities/OperationProvider';
14
17
  import './index.scss';
15
18
  const baseClass = 'field-type array';
16
19
  const ArrayFieldType = (props) => {
17
20
  var _a, _b;
18
- const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, }, } = props;
21
+ const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, className, }, } = props;
19
22
  // Handle labeling for Arrays, Global Arrays, and Blocks
20
23
  const getLabels = (p) => {
21
24
  if (p === null || p === void 0 ? void 0 : p.labels)
@@ -29,12 +32,14 @@ const ArrayFieldType = (props) => {
29
32
  const label = (_a = props === null || props === void 0 ? void 0 : props.label) !== null && _a !== void 0 ? _a : (_b = props === null || props === void 0 ? void 0 : props.labels) === null || _b === void 0 ? void 0 : _b.singular;
30
33
  const [rows, dispatchRows] = useReducer(reducer, []);
31
34
  const formContext = useForm();
35
+ const { user } = useAuth();
36
+ const { id } = useDocumentInfo();
37
+ const operation = useOperation();
32
38
  const { dispatchFields } = formContext;
33
39
  const path = pathFromProps || name;
34
- const memoizedValidate = useCallback((value) => {
35
- const validationResult = validate(value, { minRows, maxRows, required });
36
- return validationResult;
37
- }, [validate, maxRows, minRows, required]);
40
+ const memoizedValidate = useCallback((value, options) => {
41
+ return validate(value, { ...options, minRows, maxRows, required });
42
+ }, [maxRows, minRows, required, validate]);
38
43
  const [disableFormData, setDisableFormData] = useState(false);
39
44
  const { showError, errorMessage, value, setValue, } = useField({
40
45
  path,
@@ -44,11 +49,11 @@ const ArrayFieldType = (props) => {
44
49
  condition,
45
50
  });
46
51
  const addRow = useCallback(async (rowIndex) => {
47
- const subFieldState = await buildStateFromSchema(fields);
52
+ const subFieldState = await buildStateFromSchema({ fieldSchema: fields, operation, id, user });
48
53
  dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path });
49
54
  dispatchRows({ type: 'ADD', rowIndex });
50
55
  setValue(value + 1);
51
- }, [dispatchRows, dispatchFields, fields, path, setValue, value]);
56
+ }, [dispatchRows, dispatchFields, fields, path, setValue, value, operation, id, user]);
52
57
  const removeRow = useCallback((rowIndex) => {
53
58
  dispatchRows({ type: 'REMOVE', rowIndex });
54
59
  dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
@@ -78,8 +83,12 @@ const ArrayFieldType = (props) => {
78
83
  }
79
84
  }, [rows, setValue]);
80
85
  const hasMaxRows = maxRows && rows.length >= maxRows;
86
+ const classes = [
87
+ baseClass,
88
+ className,
89
+ ].filter(Boolean).join(' ');
81
90
  return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
82
- React.createElement("div", { className: baseClass },
91
+ React.createElement("div", { className: classes },
83
92
  React.createElement("div", { className: `${baseClass}__error-wrap` },
84
93
  React.createElement(Error, { showError: showError, message: errorMessage })),
85
94
  React.createElement("header", { className: `${baseClass}__header` },
@@ -1,5 +1,6 @@
1
- import React, { useEffect, useReducer, useCallback, useState, } from 'react';
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
2
  import { DragDropContext, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '@payloadcms/config-provider';
3
4
  import { usePreferences } from '../../../utilities/Preferences';
4
5
  import withCondition from '../../withCondition';
5
6
  import Button from '../../../elements/Button';
@@ -15,6 +16,7 @@ import BlockSelector from './BlockSelector';
15
16
  import { blocks as blocksValidator } from '../../../../../fields/validations';
16
17
  import Banner from '../../../elements/Banner';
17
18
  import FieldDescription from '../../FieldDescription';
19
+ import { useOperation } from '../../../utilities/OperationProvider';
18
20
  import './index.scss';
19
21
  const baseClass = 'field-type blocks';
20
22
  const labelDefaults = {
@@ -22,19 +24,19 @@ const labelDefaults = {
22
24
  plural: 'Blocks',
23
25
  };
24
26
  const Blocks = (props) => {
25
- const { label, name, path: pathFromProps, blocks, labels = labelDefaults, fieldTypes, maxRows, minRows, required, validate = blocksValidator, permissions, admin: { readOnly, description, condition, }, } = props;
27
+ const { label, name, path: pathFromProps, blocks, labels = labelDefaults, fieldTypes, maxRows, minRows, required, validate = blocksValidator, permissions, admin: { readOnly, description, condition, className, }, } = props;
26
28
  const path = pathFromProps || name;
27
29
  const { preferencesKey } = useDocumentInfo();
28
30
  const { getPreference, setPreference } = usePreferences();
29
31
  const [rows, dispatchRows] = useReducer(reducer, []);
30
32
  const formContext = useForm();
33
+ const { user } = useAuth();
34
+ const { id } = useDocumentInfo();
35
+ const operation = useOperation();
31
36
  const { dispatchFields } = formContext;
32
- const memoizedValidate = useCallback((value) => {
33
- const validationResult = validate(value, {
34
- minRows, maxRows, labels, blocks, required,
35
- });
36
- return validationResult;
37
- }, [validate, maxRows, minRows, labels, blocks, required]);
37
+ const memoizedValidate = useCallback((value, options) => {
38
+ return validate(value, { ...options, minRows, maxRows, required });
39
+ }, [maxRows, minRows, required, validate]);
38
40
  const [disableFormData, setDisableFormData] = useState(false);
39
41
  const { showError, errorMessage, value, setValue, } = useField({
40
42
  path,
@@ -45,11 +47,11 @@ const Blocks = (props) => {
45
47
  });
46
48
  const addRow = useCallback(async (rowIndex, blockType) => {
47
49
  const block = blocks.find((potentialBlock) => potentialBlock.slug === blockType);
48
- const subFieldState = await buildStateFromSchema(block.fields);
50
+ const subFieldState = await buildStateFromSchema({ fieldSchema: block.fields, operation, id, user });
49
51
  dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path, blockType });
50
52
  dispatchRows({ type: 'ADD', rowIndex, blockType });
51
53
  setValue(value + 1);
52
- }, [path, setValue, value, blocks, dispatchFields]);
54
+ }, [path, setValue, value, blocks, dispatchFields, operation, id, user]);
53
55
  const removeRow = useCallback((rowIndex) => {
54
56
  dispatchRows({ type: 'REMOVE', rowIndex });
55
57
  dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
@@ -59,19 +61,19 @@ const Blocks = (props) => {
59
61
  dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex });
60
62
  dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path });
61
63
  }, [dispatchRows, dispatchFields, path]);
62
- const setCollapse = useCallback(async (id, collapsed) => {
64
+ const setCollapse = useCallback(async (rowID, collapsed) => {
63
65
  var _a, _b, _c;
64
- dispatchRows({ type: 'SET_COLLAPSE', id, collapsed });
66
+ dispatchRows({ type: 'SET_COLLAPSE', rowID, collapsed });
65
67
  if (preferencesKey) {
66
68
  const preferences = await getPreference(preferencesKey);
67
69
  const preferencesToSet = preferences || { fields: {} };
68
70
  let newCollapsedState = ((_b = (_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed.filter((filterID) => (rows.find((row) => row.id === filterID))))
69
71
  || [];
70
72
  if (!collapsed) {
71
- newCollapsedState = newCollapsedState.filter((existingID) => existingID !== id);
73
+ newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
72
74
  }
73
75
  else {
74
- newCollapsedState.push(id);
76
+ newCollapsedState.push(rowID);
75
77
  }
76
78
  setPreference(preferencesKey, {
77
79
  ...preferencesToSet,
@@ -118,8 +120,12 @@ const Blocks = (props) => {
118
120
  }
119
121
  }, [rows, setValue]);
120
122
  const hasMaxRows = maxRows && rows.length >= maxRows;
123
+ const classes = [
124
+ baseClass,
125
+ className,
126
+ ].filter(Boolean).join(' ');
121
127
  return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
122
- React.createElement("div", { className: baseClass },
128
+ React.createElement("div", { className: classes },
123
129
  React.createElement("div", { className: `${baseClass}__error-wrap` },
124
130
  React.createElement(Error, { showError: showError, message: errorMessage })),
125
131
  React.createElement("header", { className: `${baseClass}__header` },
@@ -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, required, validate = checkbox, label, onChange, disableFormData, admin: { readOnly, style, className, width, description, condition, } = {}, } = props;
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
- const validationResult = validate(value, { required });
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, minLength, maxLength, } = props;
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
- const validationResult = validate(value, { minLength, maxLength, required });
24
- return validationResult;
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,