@contentful/field-editor-reference 5.8.6 → 5.10.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 (199) hide show
  1. package/dist/cjs/__fixtures__/FakeSdk.js +183 -0
  2. package/dist/cjs/__fixtures__/asset/index.js +37 -0
  3. package/dist/cjs/__fixtures__/content-type/index.js +16 -0
  4. package/dist/cjs/__fixtures__/entry/index.js +33 -0
  5. package/dist/cjs/__fixtures__/fixtures.js +71 -0
  6. package/dist/cjs/__fixtures__/locale/index.js +40 -0
  7. package/dist/cjs/__fixtures__/space/index.js +16 -0
  8. package/dist/cjs/assets/MultipleMediaEditor.js +86 -0
  9. package/dist/cjs/assets/SingleMediaEditor.js +69 -0
  10. package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +125 -0
  11. package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +171 -0
  12. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +159 -0
  13. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetLink.js +130 -0
  14. package/dist/cjs/assets/index.js +24 -0
  15. package/dist/cjs/common/EntityStore.js +420 -0
  16. package/dist/cjs/common/MultipleReferenceEditor.js +164 -0
  17. package/dist/cjs/common/ReferenceEditor.js +74 -0
  18. package/dist/cjs/common/SingleReferenceEditor.js +118 -0
  19. package/dist/cjs/common/SortableLinkList.js +95 -0
  20. package/dist/cjs/common/customCardTypes.js +44 -0
  21. package/dist/cjs/common/useAccessApi.js +19 -0
  22. package/dist/cjs/common/useContentTypePermissions.js +54 -0
  23. package/dist/cjs/common/useEditorPermissions.js +77 -0
  24. package/dist/cjs/common/useEditorPermissions.spec.js +205 -0
  25. package/dist/cjs/components/AssetThumbnail/AssetThumbnail.js +62 -0
  26. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.js +102 -0
  27. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +254 -0
  28. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +199 -0
  29. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +190 -0
  30. package/dist/cjs/components/CreateEntryLinkButton/useGlobalMouseUp.js +19 -0
  31. package/dist/cjs/components/LinkActions/CombinedLinkActions.js +167 -0
  32. package/dist/cjs/components/LinkActions/LinkActions.js +123 -0
  33. package/dist/cjs/components/LinkActions/LinkEntityActions.js +186 -0
  34. package/dist/cjs/components/LinkActions/NoLinkPermissionsInfo.js +54 -0
  35. package/dist/cjs/components/LinkActions/helpers.js +78 -0
  36. package/dist/cjs/components/LinkActions/redesignStyles.js +44 -0
  37. package/dist/cjs/components/LinkActions/styles.js +33 -0
  38. package/dist/cjs/components/MissingEntityCard/MissingEntityCard.js +75 -0
  39. package/dist/cjs/components/MissingEntityCard/styles.js +29 -0
  40. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduleTooltip.js +75 -0
  41. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +81 -0
  42. package/dist/cjs/components/ScheduledIconWithTooltip/formatDateAndTime.js +45 -0
  43. package/dist/cjs/components/SpaceName/SpaceName.js +91 -0
  44. package/dist/cjs/components/index.js +44 -0
  45. package/dist/cjs/entries/MultipleEntryReferenceEditor.js +86 -0
  46. package/dist/cjs/entries/SingleEntryReferenceEditor.js +74 -0
  47. package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +189 -0
  48. package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +181 -0
  49. package/dist/cjs/entries/index.js +24 -0
  50. package/dist/cjs/index.js +92 -0
  51. package/dist/cjs/resources/Cards/ContentfulEntryCard.js +87 -0
  52. package/dist/cjs/resources/Cards/ResourceCard.js +111 -0
  53. package/dist/cjs/resources/Cards/UnsupportedEntityCard.js +64 -0
  54. package/dist/cjs/resources/MultipleResourceReferenceEditor.js +157 -0
  55. package/dist/cjs/resources/MultipleResourceReferenceEditor.spec.js +297 -0
  56. package/dist/cjs/resources/SingleResourceReferenceEditor.js +87 -0
  57. package/dist/cjs/resources/SingleResourceReferenceEditor.spec.js +161 -0
  58. package/dist/cjs/resources/index.js +19 -0
  59. package/dist/cjs/resources/testHelpers/resourceEditorHelpers.js +121 -0
  60. package/dist/cjs/resources/useResourceLinkActions.js +88 -0
  61. package/dist/cjs/types.js +22 -0
  62. package/dist/cjs/utils/fromFieldValidations.js +54 -0
  63. package/dist/esm/__fixtures__/FakeSdk.js +173 -0
  64. package/dist/esm/__fixtures__/asset/index.js +6 -0
  65. package/dist/esm/__fixtures__/content-type/index.js +2 -0
  66. package/dist/esm/__fixtures__/entry/index.js +5 -0
  67. package/dist/esm/__fixtures__/fixtures.js +6 -0
  68. package/dist/esm/__fixtures__/locale/index.js +15 -0
  69. package/dist/esm/__fixtures__/space/index.js +2 -0
  70. package/dist/esm/assets/MultipleMediaEditor.js +37 -0
  71. package/dist/esm/assets/SingleMediaEditor.js +20 -0
  72. package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +63 -0
  73. package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +122 -0
  74. package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +105 -0
  75. package/dist/esm/assets/WrappedAssetCard/WrappedAssetLink.js +76 -0
  76. package/dist/esm/assets/index.js +3 -0
  77. package/dist/esm/common/EntityStore.js +347 -0
  78. package/dist/esm/common/MultipleReferenceEditor.js +111 -0
  79. package/dist/esm/common/ReferenceEditor.js +20 -0
  80. package/dist/esm/common/SingleReferenceEditor.js +70 -0
  81. package/dist/esm/common/SortableLinkList.js +41 -0
  82. package/dist/esm/common/customCardTypes.js +1 -0
  83. package/dist/esm/common/useAccessApi.js +9 -0
  84. package/dist/esm/common/useContentTypePermissions.js +44 -0
  85. package/dist/esm/common/useEditorPermissions.js +67 -0
  86. package/dist/esm/common/useEditorPermissions.spec.js +201 -0
  87. package/dist/esm/components/AssetThumbnail/AssetThumbnail.js +13 -0
  88. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.js +48 -0
  89. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +206 -0
  90. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +145 -0
  91. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +142 -0
  92. package/dist/esm/components/CreateEntryLinkButton/useGlobalMouseUp.js +9 -0
  93. package/dist/esm/components/LinkActions/CombinedLinkActions.js +118 -0
  94. package/dist/esm/components/LinkActions/LinkActions.js +66 -0
  95. package/dist/esm/components/LinkActions/LinkEntityActions.js +127 -0
  96. package/dist/esm/components/LinkActions/NoLinkPermissionsInfo.js +5 -0
  97. package/dist/esm/components/LinkActions/helpers.js +57 -0
  98. package/dist/esm/components/LinkActions/redesignStyles.js +18 -0
  99. package/dist/esm/components/LinkActions/styles.js +10 -0
  100. package/dist/esm/components/MissingEntityCard/MissingEntityCard.js +26 -0
  101. package/dist/esm/components/MissingEntityCard/styles.js +11 -0
  102. package/dist/esm/components/ScheduledIconWithTooltip/ScheduleTooltip.js +18 -0
  103. package/dist/esm/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +32 -0
  104. package/dist/esm/components/ScheduledIconWithTooltip/formatDateAndTime.js +19 -0
  105. package/dist/esm/components/SpaceName/SpaceName.js +37 -0
  106. package/dist/esm/components/index.js +8 -0
  107. package/dist/esm/entries/MultipleEntryReferenceEditor.js +37 -0
  108. package/dist/esm/entries/SingleEntryReferenceEditor.js +25 -0
  109. package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +135 -0
  110. package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +127 -0
  111. package/dist/esm/entries/index.js +3 -0
  112. package/dist/esm/index.js +7 -0
  113. package/dist/esm/resources/Cards/ContentfulEntryCard.js +38 -0
  114. package/dist/esm/resources/Cards/ResourceCard.js +62 -0
  115. package/dist/esm/resources/Cards/UnsupportedEntityCard.js +15 -0
  116. package/dist/esm/resources/MultipleResourceReferenceEditor.js +104 -0
  117. package/dist/esm/resources/MultipleResourceReferenceEditor.spec.js +254 -0
  118. package/dist/esm/resources/SingleResourceReferenceEditor.js +33 -0
  119. package/dist/esm/resources/SingleResourceReferenceEditor.spec.js +118 -0
  120. package/dist/esm/resources/index.js +2 -0
  121. package/dist/esm/resources/testHelpers/resourceEditorHelpers.js +103 -0
  122. package/dist/esm/resources/useResourceLinkActions.js +78 -0
  123. package/dist/esm/types.js +1 -0
  124. package/dist/esm/utils/fromFieldValidations.js +39 -0
  125. package/dist/{__fixtures__ → types/__fixtures__}/FakeSdk.d.ts +8 -8
  126. package/dist/{__fixtures__ → types/__fixtures__}/asset/index.d.ts +6 -6
  127. package/dist/{__fixtures__ → types/__fixtures__}/content-type/index.d.ts +2 -2
  128. package/dist/{__fixtures__ → types/__fixtures__}/entry/index.d.ts +5 -5
  129. package/dist/{__fixtures__ → types/__fixtures__}/fixtures.d.ts +6 -6
  130. package/dist/{__fixtures__ → types/__fixtures__}/locale/index.d.ts +42 -42
  131. package/dist/{__fixtures__ → types/__fixtures__}/space/index.d.ts +2 -2
  132. package/dist/{assets → types/assets}/MultipleMediaEditor.d.ts +10 -10
  133. package/dist/types/assets/SingleMediaEditor.d.ts +10 -0
  134. package/dist/{assets → types/assets}/WrappedAssetCard/AssetCardActions.d.ts +11 -11
  135. package/dist/{assets → types/assets}/WrappedAssetCard/FetchingWrappedAssetCard.d.ts +17 -17
  136. package/dist/{assets → types/assets}/WrappedAssetCard/WrappedAssetCard.d.ts +24 -24
  137. package/dist/{assets → types/assets}/WrappedAssetCard/WrappedAssetLink.d.ts +16 -16
  138. package/dist/{assets → types/assets}/index.d.ts +3 -3
  139. package/dist/{common → types/common}/EntityStore.d.ts +62 -62
  140. package/dist/{common → types/common}/MultipleReferenceEditor.d.ts +25 -25
  141. package/dist/{common → types/common}/ReferenceEditor.d.ts +46 -46
  142. package/dist/{common → types/common}/SingleReferenceEditor.d.ts +24 -24
  143. package/dist/{common → types/common}/SortableLinkList.d.ts +19 -19
  144. package/dist/{common → types/common}/customCardTypes.d.ts +29 -29
  145. package/dist/types/common/useAccessApi.d.ts +16 -0
  146. package/dist/{common → types/common}/useContentTypePermissions.d.ts +17 -17
  147. package/dist/{common → types/common}/useEditorPermissions.d.ts +17 -17
  148. package/dist/types/common/useEditorPermissions.spec.d.ts +1 -0
  149. package/dist/{components → types/components}/AssetThumbnail/AssetThumbnail.d.ts +7 -7
  150. package/dist/{components → types/components}/CreateEntryLinkButton/CreateEntryLinkButton.d.ts +19 -19
  151. package/dist/types/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.d.ts +1 -0
  152. package/dist/{components → types/components}/CreateEntryLinkButton/CreateEntryMenuTrigger.d.ts +31 -31
  153. package/dist/types/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.d.ts +1 -0
  154. package/dist/{components → types/components}/CreateEntryLinkButton/useGlobalMouseUp.d.ts +1 -1
  155. package/dist/{components → types/components}/LinkActions/CombinedLinkActions.d.ts +10 -10
  156. package/dist/{components → types/components}/LinkActions/LinkActions.d.ts +26 -26
  157. package/dist/{components → types/components}/LinkActions/LinkEntityActions.d.ts +24 -24
  158. package/dist/types/components/LinkActions/NoLinkPermissionsInfo.d.ts +2 -0
  159. package/dist/{components → types/components}/LinkActions/helpers.d.ts +26 -26
  160. package/dist/{components → types/components}/LinkActions/redesignStyles.d.ts +3 -3
  161. package/dist/{components → types/components}/LinkActions/styles.d.ts +2 -2
  162. package/dist/{components → types/components}/MissingEntityCard/MissingEntityCard.d.ts +8 -8
  163. package/dist/{components → types/components}/MissingEntityCard/styles.d.ts +2 -2
  164. package/dist/{components → types/components}/ScheduledIconWithTooltip/ScheduleTooltip.d.ts +11 -11
  165. package/dist/{components → types/components}/ScheduledIconWithTooltip/ScheduledIconWithTooltip.d.ts +10 -10
  166. package/dist/{components → types/components}/ScheduledIconWithTooltip/formatDateAndTime.d.ts +15 -15
  167. package/dist/types/components/SpaceName/SpaceName.d.ts +6 -0
  168. package/dist/{components → types/components}/index.d.ts +9 -9
  169. package/dist/{entries → types/entries}/MultipleEntryReferenceEditor.d.ts +3 -3
  170. package/dist/{entries → types/entries}/SingleEntryReferenceEditor.d.ts +8 -8
  171. package/dist/{entries → types/entries}/WrappedEntryCard/FetchingWrappedEntryCard.d.ts +18 -18
  172. package/dist/{entries → types/entries}/WrappedEntryCard/WrappedEntryCard.d.ts +35 -35
  173. package/dist/{entries → types/entries}/index.d.ts +3 -3
  174. package/dist/{index.d.ts → types/index.d.ts} +9 -8
  175. package/dist/{resources → types/resources}/Cards/ContentfulEntryCard.d.ts +21 -21
  176. package/dist/{resources → types/resources}/Cards/ResourceCard.d.ts +12 -12
  177. package/dist/{resources → types/resources}/Cards/UnsupportedEntityCard.d.ts +4 -4
  178. package/dist/{resources → types/resources}/MultipleResourceReferenceEditor.d.ts +7 -7
  179. package/dist/types/resources/MultipleResourceReferenceEditor.spec.d.ts +1 -0
  180. package/dist/{resources → types/resources}/SingleResourceReferenceEditor.d.ts +7 -7
  181. package/dist/types/resources/SingleResourceReferenceEditor.spec.d.ts +1 -0
  182. package/dist/{resources → types/resources}/index.d.ts +2 -2
  183. package/dist/{resources → types/resources}/testHelpers/resourceEditorHelpers.d.ts +50 -50
  184. package/dist/{resources → types/resources}/useResourceLinkActions.d.ts +7 -7
  185. package/dist/{types.d.ts → types/types.d.ts} +104 -104
  186. package/dist/{utils → types/utils}/fromFieldValidations.d.ts +21 -21
  187. package/package.json +25 -11
  188. package/CHANGELOG.md +0 -854
  189. package/dist/assets/SingleMediaEditor.d.ts +0 -10
  190. package/dist/common/useAccessApi.d.ts +0 -16
  191. package/dist/components/LinkActions/NoLinkPermissionsInfo.d.ts +0 -2
  192. package/dist/components/SpaceName/SpaceName.d.ts +0 -6
  193. package/dist/field-editor-reference.cjs.development.js +0 -4395
  194. package/dist/field-editor-reference.cjs.development.js.map +0 -1
  195. package/dist/field-editor-reference.cjs.production.min.js +0 -2
  196. package/dist/field-editor-reference.cjs.production.min.js.map +0 -1
  197. package/dist/field-editor-reference.esm.js +0 -4369
  198. package/dist/field-editor-reference.esm.js.map +0 -1
  199. package/dist/index.js +0 -8
@@ -0,0 +1,70 @@
1
+ import * as React from 'react';
2
+ import { useCallback } from 'react';
3
+ import { LinkEntityActions } from '../components';
4
+ import { useLinkActionsProps } from '../components/LinkActions/LinkEntityActions';
5
+ import { ReferenceEditor } from './ReferenceEditor';
6
+ import { useEditorPermissions } from './useEditorPermissions';
7
+ function Editor(props) {
8
+ const { setValue , entityType } = props;
9
+ const editorPermissions = useEditorPermissions(props);
10
+ const onCreate = useCallback((id)=>void setValue({
11
+ sys: {
12
+ type: 'Link',
13
+ linkType: entityType,
14
+ id
15
+ }
16
+ }), [
17
+ setValue,
18
+ entityType
19
+ ]);
20
+ const onLink = useCallback((ids)=>{
21
+ const [id] = ids;
22
+ setValue({
23
+ sys: {
24
+ type: 'Link',
25
+ linkType: entityType,
26
+ id
27
+ }
28
+ });
29
+ }, [
30
+ setValue,
31
+ entityType
32
+ ]);
33
+ const linkActionsProps = useLinkActionsProps({
34
+ ...props,
35
+ canLinkMultiple: false,
36
+ editorPermissions,
37
+ onCreate,
38
+ onLink
39
+ });
40
+ const customCardRenderer = useCallback((cardProps, _, renderDefaultCard)=>props.renderCustomCard ? props.renderCustomCard(cardProps, linkActionsProps, renderDefaultCard) : false, [
41
+ linkActionsProps
42
+ ]);
43
+ if (!props.entityId) {
44
+ return React.createElement(LinkEntityActions, {
45
+ renderCustomActions: props.renderCustomActions,
46
+ ...linkActionsProps
47
+ });
48
+ }
49
+ return props.children({
50
+ ...props,
51
+ renderCustomCard: props.renderCustomCard && customCardRenderer
52
+ });
53
+ }
54
+ export function SingleReferenceEditor(props) {
55
+ const allContentTypes = props.sdk.space.getCachedContentTypes();
56
+ return React.createElement(ReferenceEditor, props, ({ value , setValue , disabled , externalReset })=>{
57
+ return React.createElement(Editor, {
58
+ ...props,
59
+ key: `${externalReset}-reference`,
60
+ entityId: value ? value.sys.id : '',
61
+ isDisabled: disabled,
62
+ setValue: setValue,
63
+ allContentTypes: allContentTypes
64
+ });
65
+ });
66
+ }
67
+ SingleReferenceEditor.defaultProps = {
68
+ hasCardEditActions: true,
69
+ hasCardRemoveActions: true
70
+ };
@@ -0,0 +1,41 @@
1
+ import * as React from 'react';
2
+ import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
3
+ import tokens from '@contentful/f36-tokens';
4
+ import { css, cx } from 'emotion';
5
+ const styles = {
6
+ container: css({
7
+ position: 'relative'
8
+ }),
9
+ item: css({
10
+ marginBottom: tokens.spacingM,
11
+ zIndex: tokens.zIndexModal
12
+ })
13
+ };
14
+ const DragHandle = (props)=>{
15
+ const SortableDragHandle = SortableHandle(()=>props.drag);
16
+ return React.createElement(SortableDragHandle, null);
17
+ };
18
+ const SortableLink = SortableElement((props)=>React.createElement("div", {
19
+ className: styles.item
20
+ }, props.children));
21
+ const SortableLinkListInternal = SortableContainer((props)=>{
22
+ return React.createElement("div", {
23
+ className: cx(styles.container, props.className)
24
+ }, props.items.map((item, index)=>React.createElement(SortableLink, {
25
+ disabled: props.isDisabled,
26
+ key: `${item.sys.urn ?? item.sys.id}-${index}`,
27
+ index: index
28
+ }, props.children({
29
+ items: props.items,
30
+ isDisabled: props.isDisabled,
31
+ item,
32
+ index,
33
+ DragHandle: props.isDisabled ? undefined : DragHandle
34
+ }))));
35
+ });
36
+ export function SortableLinkList(props) {
37
+ return React.createElement(SortableLinkListInternal, {
38
+ distance: 1,
39
+ ...props
40
+ }, props.children);
41
+ }
@@ -0,0 +1 @@
1
+ import * as React from 'react';
@@ -0,0 +1,9 @@
1
+ const AllowActionsOnContentType = ()=>Promise.resolve(true);
2
+ export function useAccessApi(accessApi) {
3
+ const canPerformAction = accessApi.can;
4
+ const canPerformActionOnEntryOfType = accessApi.canPerformActionOnEntryOfType ?? AllowActionsOnContentType;
5
+ return {
6
+ canPerformAction,
7
+ canPerformActionOnEntryOfType
8
+ };
9
+ }
@@ -0,0 +1,44 @@
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ import { useAccessApi } from './useAccessApi';
3
+ async function filter(arr, predicate) {
4
+ const fail = Symbol();
5
+ const results = await Promise.all(arr.map(async (item)=>await predicate(item) ? item : fail));
6
+ return results.filter((x)=>x !== fail);
7
+ }
8
+ export function useContentTypePermissions(props) {
9
+ const availableContentTypes = useMemo(()=>{
10
+ if (props.entityType === 'Asset') {
11
+ return [];
12
+ }
13
+ if (props.validations.contentTypes) {
14
+ return props.allContentTypes.filter((ct)=>props.validations.contentTypes?.includes(ct.sys.id));
15
+ }
16
+ return props.allContentTypes;
17
+ }, [
18
+ props.allContentTypes,
19
+ props.validations.contentTypes,
20
+ props.entityType
21
+ ]);
22
+ const [creatableContentTypes, setCreatableContentTypes] = useState(availableContentTypes);
23
+ const [readableContentTypes, setReadableContentTypes] = useState(availableContentTypes);
24
+ const { canPerformActionOnEntryOfType } = useAccessApi(props.sdk.access);
25
+ useEffect(()=>{
26
+ function getContentTypes(action) {
27
+ return filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType(action, ct.sys.id));
28
+ }
29
+ async function checkContentTypeAccess() {
30
+ const creatable = await getContentTypes('create');
31
+ const readable = await getContentTypes('read');
32
+ setCreatableContentTypes(creatable);
33
+ setReadableContentTypes(readable);
34
+ }
35
+ void checkContentTypeAccess();
36
+ }, [
37
+ availableContentTypes
38
+ ]);
39
+ return {
40
+ creatableContentTypes,
41
+ readableContentTypes,
42
+ availableContentTypes
43
+ };
44
+ }
@@ -0,0 +1,67 @@
1
+ import { useEffect, useMemo, useState } from 'react';
2
+ import { fromFieldValidations } from '../utils/fromFieldValidations';
3
+ import { useAccessApi } from './useAccessApi';
4
+ import { useContentTypePermissions } from './useContentTypePermissions';
5
+ export function useEditorPermissions(props) {
6
+ const { sdk , entityType , parameters } = props;
7
+ const validations = useMemo(()=>fromFieldValidations(props.sdk.field), [
8
+ props.sdk.field
9
+ ]);
10
+ const [canCreateEntity, setCanCreateEntity] = useState(true);
11
+ const [canLinkEntity, setCanLinkEntity] = useState(true);
12
+ const { creatableContentTypes , readableContentTypes , availableContentTypes } = useContentTypePermissions({
13
+ ...props,
14
+ validations
15
+ });
16
+ const { canPerformAction } = useAccessApi(sdk.access);
17
+ useEffect(()=>{
18
+ if (parameters.instance.showCreateEntityAction === false) {
19
+ setCanCreateEntity(false);
20
+ return;
21
+ }
22
+ async function checkCreateAccess() {
23
+ if (entityType === 'Asset') {
24
+ const canCreate = await canPerformAction('create', 'Asset') || true;
25
+ setCanCreateEntity(canCreate);
26
+ }
27
+ if (entityType === 'Entry') {
28
+ const canCreate = creatableContentTypes.length > 0 || true;
29
+ setCanCreateEntity(canCreate);
30
+ }
31
+ }
32
+ void checkCreateAccess();
33
+ }, [
34
+ entityType,
35
+ parameters.instance,
36
+ creatableContentTypes
37
+ ]);
38
+ useEffect(()=>{
39
+ if (parameters.instance.showLinkEntityAction === false) {
40
+ setCanLinkEntity(false);
41
+ return;
42
+ }
43
+ async function checkLinkAccess() {
44
+ if (entityType === 'Asset') {
45
+ const canRead = await canPerformAction('read', 'Asset') || true;
46
+ setCanLinkEntity(canRead);
47
+ }
48
+ if (entityType === 'Entry') {
49
+ const canRead = true;
50
+ setCanLinkEntity(canRead);
51
+ }
52
+ }
53
+ void checkLinkAccess();
54
+ }, [
55
+ entityType,
56
+ parameters.instance,
57
+ readableContentTypes
58
+ ]);
59
+ return {
60
+ canCreateEntity,
61
+ canLinkEntity,
62
+ creatableContentTypes,
63
+ readableContentTypes,
64
+ availableContentTypes,
65
+ validations
66
+ };
67
+ }
@@ -0,0 +1,201 @@
1
+ import { createFakeFieldAPI } from '@contentful/field-editor-test-utils';
2
+ import { renderHook } from '@testing-library/react-hooks';
3
+ import { useEditorPermissions } from './useEditorPermissions';
4
+ describe('useEditorPermissions', ()=>{
5
+ const makeFieldExtensionSDK = (customizeMock)=>({
6
+ field: createFakeFieldAPI(customizeMock)[0],
7
+ access: {
8
+ can: jest.fn().mockResolvedValue(true),
9
+ canPerformActionOnEntryOfType: jest.fn().mockResolvedValue(true)
10
+ }
11
+ });
12
+ const makeContentType = (id)=>({
13
+ sys: {
14
+ id
15
+ }
16
+ });
17
+ const renderEditorPermissions = async ({ entityType , params ={} , allContentTypes =[] , customizeMock , customizeSdk })=>{
18
+ const sdk = makeFieldExtensionSDK(customizeMock);
19
+ customizeSdk?.(sdk);
20
+ const renderResult = renderHook(()=>useEditorPermissions({
21
+ sdk,
22
+ allContentTypes,
23
+ entityType,
24
+ parameters: {
25
+ instance: params
26
+ }
27
+ }));
28
+ await renderResult.waitForNextUpdate();
29
+ return {
30
+ ...renderResult,
31
+ sdk
32
+ };
33
+ };
34
+ describe(`behaviour on Asset`, ()=>{
35
+ it(`wont check access when turned off via instance params`, async ()=>{
36
+ const { result , sdk } = await renderEditorPermissions({
37
+ entityType: 'Asset',
38
+ params: {
39
+ showCreateEntityAction: false,
40
+ showLinkEntityAction: false
41
+ }
42
+ });
43
+ expect(result.current.canCreateEntity).toBe(false);
44
+ expect(result.current.canLinkEntity).toBe(false);
45
+ expect(sdk.access.can).not.toHaveBeenCalledWith();
46
+ });
47
+ it(`checks basic access`, async ()=>{
48
+ const { sdk } = await renderEditorPermissions({
49
+ entityType: 'Asset'
50
+ });
51
+ expect(sdk.access.can).toHaveBeenCalledWith('create', 'Asset');
52
+ expect(sdk.access.can).toHaveBeenCalledWith('read', 'Asset');
53
+ });
54
+ it(`defaults link asset action visibility to true`, async ()=>{
55
+ const { result } = await renderEditorPermissions({
56
+ entityType: 'Asset'
57
+ });
58
+ expect(result.current.canLinkEntity).toBeTruthy();
59
+ });
60
+ it(`returns empty contentTypes`, async ()=>{
61
+ const { result } = await renderEditorPermissions({
62
+ entityType: 'Asset',
63
+ allContentTypes: [
64
+ makeContentType('one')
65
+ ]
66
+ });
67
+ expect(result.current.creatableContentTypes).toEqual([]);
68
+ expect(result.current.readableContentTypes).toEqual([]);
69
+ });
70
+ });
71
+ describe(`behaviour on Entry`, ()=>{
72
+ const allowContentTypes = (sdk, allowedAction, ...allowed)=>{
73
+ sdk.access.canPerformActionOnEntryOfType.mockImplementation(async (action, contentTypeId)=>{
74
+ if (allowedAction === action && allowed.includes(contentTypeId)) {
75
+ return true;
76
+ }
77
+ return false;
78
+ });
79
+ };
80
+ it(`wont check access when turned off via instance params`, async ()=>{
81
+ const { result , sdk } = await renderEditorPermissions({
82
+ entityType: 'Entry',
83
+ params: {
84
+ showCreateEntityAction: false,
85
+ showLinkEntityAction: false
86
+ }
87
+ });
88
+ expect(result.current.canCreateEntity).toBe(false);
89
+ expect(result.current.canLinkEntity).toBe(false);
90
+ expect(sdk.access.can).not.toHaveBeenCalledWith();
91
+ });
92
+ it(`only allows creation when one content-type can be created`, async ()=>{
93
+ const allContentTypes = [
94
+ makeContentType('one'),
95
+ makeContentType('two')
96
+ ];
97
+ const { result } = await renderEditorPermissions({
98
+ entityType: 'Entry',
99
+ allContentTypes,
100
+ customizeSdk: (sdk)=>{
101
+ allowContentTypes(sdk, 'create', 'one');
102
+ }
103
+ });
104
+ expect(result.current.canCreateEntity).toBe(true);
105
+ });
106
+ it.skip(`denies creation when no content-type can be created`, async ()=>{
107
+ const allContentTypes = [
108
+ makeContentType('one'),
109
+ makeContentType('two')
110
+ ];
111
+ const { result } = await renderEditorPermissions({
112
+ entityType: 'Entry',
113
+ allContentTypes,
114
+ customizeSdk: (sdk)=>{
115
+ allowContentTypes(sdk, 'create');
116
+ }
117
+ });
118
+ expect(result.current.canCreateEntity).toBe(false);
119
+ });
120
+ it(`only allows linking when one content-type can be read`, async ()=>{
121
+ const allContentTypes = [
122
+ makeContentType('one'),
123
+ makeContentType('two')
124
+ ];
125
+ const { result } = await renderEditorPermissions({
126
+ entityType: 'Entry',
127
+ allContentTypes,
128
+ customizeSdk: (sdk)=>{
129
+ allowContentTypes(sdk, 'read', 'one');
130
+ }
131
+ });
132
+ expect(result.current.canLinkEntity).toBe(true);
133
+ });
134
+ it.skip(`denies creation when no content-type can be read`, async ()=>{
135
+ const allContentTypes = [
136
+ makeContentType('one'),
137
+ makeContentType('two')
138
+ ];
139
+ const { result } = await renderEditorPermissions({
140
+ entityType: 'Entry',
141
+ allContentTypes,
142
+ customizeSdk: (sdk)=>{
143
+ allowContentTypes(sdk, 'read');
144
+ }
145
+ });
146
+ expect(result.current.canLinkEntity).toBe(false);
147
+ });
148
+ it(`returns creatableContentTypes from validations that can be created`, async ()=>{
149
+ const allContentTypes = [
150
+ makeContentType('one'),
151
+ makeContentType('two')
152
+ ];
153
+ const { result } = await renderEditorPermissions({
154
+ entityType: 'Entry',
155
+ allContentTypes,
156
+ customizeMock: (field)=>{
157
+ field.validations = [
158
+ {
159
+ linkContentType: [
160
+ 'two'
161
+ ]
162
+ }
163
+ ];
164
+ return field;
165
+ },
166
+ customizeSdk: (sdk)=>{
167
+ allowContentTypes(sdk, 'create', 'two');
168
+ }
169
+ });
170
+ expect(result.current.creatableContentTypes).toEqual([
171
+ allContentTypes[1]
172
+ ]);
173
+ });
174
+ it(`returns readableContentTypes from validations that can be read`, async ()=>{
175
+ const allContentTypes = [
176
+ makeContentType('one'),
177
+ makeContentType('two')
178
+ ];
179
+ const { result } = await renderEditorPermissions({
180
+ entityType: 'Entry',
181
+ allContentTypes,
182
+ customizeMock: (field)=>{
183
+ field.validations = [
184
+ {
185
+ linkContentType: [
186
+ 'two'
187
+ ]
188
+ }
189
+ ];
190
+ return field;
191
+ },
192
+ customizeSdk: (sdk)=>{
193
+ allowContentTypes(sdk, 'read', 'two');
194
+ }
195
+ });
196
+ expect(result.current.readableContentTypes).toEqual([
197
+ allContentTypes[1]
198
+ ]);
199
+ });
200
+ });
201
+ });
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ const dimensions = {
3
+ width: 70,
4
+ height: 70
5
+ };
6
+ export function AssetThumbnail(props) {
7
+ return React.createElement("img", {
8
+ alt: props.file.fileName,
9
+ src: `${props.file.url}?w=${dimensions.width}&h=${dimensions.height}&fit=thumb`,
10
+ height: dimensions.height,
11
+ width: dimensions.width
12
+ });
13
+ }
@@ -0,0 +1,48 @@
1
+ import * as React from 'react';
2
+ import { Button } from '@contentful/f36-components';
3
+ import { ChevronDownIcon, PlusIcon } from '@contentful/f36-icons';
4
+ import tokens from '@contentful/f36-tokens';
5
+ import { css } from 'emotion';
6
+ import get from 'lodash/get';
7
+ import { CreateEntryMenuTrigger } from './CreateEntryMenuTrigger';
8
+ const standardStyles = {
9
+ spinnerMargin: css({
10
+ marginRight: tokens.spacingXs
11
+ }),
12
+ action: undefined
13
+ };
14
+ const redesignStyles = {
15
+ ...standardStyles,
16
+ action: css({
17
+ textDecoration: 'none',
18
+ fontWeight: 'bold',
19
+ maxWidth: '300px'
20
+ })
21
+ };
22
+ export const CreateEntryLinkButton = ({ contentTypes , onSelect , customDropdownItems , text , testId , hasPlusIcon =false , useExperimentalStyles , suggestedContentTypeId , dropdownSettings , disabled =false })=>{
23
+ contentTypes = contentTypes.sort((a, b)=>a.name.localeCompare(b.name));
24
+ const suggestedContentType = contentTypes.find((ct)=>ct.sys.id === suggestedContentTypeId);
25
+ const buttonText = text || `Add ${get(suggestedContentType || (contentTypes.length === 1 ? contentTypes[0] : {}), 'name', 'entry')}`;
26
+ const hasDropdown = contentTypes.length > 1 || customDropdownItems;
27
+ const plusIcon = hasPlusIcon ? React.createElement(PlusIcon, null) : undefined;
28
+ const contentTypesLabel = useExperimentalStyles ? 'New content' : undefined;
29
+ const styles = useExperimentalStyles ? redesignStyles : standardStyles;
30
+ return React.createElement(CreateEntryMenuTrigger, {
31
+ contentTypes: contentTypes,
32
+ suggestedContentTypeId: suggestedContentTypeId,
33
+ contentTypesLabel: contentTypesLabel,
34
+ onSelect: onSelect,
35
+ testId: testId,
36
+ dropdownSettings: dropdownSettings,
37
+ customDropdownItems: customDropdownItems
38
+ }, ({ isSelecting })=>React.createElement(Button, {
39
+ endIcon: hasDropdown ? React.createElement(ChevronDownIcon, null) : undefined,
40
+ variant: "secondary",
41
+ className: styles.action,
42
+ isDisabled: disabled || isSelecting,
43
+ startIcon: isSelecting ? undefined : plusIcon,
44
+ size: "small",
45
+ testId: "create-entry-link-button",
46
+ isLoading: isSelecting
47
+ }, buttonText));
48
+ };