payload 1.0.27 → 1.0.28

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 (97) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/admin/components/elements/Status/index.js +1 -1
  3. package/dist/admin/components/elements/ViewDescription/types.d.ts +1 -1
  4. package/dist/admin/components/elements/WhereBuilder/index.js +13 -7
  5. package/dist/admin/components/forms/field-types/Array/index.d.ts +3 -2
  6. package/dist/admin/components/forms/field-types/Array/index.js +201 -6
  7. package/dist/admin/components/forms/field-types/Blocks/index.d.ts +3 -2
  8. package/dist/admin/components/forms/field-types/Blocks/index.js +213 -6
  9. package/dist/admin/components/forms/field-types/Collapsible/index.js +2 -2
  10. package/dist/admin/components/forms/field-types/Row/index.js +2 -2
  11. package/dist/admin/components/forms/field-types/Tabs/index.js +2 -2
  12. package/dist/admin/components/forms/field-types/getFieldPath.d.ts +2 -0
  13. package/dist/admin/components/forms/field-types/getFieldPath.js +6 -0
  14. package/dist/admin/components/forms/field-types/index.d.ts +23 -23
  15. package/dist/admin/components/utilities/RenderCustomComponent/types.d.ts +2 -2
  16. package/dist/admin/components/views/collections/List/Cell/field-types/Relationship/index.js +1 -1
  17. package/dist/auth/operations/local/forgotPassword.js +3 -6
  18. package/dist/auth/operations/local/login.js +6 -9
  19. package/dist/auth/operations/local/resetPassword.js +4 -7
  20. package/dist/auth/operations/local/unlock.js +4 -7
  21. package/dist/collections/config/types.d.ts +2 -2
  22. package/dist/collections/dataloader.js +16 -8
  23. package/dist/collections/operations/local/create.d.ts +2 -2
  24. package/dist/collections/operations/local/create.js +11 -13
  25. package/dist/collections/operations/local/find.js +6 -10
  26. package/dist/collections/operations/local/findByID.js +6 -10
  27. package/dist/collections/operations/local/findVersionByID.js +6 -9
  28. package/dist/config/types.d.ts +13 -13
  29. package/dist/fields/config/sanitize.js +3 -3
  30. package/dist/fields/config/schema.js +3 -3
  31. package/dist/fields/config/types.d.ts +9 -9
  32. package/dist/fields/validations.js +43 -1
  33. package/dist/globals/config/types.d.ts +1 -1
  34. package/dist/utilities/getIDType.d.ts +2 -0
  35. package/dist/utilities/getIDType.js +11 -0
  36. package/dist/utilities/isValidID.d.ts +1 -0
  37. package/dist/utilities/isValidID.js +16 -0
  38. package/docs/access-control/collections.mdx +21 -12
  39. package/docs/access-control/fields.mdx +5 -3
  40. package/docs/access-control/globals.mdx +8 -4
  41. package/docs/access-control/overview.mdx +1 -1
  42. package/docs/admin/components.mdx +29 -25
  43. package/docs/admin/customizing-css.mdx +2 -2
  44. package/docs/admin/overview.mdx +2 -2
  45. package/docs/admin/webpack.mdx +8 -7
  46. package/docs/authentication/config.mdx +14 -9
  47. package/docs/authentication/operations.mdx +22 -22
  48. package/docs/authentication/overview.mdx +8 -6
  49. package/docs/authentication/using-middleware.mdx +1 -1
  50. package/docs/configuration/collections.mdx +11 -7
  51. package/docs/configuration/globals.mdx +9 -5
  52. package/docs/configuration/localization.mdx +33 -31
  53. package/docs/configuration/overview.mdx +4 -7
  54. package/docs/email/overview.mdx +11 -7
  55. package/docs/fields/array.mdx +6 -5
  56. package/docs/fields/blocks.mdx +6 -4
  57. package/docs/fields/checkbox.mdx +6 -5
  58. package/docs/fields/code.mdx +6 -5
  59. package/docs/fields/collapsible.mdx +6 -5
  60. package/docs/fields/date.mdx +6 -5
  61. package/docs/fields/email.mdx +6 -5
  62. package/docs/fields/group.mdx +6 -5
  63. package/docs/fields/number.mdx +6 -5
  64. package/docs/fields/overview.mdx +40 -38
  65. package/docs/fields/point.mdx +6 -4
  66. package/docs/fields/radio.mdx +5 -3
  67. package/docs/fields/relationship.mdx +21 -21
  68. package/docs/fields/rich-text.mdx +9 -7
  69. package/docs/fields/row.mdx +5 -3
  70. package/docs/fields/select.mdx +4 -3
  71. package/docs/fields/tabs.mdx +5 -3
  72. package/docs/fields/text.mdx +5 -3
  73. package/docs/fields/textarea.mdx +5 -3
  74. package/docs/fields/ui.mdx +5 -3
  75. package/docs/fields/upload.mdx +5 -3
  76. package/docs/getting-started/concepts.mdx +1 -1
  77. package/docs/graphql/extending.mdx +1 -1
  78. package/docs/graphql/overview.mdx +8 -4
  79. package/docs/hooks/collections.mdx +62 -36
  80. package/docs/hooks/fields.mdx +5 -3
  81. package/docs/hooks/globals.mdx +25 -17
  82. package/docs/local-api/overview.mdx +27 -4
  83. package/docs/plugins/overview.mdx +3 -4
  84. package/docs/production/deployment.mdx +1 -1
  85. package/docs/queries/overview.mdx +4 -2
  86. package/docs/queries/pagination.mdx +1 -1
  87. package/docs/rest-api/overview.mdx +4 -2
  88. package/docs/upload/overview.mdx +35 -29
  89. package/docs/versions/autosave.mdx +4 -2
  90. package/docs/versions/drafts.mdx +8 -4
  91. package/docs/versions/overview.mdx +1 -1
  92. package/package.json +1 -1
  93. package/types.d.ts +21 -0
  94. package/dist/admin/components/forms/field-types/Array/Array.d.ts +0 -5
  95. package/dist/admin/components/forms/field-types/Array/Array.js +0 -201
  96. package/dist/admin/components/forms/field-types/Blocks/Blocks.d.ts +0 -5
  97. package/dist/admin/components/forms/field-types/Blocks/Blocks.js +0 -213
package/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [1.0.28](https://github.com/payloadcms/payload/compare/v1.0.27...v1.0.28) (2022-08-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * incorrect field paths when nesting unnamed fields ([#1011](https://github.com/payloadcms/payload/issues/1011)) ([50b0303](https://github.com/payloadcms/payload/commit/50b0303ab39f0d0500c5e4116df95f02d1d7fff3)), closes [#976](https://github.com/payloadcms/payload/issues/976)
7
+ * relationship cell loading ([#1021](https://github.com/payloadcms/payload/issues/1021)) ([6a3cfce](https://github.com/payloadcms/payload/commit/6a3cfced9a6e0ef75b398ec663f908c725b10d1a))
8
+ * remove lazy loading of array and blocks ([4900fa7](https://github.com/payloadcms/payload/commit/4900fa799ffbeb70e689622b269dc04a67978552))
9
+ * require properties in blocks and arrays fields ([#1020](https://github.com/payloadcms/payload/issues/1020)) ([6bc6e7b](https://github.com/payloadcms/payload/commit/6bc6e7bb616bd9f28f2464d3e55e7a1d19a8e7f8))
10
+ * unpublish item will not crash the UI anymore ([#1016](https://github.com/payloadcms/payload/issues/1016)) ([0586d7a](https://github.com/payloadcms/payload/commit/0586d7aa7d0938df25492487aa073c2aa366e1e4))
11
+
12
+
13
+ ### Features
14
+
15
+ * export more fields config types and validation type ([#989](https://github.com/payloadcms/payload/issues/989)) ([25f5d68](https://github.com/payloadcms/payload/commit/25f5d68b74b081c060ddf6f0405c9211f5da6b54))
16
+ * types custom components to allow any props ([#1013](https://github.com/payloadcms/payload/issues/1013)) ([3736755](https://github.com/payloadcms/payload/commit/3736755a12cf5bbaaa916a5c0363026318a60823))
17
+ * validate relationship and upload ids ([#1004](https://github.com/payloadcms/payload/issues/1004)) ([d727fc8](https://github.com/payloadcms/payload/commit/d727fc8e2467e3f438ea6b1d2031e0657bffd183))
18
+
1
19
  ## [1.0.27](https://github.com/payloadcms/payload/compare/v1.0.26...v1.0.27) (2022-08-18)
2
20
 
3
21
 
@@ -45,7 +45,7 @@ const Status = () => {
45
45
  }
46
46
  if (collection) {
47
47
  url = `${serverURL}${api}/${collection.slug}/${id}?depth=0&locale=${locale}&fallback-locale=null`;
48
- method = 'PATCH';
48
+ method = 'patch';
49
49
  }
50
50
  if (global) {
51
51
  url = `${serverURL}${api}/globals/${global.slug}?depth=0&locale=${locale}&fallback-locale=null`;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  export declare type DescriptionFunction = () => string;
3
- export declare type DescriptionComponent = React.ComponentType;
3
+ export declare type DescriptionComponent = React.ComponentType<any>;
4
4
  declare type Description = string | DescriptionFunction | DescriptionComponent;
5
5
  export declare type Props = {
6
6
  description?: Description;
@@ -48,13 +48,19 @@ const WhereBuilder = (props) => {
48
48
  if (handleChange)
49
49
  handleChange(newWhereQuery);
50
50
  if (modifySearchQuery) {
51
- history.replace({
52
- search: queryString.stringify({
53
- ...currentParams,
54
- page: 1,
55
- where: newWhereQuery,
56
- }, { addQueryPrefix: true }),
57
- });
51
+ const newParams = {
52
+ ...currentParams,
53
+ page: currentParams.page,
54
+ where: newWhereQuery,
55
+ };
56
+ if (newParams.page)
57
+ delete newParams.page;
58
+ const newSearchQuery = queryString.stringify(newParams);
59
+ if (newSearchQuery) {
60
+ history.replace({
61
+ search: `?${newSearchQuery}&page=1`,
62
+ });
63
+ }
58
64
  }
59
65
  }, 500, [conditions, modifySearchQuery, handleChange]);
60
66
  return (React.createElement("div", { className: baseClass },
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  import { Props } from './types';
3
- declare const ArrayFieldType: React.FC<Props>;
4
- export default ArrayFieldType;
3
+ import './index.scss';
4
+ declare const _default: React.FC<Props>;
5
+ export default _default;
@@ -1,6 +1,201 @@
1
- import React, { Suspense, lazy } from 'react';
2
- import Loading from '../../../elements/Loading';
3
- const ArrayField = lazy(() => import('./Array'));
4
- const ArrayFieldType = (props) => (React.createElement(Suspense, { fallback: React.createElement(Loading, null) },
5
- React.createElement(ArrayField, { ...props })));
6
- export default ArrayFieldType;
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
+ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '../../../utilities/Auth';
4
+ import withCondition from '../../withCondition';
5
+ import Button from '../../../elements/Button';
6
+ import reducer from '../rowReducer';
7
+ import { useForm } from '../../Form/context';
8
+ import buildStateFromSchema from '../../Form/buildStateFromSchema';
9
+ import useField from '../../useField';
10
+ import { useLocale } from '../../../utilities/Locale';
11
+ import Error from '../../Error';
12
+ import { array } from '../../../../../fields/validations';
13
+ import Banner from '../../../elements/Banner';
14
+ import FieldDescription from '../../FieldDescription';
15
+ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
16
+ import { useOperation } from '../../../utilities/OperationProvider';
17
+ import { Collapsible } from '../../../elements/Collapsible';
18
+ import RenderFields from '../../RenderFields';
19
+ import { fieldAffectsData } from '../../../../../fields/config/types';
20
+ import { usePreferences } from '../../../utilities/Preferences';
21
+ import { ArrayAction } from '../../../elements/ArrayAction';
22
+ import { scrollToID } from '../../../../utilities/scrollToID';
23
+ import HiddenInput from '../HiddenInput';
24
+ import './index.scss';
25
+ const baseClass = 'array-field';
26
+ const ArrayFieldType = (props) => {
27
+ var _a, _b;
28
+ const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, className, }, } = props;
29
+ const path = pathFromProps || name;
30
+ // Handle labeling for Arrays, Global Arrays, and Blocks
31
+ const getLabels = (p) => {
32
+ if (p === null || p === void 0 ? void 0 : p.labels)
33
+ return p.labels;
34
+ if (p === null || p === void 0 ? void 0 : p.label)
35
+ return { singular: p.label, plural: undefined };
36
+ return { singular: 'Row', plural: 'Rows' };
37
+ };
38
+ const labels = getLabels(props);
39
+ // eslint-disable-next-line react/destructuring-assignment
40
+ 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;
41
+ const { preferencesKey } = useDocumentInfo();
42
+ const { getPreference } = usePreferences();
43
+ const { setPreference } = usePreferences();
44
+ const [rows, dispatchRows] = useReducer(reducer, undefined);
45
+ const formContext = useForm();
46
+ const { user } = useAuth();
47
+ const { id } = useDocumentInfo();
48
+ const locale = useLocale();
49
+ const operation = useOperation();
50
+ const { dispatchFields } = formContext;
51
+ const memoizedValidate = useCallback((value, options) => {
52
+ return validate(value, { ...options, minRows, maxRows, required });
53
+ }, [maxRows, minRows, required, validate]);
54
+ const [disableFormData, setDisableFormData] = useState(false);
55
+ const { showError, errorMessage, value, setValue, } = useField({
56
+ path,
57
+ validate: memoizedValidate,
58
+ disableFormData,
59
+ condition,
60
+ });
61
+ const addRow = useCallback(async (rowIndex) => {
62
+ const subFieldState = await buildStateFromSchema({ fieldSchema: fields, operation, id, user, locale });
63
+ dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path });
64
+ dispatchRows({ type: 'ADD', rowIndex });
65
+ setValue(value + 1);
66
+ setTimeout(() => {
67
+ scrollToID(`${path}-row-${rowIndex + 1}`);
68
+ }, 0);
69
+ }, [dispatchRows, dispatchFields, fields, path, setValue, value, operation, id, user, locale]);
70
+ const duplicateRow = useCallback(async (rowIndex) => {
71
+ dispatchFields({ type: 'DUPLICATE_ROW', rowIndex, path });
72
+ dispatchRows({ type: 'ADD', rowIndex });
73
+ setValue(value + 1);
74
+ setTimeout(() => {
75
+ scrollToID(`${path}-row-${rowIndex + 1}`);
76
+ }, 0);
77
+ }, [dispatchRows, dispatchFields, path, setValue, value]);
78
+ const removeRow = useCallback((rowIndex) => {
79
+ dispatchRows({ type: 'REMOVE', rowIndex });
80
+ dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
81
+ setValue(value - 1);
82
+ }, [dispatchRows, dispatchFields, path, value, setValue]);
83
+ const moveRow = useCallback((moveFromIndex, moveToIndex) => {
84
+ dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex });
85
+ dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path });
86
+ }, [dispatchRows, dispatchFields, path]);
87
+ const onDragEnd = useCallback((result) => {
88
+ if (!result.destination)
89
+ return;
90
+ const sourceIndex = result.source.index;
91
+ const destinationIndex = result.destination.index;
92
+ moveRow(sourceIndex, destinationIndex);
93
+ }, [moveRow]);
94
+ const setCollapse = useCallback(async (rowID, collapsed) => {
95
+ var _a, _b, _c;
96
+ dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
97
+ if (preferencesKey) {
98
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
99
+ 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))))
100
+ || [];
101
+ if (!collapsed) {
102
+ newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
103
+ }
104
+ else {
105
+ newCollapsedState.push(rowID);
106
+ }
107
+ setPreference(preferencesKey, {
108
+ ...preferencesToSet,
109
+ fields: {
110
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
111
+ [path]: {
112
+ ...(_c = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _c === void 0 ? void 0 : _c[path],
113
+ collapsed: newCollapsedState,
114
+ },
115
+ },
116
+ });
117
+ }
118
+ }, [preferencesKey, path, setPreference, rows, getPreference]);
119
+ const toggleCollapseAll = useCallback(async (collapse) => {
120
+ var _a;
121
+ dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
122
+ if (preferencesKey) {
123
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
124
+ setPreference(preferencesKey, {
125
+ ...preferencesToSet,
126
+ fields: {
127
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
128
+ [path]: {
129
+ ...(_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path],
130
+ collapsed: collapse ? rows.map(({ id: rowID }) => rowID) : [],
131
+ },
132
+ },
133
+ });
134
+ }
135
+ }, [path, getPreference, preferencesKey, rows, setPreference]);
136
+ useEffect(() => {
137
+ const initializeRowState = async () => {
138
+ var _a, _b;
139
+ const data = formContext.getDataByPath(path);
140
+ const preferences = await getPreference(preferencesKey) || { fields: {} };
141
+ dispatchRows({ type: 'SET_ALL', data: data || [], collapsedState: (_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed });
142
+ };
143
+ initializeRowState();
144
+ }, [formContext, path, getPreference, preferencesKey]);
145
+ useEffect(() => {
146
+ setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
147
+ if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
148
+ setDisableFormData(false);
149
+ }
150
+ else {
151
+ setDisableFormData(true);
152
+ }
153
+ }, [rows, setValue]);
154
+ const hasMaxRows = maxRows && (rows === null || rows === void 0 ? void 0 : rows.length) >= maxRows;
155
+ const classes = [
156
+ 'field-type',
157
+ baseClass,
158
+ className,
159
+ ].filter(Boolean).join(' ');
160
+ if (!rows)
161
+ return null;
162
+ return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
163
+ React.createElement("div", { id: `field-${path.replace(/\./gi, '__')}`, className: classes },
164
+ React.createElement("div", { className: `${baseClass}__error-wrap` },
165
+ React.createElement(Error, { showError: showError, message: errorMessage })),
166
+ React.createElement("header", { className: `${baseClass}__header` },
167
+ React.createElement("div", { className: `${baseClass}__header-wrap` },
168
+ React.createElement("h3", null, label),
169
+ React.createElement("ul", { className: `${baseClass}__header-actions` },
170
+ React.createElement("li", null,
171
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(true), className: `${baseClass}__header-action` }, "Collapse All")),
172
+ React.createElement("li", null,
173
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(false), className: `${baseClass}__header-action` }, "Show All")))),
174
+ React.createElement(FieldDescription, { value: value, description: description })),
175
+ React.createElement(Droppable, { droppableId: "array-drop" }, (provided) => (React.createElement("div", { ref: provided.innerRef, ...provided.droppableProps },
176
+ rows.length > 0 && rows.map((row, i) => {
177
+ const rowNumber = i + 1;
178
+ return (React.createElement(Draggable, { key: row.id, draggableId: row.id, index: i, isDragDisabled: readOnly }, (providedDrag) => (React.createElement("div", { id: `${path}-row-${i}`, ref: providedDrag.innerRef, ...providedDrag.draggableProps },
179
+ React.createElement(Collapsible, { collapsed: row.collapsed, onToggle: (collapsed) => setCollapse(row.id, collapsed), className: `${baseClass}__row`, key: row.id, dragHandleProps: providedDrag.dragHandleProps, header: `${labels.singular} ${rowNumber >= 10 ? rowNumber : `0${rowNumber}`}`, actions: !readOnly ? (React.createElement(ArrayAction, { rowCount: rows.length, duplicateRow: duplicateRow, addRow: addRow, moveRow: moveRow, removeRow: removeRow, index: i })) : undefined },
180
+ React.createElement(HiddenInput, { name: `${path}.${i}.id`, value: row.id }),
181
+ React.createElement(RenderFields, { className: `${baseClass}__fields`, forceRender: true, readOnly: readOnly, fieldTypes: fieldTypes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: fields.map((field) => ({
182
+ ...field,
183
+ path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
184
+ })) }))))));
185
+ }),
186
+ (rows.length < minRows || (required && rows.length === 0)) && (React.createElement(Banner, { type: "error" },
187
+ "This field requires at least",
188
+ ' ',
189
+ minRows
190
+ ? `${minRows} ${labels.plural}`
191
+ : `1 ${labels.singular}`)),
192
+ (rows.length === 0 && readOnly) && (React.createElement(Banner, null,
193
+ "This field has no",
194
+ ' ',
195
+ labels.plural,
196
+ ".")),
197
+ provided.placeholder))),
198
+ (!readOnly && !hasMaxRows) && (React.createElement("div", { className: `${baseClass}__add-button-wrap` },
199
+ React.createElement(Button, { onClick: () => addRow(value), buttonStyle: "icon-label", icon: "plus", iconStyle: "with-border", iconPosition: "left" }, `Add ${labels.singular}`))))));
200
+ };
201
+ export default withCondition(ArrayFieldType);
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
2
  import { Props } from './types';
3
- declare const BlocksField: React.FC<Props>;
4
- export default BlocksField;
3
+ import './index.scss';
4
+ declare const _default: React.FC<Props>;
5
+ export default _default;
@@ -1,6 +1,213 @@
1
- import React, { Suspense, lazy } from 'react';
2
- import Loading from '../../../elements/Loading';
3
- const Blocks = lazy(() => import('./Blocks'));
4
- const BlocksField = (props) => (React.createElement(Suspense, { fallback: React.createElement(Loading, null) },
5
- React.createElement(Blocks, { ...props })));
6
- export default BlocksField;
1
+ import React, { useCallback, useEffect, useReducer, useState } from 'react';
2
+ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
3
+ import { useAuth } from '../../../utilities/Auth';
4
+ import { usePreferences } from '../../../utilities/Preferences';
5
+ import { useLocale } from '../../../utilities/Locale';
6
+ import withCondition from '../../withCondition';
7
+ import Button from '../../../elements/Button';
8
+ import reducer from '../rowReducer';
9
+ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
10
+ import { useForm } from '../../Form/context';
11
+ import buildStateFromSchema from '../../Form/buildStateFromSchema';
12
+ import Error from '../../Error';
13
+ import useField from '../../useField';
14
+ import Popup from '../../../elements/Popup';
15
+ import BlockSelector from './BlockSelector';
16
+ import { blocks as blocksValidator } from '../../../../../fields/validations';
17
+ import Banner from '../../../elements/Banner';
18
+ import FieldDescription from '../../FieldDescription';
19
+ import { useOperation } from '../../../utilities/OperationProvider';
20
+ import { Collapsible } from '../../../elements/Collapsible';
21
+ import { ArrayAction } from '../../../elements/ArrayAction';
22
+ import RenderFields from '../../RenderFields';
23
+ import { fieldAffectsData } from '../../../../../fields/config/types';
24
+ import SectionTitle from './SectionTitle';
25
+ import Pill from '../../../elements/Pill';
26
+ import { scrollToID } from '../../../../utilities/scrollToID';
27
+ import HiddenInput from '../HiddenInput';
28
+ import './index.scss';
29
+ const baseClass = 'blocks-field';
30
+ const labelDefaults = {
31
+ singular: 'Block',
32
+ plural: 'Blocks',
33
+ };
34
+ const Index = (props) => {
35
+ const { label, name, path: pathFromProps, blocks, labels = labelDefaults, fieldTypes, maxRows, minRows, required, validate = blocksValidator, permissions, admin: { readOnly, description, condition, className, }, } = props;
36
+ const path = pathFromProps || name;
37
+ const { preferencesKey } = useDocumentInfo();
38
+ const { getPreference } = usePreferences();
39
+ const { setPreference } = usePreferences();
40
+ const [rows, dispatchRows] = useReducer(reducer, undefined);
41
+ const formContext = useForm();
42
+ const { user } = useAuth();
43
+ const { id } = useDocumentInfo();
44
+ const locale = useLocale();
45
+ const operation = useOperation();
46
+ const { dispatchFields } = formContext;
47
+ const memoizedValidate = useCallback((value, options) => {
48
+ return validate(value, { ...options, minRows, maxRows, required });
49
+ }, [maxRows, minRows, required, validate]);
50
+ const [disableFormData, setDisableFormData] = useState(false);
51
+ const [selectorIndexOpen, setSelectorIndexOpen] = useState();
52
+ const { showError, errorMessage, value, setValue, } = useField({
53
+ path,
54
+ validate: memoizedValidate,
55
+ disableFormData,
56
+ condition,
57
+ });
58
+ const onAddPopupToggle = useCallback((open) => {
59
+ if (!open) {
60
+ setSelectorIndexOpen(undefined);
61
+ }
62
+ }, []);
63
+ const addRow = useCallback(async (rowIndex, blockType) => {
64
+ const block = blocks.find((potentialBlock) => potentialBlock.slug === blockType);
65
+ const subFieldState = await buildStateFromSchema({ fieldSchema: block.fields, operation, id, user, locale });
66
+ dispatchFields({ type: 'ADD_ROW', rowIndex, subFieldState, path, blockType });
67
+ dispatchRows({ type: 'ADD', rowIndex, blockType });
68
+ setValue(value + 1);
69
+ setTimeout(() => {
70
+ scrollToID(`${path}-row-${rowIndex + 1}`);
71
+ }, 0);
72
+ }, [path, setValue, value, blocks, dispatchFields, operation, id, user, locale]);
73
+ const duplicateRow = useCallback(async (rowIndex, blockType) => {
74
+ dispatchFields({ type: 'DUPLICATE_ROW', rowIndex, path });
75
+ dispatchRows({ type: 'ADD', rowIndex, blockType });
76
+ setValue(value + 1);
77
+ setTimeout(() => {
78
+ scrollToID(`${path}-row-${rowIndex + 1}`);
79
+ }, 0);
80
+ }, [dispatchRows, dispatchFields, path, setValue, value]);
81
+ const removeRow = useCallback((rowIndex) => {
82
+ dispatchRows({ type: 'REMOVE', rowIndex });
83
+ dispatchFields({ type: 'REMOVE_ROW', rowIndex, path });
84
+ setValue(value - 1);
85
+ }, [path, setValue, value, dispatchFields]);
86
+ const moveRow = useCallback((moveFromIndex, moveToIndex) => {
87
+ dispatchRows({ type: 'MOVE', moveFromIndex, moveToIndex });
88
+ dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path });
89
+ }, [dispatchRows, dispatchFields, path]);
90
+ const onDragEnd = useCallback((result) => {
91
+ if (!result.destination)
92
+ return;
93
+ const sourceIndex = result.source.index;
94
+ const destinationIndex = result.destination.index;
95
+ moveRow(sourceIndex, destinationIndex);
96
+ }, [moveRow]);
97
+ const setCollapse = useCallback(async (rowID, collapsed) => {
98
+ var _a, _b, _c;
99
+ dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
100
+ if (preferencesKey) {
101
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
102
+ 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))))
103
+ || [];
104
+ if (!collapsed) {
105
+ newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
106
+ }
107
+ else {
108
+ newCollapsedState.push(rowID);
109
+ }
110
+ setPreference(preferencesKey, {
111
+ ...preferencesToSet,
112
+ fields: {
113
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
114
+ [path]: {
115
+ ...(_c = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _c === void 0 ? void 0 : _c[path],
116
+ collapsed: newCollapsedState,
117
+ },
118
+ },
119
+ });
120
+ }
121
+ }, [preferencesKey, getPreference, path, setPreference, rows]);
122
+ const toggleCollapseAll = useCallback(async (collapse) => {
123
+ var _a;
124
+ dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
125
+ if (preferencesKey) {
126
+ const preferencesToSet = await getPreference(preferencesKey) || { fields: {} };
127
+ setPreference(preferencesKey, {
128
+ ...preferencesToSet,
129
+ fields: {
130
+ ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
131
+ [path]: {
132
+ ...(_a = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _a === void 0 ? void 0 : _a[path],
133
+ collapsed: collapse ? rows.map(({ id: rowID }) => rowID) : [],
134
+ },
135
+ },
136
+ });
137
+ }
138
+ }, [getPreference, path, preferencesKey, rows, setPreference]);
139
+ // Set row count on mount and when form context is reset
140
+ useEffect(() => {
141
+ const initializeRowState = async () => {
142
+ var _a, _b;
143
+ const data = formContext.getDataByPath(path);
144
+ const preferences = await getPreference(preferencesKey) || { fields: {} };
145
+ dispatchRows({ type: 'SET_ALL', data: data || [], collapsedState: (_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[path]) === null || _b === void 0 ? void 0 : _b.collapsed });
146
+ };
147
+ initializeRowState();
148
+ }, [formContext, path, getPreference, preferencesKey]);
149
+ useEffect(() => {
150
+ setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
151
+ if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
152
+ setDisableFormData(false);
153
+ }
154
+ else {
155
+ setDisableFormData(true);
156
+ }
157
+ }, [rows, setValue]);
158
+ const hasMaxRows = maxRows && (rows === null || rows === void 0 ? void 0 : rows.length) >= maxRows;
159
+ const classes = [
160
+ 'field-type',
161
+ baseClass,
162
+ className,
163
+ ].filter(Boolean).join(' ');
164
+ if (!rows)
165
+ return null;
166
+ return (React.createElement(DragDropContext, { onDragEnd: onDragEnd },
167
+ React.createElement("div", { id: `field-${path.replace(/\./gi, '__')}`, className: classes },
168
+ React.createElement("div", { className: `${baseClass}__error-wrap` },
169
+ React.createElement(Error, { showError: showError, message: errorMessage })),
170
+ React.createElement("header", { className: `${baseClass}__header` },
171
+ React.createElement("div", { className: `${baseClass}__header-wrap` },
172
+ React.createElement("h3", null, label),
173
+ React.createElement("ul", { className: `${baseClass}__header-actions` },
174
+ React.createElement("li", null,
175
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(true), className: `${baseClass}__header-action` }, "Collapse All")),
176
+ React.createElement("li", null,
177
+ React.createElement("button", { type: "button", onClick: () => toggleCollapseAll(false), className: `${baseClass}__header-action` }, "Show All")))),
178
+ React.createElement(FieldDescription, { value: value, description: description })),
179
+ React.createElement(Droppable, { droppableId: "blocks-drop", isDropDisabled: readOnly }, (provided) => (React.createElement("div", { ref: provided.innerRef, ...provided.droppableProps },
180
+ rows.length > 0 && rows.map((row, i) => {
181
+ const { blockType } = row;
182
+ const blockToRender = blocks.find((block) => block.slug === blockType);
183
+ const rowNumber = i + 1;
184
+ if (blockToRender) {
185
+ return (React.createElement(Draggable, { key: row.id, draggableId: row.id, index: i, isDragDisabled: readOnly }, (providedDrag) => (React.createElement("div", { id: `${path}-row-${i}`, ref: providedDrag.innerRef, ...providedDrag.draggableProps },
186
+ React.createElement(Collapsible, { collapsed: row.collapsed, onToggle: (collapsed) => setCollapse(row.id, collapsed), className: `${baseClass}__row`, key: row.id, dragHandleProps: providedDrag.dragHandleProps, header: (React.createElement("div", { className: `${baseClass}__block-header` },
187
+ React.createElement("span", { className: `${baseClass}__block-number` }, rowNumber >= 10 ? rowNumber : `0${rowNumber}`),
188
+ React.createElement(Pill, { pillStyle: "white", className: `${baseClass}__block-pill ${baseClass}__block-pill-${blockType}` }, blockToRender.labels.singular),
189
+ React.createElement(SectionTitle, { path: `${path}.${i}.blockName`, readOnly: readOnly }))), actions: !readOnly ? (React.createElement(React.Fragment, null,
190
+ React.createElement(Popup, { key: `${blockType}-${i}`, forceOpen: selectorIndexOpen === i, onToggleOpen: onAddPopupToggle, buttonType: "none", size: "large", horizontalAlign: "right", render: ({ close }) => (React.createElement(BlockSelector, { blocks: blocks, addRow: addRow, addRowIndex: i, close: close })) }),
191
+ React.createElement(ArrayAction, { rowCount: rows.length, duplicateRow: () => duplicateRow(i, blockType), addRow: () => setSelectorIndexOpen(i), moveRow: moveRow, removeRow: removeRow, index: i }))) : undefined },
192
+ React.createElement(HiddenInput, { name: `${path}.${i}.id`, value: row.id }),
193
+ React.createElement(RenderFields, { className: `${baseClass}__fields`, forceRender: true, readOnly: readOnly, fieldTypes: fieldTypes, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldSchema: blockToRender.fields.map((field) => ({
194
+ ...field,
195
+ path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
196
+ })) }))))));
197
+ }
198
+ return null;
199
+ }),
200
+ (rows.length < minRows || (required && rows.length === 0)) && (React.createElement(Banner, { type: "error" },
201
+ "This field requires at least",
202
+ ' ',
203
+ `${minRows || 1} ${minRows === 1 || typeof minRows === 'undefined' ? labels.singular : labels.plural}`)),
204
+ (rows.length === 0 && readOnly) && (React.createElement(Banner, null,
205
+ "This field has no",
206
+ ' ',
207
+ labels.plural,
208
+ ".")),
209
+ provided.placeholder))),
210
+ (!readOnly && !hasMaxRows) && (React.createElement("div", { className: `${baseClass}__add-button-wrap` },
211
+ React.createElement(Popup, { buttonType: "custom", size: "large", horizontalAlign: "left", button: (React.createElement(Button, { buttonStyle: "icon-label", icon: "plus", iconPosition: "left", iconStyle: "with-border" }, `Add ${labels.singular}`)), render: ({ close }) => (React.createElement(BlockSelector, { blocks: blocks, addRow: addRow, addRowIndex: value, close: close })) }))))));
212
+ };
213
+ export default withCondition(Index);
@@ -1,12 +1,12 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
5
4
  import { Collapsible } from '../../../elements/Collapsible';
6
5
  import toKebabCase from '../../../../../utilities/toKebabCase';
7
6
  import { usePreferences } from '../../../utilities/Preferences';
8
7
  import { useDocumentInfo } from '../../../utilities/DocumentInfo';
9
8
  import FieldDescription from '../../FieldDescription';
9
+ import { getFieldPath } from '../getFieldPath';
10
10
  import './index.scss';
11
11
  const baseClass = 'collapsible-field';
12
12
  const CollapsibleField = (props) => {
@@ -47,7 +47,7 @@ const CollapsibleField = (props) => {
47
47
  ].filter(Boolean).join(' '), header: React.createElement("div", { className: `${baseClass}__label` }, label), onToggle: onToggle },
48
48
  React.createElement(RenderFields, { forceRender: true, readOnly: readOnly, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: fields.map((field) => ({
49
49
  ...field,
50
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
50
+ path: getFieldPath(path, field),
51
51
  })) })),
52
52
  React.createElement(FieldDescription, { description: description })));
53
53
  };
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
4
+ import { getFieldPath } from '../getFieldPath';
5
5
  import './index.scss';
6
6
  const Row = (props) => {
7
7
  const { fields, fieldTypes, path, permissions, admin: { readOnly, className, }, } = props;
@@ -12,7 +12,7 @@ const Row = (props) => {
12
12
  ].filter(Boolean).join(' ');
13
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) => ({
14
14
  ...field,
15
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
15
+ path: getFieldPath(path, field),
16
16
  })) }));
17
17
  };
18
18
  export default withCondition(Row);
@@ -1,11 +1,11 @@
1
1
  import React, { useState } from 'react';
2
2
  import RenderFields from '../../RenderFields';
3
3
  import withCondition from '../../withCondition';
4
- import { fieldAffectsData } from '../../../../../fields/config/types';
5
4
  import FieldDescription from '../../FieldDescription';
6
5
  import toKebabCase from '../../../../../utilities/toKebabCase';
7
6
  import { useCollapsible } from '../../../elements/Collapsible/provider';
8
7
  import { TabsProvider } from './provider';
8
+ import { getFieldPath } from '../getFieldPath';
9
9
  import './index.scss';
10
10
  const baseClass = 'tabs-field';
11
11
  const TabsField = (props) => {
@@ -33,7 +33,7 @@ const TabsField = (props) => {
33
33
  React.createElement(FieldDescription, { className: `${baseClass}__description`, description: activeTab.description }),
34
34
  React.createElement(RenderFields, { key: activeTab.label, forceRender: true, readOnly: readOnly, permissions: permissions === null || permissions === void 0 ? void 0 : permissions.fields, fieldTypes: fieldTypes, fieldSchema: activeTab.fields.map((field) => ({
35
35
  ...field,
36
- path: `${path ? `${path}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
36
+ path: getFieldPath(path, field),
37
37
  })) })))))));
38
38
  };
39
39
  export default withCondition(TabsField);
@@ -0,0 +1,2 @@
1
+ import { Field } from '../../../../fields/config/types';
2
+ export declare const getFieldPath: (path: string, field: Field) => string;
@@ -0,0 +1,6 @@
1
+ import { fieldAffectsData } from '../../../../fields/config/types';
2
+ export const getFieldPath = (path, field) => {
3
+ // prevents duplicate . on nesting non-named fields
4
+ const dot = path && path.slice(-1) === '.' ? '' : '.';
5
+ return `${path ? `${path}${dot}` : ''}${fieldAffectsData(field) ? field.name : ''}`;
6
+ };