payload 1.0.36 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/admin/components/elements/ListControls/index.js +3 -2
  2. package/dist/admin/components/elements/Nav/index.js +43 -24
  3. package/dist/admin/components/elements/Nav/index.scss +22 -26
  4. package/dist/admin/components/elements/NavGroup/index.d.ts +8 -0
  5. package/dist/admin/components/elements/NavGroup/index.js +52 -0
  6. package/dist/admin/components/elements/NavGroup/index.scss +53 -0
  7. package/dist/admin/components/elements/SearchFilter/index.js +45 -16
  8. package/dist/admin/components/elements/SearchFilter/types.d.ts +2 -0
  9. package/dist/admin/components/elements/WhereBuilder/index.js +14 -1
  10. package/dist/admin/components/forms/Form/buildStateFromSchema/addFieldStatePromise.js +3 -3
  11. package/dist/admin/components/forms/field-types/Array/index.js +14 -9
  12. package/dist/admin/components/forms/field-types/Blocks/index.js +12 -7
  13. package/dist/admin/components/forms/field-types/Collapsible/index.js +7 -7
  14. package/dist/admin/components/forms/field-types/Tabs/index.js +4 -4
  15. package/dist/admin/components/forms/field-types/rowReducer.d.ts +1 -0
  16. package/dist/admin/components/forms/field-types/rowReducer.js +2 -2
  17. package/dist/admin/components/graphics/Account/Gravatar.d.ts +3 -0
  18. package/dist/admin/components/graphics/Account/Gravatar.js +15 -0
  19. package/dist/admin/components/graphics/Account/index.d.ts +2 -2
  20. package/dist/admin/components/graphics/Account/index.js +24 -1
  21. package/dist/admin/components/views/Dashboard/Default.js +44 -12
  22. package/dist/admin/components/views/Dashboard/index.scss +1 -1
  23. package/dist/admin/components/views/collections/List/RelationshipProvider/index.js +1 -1
  24. package/dist/admin/components/views/collections/List/getInitialColumns.js +2 -2
  25. package/dist/admin/utilities/groupNavItems.d.ts +19 -0
  26. package/dist/admin/utilities/groupNavItems.js +36 -0
  27. package/dist/bin/generateTypes.js +20 -4
  28. package/dist/collections/config/schema.js +18 -2
  29. package/dist/collections/config/types.d.ts +9 -0
  30. package/dist/collections/operations/create.js +3 -1
  31. package/dist/collections/operations/local/create.d.ts +2 -2
  32. package/dist/collections/operations/local/create.js +3 -3
  33. package/dist/collections/operations/local/update.js +2 -2
  34. package/dist/collections/operations/restoreVersion.js +11 -1
  35. package/dist/collections/operations/update.js +3 -1
  36. package/dist/config/defaults.js +2 -1
  37. package/dist/config/schema.js +3 -1
  38. package/dist/config/types.d.ts +1 -0
  39. package/dist/fields/config/schema.js +11 -6
  40. package/dist/fields/config/types.d.ts +42 -9
  41. package/dist/fields/config/types.js +10 -2
  42. package/dist/fields/hooks/afterChange/index.d.ts +2 -1
  43. package/dist/fields/hooks/afterChange/index.js +4 -2
  44. package/dist/fields/hooks/afterChange/promise.d.ts +5 -3
  45. package/dist/fields/hooks/afterChange/promise.js +49 -18
  46. package/dist/fields/hooks/afterChange/traverseFields.d.ts +5 -3
  47. package/dist/fields/hooks/afterChange/traverseFields.js +4 -2
  48. package/dist/fields/hooks/afterRead/promise.d.ts +2 -2
  49. package/dist/fields/hooks/afterRead/promise.js +48 -20
  50. package/dist/fields/hooks/afterRead/traverseFields.d.ts +2 -2
  51. package/dist/fields/hooks/beforeChange/promise.d.ts +2 -2
  52. package/dist/fields/hooks/beforeChange/promise.js +51 -20
  53. package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -2
  54. package/dist/fields/hooks/beforeValidate/promise.d.ts +2 -2
  55. package/dist/fields/hooks/beforeValidate/promise.js +35 -15
  56. package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +2 -2
  57. package/dist/globals/config/schema.js +2 -1
  58. package/dist/globals/config/types.d.ts +2 -0
  59. package/dist/globals/operations/restoreVersion.js +10 -1
  60. package/dist/globals/operations/update.js +4 -1
  61. package/dist/graphql/schema/buildMutationInputType.js +27 -13
  62. package/dist/graphql/schema/buildObjectType.js +16 -1
  63. package/dist/graphql/schema/withNullableType.d.ts +2 -2
  64. package/dist/graphql/schema/withNullableType.js +1 -1
  65. package/dist/mongoose/buildQuery.js +4 -2
  66. package/dist/mongoose/buildSchema.js +25 -14
  67. package/dist/types/index.d.ts +1 -1
  68. package/dist/uploads/getFileByPath.d.ts +1 -1
  69. package/dist/uploads/getFileByPath.js +5 -5
  70. package/dist/uploads/getSafeFilename.js +3 -4
  71. package/dist/uploads/imageResizer.d.ts +1 -9
  72. package/dist/uploads/imageResizer.js +18 -18
  73. package/dist/uploads/types.d.ts +18 -3
  74. package/dist/uploads/uploadFile.js +29 -8
  75. package/dist/utilities/flattenTopLevelFields.js +2 -2
  76. package/dist/utilities/groupOrTabHasRequiredSubfield.d.ts +2 -0
  77. package/dist/utilities/groupOrTabHasRequiredSubfield.js +17 -0
  78. package/dist/utilities/logger.js +2 -3
  79. package/dist/utilities/wordBoundariesRegex.js +2 -2
  80. package/docs/admin/overview.mdx +2 -1
  81. package/docs/configuration/collections.mdx +14 -1
  82. package/docs/fields/array.mdx +10 -1
  83. package/docs/fields/blocks.mdx +9 -1
  84. package/docs/fields/collapsible.mdx +13 -5
  85. package/docs/fields/tabs.mdx +4 -2
  86. package/docs/hooks/collections.mdx +3 -2
  87. package/docs/hooks/fields.mdx +11 -9
  88. package/docs/hooks/globals.mdx +1 -0
  89. package/docs/upload/overview.mdx +5 -3
  90. package/package.json +3 -3
  91. package/CHANGELOG.md +0 -1893
@@ -11,14 +11,15 @@ import validateWhereQuery from '../WhereBuilder/validateWhereQuery';
11
11
  import './index.scss';
12
12
  const baseClass = 'list-controls';
13
13
  const ListControls = (props) => {
14
- const { collection, enableColumns = true, enableSort = false, columns, setColumns, handleSortChange, handleWhereChange, modifySearchQuery = true, collection: { fields, admin: { useAsTitle, }, }, } = props;
14
+ const { collection, enableColumns = true, enableSort = false, columns, setColumns, handleSortChange, handleWhereChange, modifySearchQuery = true, collection: { fields, admin: { useAsTitle, listSearchableFields, }, }, } = props;
15
15
  const params = useSearchParams();
16
16
  const shouldInitializeWhereOpened = validateWhereQuery(params === null || params === void 0 ? void 0 : params.where);
17
17
  const [titleField] = useState(() => fields.find((field) => fieldAffectsData(field) && field.name === useAsTitle));
18
+ const [textFieldsToBeSearched] = useState(listSearchableFields ? () => fields.filter((field) => fieldAffectsData(field) && listSearchableFields.includes(field.name)) : null);
18
19
  const [visibleDrawer, setVisibleDrawer] = useState(shouldInitializeWhereOpened ? 'where' : undefined);
19
20
  return (React.createElement("div", { className: baseClass },
20
21
  React.createElement("div", { className: `${baseClass}__wrap` },
21
- React.createElement(SearchFilter, { fieldName: titleField && fieldAffectsData(titleField) ? titleField.name : undefined, handleChange: handleWhereChange, modifySearchQuery: modifySearchQuery, fieldLabel: titleField && titleField.label ? titleField.label : undefined }),
22
+ React.createElement(SearchFilter, { fieldName: titleField && fieldAffectsData(titleField) ? titleField.name : undefined, handleChange: handleWhereChange, modifySearchQuery: modifySearchQuery, fieldLabel: titleField && titleField.label ? titleField.label : undefined, listSearchableFields: textFieldsToBeSearched }),
22
23
  React.createElement("div", { className: `${baseClass}__buttons` },
23
24
  React.createElement("div", { className: `${baseClass}__buttons-wrap` },
24
25
  enableColumns && (React.createElement(Button, { className: `${baseClass}__toggle-columns`, buttonStyle: visibleDrawer === 'columns' ? undefined : 'secondary', onClick: () => setVisibleDrawer(visibleDrawer !== 'columns' ? 'columns' : undefined), icon: "chevron", iconStyle: "none" }, "Columns")),
@@ -10,17 +10,39 @@ import CloseMenu from '../../icons/CloseMenu';
10
10
  import Icon from '../../graphics/Icon';
11
11
  import Account from '../../graphics/Account';
12
12
  import Localizer from '../Localizer';
13
+ import NavGroup from '../NavGroup';
14
+ import { groupNavItems, EntityType } from '../../../utilities/groupNavItems';
13
15
  import './index.scss';
14
16
  const baseClass = 'nav';
15
17
  const DefaultNav = () => {
16
18
  const { permissions } = useAuth();
17
19
  const [menuActive, setMenuActive] = useState(false);
20
+ const [groups, setGroups] = useState([]);
18
21
  const history = useHistory();
19
22
  const { collections, globals, routes: { admin, }, admin: { components: { beforeNavLinks, afterNavLinks, }, }, } = useConfig();
20
23
  const classes = [
21
24
  baseClass,
22
25
  menuActive && `${baseClass}--menu-active`,
23
- ].filter(Boolean).join(' ');
26
+ ].filter(Boolean)
27
+ .join(' ');
28
+ useEffect(() => {
29
+ setGroups(groupNavItems([
30
+ ...collections.map((collection) => {
31
+ const entityToGroup = {
32
+ type: EntityType.collection,
33
+ entity: collection,
34
+ };
35
+ return entityToGroup;
36
+ }),
37
+ ...globals.map((global) => {
38
+ const entityToGroup = {
39
+ type: EntityType.global,
40
+ entity: global,
41
+ };
42
+ return entityToGroup;
43
+ }),
44
+ ], permissions));
45
+ }, [collections, globals, permissions]);
24
46
  useEffect(() => history.listen(() => {
25
47
  setMenuActive(false);
26
48
  }), [history]);
@@ -32,31 +54,28 @@ const DefaultNav = () => {
32
54
  React.createElement("button", { type: "button", className: `${baseClass}__mobile-menu-btn`, onClick: () => setMenuActive(!menuActive) },
33
55
  menuActive && (React.createElement(CloseMenu, null)),
34
56
  !menuActive && (React.createElement(Menu, null)))),
35
- React.createElement("div", { className: `${baseClass}__wrap` },
57
+ React.createElement("nav", { className: `${baseClass}__wrap` },
36
58
  Array.isArray(beforeNavLinks) && beforeNavLinks.map((Component, i) => React.createElement(Component, { key: i })),
37
- React.createElement("span", { className: `${baseClass}__label` }, "Collections"),
38
- React.createElement("nav", null, collections && collections.map((collection, i) => {
39
- var _a, _b;
40
- const href = `${admin}/collections/${collection.slug}`;
41
- if ((_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.read.permission) {
42
- return (React.createElement(NavLink, { id: `nav-${collection.slug}`, activeClassName: "active", key: i, to: href },
43
- React.createElement(Chevron, null),
44
- collection.labels.plural));
45
- }
46
- return null;
47
- })),
48
- (globals && globals.length > 0) && (React.createElement(React.Fragment, null,
49
- React.createElement("span", { className: `${baseClass}__label` }, "Globals"),
50
- React.createElement("nav", null, globals.map((global, i) => {
51
- var _a;
52
- const href = `${admin}/globals/${global.slug}`;
53
- if ((_a = permissions === null || permissions === void 0 ? void 0 : permissions.globals) === null || _a === void 0 ? void 0 : _a[global.slug].read.permission) {
54
- return (React.createElement(NavLink, { id: `nav-global-${global.slug}`, activeClassName: "active", key: i, to: href },
55
- React.createElement(Chevron, null),
56
- global.label));
59
+ groups.map(({ label, entities }, key) => {
60
+ return (React.createElement(NavGroup, { ...{ key, label } }, entities.map(({ entity, type }, i) => {
61
+ let entityLabel;
62
+ let href;
63
+ let id;
64
+ if (type === EntityType.collection) {
65
+ href = `${admin}/collections/${entity.slug}`;
66
+ entityLabel = entity.labels.plural;
67
+ id = `nav-${entity.slug}`;
68
+ }
69
+ if (type === EntityType.global) {
70
+ href = `${admin}/globals/${entity.slug}`;
71
+ entityLabel = entity.label;
72
+ id = `nav-global-${entity.slug}`;
57
73
  }
58
- return null;
59
- })))),
74
+ return (React.createElement(NavLink, { id: id, className: `${baseClass}__link`, activeClassName: "active", key: i, to: href },
75
+ React.createElement(Chevron, null),
76
+ entityLabel));
77
+ })));
78
+ }),
60
79
  Array.isArray(afterNavLinks) && afterNavLinks.map((Component, i) => React.createElement(Component, { key: i })),
61
80
  React.createElement("div", { className: `${baseClass}__controls` },
62
81
  React.createElement(Localizer, null),
@@ -81,32 +81,16 @@
81
81
  }
82
82
  }
83
83
 
84
- a {
85
- padding: base(.125) 0;
86
- display: flex;
87
- text-decoration: none;
88
-
89
- &:focus {
90
- box-shadow: none;
91
- font-weight: 600;
92
- }
93
-
94
- &:active {
95
- font-weight: normal;
96
- }
97
- }
98
-
99
84
  nav {
100
- margin: base(.25) 0 $baseline;
101
-
102
85
  a {
103
86
  position: relative;
87
+ padding: base(.125) base(1.5) base(.125) 0;
88
+ display: flex;
89
+ text-decoration: none;
104
90
 
105
- svg {
106
- opacity: 0;
107
- position: absolute;
108
- left: - base(.5);
109
- transform: rotate(-90deg);
91
+ &:focus {
92
+ box-shadow: none;
93
+ font-weight: 600;
110
94
  }
111
95
 
112
96
  &:hover {
@@ -114,12 +98,24 @@
114
98
  }
115
99
 
116
100
  &.active {
101
+ font-weight: normal;
117
102
  padding-left: base(.6);
118
103
  font-weight: 600;
104
+ }
105
+ }
106
+ }
119
107
 
120
- svg {
121
- opacity: 1;
122
- }
108
+ &__link {
109
+ svg {
110
+ opacity: 0;
111
+ position: absolute;
112
+ left: - base(.5);
113
+ transform: rotate(-90deg);
114
+ }
115
+
116
+ &.active {
117
+ svg {
118
+ opacity: 1;
123
119
  }
124
120
  }
125
121
  }
@@ -184,4 +180,4 @@
184
180
  font-weight: 600;
185
181
  }
186
182
  }
187
- }
183
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import './index.scss';
3
+ declare type Props = {
4
+ children: React.ReactNode;
5
+ label: string;
6
+ };
7
+ declare const NavGroup: React.FC<Props>;
8
+ export default NavGroup;
@@ -0,0 +1,52 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import AnimateHeight from 'react-animate-height';
3
+ import Chevron from '../../icons/Chevron';
4
+ import { usePreferences } from '../../utilities/Preferences';
5
+ import './index.scss';
6
+ const baseClass = 'nav-group';
7
+ const NavGroup = ({ children, label, }) => {
8
+ const [collapsed, setCollapsed] = useState(true);
9
+ const [animate, setAnimate] = useState(false);
10
+ const { getPreference, setPreference } = usePreferences();
11
+ const preferencesKey = `collapsed-${label}-groups`;
12
+ useEffect(() => {
13
+ if (label) {
14
+ const setCollapsedFromPreferences = async () => {
15
+ const preferences = await getPreference(preferencesKey) || [];
16
+ setCollapsed(preferences.indexOf(label) !== -1);
17
+ };
18
+ setCollapsedFromPreferences();
19
+ }
20
+ }, [getPreference, label, preferencesKey]);
21
+ if (label) {
22
+ const toggleCollapsed = async () => {
23
+ setAnimate(true);
24
+ let preferences = await getPreference(preferencesKey) || [];
25
+ if (collapsed) {
26
+ preferences = preferences.filter((preference) => label !== preference);
27
+ }
28
+ else {
29
+ preferences.push(label);
30
+ }
31
+ setPreference(preferencesKey, preferences);
32
+ setCollapsed(!collapsed);
33
+ };
34
+ return (React.createElement("div", { id: `nav-group-${label}`, className: [
35
+ `${baseClass}`,
36
+ `${label}`,
37
+ collapsed && `${baseClass}--collapsed`,
38
+ ].filter(Boolean)
39
+ .join(' ') },
40
+ React.createElement("button", { type: "button", className: [
41
+ `${baseClass}__toggle`,
42
+ `${baseClass}__toggle--${collapsed ? 'collapsed' : 'open'}`,
43
+ ].filter(Boolean)
44
+ .join(' '), onClick: toggleCollapsed },
45
+ React.createElement("div", { className: `${baseClass}__label` }, label),
46
+ React.createElement(Chevron, { className: `${baseClass}__indicator` })),
47
+ React.createElement(AnimateHeight, { height: collapsed ? 0 : 'auto', duration: animate ? 200 : 0 },
48
+ React.createElement("div", { className: `${baseClass}__content` }, children))));
49
+ }
50
+ return (React.createElement(React.Fragment, null, children));
51
+ };
52
+ export default NavGroup;
@@ -0,0 +1,53 @@
1
+ @import '../../../scss/styles.scss';
2
+
3
+ .nav-group {
4
+ width: 100%;
5
+ margin-bottom: base(.5);
6
+
7
+ &__toggle {
8
+ cursor: pointer;
9
+ color: var(--theme-elevation-400);
10
+ background: transparent;
11
+ padding-left: 0;
12
+ border: 0;
13
+ margin-top: base(.25);
14
+ width: 100%;
15
+ text-align: left;
16
+ display: flex;
17
+ align-items: flex-start;
18
+ padding-right: base(.5);
19
+
20
+ svg {
21
+ flex-shrink: 0;
22
+ margin-top: base(-.2);
23
+ }
24
+
25
+ &:hover {
26
+ color: var(--theme-elevation-1000);
27
+
28
+ .stroke {
29
+ stroke: var(--theme-elevation-1000);
30
+ }
31
+ }
32
+ }
33
+
34
+ &__indicator {
35
+ margin-left: auto;
36
+
37
+ .stroke {
38
+ stroke: var(--theme-elevation-200);
39
+ }
40
+ }
41
+
42
+ &--collapsed {
43
+ .collapsible__toggle {
44
+ border-bottom-right-radius: $style-radius-s;
45
+ border-bottom-left-radius: $style-radius-s;
46
+ }
47
+
48
+ .nav-group__indicator {
49
+ transform: rotate(.5turn);
50
+ }
51
+ }
52
+
53
+ }
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { useHistory } from 'react-router-dom';
3
3
  import queryString from 'qs';
4
4
  import Search from '../../icons/Search';
@@ -7,26 +7,44 @@ import { useSearchParams } from '../../utilities/SearchParams';
7
7
  import './index.scss';
8
8
  const baseClass = 'search-filter';
9
9
  const SearchFilter = (props) => {
10
- const { fieldName = 'id', fieldLabel = 'ID', modifySearchQuery = true, handleChange, } = props;
10
+ const { fieldName = 'id', fieldLabel = 'ID', modifySearchQuery = true, listSearchableFields, handleChange, } = props;
11
11
  const params = useSearchParams();
12
12
  const history = useHistory();
13
- const [search, setSearch] = useState(() => { var _a, _b; return ((_b = (_a = params === null || params === void 0 ? void 0 : params.where) === null || _a === void 0 ? void 0 : _a[fieldName]) === null || _b === void 0 ? void 0 : _b.like) || ''; });
13
+ const [search, setSearch] = useState('');
14
+ const [previousSearch, setPreviousSearch] = useState('');
15
+ const placeholder = useRef(`Search by ${fieldLabel}`);
14
16
  const debouncedSearch = useDebounce(search, 300);
15
17
  useEffect(() => {
16
- var _a, _b, _c, _d, _e;
17
- if (debouncedSearch !== ((_b = (_a = params === null || params === void 0 ? void 0 : params.where) === null || _a === void 0 ? void 0 : _a[fieldName]) === null || _b === void 0 ? void 0 : _b.like)) {
18
- const newWhere = {
19
- ...(typeof (params === null || params === void 0 ? void 0 : params.where) === 'object' ? params.where : {}),
20
- [fieldName]: {
21
- like: debouncedSearch,
22
- },
23
- };
24
- if (!debouncedSearch) {
25
- delete newWhere[fieldName];
18
+ const newWhere = { ...typeof (params === null || params === void 0 ? void 0 : params.where) === 'object' ? params.where : {} };
19
+ const fieldNamesToSearch = [fieldName, ...(listSearchableFields || []).map(({ name }) => name)];
20
+ fieldNamesToSearch.forEach((fieldNameToSearch) => {
21
+ const hasOrQuery = Array.isArray(newWhere.or);
22
+ const existingFieldSearchIndex = hasOrQuery ? newWhere.or.findIndex((condition) => {
23
+ var _a;
24
+ return (_a = condition === null || condition === void 0 ? void 0 : condition[fieldNameToSearch]) === null || _a === void 0 ? void 0 : _a.like;
25
+ }) : -1;
26
+ if (debouncedSearch) {
27
+ if (!hasOrQuery)
28
+ newWhere.or = [];
29
+ if (existingFieldSearchIndex > -1) {
30
+ newWhere.or[existingFieldSearchIndex][fieldNameToSearch].like = debouncedSearch;
31
+ }
32
+ else {
33
+ newWhere.or.push({
34
+ [fieldNameToSearch]: {
35
+ like: debouncedSearch,
36
+ },
37
+ });
38
+ }
26
39
  }
40
+ else if (existingFieldSearchIndex > -1) {
41
+ newWhere.or.splice(existingFieldSearchIndex, 1);
42
+ }
43
+ });
44
+ if (debouncedSearch !== previousSearch) {
27
45
  if (handleChange)
28
46
  handleChange(newWhere);
29
- if (modifySearchQuery && ((_d = (_c = params === null || params === void 0 ? void 0 : params.where) === null || _c === void 0 ? void 0 : _c[fieldName]) === null || _d === void 0 ? void 0 : _d.like) !== ((_e = newWhere === null || newWhere === void 0 ? void 0 : newWhere[fieldName]) === null || _e === void 0 ? void 0 : _e.like)) {
47
+ if (modifySearchQuery) {
30
48
  history.replace({
31
49
  search: queryString.stringify({
32
50
  ...params,
@@ -34,11 +52,22 @@ const SearchFilter = (props) => {
34
52
  where: newWhere,
35
53
  }),
36
54
  });
55
+ setPreviousSearch(debouncedSearch);
37
56
  }
38
57
  }
39
- }, [debouncedSearch, history, fieldName, params, handleChange, modifySearchQuery]);
58
+ }, [debouncedSearch, previousSearch, history, fieldName, params, handleChange, modifySearchQuery, listSearchableFields]);
59
+ useEffect(() => {
60
+ if ((listSearchableFields === null || listSearchableFields === void 0 ? void 0 : listSearchableFields.length) > 0) {
61
+ placeholder.current = listSearchableFields.reduce((prev, curr, i) => {
62
+ if (i === listSearchableFields.length - 1) {
63
+ return `${prev} or ${curr.label || curr.name}`;
64
+ }
65
+ return `${prev}, ${curr.label || curr.name}`;
66
+ }, placeholder.current);
67
+ }
68
+ }, [listSearchableFields]);
40
69
  return (React.createElement("div", { className: baseClass },
41
- React.createElement("input", { className: `${baseClass}__input`, placeholder: `Search by ${fieldLabel}`, type: "text", value: search || '', onChange: (e) => setSearch(e.target.value) }),
70
+ React.createElement("input", { className: `${baseClass}__input`, placeholder: placeholder.current, type: "text", value: search || '', onChange: (e) => setSearch(e.target.value) }),
42
71
  React.createElement(Search, null)));
43
72
  };
44
73
  export default SearchFilter;
@@ -1,7 +1,9 @@
1
+ import { FieldAffectingData } from '../../../../fields/config/types';
1
2
  import { Where } from '../../../../types';
2
3
  export declare type Props = {
3
4
  fieldName?: string;
4
5
  fieldLabel?: string;
5
6
  modifySearchQuery?: boolean;
7
+ listSearchableFields?: FieldAffectingData[];
6
8
  handleChange?: (where: Where) => void;
7
9
  };
@@ -41,9 +41,22 @@ const WhereBuilder = (props) => {
41
41
  const [reducedFields] = useState(() => reduceFields(collection.fields));
42
42
  useThrottledEffect(() => {
43
43
  const currentParams = queryString.parse(history.location.search, { ignoreQueryPrefix: true, depth: 10 });
44
+ const paramsToKeep = typeof (currentParams === null || currentParams === void 0 ? void 0 : currentParams.where) === 'object' && 'or' in currentParams.where ? currentParams.where.or.reduce((keptParams, param) => {
45
+ const newParam = { ...param };
46
+ if (param.and) {
47
+ delete newParam.and;
48
+ }
49
+ return [
50
+ ...keptParams,
51
+ newParam,
52
+ ];
53
+ }, []) : [];
44
54
  const newWhereQuery = {
45
55
  ...typeof (currentParams === null || currentParams === void 0 ? void 0 : currentParams.where) === 'object' ? currentParams.where : {},
46
- or: conditions,
56
+ or: [
57
+ ...conditions,
58
+ ...paramsToKeep,
59
+ ],
47
60
  };
48
61
  if (handleChange)
49
62
  handleChange(newWhereQuery);
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-param-reassign */
2
2
  import ObjectID from 'bson-objectid';
3
- import { fieldAffectsData, fieldHasSubFields } from '../../../../../fields/config/types';
3
+ import { fieldAffectsData, fieldHasSubFields, tabHasName, } from '../../../../../fields/config/types';
4
4
  import getValueWithDefault from '../../../../../fields/getDefaultValue';
5
5
  import { iterateFields } from './iterateFields';
6
6
  export const addFieldStatePromise = async ({ field, locale, user, state, path, passesCondition, fullData, data, fieldPromises, id, operation, }) => {
@@ -162,9 +162,9 @@ export const addFieldStatePromise = async ({ field, locale, user, state, path, p
162
162
  iterateFields({
163
163
  state,
164
164
  fields: tab.fields,
165
- data,
165
+ data: tabHasName(tab) ? data === null || data === void 0 ? void 0 : data[tab.name] : data,
166
166
  parentPassesCondition: passesCondition,
167
- path,
167
+ path: tabHasName(tab) ? `${path}${tab.name}.` : path,
168
168
  user,
169
169
  fieldPromises,
170
170
  fullData,
@@ -25,7 +25,7 @@ import './index.scss';
25
25
  const baseClass = 'array-field';
26
26
  const ArrayFieldType = (props) => {
27
27
  var _a, _b;
28
- const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, className, }, } = props;
28
+ const { name, path: pathFromProps, fields, fieldTypes, validate = array, required, maxRows, minRows, permissions, admin: { readOnly, description, condition, initCollapsed, className, }, } = props;
29
29
  const path = pathFromProps || name;
30
30
  // Handle labeling for Arrays, Global Arrays, and Blocks
31
31
  const getLabels = (p) => {
@@ -95,9 +95,14 @@ const ArrayFieldType = (props) => {
95
95
  var _a, _b, _c;
96
96
  dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
97
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
- || [];
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;
100
+ if (initCollapsed && typeof newCollapsedState === 'undefined') {
101
+ newCollapsedState = rows.map((row) => row.id);
102
+ }
103
+ else if (typeof newCollapsedState === 'undefined') {
104
+ newCollapsedState = [];
105
+ }
101
106
  if (!collapsed) {
102
107
  newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
103
108
  }
@@ -107,7 +112,7 @@ const ArrayFieldType = (props) => {
107
112
  setPreference(preferencesKey, {
108
113
  ...preferencesToSet,
109
114
  fields: {
110
- ...(preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {},
115
+ ...((preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) || {}),
111
116
  [path]: {
112
117
  ...(_c = preferencesToSet === null || preferencesToSet === void 0 ? void 0 : preferencesToSet.fields) === null || _c === void 0 ? void 0 : _c[path],
113
118
  collapsed: newCollapsedState,
@@ -115,7 +120,7 @@ const ArrayFieldType = (props) => {
115
120
  },
116
121
  });
117
122
  }
118
- }, [preferencesKey, path, setPreference, rows, getPreference]);
123
+ }, [preferencesKey, getPreference, path, setPreference, initCollapsed, rows]);
119
124
  const toggleCollapseAll = useCallback(async (collapse) => {
120
125
  var _a;
121
126
  dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
@@ -137,11 +142,11 @@ const ArrayFieldType = (props) => {
137
142
  const initializeRowState = async () => {
138
143
  var _a, _b;
139
144
  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 });
145
+ const preferences = (await getPreference(preferencesKey)) || { fields: {} };
146
+ 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, initCollapsed });
142
147
  };
143
148
  initializeRowState();
144
- }, [formContext, path, getPreference, preferencesKey]);
149
+ }, [formContext, path, getPreference, preferencesKey, initCollapsed]);
145
150
  useEffect(() => {
146
151
  setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
147
152
  if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
@@ -32,7 +32,7 @@ const labelDefaults = {
32
32
  plural: 'Blocks',
33
33
  };
34
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;
35
+ const { label, name, path: pathFromProps, blocks, labels = labelDefaults, fieldTypes, maxRows, minRows, required, validate = blocksValidator, permissions, admin: { readOnly, description, condition, initCollapsed, className, }, } = props;
36
36
  const path = pathFromProps || name;
37
37
  const { preferencesKey } = useDocumentInfo();
38
38
  const { getPreference } = usePreferences();
@@ -99,8 +99,13 @@ const Index = (props) => {
99
99
  dispatchRows({ type: 'SET_COLLAPSE', id: rowID, collapsed });
100
100
  if (preferencesKey) {
101
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
- || [];
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;
103
+ if (initCollapsed && typeof newCollapsedState === 'undefined') {
104
+ newCollapsedState = rows.map((row) => row.id);
105
+ }
106
+ else if (typeof newCollapsedState === 'undefined') {
107
+ newCollapsedState = [];
108
+ }
104
109
  if (!collapsed) {
105
110
  newCollapsedState = newCollapsedState.filter((existingID) => existingID !== rowID);
106
111
  }
@@ -118,7 +123,7 @@ const Index = (props) => {
118
123
  },
119
124
  });
120
125
  }
121
- }, [preferencesKey, getPreference, path, setPreference, rows]);
126
+ }, [preferencesKey, getPreference, path, setPreference, initCollapsed, rows]);
122
127
  const toggleCollapseAll = useCallback(async (collapse) => {
123
128
  var _a;
124
129
  dispatchRows({ type: 'SET_ALL_COLLAPSED', collapse });
@@ -141,11 +146,11 @@ const Index = (props) => {
141
146
  const initializeRowState = async () => {
142
147
  var _a, _b;
143
148
  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 });
149
+ const preferences = (await getPreference(preferencesKey)) || { fields: {} };
150
+ 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, initCollapsed });
146
151
  };
147
152
  initializeRowState();
148
- }, [formContext, path, getPreference, preferencesKey]);
153
+ }, [formContext, path, getPreference, preferencesKey, initCollapsed]);
149
154
  useEffect(() => {
150
155
  setValue((rows === null || rows === void 0 ? void 0 : rows.length) || 0, true);
151
156
  if ((rows === null || rows === void 0 ? void 0 : rows.length) === 0) {
@@ -10,10 +10,10 @@ import { getFieldPath } from '../getFieldPath';
10
10
  import './index.scss';
11
11
  const baseClass = 'collapsible-field';
12
12
  const CollapsibleField = (props) => {
13
- const { label, fields, fieldTypes, path, permissions, admin: { readOnly, className, description, }, } = props;
13
+ const { label, fields, fieldTypes, path, permissions, admin: { readOnly, className, initCollapsed, description, }, } = props;
14
14
  const { getPreference, setPreference } = usePreferences();
15
15
  const { preferencesKey } = useDocumentInfo();
16
- const [initCollapsed, setInitCollapsed] = useState();
16
+ const [collapsedOnMount, setCollapsedOnMount] = useState();
17
17
  const [fieldPreferencesKey] = useState(() => `collapsible-${toKebabCase(label)}`);
18
18
  const onToggle = useCallback(async (newCollapsedState) => {
19
19
  var _a;
@@ -31,16 +31,16 @@ const CollapsibleField = (props) => {
31
31
  }, [preferencesKey, fieldPreferencesKey, getPreference, setPreference]);
32
32
  useEffect(() => {
33
33
  const fetchInitialState = async () => {
34
- var _a, _b;
34
+ var _a, _b, _c;
35
35
  const preferences = await getPreference(preferencesKey);
36
- setInitCollapsed(Boolean((_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[fieldPreferencesKey]) === null || _b === void 0 ? void 0 : _b.collapsed));
36
+ setCollapsedOnMount(Boolean((_c = (_b = (_a = preferences === null || preferences === void 0 ? void 0 : preferences.fields) === null || _a === void 0 ? void 0 : _a[fieldPreferencesKey]) === null || _b === void 0 ? void 0 : _b.collapsed) !== null && _c !== void 0 ? _c : initCollapsed));
37
37
  };
38
38
  fetchInitialState();
39
- }, [getPreference, preferencesKey, fieldPreferencesKey]);
40
- if (typeof initCollapsed !== 'boolean')
39
+ }, [getPreference, preferencesKey, fieldPreferencesKey, initCollapsed]);
40
+ if (typeof collapsedOnMount !== 'boolean')
41
41
  return null;
42
42
  return (React.createElement(React.Fragment, null,
43
- React.createElement(Collapsible, { initCollapsed: initCollapsed, className: [
43
+ React.createElement(Collapsible, { initCollapsed: collapsedOnMount, className: [
44
44
  'field-type',
45
45
  baseClass,
46
46
  className,
@@ -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, tabHasName } from '../../../../../fields/config/types';
4
5
  import FieldDescription from '../../FieldDescription';
5
6
  import toKebabCase from '../../../../../utilities/toKebabCase';
6
7
  import { useCollapsible } from '../../../elements/Collapsible/provider';
7
8
  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) => {
@@ -24,16 +24,16 @@ const TabsField = (props) => {
24
24
  return (React.createElement("button", { key: i, type: "button", className: [
25
25
  `${baseClass}__tab-button`,
26
26
  active === i && `${baseClass}__tab-button--active`,
27
- ].filter(Boolean).join(' '), onClick: () => setActive(i) }, tab.label));
27
+ ].filter(Boolean).join(' '), onClick: () => setActive(i) }, tab.label ? tab.label : (tabHasName(tab) && tab.name)));
28
28
  }))),
29
29
  React.createElement("div", { className: `${baseClass}__content-wrap` }, activeTab && (React.createElement("div", { className: [
30
30
  `${baseClass}__tab`,
31
31
  `${baseClass}__tab-${toKebabCase(activeTab.label)}`,
32
32
  ].join(' ') },
33
33
  React.createElement(FieldDescription, { className: `${baseClass}__description`, description: activeTab.description }),
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) => ({
34
+ React.createElement(RenderFields, { 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: getFieldPath(path, field),
36
+ path: `${path ? `${path}.` : ''}${tabHasName(activeTab) ? `${activeTab.name}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
37
37
  })) })))))));
38
38
  };
39
39
  export default withCondition(TabsField);
@@ -11,6 +11,7 @@ declare type SET_ALL = {
11
11
  }[];
12
12
  collapsedState?: string[];
13
13
  blockType?: string;
14
+ initCollapsed?: boolean;
14
15
  };
15
16
  declare type SET_COLLAPSE = {
16
17
  type: 'SET_COLLAPSE';