@strapi/content-manager 5.55.0 → 5.56.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/pages/EditView/components/DocumentActions.js +133 -129
- package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.mjs +137 -133
- package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +113 -28
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +113 -29
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +8 -3
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +8 -3
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +27 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +4 -4
- package/dist/server/controllers/relations.js +4 -0
- package/dist/server/controllers/relations.js.map +1 -1
- package/dist/server/controllers/relations.mjs +4 -0
- package/dist/server/controllers/relations.mjs.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/package.json +9 -9
|
@@ -8,41 +8,56 @@ import { useNavigate, useMatch, useParams } from 'react-router-dom';
|
|
|
8
8
|
import { PUBLISHED_AT_ATTRIBUTE_NAME } from '../../../constants/attributes.mjs';
|
|
9
9
|
import { SINGLE_TYPES } from '../../../constants/collections.mjs';
|
|
10
10
|
import { useDocumentRBAC } from '../../../features/DocumentRBAC.mjs';
|
|
11
|
-
import {
|
|
11
|
+
import { useDoc } from '../../../hooks/useDocument.mjs';
|
|
12
12
|
import { useDocumentActions } from '../../../hooks/useDocumentActions.mjs';
|
|
13
13
|
import { useDocumentContext } from '../../../hooks/useDocumentContext.mjs';
|
|
14
14
|
import { usePreviewContext } from '../../../preview/pages/Preview.mjs';
|
|
15
15
|
import { LIST_PATH, CLONE_PATH } from '../../../router.mjs';
|
|
16
|
-
import { useGetDraftRelationCountQuery as useLazyGetDraftRelationCountQuery
|
|
16
|
+
import { useLazyGetDocumentQuery, useGetDraftRelationCountQuery as useLazyGetDraftRelationCountQuery } from '../../../services/documents.mjs';
|
|
17
17
|
import { buildValidParams, isBaseQueryError } from '../../../utils/api.mjs';
|
|
18
|
-
import { getIn,
|
|
18
|
+
import { getIn, isObject } from '../../../utils/objects.mjs';
|
|
19
19
|
import { getTranslation } from '../../../utils/translations.mjs';
|
|
20
20
|
import { handleInvisibleAttributes } from '../utils/data.mjs';
|
|
21
21
|
import { EMPTY_DRAFT_RELATION_COUNTS, countLocalDraftRelations, normalizeDraftRelationCounts, resolveDraftRelationCounts, getDraftRelationsPublishState } from '../utils/draftRelationCounts.mjs';
|
|
22
22
|
import { getEditViewShortcut } from '../utils/keyboardShortcuts.mjs';
|
|
23
|
-
import { useRelationModal } from './FormInputs/Relations/RelationModal.mjs';
|
|
23
|
+
import { useRelationModal, isAnyRelationModalOpen } from './FormInputs/Relations/RelationModal.mjs';
|
|
24
24
|
|
|
25
25
|
const publishConfirmDialogOpeners = new Map();
|
|
26
26
|
const openPublishConfirmDialog = (scope)=>{
|
|
27
27
|
publishConfirmDialogOpeners.get(scope)?.();
|
|
28
28
|
};
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Builds the local-form patch needed to connect a newly created/published relation into the
|
|
31
|
+
* parent's own relation field, given that field's CURRENT (possibly unsaved) live value.
|
|
32
|
+
*
|
|
33
|
+
* This only ever touches the parent's in-memory form state (via `setParentFormValue`, sourced
|
|
34
|
+
* from the parent's own `useForm(...).onChange`) — it deliberately never persists the parent
|
|
35
|
+
* document to the server, so connecting a relation on the fly can't silently save unrelated
|
|
36
|
+
* unsaved edits made elsewhere in the parent's form.
|
|
37
|
+
*/ const buildRelationConnectPatch = (currentFieldValue, fieldToConnect, data, status, fieldToConnectUID)=>{
|
|
38
|
+
// Spread the freshly created/published document first so its own mainField (e.g. `name`) and
|
|
39
|
+
// other attributes — including its real numeric `id`, not just `documentId` — are available.
|
|
40
|
+
// Without the real `id`, the relation field's "already connected" search filter (which keys off
|
|
41
|
+
// `rel.id`) can't recognize this item, so it would stay selectable in the relation combobox
|
|
42
|
+
// even after being connected. Keeping the label/status render correct needs the mainField too,
|
|
43
|
+
// which is why we still spread the whole document rather than only picking id/documentId/locale.
|
|
30
44
|
const relationToConnect = {
|
|
31
|
-
|
|
45
|
+
...data,
|
|
32
46
|
documentId: data.documentId,
|
|
33
|
-
locale: data.locale
|
|
47
|
+
locale: data.locale,
|
|
48
|
+
...status ? {
|
|
49
|
+
status
|
|
50
|
+
} : {}
|
|
34
51
|
};
|
|
35
52
|
/*
|
|
36
|
-
* Check if the fieldToConnect
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
*/ const fieldValue = getIn(parentDataToUpdate, fieldToConnect);
|
|
40
|
-
const relationFieldValue = isObject(fieldValue) ? fieldValue : undefined;
|
|
53
|
+
* Check if the fieldToConnect already has a value. This happens in particular when in the
|
|
54
|
+
* parent document you have created a new component without saving.
|
|
55
|
+
*/ const relationFieldValue = isObject(currentFieldValue) ? currentFieldValue : undefined;
|
|
41
56
|
const isFieldPresent = relationFieldValue !== undefined;
|
|
42
57
|
const fieldPath = fieldToConnect.split('.');
|
|
43
58
|
const fieldName = fieldPath.at(-1);
|
|
44
59
|
if (!fieldName) {
|
|
45
|
-
return
|
|
60
|
+
return null;
|
|
46
61
|
}
|
|
47
62
|
const parentPath = fieldPath.slice(0, -1).join('.');
|
|
48
63
|
const existingConnect = Array.isArray(relationFieldValue?.connect) ? relationFieldValue.connect : [];
|
|
@@ -58,11 +73,10 @@ const connectRelationToParent = (parentDataToUpdate, fieldToConnect, data, field
|
|
|
58
73
|
connect,
|
|
59
74
|
disconnect: []
|
|
60
75
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
return dataWithRelation;
|
|
76
|
+
return {
|
|
77
|
+
relationValue,
|
|
78
|
+
componentUIDPath: !isFieldPresent && fieldToConnectUID && parentPath ? `${parentPath}.__component` : undefined
|
|
79
|
+
};
|
|
66
80
|
};
|
|
67
81
|
const DocumentActions = ({ actions })=>{
|
|
68
82
|
const { formatMessage } = useIntl();
|
|
@@ -447,18 +461,6 @@ const transformData = (data)=>{
|
|
|
447
461
|
return data;
|
|
448
462
|
};
|
|
449
463
|
const transformDocumentData = (data)=>transformData(data);
|
|
450
|
-
const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentFormValues, options)=>{
|
|
451
|
-
const parentDataToUpdate = parentFormValues ?? fallbackParentFormValues;
|
|
452
|
-
if (!parentDataToUpdate) {
|
|
453
|
-
return parentDataToUpdate;
|
|
454
|
-
}
|
|
455
|
-
const { data } = handleInvisibleAttributes(transformDocumentData(parentDataToUpdate), {
|
|
456
|
-
...options,
|
|
457
|
-
// The live snapshot can omit saved invisible fields, so retain the parent's saved initial values.
|
|
458
|
-
initialValues: fallbackParentFormValues
|
|
459
|
-
});
|
|
460
|
-
return data;
|
|
461
|
-
};
|
|
462
464
|
/* -------------------------------------------------------------------------------------------------
|
|
463
465
|
* DocumentActionComponents
|
|
464
466
|
* -----------------------------------------------------------------------------------------------*/ const PublishAction = ({ activeTab, documentId, model, collectionType, meta, document })=>{
|
|
@@ -476,6 +478,7 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
476
478
|
}));
|
|
477
479
|
const { publish, isLoading } = useDocumentActions();
|
|
478
480
|
const onPreview = usePreviewContext('PublishAction', (state)=>state.onPreview, false);
|
|
481
|
+
const [fetchDraftDocument] = useLazyGetDocumentQuery();
|
|
479
482
|
const [countDraftRelations, { isError: isErrorDraftRelations }] = useLazyGetDraftRelationCountQuery();
|
|
480
483
|
const [localDraftRelationCounts, setLocalDraftRelationCounts] = React.useState(EMPTY_DRAFT_RELATION_COUNTS);
|
|
481
484
|
const [serverDraftRelationCounts, setServerDraftRelationCounts] = React.useState(EMPTY_DRAFT_RELATION_COUNTS);
|
|
@@ -493,18 +496,15 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
493
496
|
// need to discriminate if the publish is coming from a relation modal or in the edit view
|
|
494
497
|
const relationContext = useRelationModal('PublishAction', ()=>true, false);
|
|
495
498
|
const fromRelationModal = relationContext != undefined;
|
|
496
|
-
const isRelationModalOpen = useRelationModal('PublishAction', (state)=>state.state.isModalOpen, false);
|
|
497
499
|
const publishConfirmScope = fromRelationModal ? 'relation-modal' : onPreview ? 'preview' : 'panel';
|
|
498
500
|
const dispatch = useRelationModal('PublishAction', (state)=>state.dispatch);
|
|
499
501
|
const fieldToConnect = useRelationModal('PublishAction', (state)=>state.state.fieldToConnect, false);
|
|
500
502
|
const fieldToConnectUID = useRelationModal('PublishAction', (state)=>state.state.fieldToConnectUID, false);
|
|
501
503
|
const getParentFormValues = useRelationModal('PublishAction', (state)=>state.state.getParentFormValues, false);
|
|
504
|
+
const setParentFormValue = useRelationModal('PublishAction', (state)=>state.state.setParentFormValue, false);
|
|
502
505
|
const documentHistory = useRelationModal('PublishAction', (state)=>state.state.documentHistory, false);
|
|
503
|
-
const rootDocumentMeta = useRelationModal('PublishAction', (state)=>state.rootDocumentMeta);
|
|
504
506
|
const dispatchGuidedTour = useGuidedTour('PublishAction', (s)=>s.dispatch);
|
|
505
507
|
const { currentDocumentMeta } = useDocumentContext('PublishAction');
|
|
506
|
-
const [updateDocumentMutation] = useUpdateDocumentMutation();
|
|
507
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
|
508
508
|
const idToPublish = currentDocumentMeta.documentId || id;
|
|
509
509
|
React.useEffect(()=>{
|
|
510
510
|
if (isErrorDraftRelations) {
|
|
@@ -577,16 +577,6 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
577
577
|
}, [
|
|
578
578
|
fetchDraftRelationsCount
|
|
579
579
|
]);
|
|
580
|
-
const parentDocumentMetaToUpdate = documentHistory?.at(-2) ?? rootDocumentMeta;
|
|
581
|
-
const parentDocumentData = useDocument({
|
|
582
|
-
documentId: parentDocumentMetaToUpdate?.documentId,
|
|
583
|
-
model: parentDocumentMetaToUpdate?.model,
|
|
584
|
-
collectionType: parentDocumentMetaToUpdate?.collectionType,
|
|
585
|
-
params: parentDocumentMetaToUpdate?.params
|
|
586
|
-
}, {
|
|
587
|
-
skip: !parentDocumentMetaToUpdate
|
|
588
|
-
});
|
|
589
|
-
const { getInitialFormValues } = useDoc();
|
|
590
580
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc)=>doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== 'modified';
|
|
591
581
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
592
582
|
const performPublish = async ()=>{
|
|
@@ -643,6 +633,17 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
643
633
|
// Reset form with current values as new initial values (clears errors/submitting and sets modified to false)
|
|
644
634
|
if ('data' in res) {
|
|
645
635
|
resetForm(getValues());
|
|
636
|
+
// This document is now persisted with whatever local connect patches were merged into
|
|
637
|
+
// it, if any (see the pendingConnects explanation below) — they'd be stale from here on.
|
|
638
|
+
dispatch?.({
|
|
639
|
+
type: 'CLEAR_PENDING_CONNECTS',
|
|
640
|
+
payload: {
|
|
641
|
+
documentMeta: {
|
|
642
|
+
model,
|
|
643
|
+
documentId: res.data.documentId
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
});
|
|
646
647
|
dispatchGuidedTour({
|
|
647
648
|
type: 'set_completed_actions',
|
|
648
649
|
payload: [
|
|
@@ -668,42 +669,45 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
668
669
|
params: currentDocumentMeta.params
|
|
669
670
|
};
|
|
670
671
|
/*
|
|
671
|
-
*
|
|
672
|
-
*
|
|
673
|
-
*
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
672
|
+
* Connect the newly published document to the parent's relation field, purely in local
|
|
673
|
+
* form state — never on the server. This must not persist the parent document,
|
|
674
|
+
* otherwise publishing here would silently save any of the parent's other unrelated
|
|
675
|
+
* unsaved edits too.
|
|
676
|
+
*
|
|
677
|
+
* The parent is either the root document that originally opened the modal (its own Form
|
|
678
|
+
* stays mounted for the whole session, so it's safe to write into directly) or a nested
|
|
679
|
+
* document still further up the modal's documentHistory (whose Form is the SAME shared
|
|
680
|
+
* instance the modal reuses at every level, wholesale-replaced on every navigation — a
|
|
681
|
+
* direct write there would land on the wrong document and be gone the moment we
|
|
682
|
+
* navigate). For the latter the patch is queued on GO_TO_CREATED_RELATION below instead,
|
|
683
|
+
* to be re-applied once that document becomes current again.
|
|
684
|
+
*/ const isNestedParent = Array.isArray(documentHistory) && documentHistory.length >= 2;
|
|
685
|
+
let connectPatch;
|
|
686
|
+
if (fieldToConnect && (setParentFormValue || isNestedParent)) {
|
|
687
|
+
const currentFieldValue = getIn(getParentFormValues?.(), fieldToConnect);
|
|
688
|
+
// Publishing a brand-new document creates two rows sharing one documentId — a draft
|
|
689
|
+
// and a published one, each with its own numeric id. The parent's relation search
|
|
690
|
+
// (and its "already connected" filter) identifies items by the draft row's id, so
|
|
691
|
+
// connecting with the publish response's id would leave this relation still
|
|
692
|
+
// selectable there. Fetch the draft row to get the id the search actually expects.
|
|
693
|
+
const draftDocument = await fetchDraftDocument({
|
|
694
|
+
collectionType,
|
|
695
|
+
model,
|
|
696
|
+
documentId: res.data.documentId,
|
|
697
|
+
params: currentDocumentMeta.params
|
|
679
698
|
});
|
|
680
|
-
const
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
toggleNotification({
|
|
693
|
-
type: 'danger',
|
|
694
|
-
message: formatAPIError(updateRes.error)
|
|
695
|
-
});
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
|
-
} catch (err) {
|
|
699
|
-
toggleNotification({
|
|
700
|
-
type: 'danger',
|
|
701
|
-
message: formatMessage({
|
|
702
|
-
id: 'notification.error',
|
|
703
|
-
defaultMessage: 'An error occurred'
|
|
704
|
-
})
|
|
705
|
-
});
|
|
706
|
-
throw err;
|
|
699
|
+
const patch = buildRelationConnectPatch(currentFieldValue, fieldToConnect, draftDocument.data?.data ?? res.data, 'published', fieldToConnectUID);
|
|
700
|
+
if (patch && isNestedParent) {
|
|
701
|
+
connectPatch = {
|
|
702
|
+
fieldToConnect,
|
|
703
|
+
relationValue: patch.relationValue,
|
|
704
|
+
componentUIDPath: patch.componentUIDPath,
|
|
705
|
+
componentUID: patch.componentUIDPath ? fieldToConnectUID : undefined
|
|
706
|
+
};
|
|
707
|
+
} else if (patch && setParentFormValue) {
|
|
708
|
+
setParentFormValue(fieldToConnect, patch.relationValue);
|
|
709
|
+
if (patch.componentUIDPath) {
|
|
710
|
+
setParentFormValue(patch.componentUIDPath, fieldToConnectUID);
|
|
707
711
|
}
|
|
708
712
|
}
|
|
709
713
|
}
|
|
@@ -711,7 +715,8 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
711
715
|
type: 'GO_TO_CREATED_RELATION',
|
|
712
716
|
payload: {
|
|
713
717
|
document: newRelation,
|
|
714
|
-
shouldBypassConfirmation: true
|
|
718
|
+
shouldBypassConfirmation: true,
|
|
719
|
+
connectPatch
|
|
715
720
|
}
|
|
716
721
|
});
|
|
717
722
|
}
|
|
@@ -757,7 +762,9 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
757
762
|
return;
|
|
758
763
|
}
|
|
759
764
|
e.preventDefault();
|
|
760
|
-
|
|
765
|
+
// When a relation modal is open, only its own PublishAction instance (fromRelationModal)
|
|
766
|
+
// should react to the shortcut — otherwise the background entry publishes at the same time.
|
|
767
|
+
if (!fromRelationModal && isAnyRelationModalOpen()) {
|
|
761
768
|
return;
|
|
762
769
|
}
|
|
763
770
|
if (isDisabled) {
|
|
@@ -777,7 +784,6 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
|
|
|
777
784
|
fromRelationModal,
|
|
778
785
|
getFreshDraftRelationCounts,
|
|
779
786
|
isDisabled,
|
|
780
|
-
isRelationModalOpen,
|
|
781
787
|
performPublish,
|
|
782
788
|
publishConfirmScope,
|
|
783
789
|
schema?.options?.draftAndPublish
|
|
@@ -873,7 +879,6 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
873
879
|
const { currentDocument: { components } } = useDocumentContext('UpdateAction');
|
|
874
880
|
const [{ rawQuery }] = useQueryParams();
|
|
875
881
|
const onPreview = usePreviewContext('UpdateAction', (state)=>state.onPreview, false);
|
|
876
|
-
const { getInitialFormValues } = useDoc();
|
|
877
882
|
const isSubmitting = useForm('UpdateAction', ({ isSubmitting })=>isSubmitting);
|
|
878
883
|
const modified = useForm('UpdateAction', ({ modified })=>modified);
|
|
879
884
|
const setSubmitting = useForm('UpdateAction', ({ setSubmitting })=>setSubmitting);
|
|
@@ -889,21 +894,10 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
889
894
|
const fieldToConnect = useRelationModal('UpdateAction', (state)=>state.state.fieldToConnect, false);
|
|
890
895
|
const fieldToConnectUID = useRelationModal('PublishAction', (state)=>state.state.fieldToConnectUID, false);
|
|
891
896
|
const getParentFormValues = useRelationModal('UpdateAction', (state)=>state.state.getParentFormValues, false);
|
|
897
|
+
const setParentFormValue = useRelationModal('UpdateAction', (state)=>state.state.setParentFormValue, false);
|
|
892
898
|
const documentHistory = useRelationModal('UpdateAction', (state)=>state.state.documentHistory, false);
|
|
893
|
-
const rootDocumentMeta = useRelationModal('UpdateAction', (state)=>state.rootDocumentMeta);
|
|
894
899
|
const fromRelationModal = relationContext != undefined;
|
|
895
900
|
const { currentDocumentMeta } = useDocumentContext('UpdateAction');
|
|
896
|
-
const [updateDocumentMutation] = useUpdateDocumentMutation();
|
|
897
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
|
898
|
-
const parentDocumentMetaToUpdate = documentHistory?.at(-2) ?? rootDocumentMeta;
|
|
899
|
-
const parentDocumentData = useDocument({
|
|
900
|
-
documentId: parentDocumentMetaToUpdate?.documentId,
|
|
901
|
-
model: parentDocumentMetaToUpdate?.model,
|
|
902
|
-
collectionType: parentDocumentMetaToUpdate?.collectionType,
|
|
903
|
-
params: parentDocumentMetaToUpdate?.params
|
|
904
|
-
}, {
|
|
905
|
-
skip: !parentDocumentMetaToUpdate
|
|
906
|
-
});
|
|
907
901
|
const { schema } = useDoc();
|
|
908
902
|
const suitableSchema = fromRelationModal ? relationalModalSchema : schema;
|
|
909
903
|
const hasDraftAndPublished = suitableSchema?.options?.draftAndPublish ?? false;
|
|
@@ -975,6 +969,17 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
975
969
|
setErrors(formatValidationErrors(res.error));
|
|
976
970
|
} else {
|
|
977
971
|
resetForm(latestValues);
|
|
972
|
+
// This document is now persisted with whatever local connect patches were merged into
|
|
973
|
+
// it, if any (see the pendingConnects explanation below) — they'd be stale from here on.
|
|
974
|
+
dispatch?.({
|
|
975
|
+
type: 'CLEAR_PENDING_CONNECTS',
|
|
976
|
+
payload: {
|
|
977
|
+
documentMeta: {
|
|
978
|
+
model,
|
|
979
|
+
documentId
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
});
|
|
978
983
|
}
|
|
979
984
|
} else {
|
|
980
985
|
const { data } = handleInvisibleAttributes(transformDocumentData(latestValues), {
|
|
@@ -995,43 +1000,34 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
995
1000
|
params: currentDocumentMeta.params
|
|
996
1001
|
};
|
|
997
1002
|
/*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1000
|
-
*
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
} catch (err) {
|
|
1027
|
-
toggleNotification({
|
|
1028
|
-
type: 'danger',
|
|
1029
|
-
message: formatMessage({
|
|
1030
|
-
id: 'notification.error',
|
|
1031
|
-
defaultMessage: 'An error occurred'
|
|
1032
|
-
})
|
|
1033
|
-
});
|
|
1034
|
-
throw err;
|
|
1003
|
+
* Connect the newly created document to the parent's relation field, purely in local
|
|
1004
|
+
* form state — never on the server. This must not persist the parent document,
|
|
1005
|
+
* otherwise saving here would silently save any of the parent's other unrelated
|
|
1006
|
+
* unsaved edits too.
|
|
1007
|
+
*
|
|
1008
|
+
* The parent is either the root document that originally opened the modal (its own
|
|
1009
|
+
* Form stays mounted for the whole session, so it's safe to write into directly) or a
|
|
1010
|
+
* nested document still further up the modal's documentHistory (whose Form is the
|
|
1011
|
+
* SAME shared instance the modal reuses at every level, wholesale-replaced on every
|
|
1012
|
+
* navigation — a direct write there would land on the wrong document and be gone the
|
|
1013
|
+
* moment we navigate). For the latter the patch is queued on GO_TO_CREATED_RELATION
|
|
1014
|
+
* below instead, to be re-applied once that document becomes current again.
|
|
1015
|
+
*/ const isNestedParent = Array.isArray(documentHistory) && documentHistory.length >= 2;
|
|
1016
|
+
let connectPatch;
|
|
1017
|
+
if (fieldToConnect && (setParentFormValue || isNestedParent)) {
|
|
1018
|
+
const currentFieldValue = getIn(getParentFormValues?.(), fieldToConnect);
|
|
1019
|
+
const patch = buildRelationConnectPatch(currentFieldValue, fieldToConnect, res.data, hasDraftAndPublished ? 'draft' : undefined, fieldToConnectUID);
|
|
1020
|
+
if (patch && isNestedParent) {
|
|
1021
|
+
connectPatch = {
|
|
1022
|
+
fieldToConnect,
|
|
1023
|
+
relationValue: patch.relationValue,
|
|
1024
|
+
componentUIDPath: patch.componentUIDPath,
|
|
1025
|
+
componentUID: patch.componentUIDPath ? fieldToConnectUID : undefined
|
|
1026
|
+
};
|
|
1027
|
+
} else if (patch && setParentFormValue) {
|
|
1028
|
+
setParentFormValue(fieldToConnect, patch.relationValue);
|
|
1029
|
+
if (patch.componentUIDPath) {
|
|
1030
|
+
setParentFormValue(patch.componentUIDPath, fieldToConnectUID);
|
|
1035
1031
|
}
|
|
1036
1032
|
}
|
|
1037
1033
|
}
|
|
@@ -1039,7 +1035,8 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
1039
1035
|
type: 'GO_TO_CREATED_RELATION',
|
|
1040
1036
|
payload: {
|
|
1041
1037
|
document: createdRelation,
|
|
1042
|
-
shouldBypassConfirmation: true
|
|
1038
|
+
shouldBypassConfirmation: true,
|
|
1039
|
+
connectPatch
|
|
1043
1040
|
}
|
|
1044
1041
|
});
|
|
1045
1042
|
} else {
|
|
@@ -1076,12 +1073,19 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
|
|
|
1076
1073
|
handleUpdateRef.current = handleUpdate;
|
|
1077
1074
|
const isDisabledRef = React.useRef(isDisabled);
|
|
1078
1075
|
isDisabledRef.current = isDisabled;
|
|
1076
|
+
const fromRelationModalRef = React.useRef(fromRelationModal);
|
|
1077
|
+
fromRelationModalRef.current = fromRelationModal;
|
|
1079
1078
|
React.useEffect(()=>{
|
|
1080
1079
|
const handleKeyDown = (e)=>{
|
|
1081
1080
|
if (getEditViewShortcut(e) !== 'save') {
|
|
1082
1081
|
return;
|
|
1083
1082
|
}
|
|
1084
1083
|
e.preventDefault();
|
|
1084
|
+
// When a relation modal is open, only its own UpdateAction instance (fromRelationModal)
|
|
1085
|
+
// should react to the shortcut — otherwise the background entry saves at the same time.
|
|
1086
|
+
if (!fromRelationModalRef.current && isAnyRelationModalOpen()) {
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1085
1089
|
if (!isDisabledRef.current) {
|
|
1086
1090
|
handleUpdateRef.current();
|
|
1087
1091
|
}
|