@contentful/field-editor-reference 5.19.0 → 5.20.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 (115) hide show
  1. package/dist/cjs/__fixtures__/FakeSdk.js +3 -3
  2. package/dist/cjs/__fixtures__/asset/index.js +10 -10
  3. package/dist/cjs/__fixtures__/content-type/index.js +1 -1
  4. package/dist/cjs/__fixtures__/entry/index.js +7 -7
  5. package/dist/cjs/__fixtures__/fixtures.js +8 -6
  6. package/dist/cjs/__fixtures__/locale/index.js +2 -2
  7. package/dist/cjs/__fixtures__/space/index.js +1 -1
  8. package/dist/cjs/assets/MultipleMediaEditor.js +7 -5
  9. package/dist/cjs/assets/SingleMediaEditor.js +6 -4
  10. package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +21 -19
  11. package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +18 -11
  12. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +20 -11
  13. package/dist/cjs/assets/WrappedAssetCard/WrappedAssetLink.js +12 -9
  14. package/dist/cjs/assets/index.js +3 -3
  15. package/dist/cjs/common/EntityStore.js +53 -53
  16. package/dist/cjs/common/MultipleReferenceEditor.js +20 -11
  17. package/dist/cjs/common/ReferenceEditor.js +7 -5
  18. package/dist/cjs/common/SingleReferenceEditor.js +11 -7
  19. package/dist/cjs/common/SortableLinkList.js +14 -14
  20. package/dist/cjs/common/customCardTypes.js +4 -2
  21. package/dist/cjs/common/queryClient.js +102 -0
  22. package/dist/cjs/common/useContentTypePermissions.js +3 -1
  23. package/dist/cjs/common/useEditorPermissions.js +15 -3
  24. package/dist/cjs/common/useEditorPermissions.spec.js +13 -12
  25. package/dist/cjs/components/AssetThumbnail/AssetThumbnail.js +5 -3
  26. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.js +13 -9
  27. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +17 -15
  28. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +29 -19
  29. package/dist/cjs/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +14 -12
  30. package/dist/cjs/components/LinkActions/CombinedLinkActions.js +28 -21
  31. package/dist/cjs/components/LinkActions/LinkActions.js +17 -15
  32. package/dist/cjs/components/LinkActions/LinkEntityActions.js +26 -17
  33. package/dist/cjs/components/LinkActions/NoLinkPermissionsInfo.js +5 -3
  34. package/dist/cjs/components/LinkActions/helpers.js +10 -5
  35. package/dist/cjs/components/LinkActions/redesignStyles.js +4 -4
  36. package/dist/cjs/components/LinkActions/styles.js +1 -1
  37. package/dist/cjs/components/MissingEntityCard/MissingEntityCard.js +11 -9
  38. package/dist/cjs/components/ResourceEntityErrorCard/ResourceEntityErrorCard.js +6 -4
  39. package/dist/cjs/components/ResourceEntityErrorCard/UnsupportedEntityCard.js +6 -4
  40. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduleTooltip.js +10 -8
  41. package/dist/cjs/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +9 -4
  42. package/dist/cjs/components/ScheduledIconWithTooltip/formatDateAndTime.js +5 -4
  43. package/dist/cjs/components/SpaceName/SpaceName.js +9 -7
  44. package/dist/cjs/components/index.js +12 -12
  45. package/dist/cjs/entries/MultipleEntryReferenceEditor.js +9 -7
  46. package/dist/cjs/entries/SingleEntryReferenceEditor.js +7 -5
  47. package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +20 -11
  48. package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +23 -17
  49. package/dist/cjs/entries/index.js +3 -3
  50. package/dist/cjs/index.js +38 -34
  51. package/dist/cjs/resources/Cards/ContentfulEntryCard.js +13 -4
  52. package/dist/cjs/resources/Cards/ResourceCard.js +16 -12
  53. package/dist/cjs/resources/Cards/ResourceCard.spec.js +20 -17
  54. package/dist/cjs/resources/MultipleResourceReferenceEditor.js +20 -17
  55. package/dist/cjs/resources/MultipleResourceReferenceEditor.spec.js +34 -13
  56. package/dist/cjs/resources/SingleResourceReferenceEditor.js +11 -9
  57. package/dist/cjs/resources/SingleResourceReferenceEditor.spec.js +13 -6
  58. package/dist/cjs/resources/testHelpers/resourceEditorHelpers.js +12 -5
  59. package/dist/cjs/resources/useResourceLinkActions.js +11 -2
  60. package/dist/cjs/types.js +3 -3
  61. package/dist/cjs/utils/fromFieldValidations.js +2 -1
  62. package/dist/cjs/utils/useSortIDs.js +6 -4
  63. package/dist/esm/__fixtures__/FakeSdk.js +3 -3
  64. package/dist/esm/assets/MultipleMediaEditor.js +3 -3
  65. package/dist/esm/assets/SingleMediaEditor.js +2 -2
  66. package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +12 -12
  67. package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +14 -9
  68. package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +15 -7
  69. package/dist/esm/assets/WrappedAssetCard/WrappedAssetLink.js +7 -6
  70. package/dist/esm/common/EntityStore.js +40 -42
  71. package/dist/esm/common/MultipleReferenceEditor.js +16 -9
  72. package/dist/esm/common/ReferenceEditor.js +2 -2
  73. package/dist/esm/common/SingleReferenceEditor.js +7 -5
  74. package/dist/esm/common/SortableLinkList.js +12 -12
  75. package/dist/esm/common/queryClient.js +44 -0
  76. package/dist/esm/common/useContentTypePermissions.js +3 -1
  77. package/dist/esm/common/useEditorPermissions.js +15 -3
  78. package/dist/esm/common/useEditorPermissions.spec.js +13 -12
  79. package/dist/esm/components/AssetThumbnail/AssetThumbnail.js +1 -1
  80. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.js +7 -5
  81. package/dist/esm/components/CreateEntryLinkButton/CreateEntryLinkButton.spec.js +12 -12
  82. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.js +23 -15
  83. package/dist/esm/components/CreateEntryLinkButton/CreateEntryMenuTrigger.spec.js +9 -8
  84. package/dist/esm/components/LinkActions/CombinedLinkActions.js +30 -19
  85. package/dist/esm/components/LinkActions/LinkActions.js +9 -9
  86. package/dist/esm/components/LinkActions/LinkEntityActions.js +18 -11
  87. package/dist/esm/components/LinkActions/NoLinkPermissionsInfo.js +1 -1
  88. package/dist/esm/components/LinkActions/helpers.js +7 -2
  89. package/dist/esm/components/MissingEntityCard/MissingEntityCard.js +6 -6
  90. package/dist/esm/components/ResourceEntityErrorCard/ResourceEntityErrorCard.js +2 -2
  91. package/dist/esm/components/ResourceEntityErrorCard/UnsupportedEntityCard.js +2 -2
  92. package/dist/esm/components/ScheduledIconWithTooltip/ScheduleTooltip.js +3 -3
  93. package/dist/esm/components/ScheduledIconWithTooltip/ScheduledIconWithTooltip.js +5 -2
  94. package/dist/esm/components/ScheduledIconWithTooltip/formatDateAndTime.js +11 -2
  95. package/dist/esm/components/SpaceName/SpaceName.js +4 -4
  96. package/dist/esm/entries/MultipleEntryReferenceEditor.js +5 -5
  97. package/dist/esm/entries/SingleEntryReferenceEditor.js +3 -3
  98. package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +15 -8
  99. package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +18 -14
  100. package/dist/esm/index.js +1 -0
  101. package/dist/esm/resources/Cards/ContentfulEntryCard.js +9 -2
  102. package/dist/esm/resources/Cards/ResourceCard.js +12 -10
  103. package/dist/esm/resources/Cards/ResourceCard.spec.js +12 -11
  104. package/dist/esm/resources/MultipleResourceReferenceEditor.js +14 -13
  105. package/dist/esm/resources/MultipleResourceReferenceEditor.spec.js +30 -11
  106. package/dist/esm/resources/SingleResourceReferenceEditor.js +6 -6
  107. package/dist/esm/resources/SingleResourceReferenceEditor.spec.js +9 -4
  108. package/dist/esm/resources/testHelpers/resourceEditorHelpers.js +9 -2
  109. package/dist/esm/resources/useResourceLinkActions.js +11 -2
  110. package/dist/esm/utils/fromFieldValidations.js +1 -0
  111. package/dist/esm/utils/useSortIDs.js +2 -2
  112. package/dist/types/common/EntityStore.d.ts +1 -1
  113. package/dist/types/common/queryClient.d.ts +9 -0
  114. package/dist/types/index.d.ts +1 -0
  115. package/package.json +2 -2
@@ -12,10 +12,11 @@ function _define_property(obj, key, value) {
12
12
  return obj;
13
13
  }
14
14
  import React, { useCallback, useEffect, useMemo, useRef } from 'react';
15
- import { QueryCache, QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
16
15
  import constate from 'constate';
17
16
  import { createClient } from 'contentful-management';
18
17
  import PQueue from 'p-queue';
18
+ import { SharedQueryClientProvider, useQuery, useQueryClient } from './queryClient';
19
+ // global queue for all requests, the actual number is picked without scientific research
19
20
  const globalQueue = new PQueue({
20
21
  concurrency: 50
21
22
  });
@@ -33,7 +34,8 @@ const isEntityQueryKey = (queryKey)=>{
33
34
  return Array.isArray(queryKey) && (queryKey[0] === 'Entry' || queryKey[0] === 'Asset') && queryKey.length === 4;
34
35
  };
35
36
  async function fetchContentfulEntry(params) {
36
- const { urn , fetch , options } = params;
37
+ const { urn, fetch, options } = params;
38
+ // TODO use resource-names package EntryResourceName `fromString` method instead when the package becomes public
37
39
  const resourceId = urn.split(':', 6)[5];
38
40
  const ENTITY_RESOURCE_ID_REGEX = RegExp("^spaces\\/(?<spaceId>[^/]+)(?:\\/environments\\/(?<environmentId>[^/]+))?\\/entries\\/(?<entityId>[^/]+)$");
39
41
  const resourceIdMatch = resourceId.match(ENTITY_RESOURCE_ID_REGEX);
@@ -47,7 +49,7 @@ async function fetchContentfulEntry(params) {
47
49
  fetch([
48
50
  'space',
49
51
  spaceId
50
- ], ({ cmaClient })=>cmaClient.space.get({
52
+ ], ({ cmaClient })=>cmaClient.space.get({
51
53
  spaceId
52
54
  }), options),
53
55
  fetch([
@@ -55,7 +57,7 @@ async function fetchContentfulEntry(params) {
55
57
  spaceId,
56
58
  environmentId,
57
59
  entryId
58
- ], ({ cmaClient })=>cmaClient.entry.get({
60
+ ], ({ cmaClient })=>cmaClient.entry.get({
59
61
  spaceId,
60
62
  environmentId,
61
63
  entryId
@@ -68,7 +70,7 @@ async function fetchContentfulEntry(params) {
68
70
  spaceId,
69
71
  environmentId,
70
72
  contentTypeId
71
- ], ({ cmaClient })=>cmaClient.contentType.get({
73
+ ], ({ cmaClient })=>cmaClient.contentType.get({
72
74
  contentTypeId,
73
75
  spaceId,
74
76
  environmentId
@@ -77,7 +79,7 @@ async function fetchContentfulEntry(params) {
77
79
  'defaultLocale',
78
80
  spaceId,
79
81
  environmentId
80
- ], async ({ cmaClient })=>{
82
+ ], async ({ cmaClient })=>{
81
83
  const locales = await cmaClient.locale.getMany({
82
84
  spaceId,
83
85
  environmentId,
@@ -127,7 +129,7 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
127
129
  props.queryConcurrency
128
130
  ]);
129
131
  const fetch = useCallback(function fetch(queryKey, fn, options = {}) {
130
- const { priority , ...queryOptions } = options;
132
+ const { priority, ...queryOptions } = options;
131
133
  return queryClient.fetchQuery(queryKey, ()=>queryQueue.add(()=>fn({
132
134
  cmaClient
133
135
  }), {
@@ -147,7 +149,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
147
149
  spaceId,
148
150
  environmentId
149
151
  ];
150
- return fetch(queryKey, ({ cmaClient })=>{
152
+ return fetch(queryKey, // @ts-expect-error
153
+ ({ cmaClient })=>{
151
154
  if (entityType === 'Entry') {
152
155
  return cmaClient.entry.get({
153
156
  entryId: entityId,
@@ -169,8 +172,18 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
169
172
  currentSpaceId,
170
173
  currentEnvironmentId
171
174
  ]);
172
- const getEntityScheduledActions = useCallback(function getEntityScheduledActions(entityType, entityId, options) {
175
+ /**
176
+ * Fetch all scheduled actions for a given entity.
177
+ * This function fetches all schedules for all entries and then returns
178
+ * a filtered result based on the entityID provided.
179
+ *
180
+ * The result is then reused/cached for subsequent calls to this function.
181
+ */ const getEntityScheduledActions = useCallback(function getEntityScheduledActions(entityType, entityId, options) {
182
+ // This is fixed to force the cache to reuse previous results
173
183
  const fixedEntityCacheId = 'scheduledActionEntityId';
184
+ // A space+environment combo can only have up to 500 scheduled actions
185
+ // With this request we fetch all schedules and can reuse the results.
186
+ // See https://www.contentful.com/developers/docs/references/content-management-api/#/reference/scheduled-actions/limitations
174
187
  const maxScheduledActions = 500;
175
188
  const spaceId = options?.spaceId ?? currentSpaceId;
176
189
  const environmentId = options?.environmentId ?? currentEnvironmentId;
@@ -181,7 +194,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
181
194
  spaceId,
182
195
  environmentId
183
196
  ];
184
- return fetch(queryKey, async ({ cmaClient })=>{
197
+ // Fetch + Filter by entity ID in the end
198
+ return fetch(queryKey, async ({ cmaClient })=>{
185
199
  const response = await cmaClient.scheduledActions.getMany({
186
200
  spaceId,
187
201
  query: {
@@ -225,6 +239,7 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
225
239
  currentSpaceId,
226
240
  environmentIds
227
241
  ]);
242
+ // @ts-expect-error ...
228
243
  const onEntityChanged = props.sdk.space.onEntityChanged;
229
244
  const onSlideInNavigation = props.sdk.navigator.onSlideInNavigation;
230
245
  useEffect(()=>{
@@ -235,15 +250,16 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
235
250
  });
236
251
  }
237
252
  if (typeof onEntityChanged !== 'function') {
238
- return onSlideInNavigation(({ oldSlideLevel , newSlideLevel })=>{
253
+ return onSlideInNavigation(({ oldSlideLevel, newSlideLevel })=>{
239
254
  if (oldSlideLevel > newSlideLevel) {
240
255
  findSameSpaceQueries().forEach((query)=>{
256
+ // automatically refetches the query
241
257
  void queryClient.invalidateQueries(query.queryKey);
242
258
  });
243
259
  }
244
260
  });
245
261
  }
246
- const subscribeQuery = ({ queryKey , queryHash })=>{
262
+ const subscribeQuery = ({ queryKey, queryHash })=>{
247
263
  const [entityType, entityId] = queryKey;
248
264
  entityChangeUnsubscribers.current[queryHash] = onEntityChanged(entityType, entityId, (data)=>{
249
265
  queryClient.setQueryData(queryKey, data);
@@ -254,8 +270,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
254
270
  if (!event) {
255
271
  return;
256
272
  }
257
- const { type , query } = event;
258
- const { queryKey , queryHash } = query;
273
+ const { type, query } = event;
274
+ const { queryKey, queryHash } = query;
259
275
  if (!isSameSpaceEntityQueryKey(queryKey)) {
260
276
  return;
261
277
  }
@@ -263,6 +279,7 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
263
279
  subscribeQuery(query);
264
280
  }
265
281
  if (type === 'removed') {
282
+ // calling unsubscribe
266
283
  entityChangeUnsubscribers.current[queryHash]?.();
267
284
  }
268
285
  });
@@ -287,24 +304,24 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
287
304
  getEntity,
288
305
  getEntityScheduledActions
289
306
  };
290
- }, ({ fetch })=>fetch, ({ getResource , getEntity , getEntityScheduledActions })=>({
307
+ }, ({ fetch })=>fetch, ({ getResource, getEntity, getEntityScheduledActions })=>({
291
308
  getResource,
292
309
  getEntity,
293
310
  getEntityScheduledActions
294
- }), ({ ids })=>({
311
+ }), ({ ids })=>({
295
312
  environment: ids.environmentAlias ?? ids.environment,
296
313
  space: ids.space
297
314
  }));
298
315
  export function useEntity(entityType, entityId, options) {
299
- const { space , environment } = useCurrentIds();
300
- const { getEntity } = useEntityLoader();
316
+ const { space, environment } = useCurrentIds();
317
+ const { getEntity } = useEntityLoader();
301
318
  const queryKey = [
302
319
  entityType,
303
320
  entityId,
304
321
  options?.spaceId ?? space,
305
322
  options?.environmentId ?? environment
306
323
  ];
307
- const { status , data } = useQuery(queryKey, ()=>getEntity(entityType, entityId, options), {
324
+ const { status, data } = useQuery(queryKey, ()=>getEntity(entityType, entityId, options), {
308
325
  enabled: options?.enabled
309
326
  });
310
327
  return {
@@ -318,8 +335,8 @@ export function useResource(resourceType, urn, options) {
318
335
  resourceType,
319
336
  urn
320
337
  ];
321
- const { getResource } = useEntityLoader();
322
- const { status , data , error } = useQuery(queryKey, ()=>getResource(resourceType, urn, options), {
338
+ const { getResource } = useEntityLoader();
339
+ const { status, data, error } = useQuery(queryKey, ()=>getResource(resourceType, urn, options), {
323
340
  enabled: options?.enabled
324
341
  });
325
342
  return {
@@ -328,26 +345,7 @@ export function useResource(resourceType, urn, options) {
328
345
  error
329
346
  };
330
347
  }
331
- function EntityProvider({ children , ...props }) {
332
- const reactQueryClient = useMemo(()=>{
333
- const queryCache = new QueryCache();
334
- const queryClient = new QueryClient({
335
- queryCache,
336
- defaultOptions: {
337
- queries: {
338
- useErrorBoundary: false,
339
- refetchOnWindowFocus: false,
340
- refetchOnReconnect: true,
341
- refetchOnMount: false,
342
- staleTime: Infinity,
343
- retry: false
344
- }
345
- }
346
- });
347
- return queryClient;
348
- }, []);
349
- return React.createElement(QueryClientProvider, {
350
- client: reactQueryClient
351
- }, React.createElement(InternalServiceProvider, props, children));
348
+ function EntityProvider({ children, ...props }) {
349
+ return /*#__PURE__*/ React.createElement(SharedQueryClientProvider, null, /*#__PURE__*/ React.createElement(InternalServiceProvider, props, children));
352
350
  }
353
351
  export { EntityProvider, useEntityLoader };
@@ -25,18 +25,24 @@ const nullableValue = {
25
25
  }
26
26
  };
27
27
  function Editor(props) {
28
- const { setValue , entityType , onSortingEnd , setIndexToUpdate } = props;
28
+ const { setValue, entityType, onSortingEnd, setIndexToUpdate } = props;
29
29
  const editorPermissions = useEditorPermissions(props);
30
30
  const items = React.useMemo(()=>{
31
- return (props.items || []).map((link)=>link || nullableValue);
31
+ return (props.items || [])// If null values have found their way into the persisted
32
+ // value for the multiref field, replace them with an object
33
+ // that has the shape of a Link to make the missing entry/asset
34
+ // card render
35
+ .map((link)=>link || nullableValue);
32
36
  }, [
33
37
  props.items
34
38
  ]);
35
- const { rearrangeSortIDs } = useSortIDs(items);
39
+ const { rearrangeSortIDs } = useSortIDs(items);
36
40
  const onSortStart = useCallback(()=>{
37
41
  document.body.classList.add('grabbing');
38
42
  }, []);
39
- const onSortEnd = useCallback(({ oldIndex , newIndex })=>{
43
+ const onSortEnd = useCallback(({ oldIndex, newIndex })=>{
44
+ // custom callback that is invoked *before* we sort the array
45
+ // e.g. in Compose we want to sort the references in the referenceMap before re-rendering drag and drop
40
46
  onSortingEnd && onSortingEnd({
41
47
  oldIndex,
42
48
  newIndex
@@ -80,24 +86,25 @@ function Editor(props) {
80
86
  onLink,
81
87
  itemsLength: items.length
82
88
  });
83
- const customCardRenderer = useCallback((cardProps, _, renderDefaultCard)=>props.renderCustomCard ? props.renderCustomCard(cardProps, linkActionsProps, renderDefaultCard) : false, [
89
+ const customCardRenderer = useCallback((cardProps, _, renderDefaultCard)=>props.renderCustomCard ? props.renderCustomCard(cardProps, linkActionsProps, renderDefaultCard) : false, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
90
+ [
84
91
  linkActionsProps
85
92
  ]);
86
- return React.createElement(React.Fragment, null, props.children({
93
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, props.children({
87
94
  ...props,
88
95
  onSortStart,
89
96
  onSortEnd,
90
97
  onMove,
91
98
  renderCustomCard: props.renderCustomCard && customCardRenderer
92
- }), React.createElement(LinkEntityActions, {
99
+ }), /*#__PURE__*/ React.createElement(LinkEntityActions, {
93
100
  renderCustomActions: props.renderCustomActions,
94
101
  ...linkActionsProps
95
102
  }));
96
103
  }
97
104
  export function MultipleReferenceEditor(props) {
98
105
  const allContentTypes = props.sdk.space.getCachedContentTypes();
99
- return React.createElement(ReferenceEditor, props, ({ value , disabled , setValue , externalReset })=>{
100
- return React.createElement(Editor, {
106
+ return /*#__PURE__*/ React.createElement(ReferenceEditor, props, ({ value, disabled, setValue, externalReset })=>{
107
+ return /*#__PURE__*/ React.createElement(Editor, {
101
108
  ...props,
102
109
  items: value || emptyArray,
103
110
  isDisabled: disabled,
@@ -3,9 +3,9 @@ import { FieldConnector } from '@contentful/field-editor-shared';
3
3
  import deepEqual from 'deep-equal';
4
4
  import { EntityProvider } from './EntityStore';
5
5
  export function ReferenceEditor(props) {
6
- return React.createElement(EntityProvider, {
6
+ return /*#__PURE__*/ React.createElement(EntityProvider, {
7
7
  sdk: props.sdk
8
- }, React.createElement(FieldConnector, {
8
+ }, /*#__PURE__*/ React.createElement(FieldConnector, {
9
9
  debounce: 0,
10
10
  field: props.sdk.field,
11
11
  isInitiallyDisabled: props.isInitiallyDisabled,
@@ -5,7 +5,7 @@ import { useLinkActionsProps } from '../components/LinkActions/LinkEntityActions
5
5
  import { ReferenceEditor } from './ReferenceEditor';
6
6
  import { useEditorPermissions } from './useEditorPermissions';
7
7
  function Editor(props) {
8
- const { setValue , entityType } = props;
8
+ const { setValue, entityType } = props;
9
9
  const editorPermissions = useEditorPermissions(props);
10
10
  const onCreate = useCallback((id)=>void setValue({
11
11
  sys: {
@@ -37,11 +37,13 @@ function Editor(props) {
37
37
  onCreate,
38
38
  onLink
39
39
  });
40
- const customCardRenderer = useCallback((cardProps, _, renderDefaultCard)=>props.renderCustomCard ? props.renderCustomCard(cardProps, linkActionsProps, renderDefaultCard) : false, [
40
+ // Inject card actions props into the given custom card renderer
41
+ const customCardRenderer = useCallback((cardProps, _, renderDefaultCard)=>props.renderCustomCard ? props.renderCustomCard(cardProps, linkActionsProps, renderDefaultCard) : false, // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
42
+ [
41
43
  linkActionsProps
42
44
  ]);
43
45
  if (!props.entityId) {
44
- return React.createElement(LinkEntityActions, {
46
+ return /*#__PURE__*/ React.createElement(LinkEntityActions, {
45
47
  renderCustomActions: props.renderCustomActions,
46
48
  ...linkActionsProps
47
49
  });
@@ -53,8 +55,8 @@ function Editor(props) {
53
55
  }
54
56
  export function SingleReferenceEditor(props) {
55
57
  const allContentTypes = props.sdk.space.getCachedContentTypes();
56
- return React.createElement(ReferenceEditor, props, ({ value , setValue , disabled , externalReset })=>{
57
- return React.createElement(Editor, {
58
+ return /*#__PURE__*/ React.createElement(ReferenceEditor, props, ({ value, setValue, disabled, externalReset })=>{
59
+ return /*#__PURE__*/ React.createElement(Editor, {
58
60
  ...props,
59
61
  key: `${externalReset}-reference`,
60
62
  entityId: value ? value.sys.id : '',
@@ -20,8 +20,8 @@ const styles = {
20
20
  display: 'flex'
21
21
  })
22
22
  };
23
- const SortableLink = ({ id , items , item , isDisabled =false , index , children })=>{
24
- const { listeners , setNodeRef , setActivatorNodeRef , transform , transition , isDragging } = useSortable({
23
+ const SortableLink = ({ id, items, item, isDisabled = false, index, children })=>{
24
+ const { listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging } = useSortable({
25
25
  id
26
26
  });
27
27
  const style = {
@@ -34,16 +34,16 @@ const SortableLink = ({ id , items , item , isDisabled =false , index , children
34
34
  };
35
35
  const DragHandle = React.useCallback((props)=>{
36
36
  const SortableDragHandle = ()=>props.drag;
37
- return React.createElement("div", {
37
+ return /*#__PURE__*/ React.createElement("div", {
38
38
  ref: setActivatorNodeRef,
39
39
  className: styles.dragHandle,
40
40
  ...listeners
41
- }, React.createElement(SortableDragHandle, null));
41
+ }, /*#__PURE__*/ React.createElement(SortableDragHandle, null));
42
42
  }, [
43
43
  listeners,
44
44
  setActivatorNodeRef
45
45
  ]);
46
- return React.createElement("div", {
46
+ return /*#__PURE__*/ React.createElement("div", {
47
47
  ref: setNodeRef,
48
48
  style: style,
49
49
  className: cx(styles.item, {
@@ -57,8 +57,8 @@ const SortableLink = ({ id , items , item , isDisabled =false , index , children
57
57
  DragHandle: isDisabled ? undefined : DragHandle
58
58
  }));
59
59
  };
60
- export const SortableLinkList = ({ items , isDisabled , className , children , onSortStart , onSortEnd , updateBeforeSortStart , sortingStrategy })=>{
61
- const { sortIDs , rearrangeSortIDs } = useSortIDs(items);
60
+ export const SortableLinkList = ({ items, isDisabled, className, children, onSortStart, onSortEnd, updateBeforeSortStart, sortingStrategy })=>{
61
+ const { sortIDs, rearrangeSortIDs } = useSortIDs(items);
62
62
  const onSortStartHandler = React.useCallback((event)=>{
63
63
  const index = sortIDs.findIndex((item)=>item.id === event.active.id);
64
64
  updateBeforeSortStart?.({
@@ -71,7 +71,7 @@ export const SortableLinkList = ({ items , isDisabled , className , children , o
71
71
  sortIDs
72
72
  ]);
73
73
  const onSortEndHandler = React.useCallback((event)=>{
74
- const { active , over } = event;
74
+ const { active, over } = event;
75
75
  if (active && over && active.id !== over.id) {
76
76
  const oldIndex = sortIDs.findIndex((item)=>item.id === active.id);
77
77
  const newIndex = sortIDs.findIndex((item)=>item.id === over.id);
@@ -86,17 +86,17 @@ export const SortableLinkList = ({ items , isDisabled , className , children , o
86
86
  sortIDs,
87
87
  rearrangeSortIDs
88
88
  ]);
89
- return React.createElement(DndContext, {
89
+ return /*#__PURE__*/ React.createElement(DndContext, {
90
90
  onDragStart: onSortStartHandler,
91
91
  onDragEnd: onSortEndHandler
92
- }, React.createElement(SortableContext, {
92
+ }, /*#__PURE__*/ React.createElement(SortableContext, {
93
93
  items: sortIDs,
94
94
  strategy: sortingStrategy
95
- }, React.createElement("div", {
95
+ }, /*#__PURE__*/ React.createElement("div", {
96
96
  className: cx(styles.container, className)
97
97
  }, items.map((item, index)=>{
98
98
  const id = sortIDs[index]?.id;
99
- return React.createElement(SortableLink, {
99
+ return /*#__PURE__*/ React.createElement(SortableLink, {
100
100
  key: id,
101
101
  id: id,
102
102
  items: items,
@@ -0,0 +1,44 @@
1
+ import * as React from 'react';
2
+ import { QueryClient, useQuery as useRQ } from '@tanstack/react-query';
3
+ /**
4
+ * A custom client context ensures zero conflict with host apps also using
5
+ * React Query.
6
+ */ const clientContext = /*#__PURE__*/ React.createContext(undefined);
7
+ export function useQueryClient() {
8
+ const client = React.useContext(clientContext);
9
+ return React.useMemo(()=>{
10
+ if (client) {
11
+ return client;
12
+ }
13
+ return new QueryClient({
14
+ defaultOptions: {
15
+ queries: {
16
+ useErrorBoundary: false,
17
+ refetchOnWindowFocus: false,
18
+ refetchOnReconnect: true,
19
+ refetchOnMount: false,
20
+ staleTime: Infinity,
21
+ retry: false
22
+ }
23
+ }
24
+ });
25
+ }, [
26
+ client
27
+ ]);
28
+ }
29
+ // @ts-expect-error
30
+ export const useQuery = (key, fn, opt)=>{
31
+ return useRQ(key, fn, {
32
+ ...opt,
33
+ context: clientContext
34
+ });
35
+ };
36
+ /**
37
+ * Provides access to a query client either by sharing an existing client or
38
+ * creating a new one.
39
+ */ export function SharedQueryClientProvider({ children }) {
40
+ const client = useQueryClient();
41
+ return /*#__PURE__*/ React.createElement(clientContext.Provider, {
42
+ value: client
43
+ }, children);
44
+ }
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
  import { useAccessApi } from './useAccessApi';
3
3
  async function filter(arr, predicate) {
4
+ // intentionally parallel as we assume it's cached in the implementation of the access api
4
5
  const fail = Symbol();
5
6
  const results = await Promise.all(arr.map(async (item)=>await predicate(item) ? item : fail));
6
7
  return results.filter((x)=>x !== fail);
@@ -21,7 +22,7 @@ export function useContentTypePermissions(props) {
21
22
  ]);
22
23
  const [creatableContentTypes, setCreatableContentTypes] = useState(availableContentTypes);
23
24
  const [readableContentTypes, setReadableContentTypes] = useState(availableContentTypes);
24
- const { canPerformActionOnEntryOfType } = useAccessApi(props.sdk.access);
25
+ const { canPerformActionOnEntryOfType } = useAccessApi(props.sdk.access);
25
26
  useEffect(()=>{
26
27
  function getContentTypes(action) {
27
28
  return filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType(action, ct.sys.id));
@@ -33,6 +34,7 @@ export function useContentTypePermissions(props) {
33
34
  setReadableContentTypes(readable);
34
35
  }
35
36
  void checkContentTypeAccess();
37
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
36
38
  }, [
37
39
  availableContentTypes
38
40
  ]);
@@ -3,17 +3,17 @@ import { fromFieldValidations } from '../utils/fromFieldValidations';
3
3
  import { useAccessApi } from './useAccessApi';
4
4
  import { useContentTypePermissions } from './useContentTypePermissions';
5
5
  export function useEditorPermissions(props) {
6
- const { sdk , entityType , parameters } = props;
6
+ const { sdk, entityType, parameters } = props;
7
7
  const validations = useMemo(()=>fromFieldValidations(props.sdk.field), [
8
8
  props.sdk.field
9
9
  ]);
10
10
  const [canCreateEntity, setCanCreateEntity] = useState(true);
11
11
  const [canLinkEntity, setCanLinkEntity] = useState(true);
12
- const { creatableContentTypes , readableContentTypes , availableContentTypes } = useContentTypePermissions({
12
+ const { creatableContentTypes, readableContentTypes, availableContentTypes } = useContentTypePermissions({
13
13
  ...props,
14
14
  validations
15
15
  });
16
- const { canPerformAction } = useAccessApi(sdk.access);
16
+ const { canPerformAction } = useAccessApi(sdk.access);
17
17
  useEffect(()=>{
18
18
  if (parameters.instance.showCreateEntityAction === false) {
19
19
  setCanCreateEntity(false);
@@ -21,15 +21,20 @@ export function useEditorPermissions(props) {
21
21
  }
22
22
  async function checkCreateAccess() {
23
23
  if (entityType === 'Asset') {
24
+ // Hardcoded `true` value following https://contentful.atlassian.net/browse/DANTE-486
25
+ // TODO: refine permissions check in order to account for tags in rules
24
26
  const canCreate = await canPerformAction('create', 'Asset') || true;
25
27
  setCanCreateEntity(canCreate);
26
28
  }
27
29
  if (entityType === 'Entry') {
30
+ // Hardcoded `true` value following https://contentful.atlassian.net/browse/DANTE-486
31
+ // TODO: refine permissions check in order to account for tags in rules
28
32
  const canCreate = creatableContentTypes.length > 0 || true;
29
33
  setCanCreateEntity(canCreate);
30
34
  }
31
35
  }
32
36
  void checkCreateAccess();
37
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
33
38
  }, [
34
39
  entityType,
35
40
  parameters.instance,
@@ -42,15 +47,22 @@ export function useEditorPermissions(props) {
42
47
  }
43
48
  async function checkLinkAccess() {
44
49
  if (entityType === 'Asset') {
50
+ // Hardcoded `true` value following https://contentful.atlassian.net/browse/DANTE-486
51
+ // TODO: refine permissions check in order to account for tags in rules
45
52
  const canRead = await canPerformAction('read', 'Asset') || true;
46
53
  setCanLinkEntity(canRead);
47
54
  }
48
55
  if (entityType === 'Entry') {
56
+ // Hardcoded `true` value following https://contentful.atlassian.net/browse/DANTE-486
57
+ // TODO: refine permissions check in order to account for tags in rules
58
+ // TODO: always show every content type (it's just a filter) to avoid people not seeing
59
+ // their (partly limited) content types
49
60
  const canRead = true;
50
61
  setCanLinkEntity(canRead);
51
62
  }
52
63
  }
53
64
  void checkLinkAccess();
65
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: Evaluate the dependencies
54
66
  }, [
55
67
  entityType,
56
68
  parameters.instance,
@@ -14,7 +14,7 @@ describe('useEditorPermissions', ()=>{
14
14
  id
15
15
  }
16
16
  });
17
- const renderEditorPermissions = async ({ entityType , params ={} , allContentTypes =[] , customizeMock , customizeSdk })=>{
17
+ const renderEditorPermissions = async ({ entityType, params = {}, allContentTypes = [], customizeMock, customizeSdk })=>{
18
18
  const sdk = makeFieldAppSDK(customizeMock);
19
19
  customizeSdk?.(sdk);
20
20
  const renderResult = renderHook(()=>useEditorPermissions({
@@ -33,7 +33,7 @@ describe('useEditorPermissions', ()=>{
33
33
  };
34
34
  describe(`behaviour on Asset`, ()=>{
35
35
  it(`wont check access when turned off via instance params`, async ()=>{
36
- const { result , sdk } = await renderEditorPermissions({
36
+ const { result, sdk } = await renderEditorPermissions({
37
37
  entityType: 'Asset',
38
38
  params: {
39
39
  showCreateEntityAction: false,
@@ -45,20 +45,20 @@ describe('useEditorPermissions', ()=>{
45
45
  expect(sdk.access.can).not.toHaveBeenCalledWith();
46
46
  });
47
47
  it(`checks basic access`, async ()=>{
48
- const { sdk } = await renderEditorPermissions({
48
+ const { sdk } = await renderEditorPermissions({
49
49
  entityType: 'Asset'
50
50
  });
51
51
  expect(sdk.access.can).toHaveBeenCalledWith('create', 'Asset');
52
52
  expect(sdk.access.can).toHaveBeenCalledWith('read', 'Asset');
53
53
  });
54
54
  it(`defaults link asset action visibility to true`, async ()=>{
55
- const { result } = await renderEditorPermissions({
55
+ const { result } = await renderEditorPermissions({
56
56
  entityType: 'Asset'
57
57
  });
58
58
  expect(result.current.canLinkEntity).toBeTruthy();
59
59
  });
60
60
  it(`returns empty contentTypes`, async ()=>{
61
- const { result } = await renderEditorPermissions({
61
+ const { result } = await renderEditorPermissions({
62
62
  entityType: 'Asset',
63
63
  allContentTypes: [
64
64
  makeContentType('one')
@@ -78,7 +78,7 @@ describe('useEditorPermissions', ()=>{
78
78
  });
79
79
  };
80
80
  it(`wont check access when turned off via instance params`, async ()=>{
81
- const { result , sdk } = await renderEditorPermissions({
81
+ const { result, sdk } = await renderEditorPermissions({
82
82
  entityType: 'Entry',
83
83
  params: {
84
84
  showCreateEntityAction: false,
@@ -94,7 +94,7 @@ describe('useEditorPermissions', ()=>{
94
94
  makeContentType('one'),
95
95
  makeContentType('two')
96
96
  ];
97
- const { result } = await renderEditorPermissions({
97
+ const { result } = await renderEditorPermissions({
98
98
  entityType: 'Entry',
99
99
  allContentTypes,
100
100
  customizeSdk: (sdk)=>{
@@ -108,7 +108,7 @@ describe('useEditorPermissions', ()=>{
108
108
  makeContentType('one'),
109
109
  makeContentType('two')
110
110
  ];
111
- const { result } = await renderEditorPermissions({
111
+ const { result } = await renderEditorPermissions({
112
112
  entityType: 'Entry',
113
113
  allContentTypes,
114
114
  customizeSdk: (sdk)=>{
@@ -122,7 +122,7 @@ describe('useEditorPermissions', ()=>{
122
122
  makeContentType('one'),
123
123
  makeContentType('two')
124
124
  ];
125
- const { result } = await renderEditorPermissions({
125
+ const { result } = await renderEditorPermissions({
126
126
  entityType: 'Entry',
127
127
  allContentTypes,
128
128
  customizeSdk: (sdk)=>{
@@ -131,12 +131,13 @@ describe('useEditorPermissions', ()=>{
131
131
  });
132
132
  expect(result.current.canLinkEntity).toBe(true);
133
133
  });
134
+ // eslint-disable-next-line -- TODO: describe this disable jest/no-test-prefixes
134
135
  it.skip(`denies creation when no content-type can be read`, async ()=>{
135
136
  const allContentTypes = [
136
137
  makeContentType('one'),
137
138
  makeContentType('two')
138
139
  ];
139
- const { result } = await renderEditorPermissions({
140
+ const { result } = await renderEditorPermissions({
140
141
  entityType: 'Entry',
141
142
  allContentTypes,
142
143
  customizeSdk: (sdk)=>{
@@ -150,7 +151,7 @@ describe('useEditorPermissions', ()=>{
150
151
  makeContentType('one'),
151
152
  makeContentType('two')
152
153
  ];
153
- const { result } = await renderEditorPermissions({
154
+ const { result } = await renderEditorPermissions({
154
155
  entityType: 'Entry',
155
156
  allContentTypes,
156
157
  customizeMock: (field)=>{
@@ -176,7 +177,7 @@ describe('useEditorPermissions', ()=>{
176
177
  makeContentType('one'),
177
178
  makeContentType('two')
178
179
  ];
179
- const { result } = await renderEditorPermissions({
180
+ const { result } = await renderEditorPermissions({
180
181
  entityType: 'Entry',
181
182
  allContentTypes,
182
183
  customizeMock: (field)=>{
@@ -4,7 +4,7 @@ const dimensions = {
4
4
  height: 70
5
5
  };
6
6
  export function AssetThumbnail(props) {
7
- return React.createElement("img", {
7
+ return /*#__PURE__*/ React.createElement("img", {
8
8
  alt: props.file.fileName,
9
9
  src: `${props.file.url}?w=${dimensions.width}&h=${dimensions.height}&fit=thumb`,
10
10
  height: dimensions.height,