payload 1.1.7 → 1.1.9
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/components/forms.ts +10 -0
- package/dist/admin/components/elements/Autosave/index.js +3 -3
- package/dist/admin/components/elements/Nav/index.scss +1 -5
- package/dist/admin/components/elements/ReactSelect/index.scss +5 -1
- package/dist/admin/components/forms/Form/context.d.ts +5 -2
- package/dist/admin/components/forms/Form/context.js +9 -2
- package/dist/admin/components/forms/Form/fieldReducer.d.ts +2 -2
- package/dist/admin/components/forms/Form/fieldReducer.js +4 -1
- package/dist/admin/components/forms/Form/getSiblingData.js +11 -5
- package/dist/admin/components/forms/Form/index.js +12 -12
- package/dist/admin/components/forms/Form/initContextState.js +0 -3
- package/dist/admin/components/forms/Form/reduceFieldsToValues.js +6 -3
- package/dist/admin/components/forms/Form/types.d.ts +49 -7
- package/dist/admin/components/forms/field-types/Code/Code.js +0 -1
- package/dist/admin/components/forms/field-types/ConfirmPassword/index.js +2 -4
- package/dist/admin/components/forms/field-types/Email/index.js +0 -1
- package/dist/admin/components/forms/field-types/Number/index.js +0 -1
- package/dist/admin/components/forms/field-types/Password/index.js +0 -1
- package/dist/admin/components/forms/field-types/Point/index.js +0 -1
- package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.d.ts +4 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.js +67 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/index.scss +117 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/types.d.ts +6 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/Modal/types.js +1 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/index.d.ts +4 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/index.js +79 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/index.scss +60 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/types.d.ts +10 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/types.js +1 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/useRelatedCollections.d.ts +2 -0
- package/dist/admin/components/forms/field-types/Relationship/AddNew/useRelatedCollections.js +10 -0
- package/dist/admin/components/forms/field-types/Relationship/index.js +57 -45
- package/dist/admin/components/forms/field-types/Relationship/index.scss +15 -12
- package/dist/admin/components/forms/field-types/Relationship/optionsReducer.js +8 -7
- package/dist/admin/components/forms/field-types/Relationship/types.d.ts +1 -3
- package/dist/admin/components/forms/field-types/RichText/elements/relationship/Button/Fields/index.js +2 -3
- package/dist/admin/components/forms/field-types/Select/index.scss +1 -9
- package/dist/admin/components/forms/field-types/Text/index.js +0 -1
- package/dist/admin/components/forms/field-types/Textarea/index.js +0 -1
- package/dist/admin/components/forms/field-types/Upload/SelectExisting/index.js +2 -2
- package/dist/admin/components/forms/useField/index.js +71 -97
- package/dist/admin/components/forms/useField/types.d.ts +0 -2
- package/dist/admin/components/forms/withCondition/index.js +10 -5
- package/dist/admin/components/modals/LeaveWithoutSaving/index.scss +2 -2
- package/dist/admin/components/templates/Default/index.scss +1 -1
- package/dist/admin/components/utilities/EditDepth/index.d.ts +3 -0
- package/dist/admin/components/utilities/EditDepth/index.js +3 -0
- package/dist/admin/components/views/collections/Edit/Auth/APIKey.js +2 -3
- package/dist/admin/components/views/collections/Edit/Auth/index.js +3 -3
- package/dist/admin/components/views/collections/Edit/Default.js +9 -9
- package/dist/admin/components/views/collections/Edit/index.js +15 -12
- package/dist/admin/components/views/collections/Edit/types.d.ts +6 -0
- package/dist/admin/hooks/useTitle.js +2 -3
- package/dist/admin/index.js +1 -1
- package/dist/admin/scss/app.scss +6 -1
- package/dist/collections/config/defaults.d.ts +5 -5
- package/dist/config/types.d.ts +6 -1
- package/dist/express/types.d.ts +2 -2
- package/dist/fields/config/types.d.ts +2 -2
- package/docs/admin/components.mdx +3 -45
- package/docs/admin/customizing-css.mdx +1 -1
- package/docs/admin/hooks.mdx +271 -0
- package/docs/admin/preferences.mdx +1 -1
- package/docs/admin/webpack.mdx +1 -1
- package/docs/local-api/overview.mdx +1 -1
- package/package.json +2 -1
- package/types.d.ts +4 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
@import '../../../../../../scss/styles.scss';
|
|
2
|
+
|
|
3
|
+
.relationship-add-new-modal {
|
|
4
|
+
display: flex;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
position: fixed;
|
|
7
|
+
height: 100vh;
|
|
8
|
+
|
|
9
|
+
&__blur-bg {
|
|
10
|
+
@include blur-bg();
|
|
11
|
+
position: absolute;
|
|
12
|
+
z-index: 1;
|
|
13
|
+
top: 0;
|
|
14
|
+
right: 0;
|
|
15
|
+
bottom: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
opacity: 0;
|
|
18
|
+
transition: all 300ms ease-out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.collection-edit {
|
|
22
|
+
@include blur-bg();
|
|
23
|
+
transform: translateX(#{base(4)});
|
|
24
|
+
opacity: 0;
|
|
25
|
+
transition: all 300ms ease-out;
|
|
26
|
+
position: relative;
|
|
27
|
+
z-index: 2;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.collection-edit__form {
|
|
31
|
+
overflow: auto;
|
|
32
|
+
position: relative;
|
|
33
|
+
z-index: 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.collection-edit__document-actions {
|
|
37
|
+
|
|
38
|
+
&:before,
|
|
39
|
+
&:after {
|
|
40
|
+
content: none;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&--animated {
|
|
45
|
+
|
|
46
|
+
.collection-edit,
|
|
47
|
+
.relationship-add-new-modal__blur-bg,
|
|
48
|
+
.relationship-add-new-modal__close {
|
|
49
|
+
opacity: 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.collection-edit {
|
|
53
|
+
transform: translateX(0);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.collection-edit__document-actions {
|
|
58
|
+
margin-top: base(2.75);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&__close {
|
|
62
|
+
@extend %btn-reset;
|
|
63
|
+
position: relative;
|
|
64
|
+
z-index: 2;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
text-indent: -9999px;
|
|
67
|
+
background: rgba(0, 0, 0, 0.08);
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
opacity: 0;
|
|
70
|
+
transition: all 300ms ease-in-out;
|
|
71
|
+
transition-delay: 100ms;
|
|
72
|
+
|
|
73
|
+
&:active,
|
|
74
|
+
&:focus {
|
|
75
|
+
outline: 0;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&__header {
|
|
80
|
+
display: flex;
|
|
81
|
+
justify-content: space-between;
|
|
82
|
+
align-items: flex-start;
|
|
83
|
+
margin-top: base(2.5);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&__header-close {
|
|
87
|
+
svg {
|
|
88
|
+
width: base(2.5);
|
|
89
|
+
height: base(2.5);
|
|
90
|
+
position: relative;
|
|
91
|
+
top: base(-.5);
|
|
92
|
+
right: base(-.75);
|
|
93
|
+
|
|
94
|
+
.stroke {
|
|
95
|
+
stroke-width: .5px;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@include mid-break {
|
|
101
|
+
&__header-close {
|
|
102
|
+
svg {
|
|
103
|
+
top: base(-.75);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
&__close {
|
|
108
|
+
width: base(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
html[data-theme=dark] {
|
|
114
|
+
.relationship-add-new-modal__close {
|
|
115
|
+
background: rgba(0, 0, 0, 0.2);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
|
+
import { useModal } from '@faceless-ui/modal';
|
|
3
|
+
import Button from '../../../../elements/Button';
|
|
4
|
+
import Popup from '../../../../elements/Popup';
|
|
5
|
+
import { useRelatedCollections } from './useRelatedCollections';
|
|
6
|
+
import { useAuth } from '../../../../utilities/Auth';
|
|
7
|
+
import { AddNewRelationModal } from './Modal';
|
|
8
|
+
import { useEditDepth } from '../../../../utilities/EditDepth';
|
|
9
|
+
import Plus from '../../../../icons/Plus';
|
|
10
|
+
import './index.scss';
|
|
11
|
+
const baseClass = 'relationship-add-new';
|
|
12
|
+
export const AddNewRelation = ({ path, hasMany, relationTo, value, setValue, dispatchOptions }) => {
|
|
13
|
+
const relatedCollections = useRelatedCollections(relationTo);
|
|
14
|
+
const { toggleModal, modalState } = useModal();
|
|
15
|
+
const { permissions } = useAuth();
|
|
16
|
+
const [hasPermission, setHasPermission] = useState(false);
|
|
17
|
+
const [modalCollection, setModalCollection] = useState();
|
|
18
|
+
const [popupOpen, setPopupOpen] = useState(false);
|
|
19
|
+
const editDepth = useEditDepth();
|
|
20
|
+
const modalSlug = `${path}-add-modal-depth-${editDepth}`;
|
|
21
|
+
const openModal = useCallback(async (collection) => {
|
|
22
|
+
setModalCollection(collection);
|
|
23
|
+
toggleModal(modalSlug);
|
|
24
|
+
}, [toggleModal, modalSlug]);
|
|
25
|
+
const onSave = useCallback((json) => {
|
|
26
|
+
const newValue = Array.isArray(relationTo) ? {
|
|
27
|
+
relationTo: modalCollection.slug,
|
|
28
|
+
value: json.doc.id,
|
|
29
|
+
} : json.doc.id;
|
|
30
|
+
dispatchOptions({
|
|
31
|
+
type: 'ADD',
|
|
32
|
+
hasMultipleRelations: Array.isArray(relationTo),
|
|
33
|
+
collection: modalCollection,
|
|
34
|
+
docs: [
|
|
35
|
+
json.doc,
|
|
36
|
+
],
|
|
37
|
+
sort: true,
|
|
38
|
+
});
|
|
39
|
+
if (hasMany) {
|
|
40
|
+
setValue([...(Array.isArray(value) ? value : []), newValue]);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
setValue(newValue);
|
|
44
|
+
}
|
|
45
|
+
setModalCollection(undefined);
|
|
46
|
+
toggleModal(modalSlug);
|
|
47
|
+
}, [relationTo, modalCollection, hasMany, toggleModal, modalSlug, setValue, value, dispatchOptions]);
|
|
48
|
+
const onPopopToggle = useCallback((state) => {
|
|
49
|
+
setPopupOpen(state);
|
|
50
|
+
}, []);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (permissions) {
|
|
53
|
+
if (relatedCollections.length === 1) {
|
|
54
|
+
setHasPermission(permissions.collections[relatedCollections[0].slug].create.permission);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
setHasPermission(relatedCollections.some((collection) => permissions.collections[collection.slug].create.permission));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}, [permissions, relatedCollections]);
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
var _a;
|
|
63
|
+
if (!((_a = modalState[modalSlug]) === null || _a === void 0 ? void 0 : _a.isOpen)) {
|
|
64
|
+
setModalCollection(undefined);
|
|
65
|
+
}
|
|
66
|
+
}, [modalState, modalSlug]);
|
|
67
|
+
return hasPermission ? (React.createElement("div", { className: baseClass, id: `${path}-add-new` },
|
|
68
|
+
relatedCollections.length === 1 && (React.createElement(Button, { className: `${baseClass}__add-button`, onClick: () => openModal(relatedCollections[0]), buttonStyle: "none", tooltip: `Add new ${relatedCollections[0].labels.singular}` },
|
|
69
|
+
React.createElement(Plus, null))),
|
|
70
|
+
relatedCollections.length > 1 && (React.createElement(Popup, { buttonType: "custom", horizontalAlign: "center", onToggleOpen: onPopopToggle, button: (React.createElement(Button, { className: `${baseClass}__add-button`, buttonStyle: "none", tooltip: popupOpen ? undefined : 'Add new' },
|
|
71
|
+
React.createElement(Plus, null))), render: ({ close: closePopup }) => (React.createElement("ul", { className: `${baseClass}__relations` }, relatedCollections.map((relatedCollection) => {
|
|
72
|
+
if (permissions.collections[relatedCollection.slug].create.permission) {
|
|
73
|
+
return (React.createElement("li", { key: relatedCollection.slug },
|
|
74
|
+
React.createElement("button", { className: `${baseClass}__relation-button ${baseClass}__relation-button--${relatedCollection.slug}`, type: "button", onClick: () => { closePopup(); openModal(relatedCollection); } }, relatedCollection.labels.singular)));
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}))) })),
|
|
78
|
+
modalCollection && (React.createElement(AddNewRelationModal, { ...{ onSave, modalSlug, modalCollection } })))) : null;
|
|
79
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
@import '../../../../../scss/styles.scss';
|
|
2
|
+
|
|
3
|
+
.relationship-add-new {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: stretch;
|
|
6
|
+
|
|
7
|
+
.popup__wrapper {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: stretch;
|
|
10
|
+
height: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&__add-button {
|
|
14
|
+
@include formInput;
|
|
15
|
+
height: 100%;
|
|
16
|
+
margin-left: -1px;
|
|
17
|
+
display: flex;
|
|
18
|
+
padding: 0;
|
|
19
|
+
|
|
20
|
+
.btn__content,
|
|
21
|
+
.btn__label {
|
|
22
|
+
display: flex;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.btn__content,
|
|
26
|
+
.btn__label {
|
|
27
|
+
height: 100%;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.btn__label {
|
|
31
|
+
padding: 0 base(.5);
|
|
32
|
+
align-items: center;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
&__relations {
|
|
38
|
+
list-style: none;
|
|
39
|
+
margin: 0;
|
|
40
|
+
padding: 0;
|
|
41
|
+
|
|
42
|
+
li:not(:last-child) {
|
|
43
|
+
margin-bottom: base(.375);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&__relation-button {
|
|
48
|
+
@extend %btn-reset;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
@extend %btn-reset;
|
|
51
|
+
display: block;
|
|
52
|
+
padding: base(.125) 0;
|
|
53
|
+
text-align: center;
|
|
54
|
+
width: 100%;
|
|
55
|
+
|
|
56
|
+
&:hover {
|
|
57
|
+
opacity: .7;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Action } from '../types';
|
|
3
|
+
export declare type Props = {
|
|
4
|
+
hasMany: boolean;
|
|
5
|
+
relationTo: string | string[];
|
|
6
|
+
path: string;
|
|
7
|
+
value: unknown;
|
|
8
|
+
setValue: (value: unknown) => void;
|
|
9
|
+
dispatchOptions: React.Dispatch<Action>;
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useConfig } from '../../../../utilities/Config';
|
|
3
|
+
export const useRelatedCollections = (relationTo) => {
|
|
4
|
+
const config = useConfig();
|
|
5
|
+
const [relatedCollections] = useState(() => {
|
|
6
|
+
const relations = typeof relationTo === 'string' ? [relationTo] : relationTo;
|
|
7
|
+
return relations.map((relation) => config.collections.find((collection) => collection.slug === relation));
|
|
8
|
+
});
|
|
9
|
+
return relatedCollections;
|
|
10
|
+
};
|
|
@@ -10,13 +10,16 @@ import Label from '../../Label';
|
|
|
10
10
|
import Error from '../../Error';
|
|
11
11
|
import FieldDescription from '../../FieldDescription';
|
|
12
12
|
import { relationship } from '../../../../../fields/validations';
|
|
13
|
-
import { useFormProcessing,
|
|
13
|
+
import { useFormProcessing, useAllFormFields } from '../../Form/context';
|
|
14
14
|
import optionsReducer from './optionsReducer';
|
|
15
15
|
import { createRelationMap } from './createRelationMap';
|
|
16
16
|
import { useDebouncedCallback } from '../../../../hooks/useDebouncedCallback';
|
|
17
17
|
import { useDocumentInfo } from '../../../utilities/DocumentInfo';
|
|
18
18
|
import { getFilterOptionsQuery } from '../getFilterOptionsQuery';
|
|
19
19
|
import wordBoundariesRegex from '../../../../../utilities/wordBoundariesRegex';
|
|
20
|
+
import reduceFieldsToValues from '../../Form/reduceFieldsToValues';
|
|
21
|
+
import getSiblingData from '../../Form/getSiblingData';
|
|
22
|
+
import { AddNewRelation } from './AddNew';
|
|
20
23
|
import './index.scss';
|
|
21
24
|
const maxResultsPerRequest = 10;
|
|
22
25
|
const baseClass = 'relationship';
|
|
@@ -25,7 +28,7 @@ const Relationship = (props) => {
|
|
|
25
28
|
const { serverURL, routes: { api, }, collections, } = useConfig();
|
|
26
29
|
const { id } = useDocumentInfo();
|
|
27
30
|
const { user, permissions } = useAuth();
|
|
28
|
-
const
|
|
31
|
+
const [fields] = useAllFormFields();
|
|
29
32
|
const formProcessing = useFormProcessing();
|
|
30
33
|
const hasMultipleRelations = Array.isArray(relationTo);
|
|
31
34
|
const [options, dispatchOptions] = useReducer(optionsReducer, required || hasMany ? [] : [{ value: null, label: 'None' }]);
|
|
@@ -37,6 +40,7 @@ const Relationship = (props) => {
|
|
|
37
40
|
const [search, setSearch] = useState('');
|
|
38
41
|
const [enableWordBoundarySearch, setEnableWordBoundarySearch] = useState(false);
|
|
39
42
|
const firstRun = useRef(true);
|
|
43
|
+
const fieldsRef = useRef(fields);
|
|
40
44
|
const memoizedValidate = useCallback((value, validationOptions) => {
|
|
41
45
|
return validate(value, { ...validationOptions, required });
|
|
42
46
|
}, [validate, required]);
|
|
@@ -45,6 +49,12 @@ const Relationship = (props) => {
|
|
|
45
49
|
validate: memoizedValidate,
|
|
46
50
|
condition,
|
|
47
51
|
});
|
|
52
|
+
const getFormData = useCallback(() => {
|
|
53
|
+
return [
|
|
54
|
+
reduceFieldsToValues(fieldsRef.current, true),
|
|
55
|
+
getSiblingData(fieldsRef.current, path),
|
|
56
|
+
];
|
|
57
|
+
}, [fieldsRef, path]);
|
|
48
58
|
const getResults = useCallback(async ({ lastFullyLoadedRelation: lastFullyLoadedRelationArg, lastLoadedPage: lastLoadedPageArg, search: searchArg, value: valueArg, sort, }) => {
|
|
49
59
|
if (!permissions) {
|
|
50
60
|
return;
|
|
@@ -92,7 +102,7 @@ const Relationship = (props) => {
|
|
|
92
102
|
const data = await response.json();
|
|
93
103
|
if (data.docs.length > 0) {
|
|
94
104
|
resultsFetched += data.docs.length;
|
|
95
|
-
dispatchOptions({ type: 'ADD', data,
|
|
105
|
+
dispatchOptions({ type: 'ADD', docs: data.docs, hasMultipleRelations, collection, sort });
|
|
96
106
|
setLastLoadedPage(data.page);
|
|
97
107
|
if (!data.nextPage) {
|
|
98
108
|
setLastFullyLoadedRelation(relations.indexOf(relation));
|
|
@@ -107,7 +117,7 @@ const Relationship = (props) => {
|
|
|
107
117
|
else if (response.status === 403) {
|
|
108
118
|
setLastFullyLoadedRelation(relations.indexOf(relation));
|
|
109
119
|
lastLoadedPageToUse = 1;
|
|
110
|
-
dispatchOptions({ type: 'ADD',
|
|
120
|
+
dispatchOptions({ type: 'ADD', docs: [], hasMultipleRelations, collection, sort, ids: relationMap[relation] });
|
|
111
121
|
}
|
|
112
122
|
else {
|
|
113
123
|
setErrorLoading('An error has occurred.');
|
|
@@ -175,11 +185,11 @@ const Relationship = (props) => {
|
|
|
175
185
|
getResults({ search: searchArg, value: valueArg, sort: true });
|
|
176
186
|
setSearch(searchArg);
|
|
177
187
|
}, [getResults]);
|
|
178
|
-
const handleInputChange = (searchArg, valueArg) => {
|
|
188
|
+
const handleInputChange = useCallback((searchArg, valueArg) => {
|
|
179
189
|
if (search !== searchArg) {
|
|
180
190
|
updateSearch(searchArg, valueArg);
|
|
181
191
|
}
|
|
182
|
-
};
|
|
192
|
+
}, [search, updateSearch]);
|
|
183
193
|
// ///////////////////////////
|
|
184
194
|
// Fetch value options when initialValue changes
|
|
185
195
|
// ///////////////////////////
|
|
@@ -207,10 +217,10 @@ const Relationship = (props) => {
|
|
|
207
217
|
const collection = collections.find((coll) => coll.slug === relation);
|
|
208
218
|
if (response.ok) {
|
|
209
219
|
const data = await response.json();
|
|
210
|
-
dispatchOptions({ type: 'ADD', data,
|
|
220
|
+
dispatchOptions({ type: 'ADD', docs: data.docs, hasMultipleRelations, collection, sort: true, ids });
|
|
211
221
|
}
|
|
212
222
|
else if (response.status === 403) {
|
|
213
|
-
dispatchOptions({ type: 'ADD',
|
|
223
|
+
dispatchOptions({ type: 'ADD', docs: [], hasMultipleRelations, collection, sort: true, ids });
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
}
|
|
@@ -219,20 +229,20 @@ const Relationship = (props) => {
|
|
|
219
229
|
}
|
|
220
230
|
}, [hasMany, hasMultipleRelations, relationTo, initialValue, hasLoadedValueOptions, errorLoading, collections, api, serverURL]);
|
|
221
231
|
useEffect(() => {
|
|
222
|
-
if (!filterOptions)
|
|
232
|
+
if (!filterOptions)
|
|
223
233
|
return;
|
|
224
|
-
|
|
234
|
+
const [data, siblingData] = getFormData();
|
|
225
235
|
const newOptionFilters = getFilterOptionsQuery(filterOptions, {
|
|
226
236
|
id,
|
|
227
|
-
data
|
|
237
|
+
data,
|
|
228
238
|
relationTo,
|
|
229
|
-
siblingData
|
|
239
|
+
siblingData,
|
|
230
240
|
user,
|
|
231
241
|
});
|
|
232
242
|
if (!equal(newOptionFilters, optionFilters)) {
|
|
233
243
|
setOptionFilters(newOptionFilters);
|
|
234
244
|
}
|
|
235
|
-
}, [relationTo, filterOptions, optionFilters, id,
|
|
245
|
+
}, [relationTo, filterOptions, optionFilters, id, getFormData, path, user]);
|
|
236
246
|
useEffect(() => {
|
|
237
247
|
if (optionFilters || !filterOptions) {
|
|
238
248
|
setHasLoadedValueOptions(false);
|
|
@@ -279,39 +289,41 @@ const Relationship = (props) => {
|
|
|
279
289
|
} },
|
|
280
290
|
React.createElement(Error, { showError: showError, message: errorMessage }),
|
|
281
291
|
React.createElement(Label, { htmlFor: path, label: label, required: required }),
|
|
282
|
-
!errorLoading && (React.createElement(
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
!errorLoading && (React.createElement("div", { className: `${baseClass}__wrap` },
|
|
293
|
+
React.createElement(ReactSelect, { isDisabled: readOnly, onInputChange: (newSearch) => handleInputChange(newSearch, value), onChange: !readOnly ? (selected) => {
|
|
294
|
+
if (hasMany) {
|
|
295
|
+
setValue(selected ? selected.map((option) => {
|
|
296
|
+
if (hasMultipleRelations) {
|
|
297
|
+
return {
|
|
298
|
+
relationTo: option.relationTo,
|
|
299
|
+
value: option.value,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return option.value;
|
|
303
|
+
}) : null);
|
|
304
|
+
}
|
|
305
|
+
else if (hasMultipleRelations) {
|
|
306
|
+
setValue({
|
|
307
|
+
relationTo: selected.relationTo,
|
|
308
|
+
value: selected.value,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
setValue(selected.value);
|
|
313
|
+
}
|
|
314
|
+
} : undefined, onMenuScrollToBottom: () => {
|
|
315
|
+
getResults({
|
|
316
|
+
lastFullyLoadedRelation,
|
|
317
|
+
lastLoadedPage: lastLoadedPage + 1,
|
|
318
|
+
search,
|
|
319
|
+
value: initialValue,
|
|
320
|
+
sort: false,
|
|
298
321
|
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
getResults({
|
|
305
|
-
lastFullyLoadedRelation,
|
|
306
|
-
lastLoadedPage: lastLoadedPage + 1,
|
|
307
|
-
search,
|
|
308
|
-
value: initialValue,
|
|
309
|
-
sort: false,
|
|
310
|
-
});
|
|
311
|
-
}, value: valueToRender, showError: showError, disabled: formProcessing, options: options, isMulti: hasMany, isSortable: isSortable, filterOption: enableWordBoundarySearch ? (item, searchFilter) => {
|
|
312
|
-
const r = wordBoundariesRegex(searchFilter || '');
|
|
313
|
-
return r.test(item.label);
|
|
314
|
-
} : undefined })),
|
|
322
|
+
}, value: valueToRender, showError: showError, disabled: formProcessing, options: options, isMulti: hasMany, isSortable: isSortable, filterOption: enableWordBoundarySearch ? (item, searchFilter) => {
|
|
323
|
+
const r = wordBoundariesRegex(searchFilter || '');
|
|
324
|
+
return r.test(item.label);
|
|
325
|
+
} : undefined }),
|
|
326
|
+
!readOnly && (React.createElement(AddNewRelation, { ...{ path, hasMany, relationTo, value, setValue, dispatchOptions } })))),
|
|
315
327
|
errorLoading && (React.createElement("div", { className: `${baseClass}__error-loading` }, errorLoading)),
|
|
316
328
|
React.createElement(FieldDescription, { value: value, description: description })));
|
|
317
329
|
};
|
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
margin-bottom: $baseline;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
background-color: var(--theme-error-500);
|
|
13
|
-
color: var(--theme-elevation-0);
|
|
14
|
-
}
|
|
8
|
+
.relationship {
|
|
9
|
+
&__wrap {
|
|
10
|
+
display: flex;
|
|
11
|
+
width: 100%;
|
|
15
12
|
|
|
16
|
-
.
|
|
17
|
-
|
|
18
|
-
div.rs__control {
|
|
19
|
-
background: var(--theme-elevation-100);
|
|
13
|
+
div.react-select {
|
|
14
|
+
flex-grow: 1;
|
|
20
15
|
}
|
|
21
16
|
}
|
|
22
|
-
|
|
17
|
+
|
|
18
|
+
&__error-loading {
|
|
19
|
+
border: 1px solid var(--theme-error-500);
|
|
20
|
+
min-height: base(2);
|
|
21
|
+
padding: base(.5) base(.75);
|
|
22
|
+
background-color: var(--theme-error-500);
|
|
23
|
+
color: var(--theme-elevation-0);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -23,24 +23,25 @@ const optionsReducer = (state, action) => {
|
|
|
23
23
|
return [];
|
|
24
24
|
}
|
|
25
25
|
case 'ADD': {
|
|
26
|
-
const { hasMultipleRelations, collection,
|
|
26
|
+
const { hasMultipleRelations, collection, docs, sort, ids = [] } = action;
|
|
27
|
+
const relation = collection.slug;
|
|
27
28
|
const labelKey = collection.admin.useAsTitle || 'id';
|
|
28
29
|
const loadedIDs = reduceToIDs(state);
|
|
29
30
|
if (!hasMultipleRelations) {
|
|
30
31
|
const options = [
|
|
31
32
|
...state,
|
|
32
|
-
...
|
|
33
|
+
...docs.reduce((docOptions, doc) => {
|
|
33
34
|
if (loadedIDs.indexOf(doc.id) === -1) {
|
|
34
35
|
loadedIDs.push(doc.id);
|
|
35
36
|
return [
|
|
36
|
-
...
|
|
37
|
+
...docOptions,
|
|
37
38
|
{
|
|
38
39
|
label: doc[labelKey] || `Untitled - ID: ${doc.id}`,
|
|
39
40
|
value: doc.id,
|
|
40
41
|
},
|
|
41
42
|
];
|
|
42
43
|
}
|
|
43
|
-
return
|
|
44
|
+
return docOptions;
|
|
44
45
|
}, []),
|
|
45
46
|
];
|
|
46
47
|
ids.forEach((id) => {
|
|
@@ -55,11 +56,11 @@ const optionsReducer = (state, action) => {
|
|
|
55
56
|
}
|
|
56
57
|
const newOptions = [...state];
|
|
57
58
|
const optionsToAddTo = newOptions.find((optionGroup) => optionGroup.label === collection.labels.plural);
|
|
58
|
-
const newSubOptions =
|
|
59
|
+
const newSubOptions = docs.reduce((docSubOptions, doc) => {
|
|
59
60
|
if (loadedIDs.indexOf(doc.id) === -1) {
|
|
60
61
|
loadedIDs.push(doc.id);
|
|
61
62
|
return [
|
|
62
|
-
...
|
|
63
|
+
...docSubOptions,
|
|
63
64
|
{
|
|
64
65
|
label: doc[labelKey] || `Untitled - ID: ${doc.id}`,
|
|
65
66
|
relationTo: relation,
|
|
@@ -67,7 +68,7 @@ const optionsReducer = (state, action) => {
|
|
|
67
68
|
},
|
|
68
69
|
];
|
|
69
70
|
}
|
|
70
|
-
return
|
|
71
|
+
return docSubOptions;
|
|
71
72
|
}, []);
|
|
72
73
|
ids.forEach((id) => {
|
|
73
74
|
if (!loadedIDs.includes(id)) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SanitizedCollectionConfig } from '../../../../../collections/config/types';
|
|
2
|
-
import { PaginatedDocs } from '../../../../../mongoose/types';
|
|
3
2
|
import { RelationshipField } from '../../../../../fields/config/types';
|
|
4
3
|
export declare type Props = Omit<RelationshipField, 'type'> & {
|
|
5
4
|
path?: string;
|
|
@@ -15,8 +14,7 @@ declare type CLEAR = {
|
|
|
15
14
|
};
|
|
16
15
|
declare type ADD = {
|
|
17
16
|
type: 'ADD';
|
|
18
|
-
|
|
19
|
-
relation: string;
|
|
17
|
+
docs: any[];
|
|
20
18
|
hasMultipleRelations: boolean;
|
|
21
19
|
collection: SanitizedCollectionConfig;
|
|
22
20
|
sort?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { Fragment, useState, useEffect } from 'react';
|
|
2
2
|
import { useConfig } from '../../../../../../../utilities/Config';
|
|
3
3
|
import { useAuth } from '../../../../../../../utilities/Auth';
|
|
4
|
-
import {
|
|
4
|
+
import { useFormFields } from '../../../../../../Form/context';
|
|
5
5
|
import Relationship from '../../../../../Relationship';
|
|
6
6
|
import Select from '../../../../../Select';
|
|
7
7
|
const createOptions = (collections, permissions) => collections.reduce((options, collection) => {
|
|
@@ -21,8 +21,7 @@ const RelationshipFields = () => {
|
|
|
21
21
|
const { collections } = useConfig();
|
|
22
22
|
const { permissions } = useAuth();
|
|
23
23
|
const [options, setOptions] = useState(() => createOptions(collections, permissions));
|
|
24
|
-
const {
|
|
25
|
-
const { relationTo } = getData();
|
|
24
|
+
const relationTo = useFormFields(([fields]) => { var _a; return (_a = fields.relationTo) === null || _a === void 0 ? void 0 : _a.value; });
|
|
26
25
|
useEffect(() => {
|
|
27
26
|
setOptions(createOptions(collections, permissions));
|
|
28
27
|
}, [collections, permissions]);
|
|
@@ -13,7 +13,6 @@ const Textarea = (props) => {
|
|
|
13
13
|
const { value, showError, setValue, errorMessage, } = useField({
|
|
14
14
|
path,
|
|
15
15
|
validate: memoizedValidate,
|
|
16
|
-
enableDebouncedValue: true,
|
|
17
16
|
condition,
|
|
18
17
|
});
|
|
19
18
|
return (React.createElement(TextareaInput, { path: path, name: name, onChange: (e) => {
|