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.
- package/dist/admin/components/elements/ListControls/index.js +3 -2
- package/dist/admin/components/elements/Nav/index.js +43 -24
- package/dist/admin/components/elements/Nav/index.scss +22 -26
- package/dist/admin/components/elements/NavGroup/index.d.ts +8 -0
- package/dist/admin/components/elements/NavGroup/index.js +52 -0
- package/dist/admin/components/elements/NavGroup/index.scss +53 -0
- package/dist/admin/components/elements/SearchFilter/index.js +45 -16
- package/dist/admin/components/elements/SearchFilter/types.d.ts +2 -0
- package/dist/admin/components/elements/WhereBuilder/index.js +14 -1
- package/dist/admin/components/forms/Form/buildStateFromSchema/addFieldStatePromise.js +3 -3
- package/dist/admin/components/forms/field-types/Array/index.js +14 -9
- package/dist/admin/components/forms/field-types/Blocks/index.js +12 -7
- package/dist/admin/components/forms/field-types/Collapsible/index.js +7 -7
- package/dist/admin/components/forms/field-types/Tabs/index.js +4 -4
- package/dist/admin/components/forms/field-types/rowReducer.d.ts +1 -0
- package/dist/admin/components/forms/field-types/rowReducer.js +2 -2
- package/dist/admin/components/graphics/Account/Gravatar.d.ts +3 -0
- package/dist/admin/components/graphics/Account/Gravatar.js +15 -0
- package/dist/admin/components/graphics/Account/index.d.ts +2 -2
- package/dist/admin/components/graphics/Account/index.js +24 -1
- package/dist/admin/components/views/Dashboard/Default.js +44 -12
- package/dist/admin/components/views/Dashboard/index.scss +1 -1
- package/dist/admin/components/views/collections/List/RelationshipProvider/index.js +1 -1
- package/dist/admin/components/views/collections/List/getInitialColumns.js +2 -2
- package/dist/admin/utilities/groupNavItems.d.ts +19 -0
- package/dist/admin/utilities/groupNavItems.js +36 -0
- package/dist/bin/generateTypes.js +20 -4
- package/dist/collections/config/schema.js +18 -2
- package/dist/collections/config/types.d.ts +9 -0
- package/dist/collections/operations/create.js +3 -1
- package/dist/collections/operations/local/create.d.ts +2 -2
- package/dist/collections/operations/local/create.js +3 -3
- package/dist/collections/operations/local/update.js +2 -2
- package/dist/collections/operations/restoreVersion.js +11 -1
- package/dist/collections/operations/update.js +3 -1
- package/dist/config/defaults.js +2 -1
- package/dist/config/schema.js +3 -1
- package/dist/config/types.d.ts +1 -0
- package/dist/fields/config/schema.js +11 -6
- package/dist/fields/config/types.d.ts +42 -9
- package/dist/fields/config/types.js +10 -2
- package/dist/fields/hooks/afterChange/index.d.ts +2 -1
- package/dist/fields/hooks/afterChange/index.js +4 -2
- package/dist/fields/hooks/afterChange/promise.d.ts +5 -3
- package/dist/fields/hooks/afterChange/promise.js +49 -18
- package/dist/fields/hooks/afterChange/traverseFields.d.ts +5 -3
- package/dist/fields/hooks/afterChange/traverseFields.js +4 -2
- package/dist/fields/hooks/afterRead/promise.d.ts +2 -2
- package/dist/fields/hooks/afterRead/promise.js +48 -20
- package/dist/fields/hooks/afterRead/traverseFields.d.ts +2 -2
- package/dist/fields/hooks/beforeChange/promise.d.ts +2 -2
- package/dist/fields/hooks/beforeChange/promise.js +51 -20
- package/dist/fields/hooks/beforeChange/traverseFields.d.ts +2 -2
- package/dist/fields/hooks/beforeValidate/promise.d.ts +2 -2
- package/dist/fields/hooks/beforeValidate/promise.js +35 -15
- package/dist/fields/hooks/beforeValidate/traverseFields.d.ts +2 -2
- package/dist/globals/config/schema.js +2 -1
- package/dist/globals/config/types.d.ts +2 -0
- package/dist/globals/operations/restoreVersion.js +10 -1
- package/dist/globals/operations/update.js +4 -1
- package/dist/graphql/schema/buildMutationInputType.js +27 -13
- package/dist/graphql/schema/buildObjectType.js +16 -1
- package/dist/graphql/schema/withNullableType.d.ts +2 -2
- package/dist/graphql/schema/withNullableType.js +1 -1
- package/dist/mongoose/buildQuery.js +4 -2
- package/dist/mongoose/buildSchema.js +25 -14
- package/dist/types/index.d.ts +1 -1
- package/dist/uploads/getFileByPath.d.ts +1 -1
- package/dist/uploads/getFileByPath.js +5 -5
- package/dist/uploads/getSafeFilename.js +3 -4
- package/dist/uploads/imageResizer.d.ts +1 -9
- package/dist/uploads/imageResizer.js +18 -18
- package/dist/uploads/types.d.ts +18 -3
- package/dist/uploads/uploadFile.js +29 -8
- package/dist/utilities/flattenTopLevelFields.js +2 -2
- package/dist/utilities/groupOrTabHasRequiredSubfield.d.ts +2 -0
- package/dist/utilities/groupOrTabHasRequiredSubfield.js +17 -0
- package/dist/utilities/logger.js +2 -3
- package/dist/utilities/wordBoundariesRegex.js +2 -2
- package/docs/admin/overview.mdx +2 -1
- package/docs/configuration/collections.mdx +14 -1
- package/docs/fields/array.mdx +10 -1
- package/docs/fields/blocks.mdx +9 -1
- package/docs/fields/collapsible.mdx +13 -5
- package/docs/fields/tabs.mdx +4 -2
- package/docs/hooks/collections.mdx +3 -2
- package/docs/hooks/fields.mdx +11 -9
- package/docs/hooks/globals.mdx +1 -0
- package/docs/upload/overview.mdx +5 -3
- package/package.json +3 -3
- 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)
|
|
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("
|
|
57
|
+
React.createElement("nav", { className: `${baseClass}__wrap` },
|
|
36
58
|
Array.isArray(beforeNavLinks) && beforeNavLinks.map((Component, i) => React.createElement(Component, { key: i })),
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
121
|
-
|
|
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,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(
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
if (
|
|
25
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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 = (
|
|
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,
|
|
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 = (
|
|
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 [
|
|
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
|
-
|
|
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
|
|
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:
|
|
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, {
|
|
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:
|
|
36
|
+
path: `${path ? `${path}.` : ''}${tabHasName(activeTab) ? `${activeTab.name}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
|
|
37
37
|
})) })))))));
|
|
38
38
|
};
|
|
39
39
|
export default withCondition(TabsField);
|