@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.
Files changed (21) hide show
  1. package/dist/admin/pages/EditView/components/DocumentActions.js +133 -129
  2. package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
  3. package/dist/admin/pages/EditView/components/DocumentActions.mjs +137 -133
  4. package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
  5. package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +113 -28
  6. package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
  7. package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +113 -29
  8. package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
  9. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +8 -3
  10. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
  11. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +8 -3
  12. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
  13. package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +27 -5
  14. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +2 -2
  15. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +4 -4
  16. package/dist/server/controllers/relations.js +4 -0
  17. package/dist/server/controllers/relations.js.map +1 -1
  18. package/dist/server/controllers/relations.mjs +4 -0
  19. package/dist/server/controllers/relations.mjs.map +1 -1
  20. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  21. package/package.json +9 -9
@@ -48,23 +48,38 @@ const publishConfirmDialogOpeners = new Map();
48
48
  const openPublishConfirmDialog = (scope)=>{
49
49
  publishConfirmDialogOpeners.get(scope)?.();
50
50
  };
51
- const connectRelationToParent = (parentDataToUpdate, fieldToConnect, data, fieldToConnectUID)=>{
51
+ /**
52
+ * Builds the local-form patch needed to connect a newly created/published relation into the
53
+ * parent's own relation field, given that field's CURRENT (possibly unsaved) live value.
54
+ *
55
+ * This only ever touches the parent's in-memory form state (via `setParentFormValue`, sourced
56
+ * from the parent's own `useForm(...).onChange`) — it deliberately never persists the parent
57
+ * document to the server, so connecting a relation on the fly can't silently save unrelated
58
+ * unsaved edits made elsewhere in the parent's form.
59
+ */ const buildRelationConnectPatch = (currentFieldValue, fieldToConnect, data, status, fieldToConnectUID)=>{
60
+ // Spread the freshly created/published document first so its own mainField (e.g. `name`) and
61
+ // other attributes — including its real numeric `id`, not just `documentId` — are available.
62
+ // Without the real `id`, the relation field's "already connected" search filter (which keys off
63
+ // `rel.id`) can't recognize this item, so it would stay selectable in the relation combobox
64
+ // even after being connected. Keeping the label/status render correct needs the mainField too,
65
+ // which is why we still spread the whole document rather than only picking id/documentId/locale.
52
66
  const relationToConnect = {
53
- id: data.documentId,
67
+ ...data,
54
68
  documentId: data.documentId,
55
- locale: data.locale
69
+ locale: data.locale,
70
+ ...status ? {
71
+ status
72
+ } : {}
56
73
  };
57
74
  /*
58
- * Check if the fieldToConnect is already present in the parentDataToUpdate.
59
- * This happens in particular when in the parentDocument you have created
60
- * a new component without saving.
61
- */ const fieldValue = objects.getIn(parentDataToUpdate, fieldToConnect);
62
- const relationFieldValue = objects.isObject(fieldValue) ? fieldValue : undefined;
75
+ * Check if the fieldToConnect already has a value. This happens in particular when in the
76
+ * parent document you have created a new component without saving.
77
+ */ const relationFieldValue = objects.isObject(currentFieldValue) ? currentFieldValue : undefined;
63
78
  const isFieldPresent = relationFieldValue !== undefined;
64
79
  const fieldPath = fieldToConnect.split('.');
65
80
  const fieldName = fieldPath.at(-1);
66
81
  if (!fieldName) {
67
- return parentDataToUpdate;
82
+ return null;
68
83
  }
69
84
  const parentPath = fieldPath.slice(0, -1).join('.');
70
85
  const existingConnect = Array.isArray(relationFieldValue?.connect) ? relationFieldValue.connect : [];
@@ -80,11 +95,10 @@ const connectRelationToParent = (parentDataToUpdate, fieldToConnect, data, field
80
95
  connect,
81
96
  disconnect: []
82
97
  };
83
- const dataWithRelation = objects.setIn(parentDataToUpdate, fieldToConnect, relationValue);
84
- if (!isFieldPresent && fieldToConnectUID && parentPath) {
85
- return objects.setIn(dataWithRelation, `${parentPath}.__component`, fieldToConnectUID);
86
- }
87
- return dataWithRelation;
98
+ return {
99
+ relationValue,
100
+ componentUIDPath: !isFieldPresent && fieldToConnectUID && parentPath ? `${parentPath}.__component` : undefined
101
+ };
88
102
  };
89
103
  const DocumentActions = ({ actions })=>{
90
104
  const { formatMessage } = reactIntl.useIntl();
@@ -469,18 +483,6 @@ const transformData = (data)=>{
469
483
  return data;
470
484
  };
471
485
  const transformDocumentData = (data)=>transformData(data);
472
- const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentFormValues, options)=>{
473
- const parentDataToUpdate = parentFormValues ?? fallbackParentFormValues;
474
- if (!parentDataToUpdate) {
475
- return parentDataToUpdate;
476
- }
477
- const { data: data$1 } = data.handleInvisibleAttributes(transformDocumentData(parentDataToUpdate), {
478
- ...options,
479
- // The live snapshot can omit saved invisible fields, so retain the parent's saved initial values.
480
- initialValues: fallbackParentFormValues
481
- });
482
- return data$1;
483
- };
484
486
  /* -------------------------------------------------------------------------------------------------
485
487
  * DocumentActionComponents
486
488
  * -----------------------------------------------------------------------------------------------*/ const PublishAction = ({ activeTab, documentId, model, collectionType, meta, document })=>{
@@ -498,6 +500,7 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
498
500
  }));
499
501
  const { publish, isLoading } = useDocumentActions.useDocumentActions();
500
502
  const onPreview = Preview.usePreviewContext('PublishAction', (state)=>state.onPreview, false);
503
+ const [fetchDraftDocument] = documents.useLazyGetDocumentQuery();
501
504
  const [countDraftRelations, { isError: isErrorDraftRelations }] = documents.useGetDraftRelationCountQuery();
502
505
  const [localDraftRelationCounts, setLocalDraftRelationCounts] = React__namespace.useState(draftRelationCounts.EMPTY_DRAFT_RELATION_COUNTS);
503
506
  const [serverDraftRelationCounts, setServerDraftRelationCounts] = React__namespace.useState(draftRelationCounts.EMPTY_DRAFT_RELATION_COUNTS);
@@ -515,18 +518,15 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
515
518
  // need to discriminate if the publish is coming from a relation modal or in the edit view
516
519
  const relationContext = RelationModal.useRelationModal('PublishAction', ()=>true, false);
517
520
  const fromRelationModal = relationContext != undefined;
518
- const isRelationModalOpen = RelationModal.useRelationModal('PublishAction', (state)=>state.state.isModalOpen, false);
519
521
  const publishConfirmScope = fromRelationModal ? 'relation-modal' : onPreview ? 'preview' : 'panel';
520
522
  const dispatch = RelationModal.useRelationModal('PublishAction', (state)=>state.dispatch);
521
523
  const fieldToConnect = RelationModal.useRelationModal('PublishAction', (state)=>state.state.fieldToConnect, false);
522
524
  const fieldToConnectUID = RelationModal.useRelationModal('PublishAction', (state)=>state.state.fieldToConnectUID, false);
523
525
  const getParentFormValues = RelationModal.useRelationModal('PublishAction', (state)=>state.state.getParentFormValues, false);
526
+ const setParentFormValue = RelationModal.useRelationModal('PublishAction', (state)=>state.state.setParentFormValue, false);
524
527
  const documentHistory = RelationModal.useRelationModal('PublishAction', (state)=>state.state.documentHistory, false);
525
- const rootDocumentMeta = RelationModal.useRelationModal('PublishAction', (state)=>state.rootDocumentMeta);
526
528
  const dispatchGuidedTour = strapiAdmin.useGuidedTour('PublishAction', (s)=>s.dispatch);
527
529
  const { currentDocumentMeta } = useDocumentContext.useDocumentContext('PublishAction');
528
- const [updateDocumentMutation] = documents.useUpdateDocumentMutation();
529
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
530
530
  const idToPublish = currentDocumentMeta.documentId || id;
531
531
  React__namespace.useEffect(()=>{
532
532
  if (isErrorDraftRelations) {
@@ -599,16 +599,6 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
599
599
  }, [
600
600
  fetchDraftRelationsCount
601
601
  ]);
602
- const parentDocumentMetaToUpdate = documentHistory?.at(-2) ?? rootDocumentMeta;
603
- const parentDocumentData = useDocument.useDocument({
604
- documentId: parentDocumentMetaToUpdate?.documentId,
605
- model: parentDocumentMetaToUpdate?.model,
606
- collectionType: parentDocumentMetaToUpdate?.collectionType,
607
- params: parentDocumentMetaToUpdate?.params
608
- }, {
609
- skip: !parentDocumentMetaToUpdate
610
- });
611
- const { getInitialFormValues } = useDocument.useDoc();
612
602
  const isDocumentPublished = (document?.[attributes.PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc)=>doc[attributes.PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== 'modified';
613
603
  // eslint-disable-next-line react-hooks/exhaustive-deps
614
604
  const performPublish = async ()=>{
@@ -665,6 +655,17 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
665
655
  // Reset form with current values as new initial values (clears errors/submitting and sets modified to false)
666
656
  if ('data' in res) {
667
657
  resetForm(getValues());
658
+ // This document is now persisted with whatever local connect patches were merged into
659
+ // it, if any (see the pendingConnects explanation below) — they'd be stale from here on.
660
+ dispatch?.({
661
+ type: 'CLEAR_PENDING_CONNECTS',
662
+ payload: {
663
+ documentMeta: {
664
+ model,
665
+ documentId: res.data.documentId
666
+ }
667
+ }
668
+ });
668
669
  dispatchGuidedTour({
669
670
  type: 'set_completed_actions',
670
671
  payload: [
@@ -690,42 +691,45 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
690
691
  params: currentDocumentMeta.params
691
692
  };
692
693
  /*
693
- * Update, if needed, the parent relation with the newly published document.
694
- * Check if in history we have the parent relation otherwise use the
695
- * rootDocument
696
- */ if (fieldToConnect && documentHistory && (parentDocumentMetaToUpdate.documentId || parentDocumentMetaToUpdate.collectionType === collections.SINGLE_TYPES)) {
697
- const fallbackParentFormValues = parentDocumentMetaToUpdate.collectionType === collections.SINGLE_TYPES ? getInitialFormValues() : parentDocumentData.getInitialFormValues();
698
- const parentDataToUpdate = prepareParentDataForRelationUpdate(getParentFormValues?.(), fallbackParentFormValues, {
699
- schema: parentDocumentData.schema,
700
- components: parentDocumentData.components
694
+ * Connect the newly published document to the parent's relation field, purely in local
695
+ * form state — never on the server. This must not persist the parent document,
696
+ * otherwise publishing here would silently save any of the parent's other unrelated
697
+ * unsaved edits too.
698
+ *
699
+ * The parent is either the root document that originally opened the modal (its own Form
700
+ * stays mounted for the whole session, so it's safe to write into directly) or a nested
701
+ * document still further up the modal's documentHistory (whose Form is the SAME shared
702
+ * instance the modal reuses at every level, wholesale-replaced on every navigation — a
703
+ * direct write there would land on the wrong document and be gone the moment we
704
+ * navigate). For the latter the patch is queued on GO_TO_CREATED_RELATION below instead,
705
+ * to be re-applied once that document becomes current again.
706
+ */ const isNestedParent = Array.isArray(documentHistory) && documentHistory.length >= 2;
707
+ let connectPatch;
708
+ if (fieldToConnect && (setParentFormValue || isNestedParent)) {
709
+ const currentFieldValue = objects.getIn(getParentFormValues?.(), fieldToConnect);
710
+ // Publishing a brand-new document creates two rows sharing one documentId — a draft
711
+ // and a published one, each with its own numeric id. The parent's relation search
712
+ // (and its "already connected" filter) identifies items by the draft row's id, so
713
+ // connecting with the publish response's id would leave this relation still
714
+ // selectable there. Fetch the draft row to get the id the search actually expects.
715
+ const draftDocument = await fetchDraftDocument({
716
+ collectionType,
717
+ model,
718
+ documentId: res.data.documentId,
719
+ params: currentDocumentMeta.params
701
720
  });
702
- const metaDocumentToUpdate = documentHistory.at(-2) ?? rootDocumentMeta;
703
- if (parentDataToUpdate) {
704
- const dataToUpdate = connectRelationToParent(parentDataToUpdate, fieldToConnect, res.data, fieldToConnectUID);
705
- try {
706
- const updateRes = await updateDocumentMutation({
707
- collectionType: metaDocumentToUpdate.collectionType,
708
- model: metaDocumentToUpdate.model,
709
- documentId: metaDocumentToUpdate.collectionType !== collections.SINGLE_TYPES ? metaDocumentToUpdate.documentId : undefined,
710
- params: metaDocumentToUpdate.params,
711
- data: dataToUpdate
712
- });
713
- if ('error' in updateRes) {
714
- toggleNotification({
715
- type: 'danger',
716
- message: formatAPIError(updateRes.error)
717
- });
718
- return;
719
- }
720
- } catch (err) {
721
- toggleNotification({
722
- type: 'danger',
723
- message: formatMessage({
724
- id: 'notification.error',
725
- defaultMessage: 'An error occurred'
726
- })
727
- });
728
- throw err;
721
+ const patch = buildRelationConnectPatch(currentFieldValue, fieldToConnect, draftDocument.data?.data ?? res.data, 'published', fieldToConnectUID);
722
+ if (patch && isNestedParent) {
723
+ connectPatch = {
724
+ fieldToConnect,
725
+ relationValue: patch.relationValue,
726
+ componentUIDPath: patch.componentUIDPath,
727
+ componentUID: patch.componentUIDPath ? fieldToConnectUID : undefined
728
+ };
729
+ } else if (patch && setParentFormValue) {
730
+ setParentFormValue(fieldToConnect, patch.relationValue);
731
+ if (patch.componentUIDPath) {
732
+ setParentFormValue(patch.componentUIDPath, fieldToConnectUID);
729
733
  }
730
734
  }
731
735
  }
@@ -733,7 +737,8 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
733
737
  type: 'GO_TO_CREATED_RELATION',
734
738
  payload: {
735
739
  document: newRelation,
736
- shouldBypassConfirmation: true
740
+ shouldBypassConfirmation: true,
741
+ connectPatch
737
742
  }
738
743
  });
739
744
  }
@@ -779,7 +784,9 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
779
784
  return;
780
785
  }
781
786
  e.preventDefault();
782
- if (!fromRelationModal && isRelationModalOpen) {
787
+ // When a relation modal is open, only its own PublishAction instance (fromRelationModal)
788
+ // should react to the shortcut — otherwise the background entry publishes at the same time.
789
+ if (!fromRelationModal && RelationModal.isAnyRelationModalOpen()) {
783
790
  return;
784
791
  }
785
792
  if (isDisabled) {
@@ -799,7 +806,6 @@ const prepareParentDataForRelationUpdate = (parentFormValues, fallbackParentForm
799
806
  fromRelationModal,
800
807
  getFreshDraftRelationCounts,
801
808
  isDisabled,
802
- isRelationModalOpen,
803
809
  performPublish,
804
810
  publishConfirmScope,
805
811
  schema?.options?.draftAndPublish
@@ -895,7 +901,6 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
895
901
  const { currentDocument: { components } } = useDocumentContext.useDocumentContext('UpdateAction');
896
902
  const [{ rawQuery }] = strapiAdmin.useQueryParams();
897
903
  const onPreview = Preview.usePreviewContext('UpdateAction', (state)=>state.onPreview, false);
898
- const { getInitialFormValues } = useDocument.useDoc();
899
904
  const isSubmitting = strapiAdmin.useForm('UpdateAction', ({ isSubmitting })=>isSubmitting);
900
905
  const modified = strapiAdmin.useForm('UpdateAction', ({ modified })=>modified);
901
906
  const setSubmitting = strapiAdmin.useForm('UpdateAction', ({ setSubmitting })=>setSubmitting);
@@ -911,21 +916,10 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
911
916
  const fieldToConnect = RelationModal.useRelationModal('UpdateAction', (state)=>state.state.fieldToConnect, false);
912
917
  const fieldToConnectUID = RelationModal.useRelationModal('PublishAction', (state)=>state.state.fieldToConnectUID, false);
913
918
  const getParentFormValues = RelationModal.useRelationModal('UpdateAction', (state)=>state.state.getParentFormValues, false);
919
+ const setParentFormValue = RelationModal.useRelationModal('UpdateAction', (state)=>state.state.setParentFormValue, false);
914
920
  const documentHistory = RelationModal.useRelationModal('UpdateAction', (state)=>state.state.documentHistory, false);
915
- const rootDocumentMeta = RelationModal.useRelationModal('UpdateAction', (state)=>state.rootDocumentMeta);
916
921
  const fromRelationModal = relationContext != undefined;
917
922
  const { currentDocumentMeta } = useDocumentContext.useDocumentContext('UpdateAction');
918
- const [updateDocumentMutation] = documents.useUpdateDocumentMutation();
919
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
920
- const parentDocumentMetaToUpdate = documentHistory?.at(-2) ?? rootDocumentMeta;
921
- const parentDocumentData = useDocument.useDocument({
922
- documentId: parentDocumentMetaToUpdate?.documentId,
923
- model: parentDocumentMetaToUpdate?.model,
924
- collectionType: parentDocumentMetaToUpdate?.collectionType,
925
- params: parentDocumentMetaToUpdate?.params
926
- }, {
927
- skip: !parentDocumentMetaToUpdate
928
- });
929
923
  const { schema } = useDocument.useDoc();
930
924
  const suitableSchema = fromRelationModal ? relationalModalSchema : schema;
931
925
  const hasDraftAndPublished = suitableSchema?.options?.draftAndPublish ?? false;
@@ -997,6 +991,17 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
997
991
  setErrors(formatValidationErrors(res.error));
998
992
  } else {
999
993
  resetForm(latestValues);
994
+ // This document is now persisted with whatever local connect patches were merged into
995
+ // it, if any (see the pendingConnects explanation below) — they'd be stale from here on.
996
+ dispatch?.({
997
+ type: 'CLEAR_PENDING_CONNECTS',
998
+ payload: {
999
+ documentMeta: {
1000
+ model,
1001
+ documentId
1002
+ }
1003
+ }
1004
+ });
1000
1005
  }
1001
1006
  } else {
1002
1007
  const { data: data$1 } = data.handleInvisibleAttributes(transformDocumentData(latestValues), {
@@ -1017,43 +1022,34 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
1017
1022
  params: currentDocumentMeta.params
1018
1023
  };
1019
1024
  /*
1020
- * Update, if needed, the parent relation with the newly published document.
1021
- * Check if in history we have the parent relation otherwise use the
1022
- * rootDocument
1023
- */ if (fieldToConnect && documentHistory && (parentDocumentMetaToUpdate.documentId || parentDocumentMetaToUpdate.collectionType === collections.SINGLE_TYPES)) {
1024
- const fallbackParentFormValues = parentDocumentMetaToUpdate.collectionType === collections.SINGLE_TYPES ? getInitialFormValues() : parentDocumentData.getInitialFormValues();
1025
- const parentDataToUpdate = prepareParentDataForRelationUpdate(getParentFormValues?.(), fallbackParentFormValues, {
1026
- schema: parentDocumentData.schema,
1027
- components: parentDocumentData.components
1028
- });
1029
- if (parentDataToUpdate) {
1030
- const dataToUpdate = connectRelationToParent(parentDataToUpdate, fieldToConnect, res.data, fieldToConnectUID);
1031
- try {
1032
- const updateRes = await updateDocumentMutation({
1033
- collectionType: parentDocumentMetaToUpdate.collectionType,
1034
- model: parentDocumentMetaToUpdate.model,
1035
- documentId: parentDocumentMetaToUpdate.collectionType !== collections.SINGLE_TYPES ? parentDocumentMetaToUpdate.documentId : undefined,
1036
- params: parentDocumentMetaToUpdate.params,
1037
- data: {
1038
- ...dataToUpdate
1039
- }
1040
- });
1041
- if ('error' in updateRes) {
1042
- toggleNotification({
1043
- type: 'danger',
1044
- message: formatAPIError(updateRes.error)
1045
- });
1046
- return;
1047
- }
1048
- } catch (err) {
1049
- toggleNotification({
1050
- type: 'danger',
1051
- message: formatMessage({
1052
- id: 'notification.error',
1053
- defaultMessage: 'An error occurred'
1054
- })
1055
- });
1056
- throw err;
1025
+ * Connect the newly created document to the parent's relation field, purely in local
1026
+ * form state — never on the server. This must not persist the parent document,
1027
+ * otherwise saving here would silently save any of the parent's other unrelated
1028
+ * unsaved edits too.
1029
+ *
1030
+ * The parent is either the root document that originally opened the modal (its own
1031
+ * Form stays mounted for the whole session, so it's safe to write into directly) or a
1032
+ * nested document still further up the modal's documentHistory (whose Form is the
1033
+ * SAME shared instance the modal reuses at every level, wholesale-replaced on every
1034
+ * navigation — a direct write there would land on the wrong document and be gone the
1035
+ * moment we navigate). For the latter the patch is queued on GO_TO_CREATED_RELATION
1036
+ * below instead, to be re-applied once that document becomes current again.
1037
+ */ const isNestedParent = Array.isArray(documentHistory) && documentHistory.length >= 2;
1038
+ let connectPatch;
1039
+ if (fieldToConnect && (setParentFormValue || isNestedParent)) {
1040
+ const currentFieldValue = objects.getIn(getParentFormValues?.(), fieldToConnect);
1041
+ const patch = buildRelationConnectPatch(currentFieldValue, fieldToConnect, res.data, hasDraftAndPublished ? 'draft' : undefined, fieldToConnectUID);
1042
+ if (patch && isNestedParent) {
1043
+ connectPatch = {
1044
+ fieldToConnect,
1045
+ relationValue: patch.relationValue,
1046
+ componentUIDPath: patch.componentUIDPath,
1047
+ componentUID: patch.componentUIDPath ? fieldToConnectUID : undefined
1048
+ };
1049
+ } else if (patch && setParentFormValue) {
1050
+ setParentFormValue(fieldToConnect, patch.relationValue);
1051
+ if (patch.componentUIDPath) {
1052
+ setParentFormValue(patch.componentUIDPath, fieldToConnectUID);
1057
1053
  }
1058
1054
  }
1059
1055
  }
@@ -1061,7 +1057,8 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
1061
1057
  type: 'GO_TO_CREATED_RELATION',
1062
1058
  payload: {
1063
1059
  document: createdRelation,
1064
- shouldBypassConfirmation: true
1060
+ shouldBypassConfirmation: true,
1061
+ connectPatch
1065
1062
  }
1066
1063
  });
1067
1064
  } else {
@@ -1098,12 +1095,19 @@ const UpdateAction = ({ activeTab, documentId, model, collectionType })=>{
1098
1095
  handleUpdateRef.current = handleUpdate;
1099
1096
  const isDisabledRef = React__namespace.useRef(isDisabled);
1100
1097
  isDisabledRef.current = isDisabled;
1098
+ const fromRelationModalRef = React__namespace.useRef(fromRelationModal);
1099
+ fromRelationModalRef.current = fromRelationModal;
1101
1100
  React__namespace.useEffect(()=>{
1102
1101
  const handleKeyDown = (e)=>{
1103
1102
  if (keyboardShortcuts.getEditViewShortcut(e) !== 'save') {
1104
1103
  return;
1105
1104
  }
1106
1105
  e.preventDefault();
1106
+ // When a relation modal is open, only its own UpdateAction instance (fromRelationModal)
1107
+ // should react to the shortcut — otherwise the background entry saves at the same time.
1108
+ if (!fromRelationModalRef.current && RelationModal.isAnyRelationModalOpen()) {
1109
+ return;
1110
+ }
1107
1111
  if (!isDisabledRef.current) {
1108
1112
  handleUpdateRef.current();
1109
1113
  }