@strapi/content-manager 5.17.0-beta.0 → 5.17.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/FormInputs/Relations/Relations.js +153 -105
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +156 -108
- package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
- package/dist/server/services/document-metadata.js +1 -1
- package/dist/server/services/document-metadata.js.map +1 -1
- package/dist/server/services/document-metadata.mjs +1 -1
- package/dist/server/services/document-metadata.mjs.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -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, useFocusInputField } from '@strapi/admin/strapi-admin';
|
|
4
|
-
import { Flex, Box, Link, TextButton, Field, Combobox, ComboboxOption, Typography, VisuallyHidden, useComposedRefs, IconButton } from '@strapi/design-system';
|
|
5
|
-
import { ArrowClockwise, Plus, Link as Link$1, Drag, Cross } from '@strapi/icons';
|
|
3
|
+
import { useForm, useField, useNotification, useRBAC, useFocusInputField } from '@strapi/admin/strapi-admin';
|
|
4
|
+
import { Flex, Box, Link, TextButton, EmptyStateLayout, Field, Combobox, ComboboxOption, Typography, VisuallyHidden, useComposedRefs, IconButton } from '@strapi/design-system';
|
|
5
|
+
import { ArrowClockwise, WarningCircle, Plus, Link as Link$1, Drag, Cross } 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';
|
|
@@ -11,6 +11,8 @@ import { FixedSizeList } from 'react-window';
|
|
|
11
11
|
import { styled } from 'styled-components';
|
|
12
12
|
import { COLLECTION_TYPES } from '../../../../../constants/collections.mjs';
|
|
13
13
|
import { ItemTypes } from '../../../../../constants/dragAndDrop.mjs';
|
|
14
|
+
import { PERMISSIONS } from '../../../../../constants/plugin.mjs';
|
|
15
|
+
import { DocumentRBAC, useDocumentRBAC } from '../../../../../features/DocumentRBAC.mjs';
|
|
14
16
|
import { useDebounce } from '../../../../../hooks/useDebounce.mjs';
|
|
15
17
|
import { useDocument } from '../../../../../hooks/useDocument.mjs';
|
|
16
18
|
import { useDocumentContext } from '../../../../../hooks/useDocumentContext.mjs';
|
|
@@ -307,7 +309,6 @@ const ONE_WAY_RELATIONS = [
|
|
|
307
309
|
* @description Contains all the logic for the combobox that can search
|
|
308
310
|
* for relations and then add them to the field's connect array.
|
|
309
311
|
*/ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
|
|
310
|
-
const [textValue, setTextValue] = React.useState('');
|
|
311
312
|
const [searchParams, setSearchParams] = React.useState({
|
|
312
313
|
_q: '',
|
|
313
314
|
page: 1
|
|
@@ -315,7 +316,6 @@ const ONE_WAY_RELATIONS = [
|
|
|
315
316
|
const { toggleNotification } = useNotification();
|
|
316
317
|
const { currentDocumentMeta } = useDocumentContext('RelationsInput');
|
|
317
318
|
const { formatMessage } = useIntl();
|
|
318
|
-
const fieldRef = useFocusInputField(name);
|
|
319
319
|
const field = useField(name);
|
|
320
320
|
const searchParamsDebounced = useDebounce(searchParams, 300);
|
|
321
321
|
const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
|
|
@@ -356,13 +356,6 @@ const ONE_WAY_RELATIONS = [
|
|
|
356
356
|
isRelatedToCurrentDocument,
|
|
357
357
|
currentDocumentMeta.params
|
|
358
358
|
]);
|
|
359
|
-
const handleSearch = async (search)=>{
|
|
360
|
-
setSearchParams((s)=>({
|
|
361
|
-
...s,
|
|
362
|
-
_q: search,
|
|
363
|
-
page: 1
|
|
364
|
-
}));
|
|
365
|
-
};
|
|
366
359
|
const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
|
|
367
360
|
const options = data?.results ?? [];
|
|
368
361
|
const handleChange = (relationId)=>{
|
|
@@ -390,21 +383,6 @@ const ONE_WAY_RELATIONS = [
|
|
|
390
383
|
*
|
|
391
384
|
*/ onChange(relation);
|
|
392
385
|
};
|
|
393
|
-
const handleLoadMore = ()=>{
|
|
394
|
-
if (!data || !data.pagination) {
|
|
395
|
-
return;
|
|
396
|
-
} else if (data.pagination.page < data.pagination.pageCount) {
|
|
397
|
-
setSearchParams((s)=>({
|
|
398
|
-
...s,
|
|
399
|
-
page: s.page + 1
|
|
400
|
-
}));
|
|
401
|
-
}
|
|
402
|
-
};
|
|
403
|
-
React.useLayoutEffect(()=>{
|
|
404
|
-
setTextValue('');
|
|
405
|
-
}, [
|
|
406
|
-
field.value
|
|
407
|
-
]);
|
|
408
386
|
const relation = {
|
|
409
387
|
collectionType: COLLECTION_TYPES,
|
|
410
388
|
// @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
|
|
@@ -412,9 +390,26 @@ const ONE_WAY_RELATIONS = [
|
|
|
412
390
|
documentId: '',
|
|
413
391
|
params: currentDocumentMeta.params
|
|
414
392
|
};
|
|
415
|
-
const {
|
|
416
|
-
|
|
417
|
-
|
|
393
|
+
const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
|
|
394
|
+
action,
|
|
395
|
+
subject: relation.model
|
|
396
|
+
})));
|
|
397
|
+
if (error) {
|
|
398
|
+
return /*#__PURE__*/ jsx(Flex, {
|
|
399
|
+
alignItems: "center",
|
|
400
|
+
height: "100%",
|
|
401
|
+
justifyContent: "center",
|
|
402
|
+
children: /*#__PURE__*/ jsx(EmptyStateLayout, {
|
|
403
|
+
icon: /*#__PURE__*/ jsx(WarningCircle, {
|
|
404
|
+
width: "16rem"
|
|
405
|
+
}),
|
|
406
|
+
content: formatMessage({
|
|
407
|
+
id: 'anErrorOccurred',
|
|
408
|
+
defaultMessage: 'Whoops! Something went wrong. Please, try again.'
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
});
|
|
412
|
+
}
|
|
418
413
|
return /*#__PURE__*/ jsxs(Field.Root, {
|
|
419
414
|
error: field.error,
|
|
420
415
|
hint: hint,
|
|
@@ -425,90 +420,143 @@ const ONE_WAY_RELATIONS = [
|
|
|
425
420
|
action: labelAction,
|
|
426
421
|
children: label
|
|
427
422
|
}),
|
|
428
|
-
/*#__PURE__*/ jsx(
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
423
|
+
/*#__PURE__*/ jsx(DocumentRBAC, {
|
|
424
|
+
permissions: permissions,
|
|
425
|
+
model: relation.model,
|
|
426
|
+
children: /*#__PURE__*/ jsx(RelationModalWithContext, {
|
|
427
|
+
relation: relation,
|
|
428
|
+
name: name,
|
|
429
|
+
placeholder: placeholder,
|
|
430
|
+
hasNextPage: hasNextPage,
|
|
431
|
+
isLoadingPermissions: isLoadingPermissions,
|
|
432
|
+
isLoadingSearchRelations: isLoading,
|
|
433
|
+
handleChange: handleChange,
|
|
434
|
+
setSearchParams: setSearchParams,
|
|
435
|
+
data: data,
|
|
436
|
+
mainField: mainField,
|
|
437
|
+
fieldValue: field.value,
|
|
438
|
+
...props
|
|
439
|
+
})
|
|
440
|
+
}),
|
|
441
|
+
/*#__PURE__*/ jsx(Field.Error, {}),
|
|
442
|
+
/*#__PURE__*/ jsx(Field.Hint, {})
|
|
443
|
+
]
|
|
444
|
+
});
|
|
445
|
+
};
|
|
446
|
+
const RelationModalWithContext = ({ relation, name, placeholder, hasNextPage, isLoadingSearchRelations, isLoadingPermissions, handleChange, mainField, setSearchParams, fieldValue, data, ...props })=>{
|
|
447
|
+
const [textValue, setTextValue] = React.useState('');
|
|
448
|
+
const { formatMessage } = useIntl();
|
|
449
|
+
const canCreate = useDocumentRBAC('RelationModalWrapper', (state)=>state.canCreate);
|
|
450
|
+
const fieldRef = useFocusInputField(name);
|
|
451
|
+
const { componentUID } = useComponent('RelationsField', ({ uid })=>({
|
|
452
|
+
componentUID: uid
|
|
453
|
+
}));
|
|
454
|
+
const handleLoadMore = ()=>{
|
|
455
|
+
if (!data || !data.pagination) {
|
|
456
|
+
return;
|
|
457
|
+
} else if (data.pagination.page < data.pagination.pageCount) {
|
|
458
|
+
setSearchParams((s)=>({
|
|
459
|
+
...s,
|
|
460
|
+
page: s.page + 1
|
|
461
|
+
}));
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
const options = data?.results ?? [];
|
|
465
|
+
React.useLayoutEffect(()=>{
|
|
466
|
+
setTextValue('');
|
|
467
|
+
}, [
|
|
468
|
+
fieldValue
|
|
469
|
+
]);
|
|
470
|
+
const handleSearch = async (search)=>{
|
|
471
|
+
setSearchParams((s)=>({
|
|
472
|
+
...s,
|
|
473
|
+
_q: search,
|
|
474
|
+
page: 1
|
|
475
|
+
}));
|
|
476
|
+
};
|
|
477
|
+
return /*#__PURE__*/ jsx(RelationModalRenderer, {
|
|
478
|
+
children: ({ dispatch })=>/*#__PURE__*/ jsx(Combobox, {
|
|
479
|
+
ref: fieldRef,
|
|
480
|
+
creatable: "visible",
|
|
481
|
+
creatableDisabled: !canCreate,
|
|
482
|
+
createMessage: ()=>formatMessage({
|
|
483
|
+
id: getTranslation('relation.create'),
|
|
484
|
+
defaultMessage: 'Create a relation'
|
|
485
|
+
}),
|
|
486
|
+
onCreateOption: ()=>{
|
|
487
|
+
if (canCreate) {
|
|
488
|
+
dispatch({
|
|
489
|
+
type: 'GO_TO_RELATION',
|
|
490
|
+
payload: {
|
|
491
|
+
document: relation,
|
|
492
|
+
shouldBypassConfirmation: false,
|
|
493
|
+
fieldToConnect: name,
|
|
494
|
+
fieldToConnectUID: componentUID
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
creatableStartIcon: /*#__PURE__*/ jsx(Plus, {
|
|
500
|
+
fill: "neutral500"
|
|
501
|
+
}),
|
|
502
|
+
name: name,
|
|
503
|
+
autocomplete: "list",
|
|
504
|
+
placeholder: placeholder || formatMessage({
|
|
505
|
+
id: getTranslation('relation.add'),
|
|
506
|
+
defaultMessage: 'Add relation'
|
|
507
|
+
}),
|
|
508
|
+
hasMoreItems: hasNextPage,
|
|
509
|
+
loading: isLoadingSearchRelations || isLoadingPermissions,
|
|
510
|
+
onOpenChange: ()=>{
|
|
511
|
+
handleSearch(textValue ?? '');
|
|
512
|
+
},
|
|
513
|
+
noOptionsMessage: ()=>formatMessage({
|
|
514
|
+
id: getTranslation('relation.notAvailable'),
|
|
515
|
+
defaultMessage: 'No relations available'
|
|
516
|
+
}),
|
|
517
|
+
loadingMessage: formatMessage({
|
|
518
|
+
id: getTranslation('relation.isLoading'),
|
|
519
|
+
defaultMessage: 'Relations are loading'
|
|
520
|
+
}),
|
|
521
|
+
onLoadMore: handleLoadMore,
|
|
522
|
+
textValue: textValue,
|
|
523
|
+
onChange: handleChange,
|
|
524
|
+
onTextValueChange: (text)=>{
|
|
525
|
+
setTextValue(text);
|
|
526
|
+
},
|
|
527
|
+
onInputChange: (event)=>{
|
|
528
|
+
handleSearch(event.currentTarget.value);
|
|
529
|
+
},
|
|
530
|
+
...props,
|
|
531
|
+
children: options?.map((opt)=>{
|
|
532
|
+
const textValue = getRelationLabel(opt, mainField);
|
|
533
|
+
return /*#__PURE__*/ jsx(ComboboxOption, {
|
|
534
|
+
value: opt.id.toString(),
|
|
470
535
|
textValue: textValue,
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
handleSearch(event.currentTarget.value);
|
|
477
|
-
},
|
|
478
|
-
...props,
|
|
479
|
-
children: options.map((opt)=>{
|
|
480
|
-
const textValue = getRelationLabel(opt, mainField);
|
|
481
|
-
return /*#__PURE__*/ jsx(ComboboxOption, {
|
|
482
|
-
value: opt.id.toString(),
|
|
483
|
-
textValue: textValue,
|
|
484
|
-
children: /*#__PURE__*/ jsxs(Flex, {
|
|
536
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
|
537
|
+
gap: 2,
|
|
538
|
+
justifyContent: "space-between",
|
|
539
|
+
children: [
|
|
540
|
+
/*#__PURE__*/ jsxs(Flex, {
|
|
485
541
|
gap: 2,
|
|
486
|
-
justifyContent: "space-between",
|
|
487
542
|
children: [
|
|
488
|
-
/*#__PURE__*/
|
|
489
|
-
|
|
490
|
-
children: [
|
|
491
|
-
/*#__PURE__*/ jsx(Link$1, {
|
|
492
|
-
fill: "neutral500"
|
|
493
|
-
}),
|
|
494
|
-
/*#__PURE__*/ jsx(Typography, {
|
|
495
|
-
ellipsis: true,
|
|
496
|
-
children: textValue
|
|
497
|
-
})
|
|
498
|
-
]
|
|
543
|
+
/*#__PURE__*/ jsx(Link$1, {
|
|
544
|
+
fill: "neutral500"
|
|
499
545
|
}),
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
546
|
+
/*#__PURE__*/ jsx(Typography, {
|
|
547
|
+
ellipsis: true,
|
|
548
|
+
children: textValue
|
|
549
|
+
})
|
|
503
550
|
]
|
|
504
|
-
})
|
|
505
|
-
|
|
551
|
+
}),
|
|
552
|
+
opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
|
|
553
|
+
status: opt.status
|
|
554
|
+
}) : null
|
|
555
|
+
]
|
|
506
556
|
})
|
|
507
|
-
})
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
/*#__PURE__*/ jsx(Field.Hint, {})
|
|
511
|
-
]
|
|
557
|
+
}, opt.id);
|
|
558
|
+
})
|
|
559
|
+
})
|
|
512
560
|
});
|
|
513
561
|
};
|
|
514
562
|
/* -------------------------------------------------------------------------------------------------
|