@contentful/field-editor-reference 5.9.0 → 5.11.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/cjs/__fixtures__/FakeSdk.js +183 -0
- package/dist/cjs/__fixtures__/asset/index.js +37 -0
- package/dist/cjs/__fixtures__/content-type/index.js +16 -0
- package/dist/cjs/__fixtures__/entry/index.js +33 -0
- package/dist/cjs/__fixtures__/fixtures.js +71 -0
- package/dist/cjs/__fixtures__/locale/index.js +40 -0
- package/dist/cjs/__fixtures__/space/index.js +16 -0
- package/dist/cjs/assets/MultipleMediaEditor.js +86 -0
- package/dist/cjs/assets/SingleMediaEditor.js +69 -0
- package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +125 -0
- package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +171 -0
- package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +159 -0
- package/dist/cjs/assets/WrappedAssetCard/WrappedAssetLink.js +130 -0
- package/dist/cjs/assets/index.js +24 -0
- package/dist/cjs/common/EntityStore.js +420 -0
- package/dist/cjs/common/MultipleReferenceEditor.js +164 -0
- package/dist/cjs/common/ReferenceEditor.js +74 -0
- package/dist/cjs/common/SingleReferenceEditor.js +118 -0
- package/dist/cjs/common/SortableLinkList.js +95 -0
- package/dist/cjs/common/customCardTypes.js +44 -0
- package/dist/cjs/common/useAccessApi.js +19 -0
- package/dist/cjs/common/useContentTypePermissions.js +54 -0
- package/dist/cjs/common/useEditorPermissions.js +77 -0
- package/dist/cjs/common/useEditorPermissions.spec.js +205 -0
- package/dist/cjs/components/AssetThumbnail/AssetThumbnail.js +62 -0
- package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.js +102 -0
- package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +254 -0
- package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +199 -0
- package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +190 -0
- package/dist/cjs/components/CreateEntryLinkButton/useGlobalMouseUp.js +19 -0
- package/dist/cjs/components/LinkActions/CombinedLinkActions.js +167 -0
- package/dist/cjs/components/LinkActions/LinkActions.js +123 -0
- package/dist/cjs/components/LinkActions/LinkEntityActions.js +186 -0
- package/dist/cjs/components/LinkActions/NoLinkPermissionsInfo.js +54 -0
- package/dist/cjs/components/LinkActions/helpers.js +78 -0
- package/dist/cjs/components/LinkActions/redesignStyles.js +44 -0
- package/dist/cjs/components/LinkActions/styles.js +33 -0
- package/dist/cjs/components/MissingEntityCard/MissingEntityCard.js +75 -0
- package/dist/cjs/components/MissingEntityCard/styles.js +29 -0
- package/dist/cjs/components/ScheduledIconWithTooltip/ScheduleTooltip.js +75 -0
- package/dist/cjs/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +81 -0
- package/dist/cjs/components/ScheduledIconWithTooltip/formatDateAndTime.js +45 -0
- package/dist/cjs/components/SpaceName/SpaceName.js +91 -0
- package/dist/cjs/components/index.js +44 -0
- package/dist/cjs/entries/MultipleEntryReferenceEditor.js +86 -0
- package/dist/cjs/entries/SingleEntryReferenceEditor.js +74 -0
- package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +189 -0
- package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +181 -0
- package/dist/cjs/entries/index.js +24 -0
- package/dist/cjs/index.js +92 -0
- package/dist/cjs/resources/Cards/ContentfulEntryCard.js +87 -0
- package/dist/cjs/resources/Cards/ResourceCard.js +111 -0
- package/dist/cjs/resources/Cards/UnsupportedEntityCard.js +64 -0
- package/dist/cjs/resources/MultipleResourceReferenceEditor.js +157 -0
- package/dist/cjs/resources/MultipleResourceReferenceEditor.spec.js +297 -0
- package/dist/cjs/resources/SingleResourceReferenceEditor.js +87 -0
- package/dist/cjs/resources/SingleResourceReferenceEditor.spec.js +161 -0
- package/dist/cjs/resources/index.js +19 -0
- package/dist/cjs/resources/testHelpers/resourceEditorHelpers.js +121 -0
- package/dist/cjs/resources/useResourceLinkActions.js +88 -0
- package/dist/cjs/types.js +22 -0
- package/dist/cjs/utils/fromFieldValidations.js +54 -0
- package/dist/esm/__fixtures__/FakeSdk.js +173 -0
- package/dist/esm/__fixtures__/asset/index.js +6 -0
- package/dist/esm/__fixtures__/content-type/index.js +2 -0
- package/dist/esm/__fixtures__/entry/index.js +5 -0
- package/dist/esm/__fixtures__/fixtures.js +6 -0
- package/dist/esm/__fixtures__/locale/index.js +15 -0
- package/dist/esm/__fixtures__/space/index.js +2 -0
- package/dist/esm/assets/MultipleMediaEditor.js +37 -0
- package/dist/esm/assets/SingleMediaEditor.js +20 -0
- package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +63 -0
- package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +122 -0
- package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +105 -0
- package/dist/esm/assets/WrappedAssetCard/WrappedAssetLink.js +76 -0
- package/dist/esm/assets/index.js +3 -0
- package/dist/esm/common/EntityStore.js +347 -0
- package/dist/esm/common/MultipleReferenceEditor.js +111 -0
- package/dist/esm/common/ReferenceEditor.js +20 -0
- package/dist/esm/common/SingleReferenceEditor.js +70 -0
- package/dist/esm/common/SortableLinkList.js +41 -0
- package/dist/esm/common/customCardTypes.js +1 -0
- package/dist/esm/common/useAccessApi.js +9 -0
- package/dist/esm/common/useContentTypePermissions.js +44 -0
- package/dist/esm/common/useEditorPermissions.js +67 -0
- package/dist/esm/common/useEditorPermissions.spec.js +201 -0
- package/dist/esm/components/AssetThumbnail/AssetThumbnail.js +13 -0
- package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.js +48 -0
- package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +206 -0
- package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +145 -0
- package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +142 -0
- package/dist/esm/components/CreateEntryLinkButton/useGlobalMouseUp.js +9 -0
- package/dist/esm/components/LinkActions/CombinedLinkActions.js +118 -0
- package/dist/esm/components/LinkActions/LinkActions.js +66 -0
- package/dist/esm/components/LinkActions/LinkEntityActions.js +127 -0
- package/dist/esm/components/LinkActions/NoLinkPermissionsInfo.js +5 -0
- package/dist/esm/components/LinkActions/helpers.js +57 -0
- package/dist/esm/components/LinkActions/redesignStyles.js +18 -0
- package/dist/esm/components/LinkActions/styles.js +10 -0
- package/dist/esm/components/MissingEntityCard/MissingEntityCard.js +26 -0
- package/dist/esm/components/MissingEntityCard/styles.js +11 -0
- package/dist/esm/components/ScheduledIconWithTooltip/ScheduleTooltip.js +18 -0
- package/dist/esm/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +32 -0
- package/dist/esm/components/ScheduledIconWithTooltip/formatDateAndTime.js +19 -0
- package/dist/esm/components/SpaceName/SpaceName.js +37 -0
- package/dist/esm/components/index.js +8 -0
- package/dist/esm/entries/MultipleEntryReferenceEditor.js +37 -0
- package/dist/esm/entries/SingleEntryReferenceEditor.js +25 -0
- package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +135 -0
- package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +127 -0
- package/dist/esm/entries/index.js +3 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/resources/Cards/ContentfulEntryCard.js +38 -0
- package/dist/esm/resources/Cards/ResourceCard.js +62 -0
- package/dist/esm/resources/Cards/UnsupportedEntityCard.js +15 -0
- package/dist/esm/resources/MultipleResourceReferenceEditor.js +104 -0
- package/dist/esm/resources/MultipleResourceReferenceEditor.spec.js +254 -0
- package/dist/esm/resources/SingleResourceReferenceEditor.js +33 -0
- package/dist/esm/resources/SingleResourceReferenceEditor.spec.js +118 -0
- package/dist/esm/resources/index.js +2 -0
- package/dist/esm/resources/testHelpers/resourceEditorHelpers.js +103 -0
- package/dist/esm/resources/useResourceLinkActions.js +78 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/fromFieldValidations.js +39 -0
- package/dist/{__fixtures__ → types/__fixtures__}/FakeSdk.d.ts +8 -8
- package/dist/{__fixtures__ → types/__fixtures__}/asset/index.d.ts +6 -6
- package/dist/{__fixtures__ → types/__fixtures__}/content-type/index.d.ts +2 -2
- package/dist/{__fixtures__ → types/__fixtures__}/entry/index.d.ts +5 -5
- package/dist/{__fixtures__ → types/__fixtures__}/fixtures.d.ts +6 -6
- package/dist/{__fixtures__ → types/__fixtures__}/locale/index.d.ts +42 -42
- package/dist/{__fixtures__ → types/__fixtures__}/space/index.d.ts +2 -2
- package/dist/{assets → types/assets}/MultipleMediaEditor.d.ts +10 -10
- package/dist/types/assets/SingleMediaEditor.d.ts +10 -0
- package/dist/{assets → types/assets}/WrappedAssetCard/AssetCardActions.d.ts +11 -11
- package/dist/{assets → types/assets}/WrappedAssetCard/FetchingWrappedAssetCard.d.ts +17 -17
- package/dist/{assets → types/assets}/WrappedAssetCard/WrappedAssetCard.d.ts +24 -24
- package/dist/{assets → types/assets}/WrappedAssetCard/WrappedAssetLink.d.ts +16 -16
- package/dist/{assets → types/assets}/index.d.ts +3 -3
- package/dist/{common → types/common}/EntityStore.d.ts +62 -62
- package/dist/{common → types/common}/MultipleReferenceEditor.d.ts +25 -25
- package/dist/{common → types/common}/ReferenceEditor.d.ts +46 -46
- package/dist/{common → types/common}/SingleReferenceEditor.d.ts +24 -24
- package/dist/{common → types/common}/SortableLinkList.d.ts +19 -19
- package/dist/{common → types/common}/customCardTypes.d.ts +29 -29
- package/dist/types/common/useAccessApi.d.ts +16 -0
- package/dist/{common → types/common}/useContentTypePermissions.d.ts +17 -17
- package/dist/{common → types/common}/useEditorPermissions.d.ts +17 -17
- package/dist/types/common/useEditorPermissions.spec.d.ts +1 -0
- package/dist/{components → types/components}/AssetThumbnail/AssetThumbnail.d.ts +7 -7
- package/dist/{components → types/components}/CreateEntryLinkButton/CreateEntryLinkButton.d.ts +19 -19
- package/dist/types/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.d.ts +1 -0
- package/dist/{components → types/components}/CreateEntryLinkButton/CreateEntryMenuTrigger.d.ts +31 -31
- package/dist/types/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.d.ts +1 -0
- package/dist/{components → types/components}/CreateEntryLinkButton/useGlobalMouseUp.d.ts +1 -1
- package/dist/{components → types/components}/LinkActions/CombinedLinkActions.d.ts +10 -10
- package/dist/{components → types/components}/LinkActions/LinkActions.d.ts +26 -26
- package/dist/{components → types/components}/LinkActions/LinkEntityActions.d.ts +24 -24
- package/dist/types/components/LinkActions/NoLinkPermissionsInfo.d.ts +2 -0
- package/dist/{components → types/components}/LinkActions/helpers.d.ts +26 -26
- package/dist/{components → types/components}/LinkActions/redesignStyles.d.ts +3 -3
- package/dist/{components → types/components}/LinkActions/styles.d.ts +2 -2
- package/dist/{components → types/components}/MissingEntityCard/MissingEntityCard.d.ts +8 -8
- package/dist/{components → types/components}/MissingEntityCard/styles.d.ts +2 -2
- package/dist/{components → types/components}/ScheduledIconWithTooltip/ScheduleTooltip.d.ts +11 -11
- package/dist/{components → types/components}/ScheduledIconWithTooltip/ScheduledIconWithTooltip.d.ts +10 -10
- package/dist/{components → types/components}/ScheduledIconWithTooltip/formatDateAndTime.d.ts +15 -15
- package/dist/types/components/SpaceName/SpaceName.d.ts +6 -0
- package/dist/{components → types/components}/index.d.ts +9 -9
- package/dist/{entries → types/entries}/MultipleEntryReferenceEditor.d.ts +3 -3
- package/dist/{entries → types/entries}/SingleEntryReferenceEditor.d.ts +8 -8
- package/dist/{entries → types/entries}/WrappedEntryCard/FetchingWrappedEntryCard.d.ts +18 -18
- package/dist/{entries → types/entries}/WrappedEntryCard/WrappedEntryCard.d.ts +35 -35
- package/dist/{entries → types/entries}/index.d.ts +3 -3
- package/dist/{index.d.ts → types/index.d.ts} +10 -8
- package/dist/{resources → types/resources}/Cards/ContentfulEntryCard.d.ts +21 -21
- package/dist/{resources → types/resources}/Cards/ResourceCard.d.ts +12 -12
- package/dist/{resources → types/resources}/Cards/UnsupportedEntityCard.d.ts +4 -4
- package/dist/{resources → types/resources}/MultipleResourceReferenceEditor.d.ts +7 -7
- package/dist/types/resources/MultipleResourceReferenceEditor.spec.d.ts +1 -0
- package/dist/{resources → types/resources}/SingleResourceReferenceEditor.d.ts +7 -7
- package/dist/types/resources/SingleResourceReferenceEditor.spec.d.ts +1 -0
- package/dist/{resources → types/resources}/index.d.ts +2 -2
- package/dist/{resources → types/resources}/testHelpers/resourceEditorHelpers.d.ts +50 -50
- package/dist/{resources → types/resources}/useResourceLinkActions.d.ts +7 -7
- package/dist/{types.d.ts → types/types.d.ts} +104 -104
- package/dist/{utils → types/utils}/fromFieldValidations.d.ts +21 -21
- package/package.json +25 -11
- package/CHANGELOG.md +0 -860
- package/dist/assets/SingleMediaEditor.d.ts +0 -10
- package/dist/common/useAccessApi.d.ts +0 -16
- package/dist/components/LinkActions/NoLinkPermissionsInfo.d.ts +0 -2
- package/dist/components/SpaceName/SpaceName.d.ts +0 -6
- package/dist/field-editor-reference.cjs.development.js +0 -2753
- package/dist/field-editor-reference.cjs.development.js.map +0 -1
- package/dist/field-editor-reference.cjs.production.min.js +0 -2
- package/dist/field-editor-reference.cjs.production.min.js.map +0 -1
- package/dist/field-editor-reference.esm.js +0 -2727
- package/dist/field-editor-reference.esm.js.map +0 -1
- package/dist/index.js +0 -8
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { EntryCard, MenuItem, MenuDivider } from '@contentful/f36-components';
|
|
3
|
+
import { ClockIcon } from '@contentful/f36-icons';
|
|
4
|
+
import tokens from '@contentful/f36-tokens';
|
|
5
|
+
import { entityHelpers, isValidImage } from '@contentful/field-editor-shared';
|
|
6
|
+
import { css } from 'emotion';
|
|
7
|
+
import { AssetThumbnail, MissingEntityCard, ScheduledIconWithTooltip } from '../../components';
|
|
8
|
+
import { SpaceName } from '../../components/SpaceName/SpaceName';
|
|
9
|
+
const { getEntryTitle , getEntityDescription , getEntryStatus , getEntryImage } = entityHelpers;
|
|
10
|
+
const styles = {
|
|
11
|
+
scheduleIcon: css({
|
|
12
|
+
marginRight: tokens.spacing2Xs
|
|
13
|
+
})
|
|
14
|
+
};
|
|
15
|
+
const defaultProps = {
|
|
16
|
+
isClickable: true,
|
|
17
|
+
hasCardEditActions: true,
|
|
18
|
+
hasCardMoveActions: true,
|
|
19
|
+
hasCardRemoveActions: true
|
|
20
|
+
};
|
|
21
|
+
export function WrappedEntryCard(props) {
|
|
22
|
+
const [file, setFile] = React.useState(null);
|
|
23
|
+
const { contentType } = props;
|
|
24
|
+
React.useEffect(()=>{
|
|
25
|
+
if (props.entry) {
|
|
26
|
+
getEntryImage({
|
|
27
|
+
entry: props.entry,
|
|
28
|
+
contentType,
|
|
29
|
+
localeCode: props.localeCode,
|
|
30
|
+
defaultLocaleCode: props.defaultLocaleCode
|
|
31
|
+
}, props.getAsset).then((file)=>{
|
|
32
|
+
setFile(file);
|
|
33
|
+
}).catch(()=>{
|
|
34
|
+
setFile(null);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}, [
|
|
38
|
+
props.entry,
|
|
39
|
+
props.getAsset,
|
|
40
|
+
contentType,
|
|
41
|
+
props.localeCode,
|
|
42
|
+
props.defaultLocaleCode
|
|
43
|
+
]);
|
|
44
|
+
const status = getEntryStatus(props.entry?.sys);
|
|
45
|
+
if (status === 'deleted') {
|
|
46
|
+
return React.createElement(MissingEntityCard, {
|
|
47
|
+
entityType: "Entry",
|
|
48
|
+
isDisabled: props.isDisabled,
|
|
49
|
+
onRemove: props.onRemove
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const title = getEntryTitle({
|
|
53
|
+
entry: props.entry,
|
|
54
|
+
contentType,
|
|
55
|
+
localeCode: props.localeCode,
|
|
56
|
+
defaultLocaleCode: props.defaultLocaleCode,
|
|
57
|
+
defaultTitle: 'Untitled'
|
|
58
|
+
});
|
|
59
|
+
const description = getEntityDescription({
|
|
60
|
+
entity: props.entry,
|
|
61
|
+
contentType,
|
|
62
|
+
localeCode: props.localeCode,
|
|
63
|
+
defaultLocaleCode: props.defaultLocaleCode
|
|
64
|
+
});
|
|
65
|
+
return React.createElement(EntryCard, {
|
|
66
|
+
as: props.entryUrl ? 'a' : 'article',
|
|
67
|
+
href: props.entryUrl,
|
|
68
|
+
title: title,
|
|
69
|
+
description: description,
|
|
70
|
+
contentType: contentType?.name,
|
|
71
|
+
size: props.size,
|
|
72
|
+
isSelected: props.isSelected,
|
|
73
|
+
status: status,
|
|
74
|
+
icon: props.spaceName ? React.createElement(SpaceName, {
|
|
75
|
+
spaceName: props.spaceName
|
|
76
|
+
}) : React.createElement(ScheduledIconWithTooltip, {
|
|
77
|
+
getEntityScheduledActions: props.getEntityScheduledActions,
|
|
78
|
+
entityType: "Entry",
|
|
79
|
+
entityId: props.entry.sys.id
|
|
80
|
+
}, React.createElement(ClockIcon, {
|
|
81
|
+
className: styles.scheduleIcon,
|
|
82
|
+
size: "small",
|
|
83
|
+
variant: "muted",
|
|
84
|
+
testId: "schedule-icon"
|
|
85
|
+
})),
|
|
86
|
+
thumbnailElement: file && isValidImage(file) ? React.createElement(AssetThumbnail, {
|
|
87
|
+
file: file
|
|
88
|
+
}) : undefined,
|
|
89
|
+
dragHandleRender: props.renderDragHandle,
|
|
90
|
+
withDragHandle: !!props.renderDragHandle,
|
|
91
|
+
actions: props.onEdit || props.onRemove ? [
|
|
92
|
+
props.hasCardEditActions && props.onEdit ? React.createElement(MenuItem, {
|
|
93
|
+
key: "edit",
|
|
94
|
+
testId: "edit",
|
|
95
|
+
onClick: ()=>{
|
|
96
|
+
props.onEdit && props.onEdit();
|
|
97
|
+
}
|
|
98
|
+
}, "Edit") : null,
|
|
99
|
+
props.hasCardRemoveActions && props.onRemove ? React.createElement(MenuItem, {
|
|
100
|
+
key: "delete",
|
|
101
|
+
testId: "delete",
|
|
102
|
+
onClick: ()=>{
|
|
103
|
+
props.onRemove && props.onRemove();
|
|
104
|
+
}
|
|
105
|
+
}, "Remove") : null,
|
|
106
|
+
props.hasCardMoveActions && (props.onMoveTop || props.onMoveBottom) ? React.createElement(MenuDivider, {
|
|
107
|
+
key: "divider"
|
|
108
|
+
}) : null,
|
|
109
|
+
props.hasCardMoveActions && props.onMoveTop ? React.createElement(MenuItem, {
|
|
110
|
+
key: "move-top",
|
|
111
|
+
onClick: ()=>props.onMoveTop && props.onMoveTop(),
|
|
112
|
+
testId: "move-top"
|
|
113
|
+
}, "Move to top") : null,
|
|
114
|
+
props.hasCardMoveActions && props.onMoveBottom ? React.createElement(MenuItem, {
|
|
115
|
+
key: "move-bottom",
|
|
116
|
+
onClick: ()=>props.onMoveBottom && props.onMoveBottom(),
|
|
117
|
+
testId: "move-bottom"
|
|
118
|
+
}, "Move to bottom") : null
|
|
119
|
+
].filter((item)=>item) : [],
|
|
120
|
+
onClick: props.isClickable ? (e)=>{
|
|
121
|
+
e.preventDefault();
|
|
122
|
+
if (props.onClick) return props.onClick(e);
|
|
123
|
+
props.onEdit && props.onEdit();
|
|
124
|
+
} : undefined
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
WrappedEntryCard.defaultProps = defaultProps;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CreateEntryMenuTrigger, CreateEntryLinkButton, getScheduleTooltipContent, ScheduledIconWithTooltip, AssetThumbnail, MissingEntityCard, CombinedLinkActions } from './components';
|
|
2
|
+
export { SingleEntryReferenceEditor, MultipleEntryReferenceEditor, WrappedEntryCard } from './entries';
|
|
3
|
+
export { SingleMediaEditor, MultipleMediaEditor, WrappedAssetCard } from './assets';
|
|
4
|
+
export { SortableLinkList } from './common/SortableLinkList';
|
|
5
|
+
export { EntityProvider, useEntityLoader, useEntity, useResource } from './common/EntityStore';
|
|
6
|
+
export { SingleResourceReferenceEditor, MultipleResourceReferenceEditor } from './resources';
|
|
7
|
+
export * from './types';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { WrappedEntryCard } from '../../entries';
|
|
3
|
+
const resolveAsset = ()=>Promise.resolve();
|
|
4
|
+
const resolveScheduledActions = ()=>Promise.resolve([]);
|
|
5
|
+
export function ContentfulEntryCard({ info , isDisabled , renderDragHandle , onRemove , onMoveTop , onMoveBottom , getEntryRouteHref }) {
|
|
6
|
+
const resourceSys = info.resource.sys;
|
|
7
|
+
const spaceId = resourceSys.space.sys.id;
|
|
8
|
+
const environmentId = resourceSys.environment.sys.id;
|
|
9
|
+
const entryId = resourceSys.id;
|
|
10
|
+
const resourceHref = getEntryRouteHref({
|
|
11
|
+
spaceId,
|
|
12
|
+
environmentId,
|
|
13
|
+
entryId
|
|
14
|
+
});
|
|
15
|
+
const openEntryDetail = ()=>{
|
|
16
|
+
window.open(resourceHref, '_blank', 'noopener,noreferrer');
|
|
17
|
+
};
|
|
18
|
+
return React.createElement(WrappedEntryCard, {
|
|
19
|
+
entry: info.resource,
|
|
20
|
+
isDisabled: isDisabled,
|
|
21
|
+
hasCardEditActions: false,
|
|
22
|
+
contentType: info.contentType,
|
|
23
|
+
localeCode: info.defaultLocaleCode,
|
|
24
|
+
defaultLocaleCode: info.defaultLocaleCode,
|
|
25
|
+
size: "small",
|
|
26
|
+
getAsset: resolveAsset,
|
|
27
|
+
getEntityScheduledActions: resolveScheduledActions,
|
|
28
|
+
spaceName: info.space.name,
|
|
29
|
+
renderDragHandle: renderDragHandle,
|
|
30
|
+
isClickable: true,
|
|
31
|
+
onEdit: openEntryDetail,
|
|
32
|
+
hasCardRemoveActions: Boolean(onRemove),
|
|
33
|
+
onRemove: onRemove,
|
|
34
|
+
onMoveBottom: onMoveBottom,
|
|
35
|
+
onMoveTop: onMoveTop,
|
|
36
|
+
entryUrl: resourceHref
|
|
37
|
+
});
|
|
38
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useInView } from 'react-intersection-observer';
|
|
3
|
+
import { EntryCard } from '@contentful/f36-components';
|
|
4
|
+
import { isUnsupportedError, useResource } from '../../common/EntityStore';
|
|
5
|
+
import { MissingEntityCard } from '../../components';
|
|
6
|
+
import { ContentfulEntryCard } from './ContentfulEntryCard';
|
|
7
|
+
import { UnsupportedEntityCard } from './UnsupportedEntityCard';
|
|
8
|
+
function ResourceCardSkeleton() {
|
|
9
|
+
return React.createElement(EntryCard, {
|
|
10
|
+
size: "small",
|
|
11
|
+
isLoading: true
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function ExistingResourceCard(props) {
|
|
15
|
+
const { resourceLink , inView , index =0 } = props;
|
|
16
|
+
const resourceOptions = {
|
|
17
|
+
priority: index * -1,
|
|
18
|
+
enabled: inView
|
|
19
|
+
};
|
|
20
|
+
const { data , error } = useResource(resourceLink.sys.linkType, resourceLink.sys.urn, resourceOptions);
|
|
21
|
+
if (!data && !error) {
|
|
22
|
+
return React.createElement(ResourceCardSkeleton, null);
|
|
23
|
+
}
|
|
24
|
+
if (data) {
|
|
25
|
+
return React.createElement(ContentfulEntryCard, {
|
|
26
|
+
info: data,
|
|
27
|
+
...props
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (isUnsupportedError(error)) {
|
|
31
|
+
return React.createElement(UnsupportedEntityCard, {
|
|
32
|
+
entityType: resourceLink.sys.linkType
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return React.createElement(MissingEntityCard, {
|
|
36
|
+
entityType: "Entry",
|
|
37
|
+
isDisabled: props.isDisabled,
|
|
38
|
+
onRemove: props.onRemove
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function ResourceCardWrapper(props) {
|
|
42
|
+
if (!props.resourceLink) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return React.createElement(ExistingResourceCard, {
|
|
46
|
+
...props,
|
|
47
|
+
resourceLink: props.resourceLink,
|
|
48
|
+
getEntryRouteHref: props.getEntryRouteHref
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function ResourceCard(props) {
|
|
52
|
+
const { ref , inView } = useInView({
|
|
53
|
+
triggerOnce: true,
|
|
54
|
+
rootMargin: '300px 0px 0px 300px'
|
|
55
|
+
});
|
|
56
|
+
return React.createElement("div", {
|
|
57
|
+
ref: ref
|
|
58
|
+
}, React.createElement(ResourceCardWrapper, {
|
|
59
|
+
...props,
|
|
60
|
+
inView: inView
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Card, SectionHeading } from '@contentful/f36-components';
|
|
3
|
+
import { css } from 'emotion';
|
|
4
|
+
const styles = {
|
|
5
|
+
card: css({
|
|
6
|
+
position: 'relative'
|
|
7
|
+
})
|
|
8
|
+
};
|
|
9
|
+
export function UnsupportedEntityCard(props) {
|
|
10
|
+
return React.createElement(Card, {
|
|
11
|
+
className: styles.card
|
|
12
|
+
}, React.createElement(SectionHeading, {
|
|
13
|
+
marginBottom: "none"
|
|
14
|
+
}, "Resource type ", props.entityType, " is currently not supported"));
|
|
15
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { FieldConnector } from '@contentful/field-editor-shared';
|
|
4
|
+
import arrayMove from 'array-move';
|
|
5
|
+
import deepEqual from 'deep-equal';
|
|
6
|
+
import { EntityProvider } from '../common/EntityStore';
|
|
7
|
+
import { SortableLinkList } from '../common/SortableLinkList';
|
|
8
|
+
import { CombinedLinkEntityActions } from '../components/LinkActions/LinkEntityActions';
|
|
9
|
+
import { ResourceCard } from './Cards/ResourceCard';
|
|
10
|
+
import { useResourceLinkActions } from './useResourceLinkActions';
|
|
11
|
+
function ResourceEditor(props) {
|
|
12
|
+
const { setValue , items , apiUrl } = props;
|
|
13
|
+
const onSortStart = useCallback((_, event)=>event.preventDefault(), []);
|
|
14
|
+
const onSortEnd = useCallback(({ oldIndex , newIndex })=>{
|
|
15
|
+
const newItems = arrayMove(items, oldIndex, newIndex);
|
|
16
|
+
setValue(newItems);
|
|
17
|
+
}, [
|
|
18
|
+
items,
|
|
19
|
+
setValue
|
|
20
|
+
]);
|
|
21
|
+
const onMove = useCallback((oldIndex, newIndex)=>{
|
|
22
|
+
const newItems = arrayMove(items, oldIndex, newIndex);
|
|
23
|
+
setValue(newItems);
|
|
24
|
+
}, [
|
|
25
|
+
items,
|
|
26
|
+
setValue
|
|
27
|
+
]);
|
|
28
|
+
const onRemoteItemAtIndex = useCallback((index)=>{
|
|
29
|
+
setValue(items.filter((_v, i)=>i !== index));
|
|
30
|
+
}, [
|
|
31
|
+
items,
|
|
32
|
+
setValue
|
|
33
|
+
]);
|
|
34
|
+
const { dialogs , field } = props.sdk;
|
|
35
|
+
const linkActionsProps = useResourceLinkActions({
|
|
36
|
+
dialogs,
|
|
37
|
+
field,
|
|
38
|
+
apiUrl
|
|
39
|
+
});
|
|
40
|
+
return React.createElement(React.Fragment, null, props.children({
|
|
41
|
+
...props,
|
|
42
|
+
onSortStart,
|
|
43
|
+
onSortEnd,
|
|
44
|
+
onMove,
|
|
45
|
+
onRemoteItemAtIndex
|
|
46
|
+
}), React.createElement(CombinedLinkEntityActions, {
|
|
47
|
+
...linkActionsProps,
|
|
48
|
+
renderCustomActions: props.renderCustomActions
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
function WithPerItemCallbacks({ listLength , index , onMove , onRemoteItemAtIndex , children }) {
|
|
52
|
+
const handleMoveTop = React.useMemo(()=>index > 0 ? ()=>onMove(index, 0) : undefined, [
|
|
53
|
+
index,
|
|
54
|
+
onMove
|
|
55
|
+
]);
|
|
56
|
+
const handleMoveBottom = React.useMemo(()=>index < listLength - 1 ? ()=>onMove(index, listLength - 1) : undefined, [
|
|
57
|
+
index,
|
|
58
|
+
onMove,
|
|
59
|
+
listLength
|
|
60
|
+
]);
|
|
61
|
+
const handleRemove = useCallback(()=>onRemoteItemAtIndex(index), [
|
|
62
|
+
index,
|
|
63
|
+
onRemoteItemAtIndex
|
|
64
|
+
]);
|
|
65
|
+
return React.createElement(React.Fragment, null, children({
|
|
66
|
+
onMoveBottom: handleMoveBottom,
|
|
67
|
+
onMoveTop: handleMoveTop,
|
|
68
|
+
onRemove: handleRemove
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
const EMPTY_ARRAY = [];
|
|
72
|
+
export function MultipleResourceReferenceEditor(props) {
|
|
73
|
+
return React.createElement(EntityProvider, {
|
|
74
|
+
sdk: props.sdk
|
|
75
|
+
}, React.createElement(FieldConnector, {
|
|
76
|
+
throttle: 0,
|
|
77
|
+
field: props.sdk.field,
|
|
78
|
+
isInitiallyDisabled: props.isInitiallyDisabled,
|
|
79
|
+
isEqualValues: deepEqual
|
|
80
|
+
}, ({ value , disabled , setValue , externalReset })=>{
|
|
81
|
+
return React.createElement(ResourceEditor, {
|
|
82
|
+
...props,
|
|
83
|
+
items: value || EMPTY_ARRAY,
|
|
84
|
+
isDisabled: disabled,
|
|
85
|
+
setValue: setValue,
|
|
86
|
+
renderCustomActions: props.renderCustomActions,
|
|
87
|
+
key: `${externalReset}-list`
|
|
88
|
+
}, (editorProps)=>React.createElement(SortableLinkList, editorProps, ({ item , isDisabled , DragHandle , index })=>React.createElement(WithPerItemCallbacks, {
|
|
89
|
+
index: index,
|
|
90
|
+
onMove: editorProps.onMove,
|
|
91
|
+
onRemoteItemAtIndex: editorProps.onRemoteItemAtIndex,
|
|
92
|
+
listLength: value?.length || 0
|
|
93
|
+
}, ({ onMoveBottom , onMoveTop , onRemove })=>React.createElement(ResourceCard, {
|
|
94
|
+
index: index,
|
|
95
|
+
resourceLink: item,
|
|
96
|
+
isDisabled: isDisabled,
|
|
97
|
+
renderDragHandle: DragHandle,
|
|
98
|
+
onMoveTop: onMoveTop,
|
|
99
|
+
onMoveBottom: onMoveBottom,
|
|
100
|
+
onRemove: onRemove,
|
|
101
|
+
getEntryRouteHref: props.getEntryRouteHref
|
|
102
|
+
}))));
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
3
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
4
|
+
import { useResource } from '../common/EntityStore';
|
|
5
|
+
import { MultipleResourceReferenceEditor } from './MultipleResourceReferenceEditor';
|
|
6
|
+
import { createFakeEntryResource, mockSdkForField } from './testHelpers/resourceEditorHelpers';
|
|
7
|
+
let mockedResources = {};
|
|
8
|
+
jest.mock('../common/EntityStore', ()=>{
|
|
9
|
+
const module = jest.requireActual('../common/EntityStore');
|
|
10
|
+
return {
|
|
11
|
+
...module,
|
|
12
|
+
useResource: jest.fn((linkType, urn, apiUrl)=>({
|
|
13
|
+
data: mockedResources[`${linkType}.${urn}`],
|
|
14
|
+
status: 'success',
|
|
15
|
+
apiUrl
|
|
16
|
+
}))
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
jest.mock('react-intersection-observer', ()=>{
|
|
20
|
+
const module = jest.requireActual('react-intersection-observer');
|
|
21
|
+
return {
|
|
22
|
+
...module,
|
|
23
|
+
useInView: ()=>({
|
|
24
|
+
inView: true
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
const fieldDefinition = {
|
|
29
|
+
type: 'Array',
|
|
30
|
+
items: {
|
|
31
|
+
type: 'ResourceLink'
|
|
32
|
+
},
|
|
33
|
+
id: 'foo',
|
|
34
|
+
name: 'Foo',
|
|
35
|
+
allowedResources: [
|
|
36
|
+
{
|
|
37
|
+
source: 'foo',
|
|
38
|
+
contentTypes: [
|
|
39
|
+
'bar'
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
required: true,
|
|
44
|
+
validations: []
|
|
45
|
+
};
|
|
46
|
+
describe('Multiple resource editor', ()=>{
|
|
47
|
+
it('renders the action button when no value is set', async ()=>{
|
|
48
|
+
const sdk = mockSdkForField(fieldDefinition);
|
|
49
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
50
|
+
isInitiallyDisabled: false,
|
|
51
|
+
sdk: sdk,
|
|
52
|
+
hasCardEditActions: true,
|
|
53
|
+
viewType: "card",
|
|
54
|
+
parameters: {}
|
|
55
|
+
}));
|
|
56
|
+
const button = await screen.findByText('Add existing content');
|
|
57
|
+
expect(button).toBeDefined();
|
|
58
|
+
fireEvent.click(button);
|
|
59
|
+
const dialogFn = sdk.dialogs.selectMultipleResourceEntries;
|
|
60
|
+
expect(dialogFn).toHaveBeenCalledTimes(1);
|
|
61
|
+
const options = dialogFn.mock.calls[0][0];
|
|
62
|
+
expect(options).toEqual({
|
|
63
|
+
allowedResources: fieldDefinition.allowedResources
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
it('renders custom actions when passed', async ()=>{
|
|
67
|
+
const sdk = mockSdkForField(fieldDefinition);
|
|
68
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
69
|
+
isInitiallyDisabled: false,
|
|
70
|
+
sdk: sdk,
|
|
71
|
+
hasCardEditActions: true,
|
|
72
|
+
viewType: "card",
|
|
73
|
+
parameters: {},
|
|
74
|
+
renderCustomActions: ()=>React.createElement("div", {
|
|
75
|
+
"data-testid": "custom-actions"
|
|
76
|
+
})
|
|
77
|
+
}));
|
|
78
|
+
const customActions = await screen.findByTestId('custom-actions');
|
|
79
|
+
expect(customActions).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
describe('with value', ()=>{
|
|
82
|
+
it('renders the cards', async ()=>{
|
|
83
|
+
const { entryLinks , entryInfos } = generateMultipleTestResources();
|
|
84
|
+
mockedResources = {};
|
|
85
|
+
for (const [spaceId, link] of Object.entries(entryLinks)){
|
|
86
|
+
mockedResources[`${link.sys.linkType}.${link.sys.urn}`] = entryInfos[spaceId];
|
|
87
|
+
}
|
|
88
|
+
const sdk = mockSdkForField(fieldDefinition, Object.values(entryLinks));
|
|
89
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
90
|
+
isInitiallyDisabled: false,
|
|
91
|
+
sdk: sdk,
|
|
92
|
+
hasCardEditActions: true,
|
|
93
|
+
viewType: "card",
|
|
94
|
+
apiUrl: "test-contentful",
|
|
95
|
+
getEntryRouteHref: ()=>'',
|
|
96
|
+
parameters: {}
|
|
97
|
+
}));
|
|
98
|
+
expect(useResource).toHaveBeenCalledTimes(Object.values(entryInfos).length);
|
|
99
|
+
const cards = [];
|
|
100
|
+
const entriesArray = Object.values(entryInfos);
|
|
101
|
+
for (const info of Array.from(entriesArray.values())){
|
|
102
|
+
const entryTitle = info.resource.fields.title[info.defaultLocaleCode];
|
|
103
|
+
const spaceName = info.space.name;
|
|
104
|
+
const card = await expectEntryCard(entryTitle, spaceName);
|
|
105
|
+
cards.push(card);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
describe('card actions', ()=>{
|
|
109
|
+
it('should have a move to top button', async ()=>{
|
|
110
|
+
const { entryLinks , entryInfos } = generateMultipleTestResources();
|
|
111
|
+
mockedResources = {};
|
|
112
|
+
for (const [spaceId, link] of Object.entries(entryLinks)){
|
|
113
|
+
mockedResources[`${link.sys.linkType}.${link.sys.urn}`] = entryInfos[spaceId];
|
|
114
|
+
}
|
|
115
|
+
const sdk = mockSdkForField(fieldDefinition, Object.values(entryLinks));
|
|
116
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
117
|
+
isInitiallyDisabled: false,
|
|
118
|
+
sdk: sdk,
|
|
119
|
+
hasCardEditActions: true,
|
|
120
|
+
viewType: "card",
|
|
121
|
+
apiUrl: "test-contentful",
|
|
122
|
+
getEntryRouteHref: ()=>'',
|
|
123
|
+
parameters: {}
|
|
124
|
+
}));
|
|
125
|
+
const linkExistingBtn = screen.queryByText('Add existing content');
|
|
126
|
+
expect(linkExistingBtn).toBeInTheDocument();
|
|
127
|
+
const entriesArray = Object.values(entryInfos);
|
|
128
|
+
const firstItem = entriesArray[0];
|
|
129
|
+
await expectToNotHaveMoveButton(firstItem, 'Move to top');
|
|
130
|
+
const allButFirst = entriesArray.slice(1);
|
|
131
|
+
for (const info of allButFirst){
|
|
132
|
+
await expectToHaveMoveButton(info, 'Move to top');
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
it('should have a move to bottom button', async ()=>{
|
|
136
|
+
const { entryLinks , entryInfos } = generateMultipleTestResources();
|
|
137
|
+
mockedResources = {};
|
|
138
|
+
for (const [spaceId, link] of Object.entries(entryLinks)){
|
|
139
|
+
mockedResources[`${link.sys.linkType}.${link.sys.urn}`] = entryInfos[spaceId];
|
|
140
|
+
}
|
|
141
|
+
const sdk = mockSdkForField(fieldDefinition, Object.values(entryLinks));
|
|
142
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
143
|
+
isInitiallyDisabled: false,
|
|
144
|
+
sdk: sdk,
|
|
145
|
+
hasCardEditActions: true,
|
|
146
|
+
viewType: "card",
|
|
147
|
+
apiUrl: "test-contentful",
|
|
148
|
+
getEntryRouteHref: ()=>'',
|
|
149
|
+
parameters: {}
|
|
150
|
+
}));
|
|
151
|
+
const linkExistingBtn = screen.queryByText('Add existing content');
|
|
152
|
+
expect(linkExistingBtn).toBeInTheDocument();
|
|
153
|
+
const entriesArray = Object.values(entryInfos);
|
|
154
|
+
const lastItem = entriesArray[entriesArray.length - 1];
|
|
155
|
+
await expectToNotHaveMoveButton(lastItem, 'Move to bottom');
|
|
156
|
+
const allButLast = entriesArray.slice(0, -1);
|
|
157
|
+
for (const info of allButLast){
|
|
158
|
+
await expectToHaveMoveButton(info, 'Move to bottom');
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
it('works when using remove action', async ()=>{
|
|
162
|
+
const { entryLinks , entryInfos } = generateMultipleTestResources();
|
|
163
|
+
mockedResources = {};
|
|
164
|
+
for (const [spaceId, link] of Object.entries(entryLinks)){
|
|
165
|
+
mockedResources[`${link.sys.linkType}.${link.sys.urn}`] = entryInfos[spaceId];
|
|
166
|
+
}
|
|
167
|
+
const sdk = mockSdkForField(fieldDefinition, Object.values(entryLinks));
|
|
168
|
+
render(React.createElement(MultipleResourceReferenceEditor, {
|
|
169
|
+
isInitiallyDisabled: false,
|
|
170
|
+
sdk: sdk,
|
|
171
|
+
hasCardEditActions: true,
|
|
172
|
+
viewType: "card",
|
|
173
|
+
apiUrl: "test-contentful",
|
|
174
|
+
getEntryRouteHref: ()=>'',
|
|
175
|
+
parameters: {}
|
|
176
|
+
}));
|
|
177
|
+
const linkExistingBtn = screen.queryByText('Add existing content');
|
|
178
|
+
expect(linkExistingBtn).toBeInTheDocument();
|
|
179
|
+
const entriesArray = Object.values(entryInfos);
|
|
180
|
+
for (const info of entriesArray){
|
|
181
|
+
await clickCardActionsButton(info);
|
|
182
|
+
const removeBtn = await screen.findByText('Remove', {
|
|
183
|
+
selector: '[role="menuitem"]'
|
|
184
|
+
});
|
|
185
|
+
fireEvent.click(removeBtn);
|
|
186
|
+
}
|
|
187
|
+
expect(sdk.field.setValue).toHaveBeenCalledTimes(3);
|
|
188
|
+
expect(sdk.field.setValue).toHaveBeenCalledWith([]);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
async function expectToHaveMoveButton(info, buttonString) {
|
|
194
|
+
await clickCardActionsButton(info);
|
|
195
|
+
await screen.findByText(buttonString, {
|
|
196
|
+
selector: '[role="menuitem"]'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
async function expectToNotHaveMoveButton(info, buttonString) {
|
|
200
|
+
await clickCardActionsButton(info);
|
|
201
|
+
expect(screen.queryByText(buttonString, {
|
|
202
|
+
selector: '[role="menuitem"]'
|
|
203
|
+
})).toBeNull();
|
|
204
|
+
}
|
|
205
|
+
async function clickCardActionsButton(info) {
|
|
206
|
+
fireEvent.click(document.body);
|
|
207
|
+
const entryTitle = info.resource.fields.title[info.defaultLocaleCode];
|
|
208
|
+
const spaceName = info.space.name;
|
|
209
|
+
const card = await expectEntryCard(entryTitle, spaceName);
|
|
210
|
+
const actionsBtn = card.querySelector('[data-test-id="cf-ui-card-actions"]');
|
|
211
|
+
expect(actionsBtn).toBeInTheDocument();
|
|
212
|
+
fireEvent.click(actionsBtn);
|
|
213
|
+
}
|
|
214
|
+
async function expectEntryCard(entryTitle, spaceName) {
|
|
215
|
+
const title = await screen.findByText(entryTitle);
|
|
216
|
+
await screen.findByText(spaceName);
|
|
217
|
+
const theCard = title.closest('[data-test-id="cf-ui-entry-card"]');
|
|
218
|
+
expect(theCard).toBeDefined();
|
|
219
|
+
const actionsBtn = theCard?.querySelector('[data-test-id="cf-ui-card-actions"]');
|
|
220
|
+
expect(actionsBtn).toBeDefined();
|
|
221
|
+
return theCard;
|
|
222
|
+
}
|
|
223
|
+
function generateMultipleTestResources() {
|
|
224
|
+
return [
|
|
225
|
+
'Space A',
|
|
226
|
+
'Space B',
|
|
227
|
+
'Space C'
|
|
228
|
+
].reduce((acc, spaceName)=>{
|
|
229
|
+
const spaceId = spaceName.toLowerCase().replace(' ', '-');
|
|
230
|
+
const entryInfo = {
|
|
231
|
+
title: `An entry in ${spaceName}`,
|
|
232
|
+
id: `linkedEntryId`
|
|
233
|
+
};
|
|
234
|
+
acc.entryLinks[spaceId] = {
|
|
235
|
+
sys: {
|
|
236
|
+
type: 'ResourceLink',
|
|
237
|
+
linkType: 'Contentful:Entry',
|
|
238
|
+
urn: `crn:test:::content:spaces/${spaceId}/entries/${entryInfo.id}`
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
acc.entryInfos[spaceId] = createFakeEntryResource({
|
|
242
|
+
title: entryInfo.title,
|
|
243
|
+
id: entryInfo.id,
|
|
244
|
+
space: {
|
|
245
|
+
id: spaceId,
|
|
246
|
+
name: spaceName
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return acc;
|
|
250
|
+
}, {
|
|
251
|
+
entryLinks: {},
|
|
252
|
+
entryInfos: {}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { FieldConnector } from '@contentful/field-editor-shared';
|
|
3
|
+
import deepEqual from 'deep-equal';
|
|
4
|
+
import { EntityProvider } from '../common/EntityStore';
|
|
5
|
+
import { CombinedLinkEntityActions } from '../components/LinkActions/LinkEntityActions';
|
|
6
|
+
import { ResourceCard } from './Cards/ResourceCard';
|
|
7
|
+
import { useResourceLinkActions } from './useResourceLinkActions';
|
|
8
|
+
export function SingleResourceReferenceEditor(props) {
|
|
9
|
+
const { dialogs , field } = props.sdk;
|
|
10
|
+
const linkActionsProps = useResourceLinkActions({
|
|
11
|
+
dialogs,
|
|
12
|
+
field,
|
|
13
|
+
apiUrl: props.apiUrl
|
|
14
|
+
});
|
|
15
|
+
return React.createElement(EntityProvider, {
|
|
16
|
+
sdk: props.sdk
|
|
17
|
+
}, React.createElement(FieldConnector, {
|
|
18
|
+
throttle: 0,
|
|
19
|
+
field: props.sdk.field,
|
|
20
|
+
isInitiallyDisabled: props.isInitiallyDisabled,
|
|
21
|
+
isEqualValues: deepEqual
|
|
22
|
+
}, ({ value , disabled })=>{
|
|
23
|
+
return value ? React.createElement(ResourceCard, {
|
|
24
|
+
onRemove: ()=>props.sdk.field.removeValue(),
|
|
25
|
+
resourceLink: value,
|
|
26
|
+
isDisabled: disabled,
|
|
27
|
+
getEntryRouteHref: props.getEntryRouteHref
|
|
28
|
+
}) : React.createElement(CombinedLinkEntityActions, {
|
|
29
|
+
...linkActionsProps,
|
|
30
|
+
renderCustomActions: props.renderCustomActions
|
|
31
|
+
});
|
|
32
|
+
}));
|
|
33
|
+
}
|