@strapi/content-manager 5.38.0 → 5.38.1
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/history/components/VersionContent.js +48 -16
- package/dist/admin/history/components/VersionContent.js.map +1 -1
- package/dist/admin/history/components/VersionContent.mjs +48 -16
- package/dist/admin/history/components/VersionContent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js +51 -0
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs +52 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +6 -2
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +6 -2
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +148 -111
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +152 -115
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js +15 -5
- package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs +15 -5
- package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.js +54 -1
- package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
- package/dist/admin/pages/ListView/components/Filters.mjs +54 -1
- package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.d.ts +1 -0
- package/dist/admin/src/utils/conditionalFields.d.ts +12 -0
- package/dist/admin/translations/en.json.js +5 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +5 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +136 -2
- package/dist/admin/translations/es.json.js.map +1 -1
- package/dist/admin/translations/es.json.mjs +136 -2
- package/dist/admin/translations/es.json.mjs.map +1 -1
- package/dist/admin/utils/conditionalFields.js +76 -0
- package/dist/admin/utils/conditionalFields.js.map +1 -0
- package/dist/admin/utils/conditionalFields.mjs +69 -0
- package/dist/admin/utils/conditionalFields.mjs.map +1 -0
- package/dist/server/controllers/collection-types.js +157 -4
- package/dist/server/controllers/collection-types.js.map +1 -1
- package/dist/server/controllers/collection-types.mjs +159 -6
- package/dist/server/controllers/collection-types.mjs.map +1 -1
- package/dist/server/controllers/single-types.js +19 -4
- package/dist/server/controllers/single-types.js.map +1 -1
- package/dist/server/controllers/single-types.mjs +19 -4
- package/dist/server/controllers/single-types.mjs.map +1 -1
- package/dist/server/preview/services/preview.js +2 -1
- package/dist/server/preview/services/preview.js.map +1 -1
- package/dist/server/preview/services/preview.mjs +2 -1
- package/dist/server/preview/services/preview.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/preview/services/preview.d.ts.map +1 -1
- package/package.json +13 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { useForm, useField, useNotification, useRBAC,
|
|
4
|
-
import { Flex, Box, Link, TextButton, EmptyStateLayout, Field, VisuallyHidden,
|
|
5
|
-
import { ArrowClockwise, WarningCircle, Link as Link$1, Plus
|
|
3
|
+
import { useForm, useField, useNotification, useRBAC, useIsDesktop, useFocusInputField } from '@strapi/admin/strapi-admin';
|
|
4
|
+
import { Flex, Box, Link, TextButton, EmptyStateLayout, Field, VisuallyHidden, useComposedRefs, IconButton, Combobox, ComboboxOption, Typography } from '@strapi/design-system';
|
|
5
|
+
import { ArrowClockwise, WarningCircle, Drag, Cross, Link as Link$1, Plus } from '@strapi/icons';
|
|
6
6
|
import { generateNKeysBetween } from 'fractional-indexing';
|
|
7
7
|
import pipe from 'lodash/fp/pipe';
|
|
8
8
|
import { getEmptyImage } from 'react-dnd-html5-backend';
|
|
@@ -22,7 +22,7 @@ import { getRelationLabel } from '../../../../../utils/relations.mjs';
|
|
|
22
22
|
import { getTranslation } from '../../../../../utils/translations.mjs';
|
|
23
23
|
import { DocumentStatus } from '../../DocumentStatus.mjs';
|
|
24
24
|
import { useComponent } from '../ComponentContext.mjs';
|
|
25
|
-
import {
|
|
25
|
+
import { getCollectionType, RelationModalRenderer } from './RelationModal.mjs';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Remove a relation, whether it's been already saved or not.
|
|
@@ -32,13 +32,13 @@ import { RelationModalRenderer, getCollectionType } from './RelationModal.mjs';
|
|
|
32
32
|
const field = useField(fieldName);
|
|
33
33
|
const removeFieldRow = useForm(consumerName, (state)=>state.removeFieldRow);
|
|
34
34
|
const addFieldRow = useForm(consumerName, (state)=>state.addFieldRow);
|
|
35
|
-
const handleDisconnect = (relation)=>{
|
|
35
|
+
const handleDisconnect = React.useCallback((relation)=>{
|
|
36
36
|
if (field.value && field.value.connect) {
|
|
37
37
|
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
* A relation will exist in the `connect` array _if_ it has
|
|
39
|
+
* been added without saving. In this case, we just remove it
|
|
40
|
+
* from the connect array
|
|
41
|
+
*/ const indexOfRelationInConnectArray = field.value.connect.findIndex((rel)=>rel.id === relation.id);
|
|
42
42
|
if (indexOfRelationInConnectArray >= 0) {
|
|
43
43
|
removeFieldRow(`${fieldName}.connect`, indexOfRelationInConnectArray);
|
|
44
44
|
return;
|
|
@@ -52,7 +52,12 @@ import { RelationModalRenderer, getCollectionType } from './RelationModal.mjs';
|
|
|
52
52
|
locale: relation.locale
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
|
-
}
|
|
55
|
+
}, [
|
|
56
|
+
addFieldRow,
|
|
57
|
+
field.value,
|
|
58
|
+
fieldName,
|
|
59
|
+
removeFieldRow
|
|
60
|
+
]);
|
|
56
61
|
return handleDisconnect;
|
|
57
62
|
}
|
|
58
63
|
/* -------------------------------------------------------------------------------------------------
|
|
@@ -65,6 +70,7 @@ const ONE_WAY_RELATIONS = [
|
|
|
65
70
|
'oneToManyMorph',
|
|
66
71
|
'oneToOneMorph'
|
|
67
72
|
];
|
|
73
|
+
const EMPTY_RELATION_RESULTS = [];
|
|
68
74
|
/**
|
|
69
75
|
* TODO: we get a rather ugly flash when we remove a single relation from the list leaving
|
|
70
76
|
* no other relations when we press save. The initial relation re-renders, probably because
|
|
@@ -84,10 +90,10 @@ const ONE_WAY_RELATIONS = [
|
|
|
84
90
|
const { formatMessage } = useIntl();
|
|
85
91
|
const isMorph = props.attribute.relation.toLowerCase().includes('morph');
|
|
86
92
|
const isDisabled = isMorph || disabled;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
// @ts-expect-error – `targetModel` exists on supported non-morph relations (morph is disabled).
|
|
94
|
+
const targetModel = props.attribute.targetModel;
|
|
95
|
+
const componentId = useComponent('RelationsField', (state)=>state.id);
|
|
96
|
+
const componentUID = useComponent('RelationsField', (state)=>state.uid);
|
|
91
97
|
const isSubmitting = useForm('RelationsList', (state)=>state.isSubmitting);
|
|
92
98
|
React.useEffect(()=>{
|
|
93
99
|
setCurrentPage(1);
|
|
@@ -125,27 +131,19 @@ const ONE_WAY_RELATIONS = [
|
|
|
125
131
|
}
|
|
126
132
|
}, {
|
|
127
133
|
refetchOnMountOrArgChange: true,
|
|
128
|
-
skip: !id || !isRelatedToCurrentDocument
|
|
129
|
-
selectFromResult: (result)=>{
|
|
130
|
-
return {
|
|
131
|
-
...result,
|
|
132
|
-
data: {
|
|
133
|
-
...result.data,
|
|
134
|
-
results: result.data?.results ? result.data.results : []
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
}
|
|
134
|
+
skip: !id || !isRelatedToCurrentDocument
|
|
138
135
|
});
|
|
139
136
|
const handleLoadMore = ()=>{
|
|
140
137
|
setCurrentPage((prev)=>prev + 1);
|
|
141
138
|
};
|
|
142
139
|
const field = useField(props.name);
|
|
140
|
+
const serverData = data?.results ?? EMPTY_RELATION_RESULTS;
|
|
143
141
|
const isFetchingMoreRelations = isLoading || isFetching;
|
|
144
|
-
const realServerRelationsCount =
|
|
142
|
+
const realServerRelationsCount = data?.pagination ? data.pagination.total : 0;
|
|
145
143
|
/**
|
|
146
144
|
* Items that are already connected, but reordered would be in
|
|
147
145
|
* this list, so to get an accurate figure, we remove them.
|
|
148
|
-
*/ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>
|
|
146
|
+
*/ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>serverData.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
|
|
149
147
|
const relationsDisconnected = field.value?.disconnect?.length ?? 0;
|
|
150
148
|
const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
|
|
151
149
|
/**
|
|
@@ -155,15 +153,14 @@ const ONE_WAY_RELATIONS = [
|
|
|
155
153
|
*/ const relations = React.useMemo(()=>{
|
|
156
154
|
const ctx = {
|
|
157
155
|
field: field.value,
|
|
158
|
-
|
|
159
|
-
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
|
|
156
|
+
href: `../${COLLECTION_TYPES}/${targetModel}`,
|
|
160
157
|
mainField: props.mainField
|
|
161
158
|
};
|
|
162
159
|
/**
|
|
163
160
|
* Tidy up our data.
|
|
164
161
|
*/ const transformations = pipe(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
|
|
165
162
|
const transformedRels = transformations([
|
|
166
|
-
...
|
|
163
|
+
...serverData
|
|
167
164
|
]);
|
|
168
165
|
/**
|
|
169
166
|
* THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
|
|
@@ -177,14 +174,13 @@ const ONE_WAY_RELATIONS = [
|
|
|
177
174
|
return 0;
|
|
178
175
|
});
|
|
179
176
|
}, [
|
|
180
|
-
|
|
177
|
+
serverData,
|
|
181
178
|
field.value,
|
|
182
|
-
|
|
183
|
-
props.attribute.targetModel,
|
|
179
|
+
targetModel,
|
|
184
180
|
props.mainField
|
|
185
181
|
]);
|
|
186
182
|
const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
|
|
187
|
-
const handleConnect = (relation)=>{
|
|
183
|
+
const handleConnect = React.useCallback((relation)=>{
|
|
188
184
|
const [lastItemInList] = relations.slice(-1);
|
|
189
185
|
const item = {
|
|
190
186
|
id: relation.id,
|
|
@@ -196,13 +192,12 @@ const ONE_WAY_RELATIONS = [
|
|
|
196
192
|
},
|
|
197
193
|
status: relation.status,
|
|
198
194
|
/**
|
|
199
|
-
|
|
200
|
-
|
|
195
|
+
* If there's a last item, that's the first key we use to generate out next one.
|
|
196
|
+
*/ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
|
|
201
197
|
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
|
|
202
198
|
[props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
|
|
203
199
|
label: getRelationLabel(relation, props.mainField),
|
|
204
|
-
|
|
205
|
-
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
|
|
200
|
+
href: `../${COLLECTION_TYPES}/${targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
|
|
206
201
|
};
|
|
207
202
|
if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
|
|
208
203
|
// Remove any existing relation so they can be replaced with the new one
|
|
@@ -217,7 +212,15 @@ const ONE_WAY_RELATIONS = [
|
|
|
217
212
|
item
|
|
218
213
|
]);
|
|
219
214
|
}
|
|
220
|
-
}
|
|
215
|
+
}, [
|
|
216
|
+
field,
|
|
217
|
+
handleDisconnect,
|
|
218
|
+
props.attribute.relation,
|
|
219
|
+
props.mainField,
|
|
220
|
+
props.name,
|
|
221
|
+
relations,
|
|
222
|
+
targetModel
|
|
223
|
+
]);
|
|
221
224
|
return /*#__PURE__*/ jsxs(Flex, {
|
|
222
225
|
ref: ref,
|
|
223
226
|
direction: "column",
|
|
@@ -232,7 +235,7 @@ const ONE_WAY_RELATIONS = [
|
|
|
232
235
|
gap: 2,
|
|
233
236
|
width: "100%",
|
|
234
237
|
children: [
|
|
235
|
-
/*#__PURE__*/ jsx(
|
|
238
|
+
/*#__PURE__*/ jsx(MemoizedRelationsComboboxInput, {
|
|
236
239
|
disabled: isDisabled,
|
|
237
240
|
// NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
|
|
238
241
|
id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
|
|
@@ -242,7 +245,7 @@ const ONE_WAY_RELATIONS = [
|
|
|
242
245
|
isRelatedToCurrentDocument: isRelatedToCurrentDocument,
|
|
243
246
|
...props
|
|
244
247
|
}),
|
|
245
|
-
|
|
248
|
+
data?.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
|
|
246
249
|
disabled: isFetchingMoreRelations,
|
|
247
250
|
onClick: handleLoadMore,
|
|
248
251
|
loading: isFetchingMoreRelations,
|
|
@@ -256,15 +259,15 @@ const ONE_WAY_RELATIONS = [
|
|
|
256
259
|
}) : null
|
|
257
260
|
]
|
|
258
261
|
}),
|
|
259
|
-
/*#__PURE__*/ jsx(
|
|
262
|
+
/*#__PURE__*/ jsx(MemoizedRelationsList, {
|
|
260
263
|
data: relations,
|
|
261
|
-
serverData:
|
|
264
|
+
serverData: serverData,
|
|
262
265
|
disabled: isDisabled,
|
|
263
266
|
name: props.name,
|
|
264
267
|
isLoading: isFetchingMoreRelations,
|
|
265
268
|
relationType: props.attribute.relation,
|
|
266
|
-
|
|
267
|
-
|
|
269
|
+
targetModel: targetModel,
|
|
270
|
+
documentParams: currentDocumentMeta.params,
|
|
268
271
|
mainField: props.mainField
|
|
269
272
|
})
|
|
270
273
|
]
|
|
@@ -317,6 +320,8 @@ const ONE_WAY_RELATIONS = [
|
|
|
317
320
|
const { currentDocumentMeta } = useDocumentContext('RelationsInput');
|
|
318
321
|
const { formatMessage } = useIntl();
|
|
319
322
|
const field = useField(name);
|
|
323
|
+
// @ts-expect-error – `targetModel` exists on supported non-morph relations (morph is disabled).
|
|
324
|
+
const targetModel = props.attribute.targetModel;
|
|
320
325
|
const searchParamsDebounced = useDebounce(searchParams, 300);
|
|
321
326
|
const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
|
|
322
327
|
/**
|
|
@@ -358,7 +363,7 @@ const ONE_WAY_RELATIONS = [
|
|
|
358
363
|
]);
|
|
359
364
|
const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
|
|
360
365
|
const options = data?.results ?? [];
|
|
361
|
-
const handleChange = (relationId)=>{
|
|
366
|
+
const handleChange = React.useCallback((relationId)=>{
|
|
362
367
|
if (!relationId) {
|
|
363
368
|
return;
|
|
364
369
|
}
|
|
@@ -376,20 +381,27 @@ const ONE_WAY_RELATIONS = [
|
|
|
376
381
|
return;
|
|
377
382
|
}
|
|
378
383
|
/**
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
384
|
+
* You need to give this relation a correct _temp_key_ but
|
|
385
|
+
* this component doesn't know about those ones, you can't rely
|
|
386
|
+
* on the connect array because that doesn't hold items that haven't
|
|
387
|
+
* moved. So use a callback to fill in the gaps when connecting.
|
|
388
|
+
*
|
|
389
|
+
*/ onChange(relation);
|
|
390
|
+
}, [
|
|
391
|
+
formatMessage,
|
|
392
|
+
onChange,
|
|
393
|
+
options,
|
|
394
|
+
toggleNotification
|
|
395
|
+
]);
|
|
396
|
+
const relation = React.useMemo(()=>({
|
|
397
|
+
collectionType: COLLECTION_TYPES,
|
|
398
|
+
model: targetModel,
|
|
399
|
+
documentId: '',
|
|
400
|
+
params: currentDocumentMeta.params
|
|
401
|
+
}), [
|
|
402
|
+
currentDocumentMeta.params,
|
|
403
|
+
targetModel
|
|
404
|
+
]);
|
|
393
405
|
const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
|
|
394
406
|
action,
|
|
395
407
|
subject: relation.model
|
|
@@ -423,7 +435,7 @@ const ONE_WAY_RELATIONS = [
|
|
|
423
435
|
/*#__PURE__*/ jsx(DocumentRBAC, {
|
|
424
436
|
permissions: permissions,
|
|
425
437
|
model: relation.model,
|
|
426
|
-
children: /*#__PURE__*/ jsx(
|
|
438
|
+
children: /*#__PURE__*/ jsx(MemoizedRelationModalWithContext, {
|
|
427
439
|
relation: relation,
|
|
428
440
|
name: name,
|
|
429
441
|
placeholder: placeholder,
|
|
@@ -443,14 +455,13 @@ const ONE_WAY_RELATIONS = [
|
|
|
443
455
|
]
|
|
444
456
|
});
|
|
445
457
|
};
|
|
458
|
+
const MemoizedRelationsComboboxInput = /*#__PURE__*/ React.memo(RelationsInput);
|
|
446
459
|
const RelationModalWithContext = ({ relation, name, placeholder, hasNextPage, isLoadingSearchRelations, isLoadingPermissions, handleChange, mainField, setSearchParams, fieldValue, data, ...props })=>{
|
|
447
460
|
const [textValue, setTextValue] = React.useState('');
|
|
448
461
|
const { formatMessage } = useIntl();
|
|
449
462
|
const canCreate = useDocumentRBAC('RelationModalWrapper', (state)=>state.canCreate);
|
|
450
463
|
const fieldRef = useFocusInputField(name);
|
|
451
|
-
const
|
|
452
|
-
componentUID: uid
|
|
453
|
-
}));
|
|
464
|
+
const componentUID = useComponent('RelationsField', (state)=>state.uid);
|
|
454
465
|
const handleLoadMore = ()=>{
|
|
455
466
|
if (!data || !data.pagination) {
|
|
456
467
|
return;
|
|
@@ -562,11 +573,12 @@ const RelationModalWithContext = ({ relation, name, placeholder, hasNextPage, is
|
|
|
562
573
|
})
|
|
563
574
|
});
|
|
564
575
|
};
|
|
576
|
+
const MemoizedRelationModalWithContext = /*#__PURE__*/ React.memo(RelationModalWithContext);
|
|
565
577
|
/* -------------------------------------------------------------------------------------------------
|
|
566
578
|
* RelationsList
|
|
567
579
|
* -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
|
|
568
580
|
const RELATION_GUTTER = 4;
|
|
569
|
-
const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel, mainField })=>{
|
|
581
|
+
const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel, documentParams, mainField })=>{
|
|
570
582
|
const ariaDescriptionId = React.useId();
|
|
571
583
|
const { formatMessage } = useIntl();
|
|
572
584
|
const listRef = React.useRef(null);
|
|
@@ -603,38 +615,37 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
|
603
615
|
isLoading,
|
|
604
616
|
data.length
|
|
605
617
|
]);
|
|
606
|
-
const
|
|
607
|
-
const handleMoveItem = (newIndex, oldIndex)=>{
|
|
618
|
+
const handleMoveItem = React.useCallback((newIndex, oldIndex)=>{
|
|
608
619
|
const item = data[oldIndex];
|
|
609
620
|
setLiveText(formatMessage({
|
|
610
621
|
id: getTranslation('dnd.reorder'),
|
|
611
622
|
defaultMessage: '{item}, moved. New position in list: {position}.'
|
|
612
623
|
}, {
|
|
613
624
|
item: item.label ?? item.documentId,
|
|
614
|
-
position:
|
|
625
|
+
position: `${newIndex + 1} of ${data.length}`
|
|
615
626
|
}));
|
|
616
627
|
/**
|
|
617
|
-
|
|
618
|
-
|
|
628
|
+
* Splicing mutates the array, so we need to create a new array
|
|
629
|
+
*/ const newData = [
|
|
619
630
|
...data
|
|
620
631
|
];
|
|
621
632
|
const currentRow = data[oldIndex];
|
|
622
633
|
const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
|
|
623
634
|
const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
|
|
624
635
|
/**
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
636
|
+
* We're moving the relation between two other relations, so
|
|
637
|
+
* we need to generate a new key that keeps the order
|
|
638
|
+
*/ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
|
|
628
639
|
newData.splice(oldIndex, 1);
|
|
629
640
|
newData.splice(newIndex, 0, {
|
|
630
641
|
...currentRow,
|
|
631
642
|
__temp_key__: newKey
|
|
632
643
|
});
|
|
633
644
|
/**
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
645
|
+
* Now we diff against the server to understand what's different so we
|
|
646
|
+
* can keep the connect array nice and tidy. It also needs reversing because
|
|
647
|
+
* we reverse the relations from the server in the first place.
|
|
648
|
+
*/ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
|
|
638
649
|
const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
|
|
639
650
|
const relationInFront = array[currentIndex + 1];
|
|
640
651
|
if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
|
|
@@ -665,28 +676,40 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
|
665
676
|
return acc;
|
|
666
677
|
}, []).toReversed();
|
|
667
678
|
field.onChange(`${name}.connect`, connectedRelations);
|
|
668
|
-
}
|
|
669
|
-
|
|
679
|
+
}, [
|
|
680
|
+
data,
|
|
681
|
+
field,
|
|
682
|
+
formatMessage,
|
|
683
|
+
name,
|
|
684
|
+
serverData
|
|
685
|
+
]);
|
|
686
|
+
const handleGrabItem = React.useCallback((index)=>{
|
|
670
687
|
const item = data[index];
|
|
671
688
|
setLiveText(formatMessage({
|
|
672
689
|
id: getTranslation('dnd.grab-item'),
|
|
673
690
|
defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
|
|
674
691
|
}, {
|
|
675
692
|
item: item.label ?? item.documentId,
|
|
676
|
-
position:
|
|
693
|
+
position: `${index + 1} of ${data.length}`
|
|
677
694
|
}));
|
|
678
|
-
}
|
|
679
|
-
|
|
695
|
+
}, [
|
|
696
|
+
data,
|
|
697
|
+
formatMessage
|
|
698
|
+
]);
|
|
699
|
+
const handleDropItem = React.useCallback((index)=>{
|
|
680
700
|
const { href: _href, label, ...item } = data[index];
|
|
681
701
|
setLiveText(formatMessage({
|
|
682
702
|
id: getTranslation('dnd.drop-item'),
|
|
683
703
|
defaultMessage: `{item}, dropped. Final position in list: {position}.`
|
|
684
704
|
}, {
|
|
685
705
|
item: label ?? item.documentId,
|
|
686
|
-
position:
|
|
706
|
+
position: `${index + 1} of ${data.length}`
|
|
687
707
|
}));
|
|
688
|
-
}
|
|
689
|
-
|
|
708
|
+
}, [
|
|
709
|
+
data,
|
|
710
|
+
formatMessage
|
|
711
|
+
]);
|
|
712
|
+
const handleCancel = React.useCallback((index)=>{
|
|
690
713
|
const item = data[index];
|
|
691
714
|
setLiveText(formatMessage({
|
|
692
715
|
id: getTranslation('dnd.cancel-item'),
|
|
@@ -694,13 +717,45 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
|
694
717
|
}, {
|
|
695
718
|
item: item.label ?? item.documentId
|
|
696
719
|
}));
|
|
697
|
-
}
|
|
720
|
+
}, [
|
|
721
|
+
data,
|
|
722
|
+
formatMessage
|
|
723
|
+
]);
|
|
698
724
|
const handleDisconnect = useHandleDisconnect(name, 'RelationsList');
|
|
699
725
|
/**
|
|
700
726
|
* These relation types will only ever have one item
|
|
701
727
|
* in their list, so you can't reorder a single item!
|
|
702
728
|
*/ const canReorder = !ONE_WAY_RELATIONS.includes(relationType);
|
|
703
729
|
const dynamicListHeight = data.length > RELATIONS_TO_DISPLAY ? Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER) + RELATION_ITEM_HEIGHT / 2 : Math.min(data.length, RELATIONS_TO_DISPLAY) * (RELATION_ITEM_HEIGHT + RELATION_GUTTER);
|
|
730
|
+
const itemData = React.useMemo(()=>({
|
|
731
|
+
ariaDescribedBy: ariaDescriptionId,
|
|
732
|
+
canDrag: canReorder,
|
|
733
|
+
disabled,
|
|
734
|
+
documentParams,
|
|
735
|
+
handleCancel,
|
|
736
|
+
handleDropItem,
|
|
737
|
+
handleGrabItem,
|
|
738
|
+
handleMoveItem,
|
|
739
|
+
name,
|
|
740
|
+
handleDisconnect,
|
|
741
|
+
relations: data,
|
|
742
|
+
targetModel,
|
|
743
|
+
mainField
|
|
744
|
+
}), [
|
|
745
|
+
ariaDescriptionId,
|
|
746
|
+
canReorder,
|
|
747
|
+
disabled,
|
|
748
|
+
documentParams,
|
|
749
|
+
handleCancel,
|
|
750
|
+
handleDisconnect,
|
|
751
|
+
handleDropItem,
|
|
752
|
+
handleGrabItem,
|
|
753
|
+
handleMoveItem,
|
|
754
|
+
name,
|
|
755
|
+
data,
|
|
756
|
+
targetModel,
|
|
757
|
+
mainField
|
|
758
|
+
]);
|
|
704
759
|
return /*#__PURE__*/ jsxs(ShadowBox, {
|
|
705
760
|
$overflowDirection: overflow,
|
|
706
761
|
children: [
|
|
@@ -721,20 +776,7 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
|
721
776
|
outerRef: outerListRef,
|
|
722
777
|
itemCount: data.length,
|
|
723
778
|
itemSize: RELATION_ITEM_HEIGHT + RELATION_GUTTER,
|
|
724
|
-
itemData:
|
|
725
|
-
ariaDescribedBy: ariaDescriptionId,
|
|
726
|
-
canDrag: canReorder,
|
|
727
|
-
disabled,
|
|
728
|
-
handleCancel,
|
|
729
|
-
handleDropItem,
|
|
730
|
-
handleGrabItem,
|
|
731
|
-
handleMoveItem,
|
|
732
|
-
name,
|
|
733
|
-
handleDisconnect,
|
|
734
|
-
relations: data,
|
|
735
|
-
targetModel,
|
|
736
|
-
mainField
|
|
737
|
-
},
|
|
779
|
+
itemData: itemData,
|
|
738
780
|
itemKey: (index)=>data[index].id,
|
|
739
781
|
innerElementType: "ol",
|
|
740
782
|
children: ListItem
|
|
@@ -742,6 +784,7 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
|
742
784
|
]
|
|
743
785
|
});
|
|
744
786
|
};
|
|
787
|
+
const MemoizedRelationsList = /*#__PURE__*/ React.memo(RelationsList);
|
|
745
788
|
const ShadowBox = styled(Box)`
|
|
746
789
|
position: relative;
|
|
747
790
|
overflow: hidden;
|
|
@@ -783,9 +826,8 @@ const RelationRow = styled(Flex)`
|
|
|
783
826
|
}
|
|
784
827
|
`;
|
|
785
828
|
const ListItem = ({ data, index, style })=>{
|
|
786
|
-
const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel, mainField } = data;
|
|
829
|
+
const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel, documentParams, mainField } = data;
|
|
787
830
|
const isDesktop = useIsDesktop();
|
|
788
|
-
const { currentDocumentMeta } = useDocumentContext('RelationsField');
|
|
789
831
|
const { formatMessage } = useIntl();
|
|
790
832
|
const { href, id, label: originalLabel, status: originalStatus, documentId, apiData, locale } = relations[index];
|
|
791
833
|
/**
|
|
@@ -798,7 +840,7 @@ const ListItem = ({ data, index, style })=>{
|
|
|
798
840
|
collectionType,
|
|
799
841
|
model: targetModel,
|
|
800
842
|
documentId: documentId ?? apiData?.documentId,
|
|
801
|
-
params:
|
|
843
|
+
params: documentParams
|
|
802
844
|
}, {
|
|
803
845
|
skip: !isTemporary
|
|
804
846
|
});
|
|
@@ -827,19 +869,14 @@ const ListItem = ({ data, index, style })=>{
|
|
|
827
869
|
]);
|
|
828
870
|
const safeDocumentId = documentId ?? apiData?.documentId;
|
|
829
871
|
const safeLocale = locale ?? apiData?.locale ?? null;
|
|
830
|
-
const documentMeta =
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
safeDocumentId,
|
|
839
|
-
href,
|
|
840
|
-
safeLocale,
|
|
841
|
-
targetModel
|
|
842
|
-
]);
|
|
872
|
+
const documentMeta = {
|
|
873
|
+
documentId: safeDocumentId,
|
|
874
|
+
model: targetModel,
|
|
875
|
+
collectionType: getCollectionType(href),
|
|
876
|
+
params: {
|
|
877
|
+
locale: safeLocale
|
|
878
|
+
}
|
|
879
|
+
};
|
|
843
880
|
return /*#__PURE__*/ jsx(Box, {
|
|
844
881
|
style: style,
|
|
845
882
|
tag: "li",
|