@contentful/field-editor-reference 6.19.2 → 6.19.3-canary.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.
Files changed (42) hide show
  1. package/dist/cjs/__fixtures__/FakeSdk.js +13 -20
  2. package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +11 -1
  3. package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +10 -1
  4. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +4 -2
  5. package/dist/cjs/common/EntityStore.js +45 -25
  6. package/dist/cjs/common/MultipleReferenceEditor.js +6 -1
  7. package/dist/cjs/common/SingleReferenceEditor.js +8 -2
  8. package/dist/cjs/common/queryClient.js +4 -4
  9. package/dist/cjs/common/useContentTypePermissions.js +6 -9
  10. package/dist/cjs/common/useEditorPermissions.js +5 -1
  11. package/dist/cjs/components/LinkActions/LinkEntityActions.js +2 -0
  12. package/dist/cjs/entries/MultipleEntryReferenceEditor.js +2 -1
  13. package/dist/cjs/entries/SingleEntryReferenceEditor.js +1 -0
  14. package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +10 -1
  15. package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +13 -2
  16. package/dist/cjs/resources/Cards/ResourceCard.spec.js +28 -2
  17. package/dist/esm/__fixtures__/FakeSdk.js +13 -20
  18. package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +11 -1
  19. package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +10 -1
  20. package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +4 -2
  21. package/dist/esm/common/EntityStore.js +45 -25
  22. package/dist/esm/common/MultipleReferenceEditor.js +6 -1
  23. package/dist/esm/common/SingleReferenceEditor.js +8 -2
  24. package/dist/esm/common/queryClient.js +1 -1
  25. package/dist/esm/common/useContentTypePermissions.js +6 -9
  26. package/dist/esm/common/useEditorPermissions.js +5 -1
  27. package/dist/esm/components/LinkActions/LinkEntityActions.js +2 -0
  28. package/dist/esm/entries/MultipleEntryReferenceEditor.js +2 -1
  29. package/dist/esm/entries/SingleEntryReferenceEditor.js +1 -0
  30. package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +10 -1
  31. package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +13 -2
  32. package/dist/esm/resources/Cards/ResourceCard.spec.js +28 -2
  33. package/dist/types/assets/WrappedAssetCard/AssetCardActions.d.ts +1 -0
  34. package/dist/types/assets/WrappedAssetCard/FetchingWrappedAssetCard.d.ts +5 -1
  35. package/dist/types/assets/WrappedAssetCard/WrappedAssetCard.d.ts +2 -1
  36. package/dist/types/common/EntityStore.d.ts +2 -0
  37. package/dist/types/common/ReferenceEditor.d.ts +5 -1
  38. package/dist/types/common/customCardTypes.d.ts +1 -0
  39. package/dist/types/common/queryClient.d.ts +1 -1
  40. package/dist/types/entries/WrappedEntryCard/FetchingWrappedEntryCard.d.ts +5 -1
  41. package/dist/types/entries/WrappedEntryCard/WrappedEntryCard.d.ts +2 -1
  42. package/package.json +4 -4
@@ -45,15 +45,6 @@ function newReferenceEditorFakeSdk(props) {
45
45
  const delay = (ms)=>{
46
46
  return new Promise((resolve)=>setTimeout(resolve, ms));
47
47
  };
48
- const localizeContentTypes = (contentTypes)=>{
49
- return contentTypes.map((contentType)=>({
50
- ...contentType,
51
- fields: contentType.fields.map((field)=>({
52
- ...field,
53
- localized: true
54
- }))
55
- }));
56
- };
57
48
  const sdk = {
58
49
  field,
59
50
  locales,
@@ -106,6 +97,19 @@ function newReferenceEditorFakeSdk(props) {
106
97
  return _fixtures.contentTypes.published;
107
98
  }
108
99
  return Promise.reject({});
100
+ },
101
+ getMany: async ()=>{
102
+ return Promise.resolve({
103
+ items: [
104
+ _fixtures.contentTypes.published
105
+ ],
106
+ total: 1,
107
+ skip: 0,
108
+ limit: 1000,
109
+ sys: {
110
+ type: 'Array'
111
+ }
112
+ });
109
113
  }
110
114
  },
111
115
  Locale: {
@@ -114,17 +118,6 @@ function newReferenceEditorFakeSdk(props) {
114
118
  },
115
119
  space: {
116
120
  ...space,
117
- getCachedContentTypes () {
118
- return localizeContentTypes(space.getCachedContentTypes());
119
- },
120
- getContentTypes () {
121
- return Promise.resolve(space.getContentTypes().then((response)=>{
122
- return {
123
- ...response,
124
- items: localizeContentTypes(response.items)
125
- };
126
- }));
127
- },
128
121
  async getEntityScheduledActions () {
129
122
  return [];
130
123
  }
@@ -18,6 +18,7 @@ _export(exports, {
18
18
  });
19
19
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
20
20
  const _f36components = require("@contentful/f36-components");
21
+ const _f36icons = require("@contentful/f36-icons");
21
22
  const _f36tokens = /*#__PURE__*/ _interop_require_default(require("@contentful/f36-tokens"));
22
23
  const _fieldeditorshared = require("@contentful/field-editor-shared");
23
24
  const _emotion = require("emotion");
@@ -134,7 +135,7 @@ function renderAssetInfo(props) {
134
135
  ];
135
136
  }
136
137
  function renderActions(props) {
137
- const { entityFile, isDisabled, onEdit, onRemove } = props;
138
+ const { entityFile, isDisabled, onEdit, onRemove, onAddToReleaseAction } = props;
138
139
  return [
139
140
  /*#__PURE__*/ _react.createElement(_f36components.MenuSectionTitle, {
140
141
  key: "section-title"
@@ -144,6 +145,15 @@ function renderActions(props) {
144
145
  onClick: onEdit,
145
146
  testId: "card-action-edit"
146
147
  }, "Edit") : null,
148
+ onAddToReleaseAction ? /*#__PURE__*/ _react.createElement(_f36components.MenuItem, {
149
+ key: "add-to-release",
150
+ testId: "add-to-release",
151
+ onClick: ()=>{
152
+ onAddToReleaseAction();
153
+ }
154
+ }, /*#__PURE__*/ _react.createElement(_f36icons.PlusIcon, {
155
+ size: "tiny"
156
+ }), "Add to release") : null,
147
157
  entityFile ? /*#__PURE__*/ _react.createElement(_f36components.MenuItem, {
148
158
  key: "download",
149
159
  onClick: ()=>{
@@ -72,6 +72,14 @@ function FetchingWrappedAssetCard(props) {
72
72
  locales: props.sdk.locales,
73
73
  isReference: true
74
74
  });
75
+ const onAddToRelease = ()=>{
76
+ if (asset && props.addReferenceToRelease) {
77
+ void props.addReferenceToRelease(asset, props.sdk.field.locale, {
78
+ openModalForVersionSelection: true,
79
+ skipNestedReferencesPrompt: true
80
+ });
81
+ }
82
+ };
75
83
  _react.useEffect(()=>{
76
84
  if (asset) {
77
85
  props.onAction && props.onAction({
@@ -138,7 +146,8 @@ function FetchingWrappedAssetCard(props) {
138
146
  activeLocales,
139
147
  releaseStatusMap,
140
148
  release: props.sdk.release,
141
- releaseEntityStatus
149
+ releaseEntityStatus,
150
+ onAddToRelease
142
151
  };
143
152
  if (status === 'loading') {
144
153
  return props.viewType === 'link' ? /*#__PURE__*/ _react.createElement(_f36components.EntryCard, {
@@ -87,7 +87,7 @@ function getFileType(file) {
87
87
  return groupToIconMap[groupName] || 'archive';
88
88
  }
89
89
  const THUMBNAIL_SIZE = 150;
90
- const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCode, activeLocales, localesStatusMap, isDisabled, isSelected, isClickable, useLocalizedEntityStatus, renderDragHandle, getEntityScheduledActions, onEdit, getAssetUrl, onRemove, releaseEntityStatus, releaseStatusMap, release })=>{
90
+ const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCode, activeLocales, localesStatusMap, isDisabled, isSelected, isClickable, useLocalizedEntityStatus, renderDragHandle, getEntityScheduledActions, onEdit, getAssetUrl, onRemove, releaseEntityStatus, releaseStatusMap, release, onAddToRelease })=>{
91
91
  const status = _fieldeditorshared.entityHelpers.getEntityStatus(asset.sys, useLocalizedEntityStatus ? localeCode : undefined);
92
92
  const entityFile = asset.fields.file ? asset.fields.file[localeCode] || asset.fields.file[defaultLocaleCode] : undefined;
93
93
  const imageUrl = _react.useMemo(()=>{
@@ -120,6 +120,7 @@ const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCod
120
120
  defaultTitle: 'Untitled'
121
121
  });
122
122
  const href = getAssetUrl ? getAssetUrl(asset.sys.id) : undefined;
123
+ const onAddToReleaseAction = releaseEntityStatus === 'notInRelease' && release !== undefined && onAddToRelease !== undefined && !isDisabled ? onAddToRelease : undefined;
123
124
  return /*#__PURE__*/ _react.createElement(_f36components.AssetCard, {
124
125
  as: isClickable && href ? 'a' : 'article',
125
126
  type: getFileType(entityFile),
@@ -158,7 +159,8 @@ const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCod
158
159
  entityFile,
159
160
  isDisabled: isDisabled,
160
161
  onEdit,
161
- onRemove
162
+ onRemove,
163
+ onAddToReleaseAction
162
164
  }),
163
165
  ...entityFile ? (0, _AssetCardActions.renderAssetInfo)({
164
166
  entityFile
@@ -41,6 +41,7 @@ _export(exports, {
41
41
  }
42
42
  });
43
43
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
44
+ const _fieldeditorshared = require("@contentful/field-editor-shared");
44
45
  const _constate = /*#__PURE__*/ _interop_require_default(require("constate"));
45
46
  const _contentfulmanagement = require("contentful-management");
46
47
  const _lodash = require("lodash");
@@ -162,18 +163,10 @@ async function fetchContentfulEntry({ urn, fetch, options }) {
162
163
  const environmentId = resourceIdMatch?.groups?.environmentId || 'master';
163
164
  const entryId = resourceIdMatch.groups.entityId;
164
165
  const [space, entry] = await Promise.all([
165
- fetch([
166
- 'space',
167
- spaceId
168
- ], ({ cmaClient })=>cmaClient.space.get({
166
+ fetch((0, _fieldeditorshared.createGetSpaceKey)(spaceId), ({ cmaClient })=>cmaClient.space.get({
169
167
  spaceId
170
168
  }), options),
171
- fetch([
172
- 'entry',
173
- spaceId,
174
- environmentId,
175
- entryId
176
- ], ({ cmaClient })=>cmaClient.entry.get({
169
+ fetch((0, _fieldeditorshared.createGetEntryKey)(spaceId, environmentId, entryId), ({ cmaClient })=>cmaClient.entry.get({
177
170
  spaceId,
178
171
  environmentId,
179
172
  entryId
@@ -181,12 +174,7 @@ async function fetchContentfulEntry({ urn, fetch, options }) {
181
174
  ]);
182
175
  const contentTypeId = entry.sys.contentType.sys.id;
183
176
  const [contentType, defaultLocaleCode] = await Promise.all([
184
- fetch([
185
- 'contentType',
186
- spaceId,
187
- environmentId,
188
- contentTypeId
189
- ], ({ cmaClient })=>cmaClient.contentType.get({
177
+ fetch((0, _fieldeditorshared.createGetContentTypeKey)(spaceId, environmentId, contentTypeId), ({ cmaClient })=>cmaClient.contentType.get({
190
178
  contentTypeId,
191
179
  spaceId,
192
180
  environmentId
@@ -429,7 +417,9 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = (0,
429
417
  resourceType,
430
418
  urn,
431
419
  options?.locale,
432
- options?.referencingEntryId
420
+ options?.referencingEntryId,
421
+ currentSpaceId,
422
+ currentEnvironmentId
433
423
  ];
434
424
  return fetch(queryKey, ()=>{
435
425
  if (resourceType === 'Contentful:Entry') {
@@ -471,17 +461,41 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = (0,
471
461
  (0, _react.useEffect)(()=>{
472
462
  function findSameSpaceQueries() {
473
463
  const queries = queryCache.findAll({
474
- type: 'active',
475
464
  predicate: (query)=>isSameSpaceEntityQueryKey(query.queryKey)
476
465
  });
477
466
  return queries;
478
467
  }
479
468
  if (typeof onEntityChanged !== 'function') {
480
- return onSlideInNavigation(({ oldSlideLevel, newSlideLevel })=>{
469
+ return onSlideInNavigation(async ({ oldSlideLevel, newSlideLevel })=>{
481
470
  if (oldSlideLevel > newSlideLevel) {
482
- findSameSpaceQueries().forEach((query)=>{
483
- void queryClient.invalidateQueries(query.queryKey);
484
- });
471
+ const queries = findSameSpaceQueries();
472
+ await Promise.all(queries.map(async (query)=>{
473
+ const [entityType, entityId, spaceId, environmentId, releaseId] = query.queryKey;
474
+ try {
475
+ let freshData;
476
+ if (entityType === 'Entry') {
477
+ freshData = await cmaClient.entry.get({
478
+ entryId: entityId,
479
+ spaceId: spaceId,
480
+ environmentId: environmentId,
481
+ releaseId: releaseId
482
+ });
483
+ } else if (entityType === 'Asset') {
484
+ freshData = await cmaClient.asset.get({
485
+ assetId: entityId,
486
+ spaceId: spaceId,
487
+ environmentId: environmentId,
488
+ releaseId: releaseId
489
+ });
490
+ } else {
491
+ await queryClient.invalidateQueries(query.queryKey);
492
+ return;
493
+ }
494
+ queryClient.setQueryData(query.queryKey, freshData);
495
+ } catch (error) {
496
+ await queryClient.invalidateQueries(query.queryKey);
497
+ }
498
+ }));
485
499
  }
486
500
  });
487
501
  }
@@ -524,7 +538,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = (0,
524
538
  isSameSpaceEntityQueryKey,
525
539
  queryClient,
526
540
  getEntity,
527
- onSlideInNavigation
541
+ onSlideInNavigation,
542
+ cmaClient
528
543
  ]);
529
544
  const getResourceProvider = (0, _react.useCallback)(function getResourceProvider(organizationId, appDefinitionId) {
530
545
  const queryKey = [
@@ -594,12 +609,15 @@ function useResource(resourceType, urn, { locale, referencingEntryId, ...options
594
609
  locale = undefined;
595
610
  referencingEntryId = undefined;
596
611
  }
612
+ const { space, environment } = useCurrentIds();
597
613
  const queryKey = [
598
614
  'Resource',
599
615
  resourceType,
600
616
  urn,
601
617
  locale,
602
- referencingEntryId
618
+ referencingEntryId,
619
+ space,
620
+ environment
603
621
  ];
604
622
  const { getResource } = useEntityLoader();
605
623
  const { status, data, error } = (0, _queryClient.useQuery)(queryKey, ()=>getResource(resourceType, urn, {
@@ -630,5 +648,7 @@ function useResourceProvider(organizationId, appDefinitionId) {
630
648
  };
631
649
  }
632
650
  function EntityProvider({ children, ...props }) {
633
- return /*#__PURE__*/ _react.default.createElement(_queryClient.SharedQueryClientProvider, null, /*#__PURE__*/ _react.default.createElement(InternalServiceProvider, props, children));
651
+ return /*#__PURE__*/ _react.default.createElement(_queryClient.SharedQueryClientProvider, {
652
+ client: props.queryClient
653
+ }, /*#__PURE__*/ _react.default.createElement(InternalServiceProvider, props, children));
634
654
  }
@@ -9,10 +9,12 @@ Object.defineProperty(exports, "MultipleReferenceEditor", {
9
9
  }
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
+ const _reactquery = require("@contentful/field-editor-shared/react-query");
12
13
  const _sortable = require("@dnd-kit/sortable");
13
14
  const _components = require("../components");
14
15
  const _LinkEntityActions = require("../components/LinkActions/LinkEntityActions");
15
16
  const _useSortIDs = require("../utils/useSortIDs");
17
+ const _queryClient = require("./queryClient");
16
18
  const _ReferenceEditor = require("./ReferenceEditor");
17
19
  const _useEditorPermissions = require("./useEditorPermissions");
18
20
  function _getRequireWildcardCache(nodeInterop) {
@@ -145,7 +147,10 @@ function Editor(props) {
145
147
  }));
146
148
  }
147
149
  function MultipleReferenceEditor(props) {
148
- const allContentTypes = props.sdk.space.getCachedContentTypes();
150
+ return /*#__PURE__*/ _react.createElement(_queryClient.SharedQueryClientProvider, null, /*#__PURE__*/ _react.createElement(MultipleReferenceEditorInner, props));
151
+ }
152
+ function MultipleReferenceEditorInner(props) {
153
+ const { contentTypes: allContentTypes } = (0, _reactquery.useContentTypes)(props.sdk);
149
154
  return /*#__PURE__*/ _react.createElement(_ReferenceEditor.ReferenceEditor, props, ({ value, disabled, setValue, externalReset })=>{
150
155
  return /*#__PURE__*/ _react.createElement(Editor, {
151
156
  ...props,
@@ -9,8 +9,10 @@ Object.defineProperty(exports, "SingleReferenceEditor", {
9
9
  }
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
+ const _reactquery = require("@contentful/field-editor-shared/react-query");
12
13
  const _components = require("../components");
13
14
  const _LinkEntityActions = require("../components/LinkActions/LinkEntityActions");
15
+ const _queryClient = require("./queryClient");
14
16
  const _ReferenceEditor = require("./ReferenceEditor");
15
17
  const _useEditorPermissions = require("./useEditorPermissions");
16
18
  function _getRequireWildcardCache(nodeInterop) {
@@ -98,11 +100,15 @@ function Editor(props) {
98
100
  }
99
101
  return props.children({
100
102
  ...props,
101
- renderCustomCard: props.renderCustomCard && customCardRenderer
103
+ renderCustomCard: props.renderCustomCard && customCardRenderer,
104
+ addReferenceToRelease: props.addReferenceToRelease
102
105
  });
103
106
  }
104
107
  function SingleReferenceEditor(props) {
105
- const allContentTypes = props.sdk.space.getCachedContentTypes();
108
+ return /*#__PURE__*/ _react.createElement(_queryClient.SharedQueryClientProvider, null, /*#__PURE__*/ _react.createElement(SingleReferenceEditorInner, props));
109
+ }
110
+ function SingleReferenceEditorInner(props) {
111
+ const { contentTypes: allContentTypes } = (0, _reactquery.useContentTypes)(props.sdk);
106
112
  return /*#__PURE__*/ _react.createElement(_ReferenceEditor.ReferenceEditor, props, ({ value, setValue, disabled, externalReset })=>{
107
113
  return /*#__PURE__*/ _react.createElement(Editor, {
108
114
  ...props,
@@ -10,13 +10,13 @@ function _export(target, all) {
10
10
  }
11
11
  _export(exports, {
12
12
  SharedQueryClientProvider: function() {
13
- return _fieldeditorshared.SharedQueryClientProvider;
13
+ return _reactquery.SharedQueryClientProvider;
14
14
  },
15
15
  useQuery: function() {
16
- return _fieldeditorshared.useQuery;
16
+ return _reactquery.useQuery;
17
17
  },
18
18
  useQueryClient: function() {
19
- return _fieldeditorshared.useQueryClient;
19
+ return _reactquery.useQueryClient;
20
20
  }
21
21
  });
22
- const _fieldeditorshared = require("@contentful/field-editor-shared");
22
+ const _reactquery = require("@contentful/field-editor-shared/react-query");
@@ -26,6 +26,9 @@ function useContentTypePermissions({ entityType, validations, sdk, allContentTyp
26
26
  if (entityType === 'Asset') {
27
27
  return [];
28
28
  }
29
+ if (validations.contentTypes && allContentTypes.length === 0) {
30
+ return [];
31
+ }
29
32
  if (validations.contentTypes) {
30
33
  return allContentTypes.filter((ct)=>validations.contentTypes?.includes(ct.sys.id));
31
34
  }
@@ -38,21 +41,15 @@ function useContentTypePermissions({ entityType, validations, sdk, allContentTyp
38
41
  const [creatableContentTypes, setCreatableContentTypes] = (0, _react.useState)(availableContentTypes);
39
42
  const { canPerformActionOnEntryOfType } = (0, _useAccessApi.useAccessApi)(sdk.access);
40
43
  (0, _react.useEffect)(()=>{
41
- function getContentTypes(action) {
42
- return filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType(action, ct.sys.id));
43
- }
44
44
  async function checkContentTypeAccess() {
45
- const creatable = await getContentTypes('create');
46
- if (!(0, _isEqual.default)(creatable, creatableContentTypes)) {
47
- setCreatableContentTypes(creatable);
48
- }
45
+ const creatable = await filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType('create', ct.sys.id));
46
+ setCreatableContentTypes((creatableContentTypes)=>(0, _isEqual.default)(creatable, creatableContentTypes) ? creatableContentTypes : creatable);
49
47
  }
50
48
  if (availableContentTypes.length > 0) {
51
49
  void checkContentTypeAccess();
52
50
  }
53
51
  }, [
54
- availableContentTypes,
55
- creatableContentTypes
52
+ availableContentTypes
56
53
  ]);
57
54
  return {
58
55
  creatableContentTypes,
@@ -13,8 +13,12 @@ const _fromFieldValidations = require("../utils/fromFieldValidations");
13
13
  const _useAccessApi = require("./useAccessApi");
14
14
  const _useContentTypePermissions = require("./useContentTypePermissions");
15
15
  function useEditorPermissions({ sdk, entityType, parameters, allContentTypes }) {
16
+ const fieldValidations = sdk.field.validations;
17
+ const itemsValidations = sdk.field.type === 'Array' ? sdk.field.items?.validations : undefined;
16
18
  const validations = (0, _react.useMemo)(()=>(0, _fromFieldValidations.fromFieldValidations)(sdk.field), [
17
- sdk.field
19
+ sdk.field,
20
+ JSON.stringify(fieldValidations),
21
+ JSON.stringify(itemsValidations)
18
22
  ]);
19
23
  const [canCreateEntity, setCanCreateEntity] = (0, _react.useState)(true);
20
24
  const [canLinkEntity, setCanLinkEntity] = (0, _react.useState)(true);
@@ -130,6 +130,7 @@ function useLinkActionsProps(props) {
130
130
  }, [
131
131
  sdk,
132
132
  entityType,
133
+ editorPermissions,
133
134
  onLinkedExisting
134
135
  ]);
135
136
  const onLinkSeveralExisting = _react.useCallback(async (index)=>{
@@ -145,6 +146,7 @@ function useLinkActionsProps(props) {
145
146
  }, [
146
147
  sdk,
147
148
  entityType,
149
+ editorPermissions,
148
150
  onLinkedExisting
149
151
  ]);
150
152
  return (0, _react.useMemo)(()=>({
@@ -85,7 +85,8 @@ function MultipleEntryReferenceEditor(props) {
85
85
  onMoveTop: index !== 0 ? ()=>childrenProps.onMove(index, 0) : undefined,
86
86
  onMoveBottom: index !== lastIndex ? ()=>childrenProps.onMove(index, lastIndex) : undefined,
87
87
  renderDragHandle: DragHandle,
88
- isBeingDragged: index === indexToUpdate
88
+ isBeingDragged: index === indexToUpdate,
89
+ addReferenceToRelease: props.addReferenceToRelease
89
90
  });
90
91
  }));
91
92
  }
@@ -68,6 +68,7 @@ function SingleEntryReferenceEditor(props) {
68
68
  hasCardEditActions: hasCardEditActions,
69
69
  hasCardRemoveActions: hasCardRemoveActions,
70
70
  activeLocales: activeLocales,
71
+ addReferenceToRelease: props.addReferenceToRelease,
71
72
  onRemove: ()=>{
72
73
  setValue(null);
73
74
  }
@@ -114,6 +114,14 @@ function FetchingWrappedEntryCard(props) {
114
114
  contentTypeId: entry?.sys?.contentType?.sys?.id ?? ''
115
115
  });
116
116
  };
117
+ const onAddToRelease = ()=>{
118
+ if (entry && props.addReferenceToRelease) {
119
+ void props.addReferenceToRelease(entry, props.sdk.field.locale, {
120
+ openModalForVersionSelection: true,
121
+ skipNestedReferencesPrompt: true
122
+ });
123
+ }
124
+ };
117
125
  _react.useEffect(()=>{
118
126
  if (entry) {
119
127
  props.onAction?.({
@@ -168,7 +176,8 @@ function FetchingWrappedEntryCard(props) {
168
176
  activeLocales: props.activeLocales,
169
177
  releaseStatusMap,
170
178
  release: props.sdk.release,
171
- releaseEntityStatus
179
+ releaseEntityStatus,
180
+ onAddToRelease
172
181
  };
173
182
  const { hasCardEditActions, hasCardMoveActions, hasCardRemoveActions } = props;
174
183
  function renderDefaultCard(props) {
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "WrappedEntryCard", {
10
10
  });
11
11
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
12
12
  const _f36components = require("@contentful/f36-components");
13
+ const _f36icons = require("@contentful/f36-icons");
13
14
  const _fieldeditorshared = require("@contentful/field-editor-shared");
14
15
  const _components = require("../../components");
15
16
  const _SpaceName = require("../../components/SpaceName/SpaceName");
@@ -61,7 +62,7 @@ const defaultProps = {
61
62
  hasCardMoveActions: true,
62
63
  hasCardRemoveActions: true
63
64
  };
64
- function WrappedEntryCard({ entry, entryUrl, contentType, activeLocales, localeCode, defaultLocaleCode, localesStatusMap, useLocalizedEntityStatus, size, spaceName, isClickable, isDisabled, isSelected, hasCardMoveActions, hasCardEditActions, hasCardRemoveActions, renderDragHandle, getAsset, getEntityScheduledActions, onClick, onEdit, onRemove, onMoveTop, onMoveBottom, releaseEntityStatus, releaseStatusMap, release }) {
65
+ function WrappedEntryCard({ entry, entryUrl, contentType, activeLocales, localeCode, defaultLocaleCode, localesStatusMap, useLocalizedEntityStatus, size, spaceName, isClickable, isDisabled, isSelected, hasCardMoveActions, hasCardEditActions, hasCardRemoveActions, renderDragHandle, getAsset, getEntityScheduledActions, onClick, onEdit, onRemove, onMoveTop, onMoveBottom, releaseEntityStatus, releaseStatusMap, release, onAddToRelease }) {
65
66
  const [file, setFile] = _react.useState(null);
66
67
  _react.useEffect(()=>{
67
68
  let mounted = true;
@@ -112,6 +113,7 @@ function WrappedEntryCard({ entry, entryUrl, contentType, activeLocales, localeC
112
113
  localeCode,
113
114
  defaultLocaleCode
114
115
  });
116
+ const showAddToReleaseAction = releaseEntityStatus === 'notInRelease' && release !== undefined && onAddToRelease !== undefined && !isDisabled;
115
117
  return /*#__PURE__*/ _react.createElement(_f36components.EntryCard, {
116
118
  as: isClickable && entryUrl ? 'a' : 'article',
117
119
  href: isClickable ? entryUrl : undefined,
@@ -142,7 +144,7 @@ function WrappedEntryCard({ entry, entryUrl, contentType, activeLocales, localeC
142
144
  dragHandleRender: renderDragHandle,
143
145
  withDragHandle: !!renderDragHandle && !isDisabled,
144
146
  draggable: !!renderDragHandle && !isDisabled,
145
- actions: onEdit || onRemove ? [
147
+ actions: onEdit || onRemove || showAddToReleaseAction ? [
146
148
  hasCardEditActions && onEdit ? /*#__PURE__*/ _react.createElement(_f36components.MenuItem, {
147
149
  key: "edit",
148
150
  testId: "edit",
@@ -157,6 +159,15 @@ function WrappedEntryCard({ entry, entryUrl, contentType, activeLocales, localeC
157
159
  onRemove && onRemove();
158
160
  }
159
161
  }, "Remove") : null,
162
+ showAddToReleaseAction ? /*#__PURE__*/ _react.createElement(_f36components.MenuItem, {
163
+ key: "add-to-release",
164
+ testId: "add-to-release",
165
+ onClick: ()=>{
166
+ onAddToRelease();
167
+ }
168
+ }, /*#__PURE__*/ _react.createElement(_f36icons.PlusIcon, {
169
+ size: "tiny"
170
+ }), "Add to release") : null,
160
171
  hasCardMoveActions && (onMoveTop || onMoveBottom) && !isDisabled ? /*#__PURE__*/ _react.createElement(_f36components.MenuDivider, {
161
172
  key: "divider"
162
173
  }) : null,
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", {
4
4
  });
5
5
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
6
6
  require("@testing-library/jest-dom");
7
+ const _reactquery = require("@contentful/field-editor-shared/react-query");
8
+ const _fieldeditortestutils = require("@contentful/field-editor-test-utils");
7
9
  const _react1 = require("@testing-library/react");
8
10
  const _published_content_typejson = /*#__PURE__*/ _interop_require_default(require("../../__fixtures__/content-type/published_content_type.json"));
9
11
  const _published_entry_non_masterjson = /*#__PURE__*/ _interop_require_default(require("../../__fixtures__/entry/published_entry_non_master.json"));
@@ -217,9 +219,33 @@ describe('ResourceCard', ()=>{
217
219
  _react1.fireEvent.mouseEnter(getByText(_indifferent_spacejson.default.name));
218
220
  await (0, _react1.waitFor)(()=>expect(getByText(tooltipContent)).toBeDefined());
219
221
  });
220
- it('renders skeleton when no data is provided', ()=>{
221
- const { getByTestId } = renderResourceCard();
222
+ it('renders skeleton while data is loading', async ()=>{
223
+ const queryClient = (0, _fieldeditortestutils.createTestQueryClient)();
224
+ let resolveEntry;
225
+ const pendingPromise = new Promise((resolve)=>{
226
+ resolveEntry = resolve;
227
+ });
228
+ sdk.cma.entry.get.mockReturnValueOnce(pendingPromise);
229
+ const { getByTestId, queryByTestId } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_reactquery.SharedQueryClientProvider, {
230
+ client: queryClient
231
+ }, /*#__PURE__*/ _react.createElement(_EntityStore.EntityProvider, {
232
+ sdk: sdk
233
+ }, /*#__PURE__*/ _react.createElement(_ResourceCard.ResourceCard, {
234
+ isDisabled: false,
235
+ getEntryRouteHref: ()=>'',
236
+ resourceLink: {
237
+ sys: {
238
+ type: 'ResourceLink',
239
+ linkType: 'Contentful:Entry',
240
+ urn: resolvableEntryUrn
241
+ }
242
+ }
243
+ }))));
222
244
  expect(getByTestId('cf-ui-skeleton-form')).toBeDefined();
245
+ expect(queryByTestId('cf-ui-entry-card')).toBeNull();
246
+ resolveEntry(_published_entryjson.default);
247
+ await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
248
+ expect(queryByTestId('cf-ui-skeleton-form')).toBeNull();
223
249
  });
224
250
  it('renders unsupported entity card when resource type is unknown', async ()=>{
225
251
  const { getByText } = renderResourceCard({
@@ -35,15 +35,6 @@ export function newReferenceEditorFakeSdk(props) {
35
35
  const delay = (ms)=>{
36
36
  return new Promise((resolve)=>setTimeout(resolve, ms));
37
37
  };
38
- const localizeContentTypes = (contentTypes)=>{
39
- return contentTypes.map((contentType)=>({
40
- ...contentType,
41
- fields: contentType.fields.map((field)=>({
42
- ...field,
43
- localized: true
44
- }))
45
- }));
46
- };
47
38
  const sdk = {
48
39
  field,
49
40
  locales,
@@ -96,6 +87,19 @@ export function newReferenceEditorFakeSdk(props) {
96
87
  return contentTypes.published;
97
88
  }
98
89
  return Promise.reject({});
90
+ },
91
+ getMany: async ()=>{
92
+ return Promise.resolve({
93
+ items: [
94
+ contentTypes.published
95
+ ],
96
+ total: 1,
97
+ skip: 0,
98
+ limit: 1000,
99
+ sys: {
100
+ type: 'Array'
101
+ }
102
+ });
99
103
  }
100
104
  },
101
105
  Locale: {
@@ -104,17 +108,6 @@ export function newReferenceEditorFakeSdk(props) {
104
108
  },
105
109
  space: {
106
110
  ...space,
107
- getCachedContentTypes () {
108
- return localizeContentTypes(space.getCachedContentTypes());
109
- },
110
- getContentTypes () {
111
- return Promise.resolve(space.getContentTypes().then((response)=>{
112
- return {
113
- ...response,
114
- items: localizeContentTypes(response.items)
115
- };
116
- }));
117
- },
118
111
  async getEntityScheduledActions () {
119
112
  return [];
120
113
  }
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { MenuItem, Text, MenuSectionTitle } from '@contentful/f36-components';
3
+ import { PlusIcon } from '@contentful/f36-icons';
3
4
  import tokens from '@contentful/f36-tokens';
4
5
  import { shortenStorageUnit } from '@contentful/field-editor-shared';
5
6
  import { css } from 'emotion';
@@ -70,7 +71,7 @@ export function renderAssetInfo(props) {
70
71
  ];
71
72
  }
72
73
  export function renderActions(props) {
73
- const { entityFile, isDisabled, onEdit, onRemove } = props;
74
+ const { entityFile, isDisabled, onEdit, onRemove, onAddToReleaseAction } = props;
74
75
  return [
75
76
  /*#__PURE__*/ React.createElement(MenuSectionTitle, {
76
77
  key: "section-title"
@@ -80,6 +81,15 @@ export function renderActions(props) {
80
81
  onClick: onEdit,
81
82
  testId: "card-action-edit"
82
83
  }, "Edit") : null,
84
+ onAddToReleaseAction ? /*#__PURE__*/ React.createElement(MenuItem, {
85
+ key: "add-to-release",
86
+ testId: "add-to-release",
87
+ onClick: ()=>{
88
+ onAddToReleaseAction();
89
+ }
90
+ }, /*#__PURE__*/ React.createElement(PlusIcon, {
91
+ size: "tiny"
92
+ }), "Add to release") : null,
83
93
  entityFile ? /*#__PURE__*/ React.createElement(MenuItem, {
84
94
  key: "download",
85
95
  onClick: ()=>{