@strapi/admin 4.5.4 → 4.6.0-beta.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 (90) hide show
  1. package/admin/src/components/AuthenticatedApp/index.js +2 -13
  2. package/admin/src/content-manager/components/ComponentInitializer/index.js +1 -7
  3. package/admin/src/content-manager/components/{RepeatableComponent/DragPreview.js → DragLayer/ComponentDragPreview.js} +25 -12
  4. package/admin/src/content-manager/components/DragLayer/RelationDragPreview.js +75 -0
  5. package/admin/src/content-manager/components/DragLayer/index.js +23 -7
  6. package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +130 -84
  7. package/admin/src/content-manager/components/DynamicZone/index.js +99 -24
  8. package/admin/src/content-manager/components/DynamicZone/utils/select.js +9 -5
  9. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +37 -11
  10. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +18 -22
  11. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +24 -5
  12. package/admin/src/content-manager/components/RelationInput/RelationInput.js +209 -64
  13. package/admin/src/content-manager/components/RelationInput/components/RelationItem.js +134 -21
  14. package/admin/src/content-manager/components/RelationInput/components/RelationList.js +1 -2
  15. package/admin/src/content-manager/components/RelationInput/constants.js +1 -0
  16. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +131 -9
  17. package/admin/src/content-manager/components/RepeatableComponent/components/Accordion.js +77 -0
  18. package/admin/src/content-manager/components/RepeatableComponent/components/Component.js +262 -0
  19. package/admin/src/content-manager/components/RepeatableComponent/{DraggedItem → components}/Preview.js +0 -0
  20. package/admin/src/content-manager/components/RepeatableComponent/index.js +147 -87
  21. package/admin/src/content-manager/components/RepeatableComponent/utils/getComponentErrorKeys.js +1 -1
  22. package/admin/src/content-manager/hooks/index.js +2 -0
  23. package/admin/src/content-manager/hooks/useDragAndDrop.js +120 -0
  24. package/admin/src/content-manager/hooks/useKeyboardDragAndDrop.js +98 -0
  25. package/admin/src/content-manager/utils/ItemTypes.js +1 -1
  26. package/admin/src/content-manager/utils/composeRefs.js +28 -0
  27. package/admin/src/content-manager/utils/getMaxTempKey.js +1 -1
  28. package/admin/src/content-manager/utils/index.js +7 -0
  29. package/admin/src/pages/App/index.js +13 -20
  30. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +3 -2
  31. package/admin/src/translations/en.json +6 -0
  32. package/admin/src/translations/tr.json +5 -485
  33. package/admin/src/utils/index.js +0 -1
  34. package/build/4318.80bdf035.chunk.js +30 -0
  35. package/build/{8176.e929d326.chunk.js → 8176.b19bc128.chunk.js} +32 -32
  36. package/build/{1233.802422fa.chunk.js → 8186.55910742.chunk.js} +96 -96
  37. package/build/{8633.43ec9042.chunk.js → 8633.59223842.chunk.js} +1 -1
  38. package/build/Admin-authenticatedApp.f9e74dc0.chunk.js +80 -0
  39. package/build/{Admin_profilePage.60ab80bb.chunk.js → Admin_profilePage.c07bdf08.chunk.js} +1 -1
  40. package/build/{Admin_settingsPage.6ef8acc9.chunk.js → Admin_settingsPage.50a8765b.chunk.js} +1 -1
  41. package/build/admin-app.2861b6d2.chunk.js +112 -0
  42. package/build/admin-edit-users.85231e4c.chunk.js +10 -0
  43. package/build/{admin-users.e64fb0f1.chunk.js → admin-users.a2707644.chunk.js} +2 -2
  44. package/build/api-tokens-create-page.dd4ddfcb.chunk.js +1 -0
  45. package/build/api-tokens-edit-page.821c5a6c.chunk.js +1 -0
  46. package/build/content-manager.ee948f75.chunk.js +1186 -0
  47. package/build/content-type-builder-translation-tr-json.2e52bc60.chunk.js +1 -0
  48. package/build/email-settings-page.db0d98d1.chunk.js +15 -0
  49. package/build/email-translation-tr-json.87f2feb3.chunk.js +1 -0
  50. package/build/{en-json.7dd57947.chunk.js → en-json.4a56dca7.chunk.js} +1 -1
  51. package/build/index.html +1 -1
  52. package/build/main.faac89ee.js +2025 -0
  53. package/build/runtime~main.75a15b8e.js +2 -0
  54. package/build/sso-settings-page.adb12ac3.chunk.js +1 -0
  55. package/build/tr-json.9c44ea0c.chunk.js +1 -0
  56. package/build/{upload.74540aab.chunk.js → upload.e2034370.chunk.js} +3 -3
  57. package/build/users-permissions-translation-tr-json.cdc49a3c.chunk.js +1 -0
  58. package/package.json +9 -9
  59. package/server/controllers/admin.js +0 -2
  60. package/server/routes/admin.js +1 -1
  61. package/server/services/metrics.js +2 -5
  62. package/admin/src/content-manager/components/RepeatableComponent/AccordionGroupCustom/index.js +0 -122
  63. package/admin/src/content-manager/components/RepeatableComponent/AddFieldButton.js +0 -58
  64. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/DraggingSibling.js +0 -72
  65. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/IconButtonCustoms.js +0 -32
  66. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/index.js +0 -326
  67. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/utils/connect.js +0 -11
  68. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/utils/index.js +0 -2
  69. package/admin/src/content-manager/components/RepeatableComponent/DraggedItem/utils/select.js +0 -30
  70. package/admin/src/content-manager/components/RepeatableComponent/utils/connect.js +0 -11
  71. package/admin/src/content-manager/components/RepeatableComponent/utils/select.js +0 -12
  72. package/admin/src/content-manager/hooks/__test__/usePrev.test.js +0 -26
  73. package/admin/src/utils/uniqueAdminHash.js +0 -22
  74. package/build/4318.9283c350.chunk.js +0 -30
  75. package/build/Admin-authenticatedApp.0da578b8.chunk.js +0 -80
  76. package/build/admin-app.a3277e72.chunk.js +0 -112
  77. package/build/admin-edit-users.5547b126.chunk.js +0 -10
  78. package/build/api-tokens-create-page.93dd0689.chunk.js +0 -1
  79. package/build/api-tokens-edit-page.b0adac81.chunk.js +0 -1
  80. package/build/content-manager.f9630c3b.chunk.js +0 -1197
  81. package/build/content-type-builder-translation-tr-json.949e22eb.chunk.js +0 -1
  82. package/build/email-settings-page.c6e62f6b.chunk.js +0 -15
  83. package/build/email-translation-tr-json.8aa034bb.chunk.js +0 -1
  84. package/build/i18n-translation-tr-json.34ca9d61.chunk.js +0 -1
  85. package/build/main.71f24343.js +0 -2034
  86. package/build/runtime~main.1115f82b.js +0 -2
  87. package/build/sso-settings-page.feed2f45.chunk.js +0 -1
  88. package/build/tr-json.eac8bd79.chunk.js +0 -1
  89. package/build/upload-translation-tr-json.b173223a.chunk.js +0 -1
  90. package/build/users-permissions-translation-tr-json.9bebc250.chunk.js +0 -1
@@ -2,9 +2,9 @@ import React, { memo, useMemo, useState } from 'react';
2
2
  import get from 'lodash/get';
3
3
  import isEqual from 'react-fast-compare';
4
4
  import PropTypes from 'prop-types';
5
- import { Stack } from '@strapi/design-system/Stack';
6
- import { Box } from '@strapi/design-system/Box';
5
+ import { Box, Stack, VisuallyHidden } from '@strapi/design-system';
7
6
  import { NotAllowedInput, useNotification } from '@strapi/helper-plugin';
7
+ import { useIntl } from 'react-intl';
8
8
 
9
9
  import { getTrad } from '../../utils';
10
10
 
@@ -27,14 +27,16 @@ const DynamicZone = ({
27
27
  isFieldAllowed,
28
28
  isFieldReadable,
29
29
  labelAction,
30
- moveComponentUp,
31
- moveComponentDown,
30
+ moveComponentField,
32
31
  removeComponentFromDynamicZone,
33
32
  dynamicDisplayedComponents,
34
33
  fieldSchema,
35
34
  metadatas,
36
35
  }) => {
37
36
  const [addComponentIsOpen, setAddComponentIsOpen] = useState(false);
37
+ const [liveText, setLiveText] = useState('');
38
+
39
+ const { formatMessage } = useIntl();
38
40
 
39
41
  const toggleNotification = useNotification();
40
42
  const { getComponentLayout, components } = useContentTypeLayout();
@@ -82,12 +84,76 @@ const DynamicZone = ({
82
84
  }
83
85
  };
84
86
 
85
- const handleMoveComponentDown = (name, componentIndex) => () => {
86
- moveComponentDown(name, componentIndex);
87
+ const handleMoveComponent = (newIndex, currentIndex) => {
88
+ setLiveText(
89
+ formatMessage(
90
+ {
91
+ id: getTrad('dnd.reorder'),
92
+ defaultMessage: '{item}, moved. New position in list: {position}.',
93
+ },
94
+ {
95
+ item: `${name}.${currentIndex}`,
96
+ position: getItemPos(newIndex),
97
+ }
98
+ )
99
+ );
100
+
101
+ moveComponentField({
102
+ name,
103
+ newIndex,
104
+ currentIndex,
105
+ });
87
106
  };
88
107
 
89
- const handleMoveComponentUp = (name, componentIndex) => () => {
90
- moveComponentUp(name, componentIndex);
108
+ /**
109
+ *
110
+ * @param {number} index
111
+ * @returns {string}
112
+ */
113
+ const getItemPos = (index) => `${index + 1} of ${dynamicDisplayedComponents.length}`;
114
+
115
+ const handleCancel = (index) => {
116
+ setLiveText(
117
+ formatMessage(
118
+ {
119
+ id: getTrad('dnd.cancel-item'),
120
+ defaultMessage: '{item}, dropped. Re-order cancelled.',
121
+ },
122
+ {
123
+ item: `${name}.${index}`,
124
+ }
125
+ )
126
+ );
127
+ };
128
+
129
+ const handleGrabItem = (index) => {
130
+ setLiveText(
131
+ formatMessage(
132
+ {
133
+ id: getTrad('dnd.grab-item'),
134
+ defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`,
135
+ },
136
+ {
137
+ item: `${name}.${index}`,
138
+ position: getItemPos(index),
139
+ }
140
+ )
141
+ );
142
+ };
143
+
144
+ const handleDropItem = (index) => {
145
+ setLiveText(
146
+ formatMessage(
147
+ {
148
+ id: getTrad('dnd.drop-item'),
149
+ defaultMessage: `{item}, dropped. Final position in list: {position}.`,
150
+ },
151
+ {
152
+ item: `${name}.${index}`,
153
+ position: getItemPos(index),
154
+ }
155
+ )
156
+ );
91
157
  };
92
158
 
93
159
  const handleRemoveComponent = (name, currentIndex) => () => {
@@ -105,6 +171,8 @@ const DynamicZone = ({
105
171
  );
106
172
  }
107
173
 
174
+ const ariaDescriptionId = `${name}-item-instructions`;
175
+
108
176
  return (
109
177
  <Stack spacing={6}>
110
178
  {dynamicDisplayedComponentsLength > 0 && (
@@ -117,27 +185,30 @@ const DynamicZone = ({
117
185
  numberOfComponents={dynamicDisplayedComponentsLength}
118
186
  required={fieldSchema.required || false}
119
187
  />
120
- {dynamicDisplayedComponents.map((componentUid, index) => {
121
- const showDownIcon = isFieldAllowed && index < dynamicDisplayedComponentsLength - 1;
122
- const showUpIcon = isFieldAllowed && index > 0;
123
-
124
- return (
188
+ <VisuallyHidden id={ariaDescriptionId}>
189
+ {formatMessage({
190
+ id: getTrad('dnd.instructions'),
191
+ defaultMessage: `Press spacebar to grab and re-order`,
192
+ })}
193
+ </VisuallyHidden>
194
+ <VisuallyHidden aria-live="assertive">{liveText}</VisuallyHidden>
195
+ <ol aria-describedby={ariaDescriptionId}>
196
+ {dynamicDisplayedComponents.map(({ componentUid, id }, index) => (
125
197
  <DynamicZoneComponent
126
198
  componentUid={componentUid}
127
199
  formErrors={formErrors}
128
- // eslint-disable-next-line react/no-array-index-key
129
- key={index}
200
+ key={`${componentUid}-${id}`}
130
201
  index={index}
131
202
  isFieldAllowed={isFieldAllowed}
132
- onMoveComponentDownClick={handleMoveComponentDown(name, index)}
133
- onMoveComponentUpClick={handleMoveComponentUp(name, index)}
134
203
  name={name}
204
+ onMoveComponent={handleMoveComponent}
135
205
  onRemoveComponentClick={handleRemoveComponent(name, index)}
136
- showDownIcon={showDownIcon}
137
- showUpIcon={showUpIcon}
206
+ onCancel={handleCancel}
207
+ onDropItem={handleDropItem}
208
+ onGrabItem={handleGrabItem}
138
209
  />
139
- );
140
- })}
210
+ ))}
211
+ </ol>
141
212
  </Box>
142
213
  )}
143
214
 
@@ -172,7 +243,12 @@ DynamicZone.defaultProps = {
172
243
 
173
244
  DynamicZone.propTypes = {
174
245
  addComponentToDynamicZone: PropTypes.func.isRequired,
175
- dynamicDisplayedComponents: PropTypes.array,
246
+ dynamicDisplayedComponents: PropTypes.arrayOf(
247
+ PropTypes.shape({
248
+ componentUid: PropTypes.string.isRequired,
249
+ id: PropTypes.number.isRequired,
250
+ })
251
+ ),
176
252
  fieldSchema: PropTypes.shape({
177
253
  components: PropTypes.array.isRequired,
178
254
  max: PropTypes.number,
@@ -188,8 +264,7 @@ DynamicZone.propTypes = {
188
264
  description: PropTypes.string,
189
265
  label: PropTypes.string,
190
266
  }).isRequired,
191
- moveComponentUp: PropTypes.func.isRequired,
192
- moveComponentDown: PropTypes.func.isRequired,
267
+ moveComponentField: PropTypes.func.isRequired,
193
268
  name: PropTypes.string.isRequired,
194
269
  removeComponentFromDynamicZone: PropTypes.func.isRequired,
195
270
  };
@@ -9,15 +9,20 @@ function useSelect(name) {
9
9
  isCreatingEntry,
10
10
  formErrors,
11
11
  modifiedData,
12
- moveComponentUp,
13
- moveComponentDown,
12
+ moveComponentField,
14
13
  removeComponentFromDynamicZone,
15
14
  readActionAllowedFields,
16
15
  updateActionAllowedFields,
17
16
  } = useCMEditViewDataManager();
18
17
 
19
18
  const dynamicDisplayedComponents = useMemo(
20
- () => get(modifiedData, [name], []).map((data) => data.__component),
19
+ () =>
20
+ get(modifiedData, [name], []).map((data) => {
21
+ return {
22
+ componentUid: data.__component,
23
+ id: data.id ?? data.__temp_key__,
24
+ };
25
+ }),
21
26
  [modifiedData, name]
22
27
  );
23
28
 
@@ -39,8 +44,7 @@ function useSelect(name) {
39
44
  isCreatingEntry,
40
45
  isFieldAllowed,
41
46
  isFieldReadable,
42
- moveComponentUp,
43
- moveComponentDown,
47
+ moveComponentField,
44
48
  removeComponentFromDynamicZone,
45
49
  dynamicDisplayedComponents,
46
50
  };
@@ -252,7 +252,7 @@ const EditViewDataManagerProvider = ({
252
252
  /**
253
253
  * @type {({ name: string, value: Relation, toOneRelation: boolean}) => void}
254
254
  */
255
- const connectRelation = useCallback(({ name, value, toOneRelation }) => {
255
+ const relationConnect = useCallback(({ name, value, toOneRelation }) => {
256
256
  dispatch({
257
257
  type: 'CONNECT_RELATION',
258
258
  keys: name.split('.'),
@@ -261,7 +261,7 @@ const EditViewDataManagerProvider = ({
261
261
  });
262
262
  }, []);
263
263
 
264
- const loadRelation = useCallback(({ target: { name, value } }) => {
264
+ const relationLoad = useCallback(({ target: { name, value } }) => {
265
265
  dispatch({
266
266
  type: 'LOAD_RELATION',
267
267
  keys: name.split('.'),
@@ -534,16 +534,16 @@ const EditViewDataManagerProvider = ({
534
534
  [shouldCheckDZErrors]
535
535
  );
536
536
 
537
- const moveComponentField = useCallback((pathToComponent, dragIndex, hoverIndex) => {
537
+ const moveComponentField = useCallback(({ name, newIndex, currentIndex }) => {
538
538
  dispatch({
539
539
  type: 'MOVE_COMPONENT_FIELD',
540
- pathToComponent,
541
- dragIndex,
542
- hoverIndex,
540
+ keys: name.split('.'),
541
+ newIndex,
542
+ oldIndex: currentIndex,
543
543
  });
544
544
  }, []);
545
545
 
546
- const disconnectRelation = useCallback(({ name, id }) => {
546
+ const relationDisconnect = useCallback(({ name, id }) => {
547
547
  dispatch({
548
548
  type: 'DISCONNECT_RELATION',
549
549
  keys: name.split('.'),
@@ -551,6 +551,25 @@ const EditViewDataManagerProvider = ({
551
551
  });
552
552
  }, []);
553
553
 
554
+ /**
555
+ * @typedef Payload
556
+ * @type {object}
557
+ * @property {string} name - The name of the field in `modifiedData`
558
+ * @property {number} oldIndex - The relation's current index
559
+ * @property {number} newIndex - The relation's new index
560
+ *
561
+ *
562
+ * @type {(payload: Payload) => void}
563
+ */
564
+ const relationReorder = useCallback(({ name, oldIndex, newIndex }) => {
565
+ dispatch({
566
+ type: 'REORDER_RELATION',
567
+ keys: name.split('.'),
568
+ oldIndex,
569
+ newIndex,
570
+ });
571
+ }, []);
572
+
554
573
  const removeComponentFromDynamicZone = useCallback(
555
574
  (dynamicZoneName, index) => {
556
575
  trackUsageRef.current('removeComponentFromDynamicZone');
@@ -601,7 +620,6 @@ const EditViewDataManagerProvider = ({
601
620
  value={{
602
621
  addComponentToDynamicZone,
603
622
  addNonRepeatableComponentToField,
604
- connectRelation,
605
623
  addRepeatableComponentToField,
606
624
  allLayoutData,
607
625
  checkFormErrors,
@@ -614,20 +632,28 @@ const EditViewDataManagerProvider = ({
614
632
  shouldNotRunValidations,
615
633
  status,
616
634
  layout: currentContentTypeLayout,
617
- loadRelation,
618
635
  modifiedData,
619
- moveComponentDown,
620
636
  moveComponentField,
637
+ /**
638
+ * @deprecated use `moveComponentField` instead. This will be removed in v5.
639
+ */
640
+ moveComponentDown,
641
+ /**
642
+ * @deprecated use `moveComponentField` instead. This will be removed in v5.
643
+ */
621
644
  moveComponentUp,
622
645
  onChange: handleChange,
623
646
  onPublish: handlePublish,
624
647
  onUnpublish,
625
- disconnectRelation,
626
648
  readActionAllowedFields,
627
649
  redirectToPreviousPage,
628
650
  removeComponentFromDynamicZone,
629
651
  removeComponentFromField,
630
652
  removeRepeatableField,
653
+ relationConnect,
654
+ relationDisconnect,
655
+ relationLoad,
656
+ relationReorder,
631
657
  slug,
632
658
  triggerFormValidation,
633
659
  updateActionAllowedFields,
@@ -88,6 +88,7 @@ const reducer = (state, action) =>
88
88
  ? {
89
89
  ...state.componentsDataStructure[componentLayoutData.uid],
90
90
  __component: componentLayoutData.uid,
91
+ __temp_key__: getMaxTempKey(currentValue) + 1,
91
92
  }
92
93
  : {
93
94
  ...state.componentsDataStructure[componentLayoutData.uid],
@@ -172,15 +173,29 @@ const reducer = (state, action) =>
172
173
  const { id } = action;
173
174
  const modifiedDataRelation = get(state, [...path]);
174
175
 
175
- /**
176
- * TODO: before merge make this performant (e.g. 1000 relations === long time)
177
- */
178
176
  const newRelations = modifiedDataRelation.filter((rel) => rel.id !== id);
179
177
 
180
178
  set(draftState, path, newRelations);
181
179
 
182
180
  break;
183
181
  }
182
+ case 'MOVE_COMPONENT_FIELD':
183
+ case 'REORDER_RELATION': {
184
+ const { oldIndex, newIndex, keys } = action;
185
+ const path = ['modifiedData', ...keys];
186
+ const modifiedDataRelations = get(state, [...path]);
187
+
188
+ const currentItem = modifiedDataRelations[oldIndex];
189
+
190
+ const newRelations = [...modifiedDataRelations];
191
+
192
+ newRelations.splice(oldIndex, 1);
193
+ newRelations.splice(newIndex, 0, currentItem);
194
+
195
+ set(draftState, path, newRelations);
196
+
197
+ break;
198
+ }
184
199
  /**
185
200
  * This action will be called when you open your entry (first load)
186
201
  * but also every time you press publish.
@@ -256,25 +271,6 @@ const reducer = (state, action) =>
256
271
  draftState.shouldCheckErrors = false;
257
272
  break;
258
273
  }
259
- case 'MOVE_COMPONENT_FIELD': {
260
- const currentValue = get(state, ['modifiedData', ...action.pathToComponent]);
261
- const valueToInsert = get(state, [
262
- 'modifiedData',
263
- ...action.pathToComponent,
264
- action.dragIndex,
265
- ]);
266
-
267
- const updatedValue = moveFields(
268
- currentValue,
269
- action.dragIndex,
270
- action.hoverIndex,
271
- valueToInsert
272
- );
273
-
274
- set(draftState, ['modifiedData', ...action.pathToComponent], updatedValue);
275
-
276
- break;
277
- }
278
274
  case 'MOVE_COMPONENT_UP':
279
275
  case 'MOVE_COMPONENT_DOWN': {
280
276
  const { currentIndex, dynamicZoneName, shouldCheckErrors } = action;
@@ -84,14 +84,28 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
84
84
  */
85
85
  let actualOldValue = oldValue ?? [];
86
86
 
87
+ const valuesWithPositions = value.map((relation, index, allRelations) => {
88
+ const nextRelation = allRelations[index + 1];
89
+
90
+ if (nextRelation) {
91
+ return { ...relation, position: { before: nextRelation.id } };
92
+ }
93
+
94
+ return { ...relation, position: { end: true } };
95
+ });
96
+
87
97
  /**
88
98
  * Instead of the full relation object, we only want to send its ID
89
99
  * connectedRelations are the items that are in the browserState
90
100
  * array but not in the serverState
91
101
  */
92
- const connectedRelations = value.reduce((acc, relation) => {
93
- if (!actualOldValue.find((oldRelation) => oldRelation.id === relation.id)) {
94
- return [...acc, { id: relation.id }];
102
+ const connectedRelations = valuesWithPositions.reduce((acc, relation, currentIndex) => {
103
+ const indexOfRelationOnServer = actualOldValue.findIndex(
104
+ (oldRelation) => oldRelation.id === relation.id
105
+ );
106
+
107
+ if (indexOfRelationOnServer === -1 || indexOfRelationOnServer !== currentIndex) {
108
+ return [...acc, { id: relation.id, position: relation.position }];
95
109
  }
96
110
 
97
111
  return acc;
@@ -102,7 +116,7 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
102
116
  * are no longer in the browserState
103
117
  */
104
118
  const disconnectedRelations = actualOldValue.reduce((acc, relation) => {
105
- if (!value.find((newRelation) => newRelation.id === relation.id)) {
119
+ if (!valuesWithPositions.find((newRelation) => newRelation.id === relation.id)) {
106
120
  return [...acc, { id: relation.id }];
107
121
  }
108
122
 
@@ -111,7 +125,12 @@ const cleanData = ({ browserState, serverState }, currentSchema, componentsSchem
111
125
 
112
126
  cleanedData = {
113
127
  disconnect: disconnectedRelations,
114
- connect: connectedRelations,
128
+ /**
129
+ * Reverse the array because the API sequentially goes through the list
130
+ * so in an instance where you add two to the end it would fail because index0
131
+ * would want to attach itself to index1 which doesn't exist yet.
132
+ */
133
+ connect: connectedRelations.reverse(),
115
134
  };
116
135
 
117
136
  break;