@contentful/field-editor-reference 6.18.0 → 6.19.1-canary.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/__fixtures__/FakeSdk.js +13 -20
- package/dist/cjs/assets/WrappedAssetCard/AssetCardActions.js +11 -1
- package/dist/cjs/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +10 -1
- package/dist/cjs/assets/WrappedAssetCard/WrappedAssetCard.js +4 -2
- package/dist/cjs/common/EntityStore.js +59 -33
- package/dist/cjs/common/MultipleReferenceEditor.js +6 -1
- package/dist/cjs/common/SingleReferenceEditor.js +8 -2
- package/dist/cjs/common/queryClient.js +4 -91
- package/dist/cjs/common/useContentTypePermissions.js +6 -9
- package/dist/cjs/common/useEditorPermissions.js +5 -1
- package/dist/cjs/components/LinkActions/LinkEntityActions.js +2 -0
- package/dist/cjs/entries/MultipleEntryReferenceEditor.js +2 -1
- package/dist/cjs/entries/SingleEntryReferenceEditor.js +1 -0
- package/dist/cjs/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +10 -1
- package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +13 -2
- package/dist/cjs/resources/Cards/ResourceCard.js +2 -1
- package/dist/cjs/resources/Cards/ResourceCard.spec.js +28 -2
- package/dist/cjs/resources/MultipleResourceReferenceEditor.js +1 -0
- package/dist/cjs/resources/MultipleResourceReferenceEditor.spec.js +2 -1
- package/dist/cjs/resources/SingleResourceReferenceEditor.js +1 -0
- package/dist/cjs/resources/SingleResourceReferenceEditor.spec.js +2 -1
- package/dist/cjs/resources/useResourceLinkActions.js +10 -5
- package/dist/esm/__fixtures__/FakeSdk.js +13 -20
- package/dist/esm/assets/WrappedAssetCard/AssetCardActions.js +11 -1
- package/dist/esm/assets/WrappedAssetCard/FetchingWrappedAssetCard.js +10 -1
- package/dist/esm/assets/WrappedAssetCard/WrappedAssetCard.js +4 -2
- package/dist/esm/common/EntityStore.js +59 -33
- package/dist/esm/common/MultipleReferenceEditor.js +6 -1
- package/dist/esm/common/SingleReferenceEditor.js +8 -2
- package/dist/esm/common/queryClient.js +1 -47
- package/dist/esm/common/useContentTypePermissions.js +6 -9
- package/dist/esm/common/useEditorPermissions.js +5 -1
- package/dist/esm/components/LinkActions/LinkEntityActions.js +2 -0
- package/dist/esm/entries/MultipleEntryReferenceEditor.js +2 -1
- package/dist/esm/entries/SingleEntryReferenceEditor.js +1 -0
- package/dist/esm/entries/WrappedEntryCard/FetchingWrappedEntryCard.js +10 -1
- package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +13 -2
- package/dist/esm/resources/Cards/ResourceCard.js +2 -1
- package/dist/esm/resources/Cards/ResourceCard.spec.js +28 -2
- package/dist/esm/resources/MultipleResourceReferenceEditor.js +1 -0
- package/dist/esm/resources/MultipleResourceReferenceEditor.spec.js +2 -1
- package/dist/esm/resources/SingleResourceReferenceEditor.js +1 -0
- package/dist/esm/resources/SingleResourceReferenceEditor.spec.js +2 -1
- package/dist/esm/resources/useResourceLinkActions.js +10 -5
- package/dist/types/assets/WrappedAssetCard/AssetCardActions.d.ts +1 -0
- package/dist/types/assets/WrappedAssetCard/FetchingWrappedAssetCard.d.ts +5 -1
- package/dist/types/assets/WrappedAssetCard/WrappedAssetCard.d.ts +2 -1
- package/dist/types/common/EntityStore.d.ts +6 -4
- package/dist/types/common/ReferenceEditor.d.ts +5 -1
- package/dist/types/common/customCardTypes.d.ts +1 -0
- package/dist/types/common/queryClient.d.ts +3 -7
- package/dist/types/entries/WrappedEntryCard/FetchingWrappedEntryCard.d.ts +5 -1
- package/dist/types/entries/WrappedEntryCard/WrappedEntryCard.d.ts +2 -1
- package/dist/types/resources/Cards/ResourceCard.d.ts +1 -0
- package/package.json +5 -5
|
@@ -63,9 +63,10 @@ function ResourceCardSkeleton() {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
function ExistingResourceCard(props) {
|
|
66
|
-
const { resourceLink, inView, index = 0, locale } = props;
|
|
66
|
+
const { resourceLink, inView, index = 0, locale, referencingEntryId } = props;
|
|
67
67
|
const resourceOptions = {
|
|
68
68
|
locale,
|
|
69
|
+
referencingEntryId,
|
|
69
70
|
priority: index * -1,
|
|
70
71
|
enabled: inView,
|
|
71
72
|
allowExternal: true
|
|
@@ -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 _fieldeditorshared = require("@contentful/field-editor-shared");
|
|
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
|
|
221
|
-
const
|
|
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(_fieldeditorshared.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({
|
|
@@ -149,6 +149,7 @@ function MultipleResourceReferenceEditor(props) {
|
|
|
149
149
|
index: index,
|
|
150
150
|
resourceLink: item,
|
|
151
151
|
locale: props.sdk.field.locale,
|
|
152
|
+
referencingEntryId: props.sdk.ids.entry,
|
|
152
153
|
isDisabled: isDisabled,
|
|
153
154
|
renderDragHandle: DragHandle,
|
|
154
155
|
onMoveTop: onMoveTop,
|
|
@@ -118,7 +118,8 @@ describe('Multiple resource editor', ()=>{
|
|
|
118
118
|
const options = dialogFn.mock.calls[0][0];
|
|
119
119
|
expect(options).toEqual({
|
|
120
120
|
allowedResources: fieldDefinition.allowedResources,
|
|
121
|
-
locale: 'en'
|
|
121
|
+
locale: 'en',
|
|
122
|
+
referencingEntryId: 'testEntry'
|
|
122
123
|
});
|
|
123
124
|
});
|
|
124
125
|
it('hides the action button when insufficient permissions', async ()=>{
|
|
@@ -71,6 +71,7 @@ function SingleResourceReferenceEditor(props) {
|
|
|
71
71
|
onRemove: ()=>props.sdk.field.removeValue(),
|
|
72
72
|
resourceLink: value,
|
|
73
73
|
locale: props.sdk.field.locale,
|
|
74
|
+
referencingEntryId: props.sdk.ids.entry,
|
|
74
75
|
isDisabled: disabled,
|
|
75
76
|
getEntryRouteHref: props.getEntryRouteHref
|
|
76
77
|
}) : /*#__PURE__*/ _react.createElement(_LinkEntityActions.CombinedLinkEntityActions, {
|
|
@@ -114,7 +114,8 @@ describe('Single resource editor', ()=>{
|
|
|
114
114
|
const options = dialogFn.mock.calls[0][0];
|
|
115
115
|
expect(options).toEqual({
|
|
116
116
|
allowedResources: fieldDefinition.allowedResources,
|
|
117
|
-
locale: 'en'
|
|
117
|
+
locale: 'en',
|
|
118
|
+
referencingEntryId: 'testEntry'
|
|
118
119
|
});
|
|
119
120
|
});
|
|
120
121
|
it('renders no the action button when permissions insufficient', async ()=>{
|
|
@@ -35,14 +35,18 @@ function useResourceLinkActions({ parameters, sdk }) {
|
|
|
35
35
|
field
|
|
36
36
|
]);
|
|
37
37
|
const multiple = field.type === 'Array';
|
|
38
|
+
const referencingEntryId = sdk.ids.entry;
|
|
39
|
+
const allowedResources = field.allowedResources;
|
|
38
40
|
const onLinkExisting = (0, _react.useMemo)(()=>{
|
|
39
41
|
const promptSelection = multiple ? async ()=>await dialogs.selectMultipleResourceEntities({
|
|
40
|
-
allowedResources
|
|
41
|
-
locale: field.locale
|
|
42
|
+
allowedResources,
|
|
43
|
+
locale: field.locale,
|
|
44
|
+
referencingEntryId
|
|
42
45
|
}) : async ()=>[
|
|
43
46
|
await dialogs.selectSingleResourceEntity({
|
|
44
|
-
allowedResources
|
|
45
|
-
locale: field.locale
|
|
47
|
+
allowedResources,
|
|
48
|
+
locale: field.locale,
|
|
49
|
+
referencingEntryId
|
|
46
50
|
})
|
|
47
51
|
];
|
|
48
52
|
return async ()=>{
|
|
@@ -50,8 +54,9 @@ function useResourceLinkActions({ parameters, sdk }) {
|
|
|
50
54
|
};
|
|
51
55
|
}, [
|
|
52
56
|
dialogs,
|
|
53
|
-
|
|
57
|
+
allowedResources,
|
|
54
58
|
field.locale,
|
|
59
|
+
referencingEntryId,
|
|
55
60
|
multiple,
|
|
56
61
|
onLinkedExisting
|
|
57
62
|
]);
|
|
@@ -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: ()=>{
|
|
@@ -21,6 +21,14 @@ export function FetchingWrappedAssetCard(props) {
|
|
|
21
21
|
locales: props.sdk.locales,
|
|
22
22
|
isReference: true
|
|
23
23
|
});
|
|
24
|
+
const onAddToRelease = ()=>{
|
|
25
|
+
if (asset && props.addReferenceToRelease) {
|
|
26
|
+
void props.addReferenceToRelease(asset, props.sdk.field.locale, {
|
|
27
|
+
openModalForVersionSelection: true,
|
|
28
|
+
skipNestedReferencesPrompt: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
24
32
|
React.useEffect(()=>{
|
|
25
33
|
if (asset) {
|
|
26
34
|
props.onAction && props.onAction({
|
|
@@ -87,7 +95,8 @@ export function FetchingWrappedAssetCard(props) {
|
|
|
87
95
|
activeLocales,
|
|
88
96
|
releaseStatusMap,
|
|
89
97
|
release: props.sdk.release,
|
|
90
|
-
releaseEntityStatus
|
|
98
|
+
releaseEntityStatus,
|
|
99
|
+
onAddToRelease
|
|
91
100
|
};
|
|
92
101
|
if (status === 'loading') {
|
|
93
102
|
return props.viewType === 'link' ? /*#__PURE__*/ React.createElement(EntryCard, {
|
|
@@ -31,7 +31,7 @@ function getFileType(file) {
|
|
|
31
31
|
return groupToIconMap[groupName] || 'archive';
|
|
32
32
|
}
|
|
33
33
|
const THUMBNAIL_SIZE = 150;
|
|
34
|
-
export const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCode, activeLocales, localesStatusMap, isDisabled, isSelected, isClickable, useLocalizedEntityStatus, renderDragHandle, getEntityScheduledActions, onEdit, getAssetUrl, onRemove, releaseEntityStatus, releaseStatusMap, release })=>{
|
|
34
|
+
export const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLocaleCode, activeLocales, localesStatusMap, isDisabled, isSelected, isClickable, useLocalizedEntityStatus, renderDragHandle, getEntityScheduledActions, onEdit, getAssetUrl, onRemove, releaseEntityStatus, releaseStatusMap, release, onAddToRelease })=>{
|
|
35
35
|
const status = entityHelpers.getEntityStatus(asset.sys, useLocalizedEntityStatus ? localeCode : undefined);
|
|
36
36
|
const entityFile = asset.fields.file ? asset.fields.file[localeCode] || asset.fields.file[defaultLocaleCode] : undefined;
|
|
37
37
|
const imageUrl = React.useMemo(()=>{
|
|
@@ -64,6 +64,7 @@ export const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLo
|
|
|
64
64
|
defaultTitle: 'Untitled'
|
|
65
65
|
});
|
|
66
66
|
const href = getAssetUrl ? getAssetUrl(asset.sys.id) : undefined;
|
|
67
|
+
const onAddToReleaseAction = releaseEntityStatus === 'notInRelease' && release !== undefined && onAddToRelease !== undefined && !isDisabled ? onAddToRelease : undefined;
|
|
67
68
|
return /*#__PURE__*/ React.createElement(AssetCard, {
|
|
68
69
|
as: isClickable && href ? 'a' : 'article',
|
|
69
70
|
type: getFileType(entityFile),
|
|
@@ -102,7 +103,8 @@ export const WrappedAssetCard = ({ asset, className, size, localeCode, defaultLo
|
|
|
102
103
|
entityFile,
|
|
103
104
|
isDisabled: isDisabled,
|
|
104
105
|
onEdit,
|
|
105
|
-
onRemove
|
|
106
|
+
onRemove,
|
|
107
|
+
onAddToReleaseAction
|
|
106
108
|
}),
|
|
107
109
|
...entityFile ? renderAssetInfo({
|
|
108
110
|
entityFile
|
|
@@ -12,6 +12,7 @@ function _define_property(obj, key, value) {
|
|
|
12
12
|
return obj;
|
|
13
13
|
}
|
|
14
14
|
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
15
|
+
import { createGetContentTypeKey, createGetEntryKey, createGetSpaceKey } from '@contentful/field-editor-shared';
|
|
15
16
|
import constate from 'constate';
|
|
16
17
|
import { fetchAll } from 'contentful-management';
|
|
17
18
|
import { get } from 'lodash';
|
|
@@ -61,7 +62,7 @@ function handleResourceFetchError(resourceFetchError, resourceTypeEntity) {
|
|
|
61
62
|
throw resourceFetchError;
|
|
62
63
|
}
|
|
63
64
|
const isEntityQueryKey = (queryKey)=>{
|
|
64
|
-
return Array.isArray(queryKey) && (queryKey[0] === 'Entry' || queryKey[0] === 'Asset') && queryKey.length === 4;
|
|
65
|
+
return Array.isArray(queryKey) && (queryKey[0] === 'Entry' || queryKey[0] === 'Asset') && (queryKey.length === 4 || queryKey.length === 5);
|
|
65
66
|
};
|
|
66
67
|
async function fetchContentfulEntry({ urn, fetch, options }) {
|
|
67
68
|
const resourceId = urn.split(':', 6)[5];
|
|
@@ -74,18 +75,10 @@ async function fetchContentfulEntry({ urn, fetch, options }) {
|
|
|
74
75
|
const environmentId = resourceIdMatch?.groups?.environmentId || 'master';
|
|
75
76
|
const entryId = resourceIdMatch.groups.entityId;
|
|
76
77
|
const [space, entry] = await Promise.all([
|
|
77
|
-
fetch(
|
|
78
|
-
'space',
|
|
79
|
-
spaceId
|
|
80
|
-
], ({ cmaClient })=>cmaClient.space.get({
|
|
78
|
+
fetch(createGetSpaceKey(spaceId), ({ cmaClient })=>cmaClient.space.get({
|
|
81
79
|
spaceId
|
|
82
80
|
}), options),
|
|
83
|
-
fetch(
|
|
84
|
-
'entry',
|
|
85
|
-
spaceId,
|
|
86
|
-
environmentId,
|
|
87
|
-
entryId
|
|
88
|
-
], ({ cmaClient })=>cmaClient.entry.get({
|
|
81
|
+
fetch(createGetEntryKey(spaceId, environmentId, entryId), ({ cmaClient })=>cmaClient.entry.get({
|
|
89
82
|
spaceId,
|
|
90
83
|
environmentId,
|
|
91
84
|
entryId
|
|
@@ -93,12 +86,7 @@ async function fetchContentfulEntry({ urn, fetch, options }) {
|
|
|
93
86
|
]);
|
|
94
87
|
const contentTypeId = entry.sys.contentType.sys.id;
|
|
95
88
|
const [contentType, defaultLocaleCode] = await Promise.all([
|
|
96
|
-
fetch(
|
|
97
|
-
'contentType',
|
|
98
|
-
spaceId,
|
|
99
|
-
environmentId,
|
|
100
|
-
contentTypeId
|
|
101
|
-
], ({ cmaClient })=>cmaClient.contentType.get({
|
|
89
|
+
fetch(createGetContentTypeKey(spaceId, environmentId, contentTypeId), ({ cmaClient })=>cmaClient.contentType.get({
|
|
102
90
|
contentTypeId,
|
|
103
91
|
spaceId,
|
|
104
92
|
environmentId
|
|
@@ -126,7 +114,7 @@ async function fetchContentfulEntry({ urn, fetch, options }) {
|
|
|
126
114
|
contentType: contentType
|
|
127
115
|
};
|
|
128
116
|
}
|
|
129
|
-
async function fetchExternalResource({ urn, fetch, options, spaceId, environmentId, resourceType, locale }) {
|
|
117
|
+
async function fetchExternalResource({ urn, fetch, options, spaceId, environmentId, resourceType, locale, referencingEntryId }) {
|
|
130
118
|
let resourceFetchError;
|
|
131
119
|
const [resource, resourceTypes] = await Promise.all([
|
|
132
120
|
fetch([
|
|
@@ -135,14 +123,16 @@ async function fetchExternalResource({ urn, fetch, options, spaceId, environment
|
|
|
135
123
|
environmentId,
|
|
136
124
|
resourceType,
|
|
137
125
|
urn,
|
|
138
|
-
locale
|
|
126
|
+
locale,
|
|
127
|
+
referencingEntryId
|
|
139
128
|
], ({ cmaClient })=>cmaClient.resource.getMany({
|
|
140
129
|
spaceId,
|
|
141
130
|
environmentId,
|
|
142
131
|
resourceTypeId: resourceType,
|
|
143
132
|
query: {
|
|
144
133
|
'sys.urn[in]': urn,
|
|
145
|
-
locale
|
|
134
|
+
locale,
|
|
135
|
+
referencingEntryId
|
|
146
136
|
}
|
|
147
137
|
}).then(({ items })=>{
|
|
148
138
|
return items[0] ?? null;
|
|
@@ -338,7 +328,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
|
|
|
338
328
|
'Resource',
|
|
339
329
|
resourceType,
|
|
340
330
|
urn,
|
|
341
|
-
options?.locale
|
|
331
|
+
options?.locale,
|
|
332
|
+
options?.referencingEntryId
|
|
342
333
|
];
|
|
343
334
|
return fetch(queryKey, ()=>{
|
|
344
335
|
if (resourceType === 'Contentful:Entry') {
|
|
@@ -355,6 +346,7 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
|
|
|
355
346
|
fetch,
|
|
356
347
|
urn,
|
|
357
348
|
locale: options?.locale,
|
|
349
|
+
referencingEntryId: options?.referencingEntryId,
|
|
358
350
|
options,
|
|
359
351
|
resourceType,
|
|
360
352
|
spaceId: currentSpaceId,
|
|
@@ -378,25 +370,53 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
|
|
|
378
370
|
const onSlideInNavigation = props.sdk.navigator.onSlideInNavigation;
|
|
379
371
|
useEffect(()=>{
|
|
380
372
|
function findSameSpaceQueries() {
|
|
381
|
-
|
|
382
|
-
type: 'active',
|
|
373
|
+
const queries = queryCache.findAll({
|
|
383
374
|
predicate: (query)=>isSameSpaceEntityQueryKey(query.queryKey)
|
|
384
375
|
});
|
|
376
|
+
return queries;
|
|
385
377
|
}
|
|
386
378
|
if (typeof onEntityChanged !== 'function') {
|
|
387
|
-
return onSlideInNavigation(({ oldSlideLevel, newSlideLevel })=>{
|
|
379
|
+
return onSlideInNavigation(async ({ oldSlideLevel, newSlideLevel })=>{
|
|
388
380
|
if (oldSlideLevel > newSlideLevel) {
|
|
389
|
-
findSameSpaceQueries()
|
|
390
|
-
|
|
391
|
-
|
|
381
|
+
const queries = findSameSpaceQueries();
|
|
382
|
+
await Promise.all(queries.map(async (query)=>{
|
|
383
|
+
const [entityType, entityId, spaceId, environmentId, releaseId] = query.queryKey;
|
|
384
|
+
try {
|
|
385
|
+
let freshData;
|
|
386
|
+
if (entityType === 'Entry') {
|
|
387
|
+
freshData = await cmaClient.entry.get({
|
|
388
|
+
entryId: entityId,
|
|
389
|
+
spaceId: spaceId,
|
|
390
|
+
environmentId: environmentId,
|
|
391
|
+
releaseId: releaseId
|
|
392
|
+
});
|
|
393
|
+
} else if (entityType === 'Asset') {
|
|
394
|
+
freshData = await cmaClient.asset.get({
|
|
395
|
+
assetId: entityId,
|
|
396
|
+
spaceId: spaceId,
|
|
397
|
+
environmentId: environmentId,
|
|
398
|
+
releaseId: releaseId
|
|
399
|
+
});
|
|
400
|
+
} else {
|
|
401
|
+
await queryClient.invalidateQueries(query.queryKey);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
queryClient.setQueryData(query.queryKey, freshData);
|
|
405
|
+
} catch (error) {
|
|
406
|
+
await queryClient.invalidateQueries(query.queryKey);
|
|
407
|
+
}
|
|
408
|
+
}));
|
|
392
409
|
}
|
|
393
410
|
});
|
|
394
411
|
}
|
|
395
412
|
const subscribeQuery = ({ queryKey, queryHash })=>{
|
|
396
413
|
const [entityType, entityId, , , releaseId] = queryKey;
|
|
397
414
|
entityChangeUnsubscribers.current[queryHash] = onEntityChanged(entityType, entityId, (data)=>{
|
|
398
|
-
|
|
415
|
+
const dataReleaseId = get(data, 'sys.release.id');
|
|
416
|
+
if (dataReleaseId === releaseId) {
|
|
399
417
|
queryClient.setQueryData(queryKey, data);
|
|
418
|
+
} else if (releaseId && !dataReleaseId) {
|
|
419
|
+
void queryClient.invalidateQueries(queryKey);
|
|
400
420
|
}
|
|
401
421
|
});
|
|
402
422
|
};
|
|
@@ -428,7 +448,8 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = cons
|
|
|
428
448
|
isSameSpaceEntityQueryKey,
|
|
429
449
|
queryClient,
|
|
430
450
|
getEntity,
|
|
431
|
-
onSlideInNavigation
|
|
451
|
+
onSlideInNavigation,
|
|
452
|
+
cmaClient
|
|
432
453
|
]);
|
|
433
454
|
const getResourceProvider = useCallback(function getResourceProvider(organizationId, appDefinitionId) {
|
|
434
455
|
const queryKey = [
|
|
@@ -493,20 +514,23 @@ export function useEntity(entityType, entityId, options) {
|
|
|
493
514
|
currentEntity
|
|
494
515
|
};
|
|
495
516
|
}
|
|
496
|
-
export function useResource(resourceType, urn, { locale, ...options } = {}) {
|
|
517
|
+
export function useResource(resourceType, urn, { locale, referencingEntryId, ...options } = {}) {
|
|
497
518
|
if (resourceType.startsWith('Contentful:')) {
|
|
498
519
|
locale = undefined;
|
|
520
|
+
referencingEntryId = undefined;
|
|
499
521
|
}
|
|
500
522
|
const queryKey = [
|
|
501
523
|
'Resource',
|
|
502
524
|
resourceType,
|
|
503
525
|
urn,
|
|
504
|
-
locale
|
|
526
|
+
locale,
|
|
527
|
+
referencingEntryId
|
|
505
528
|
];
|
|
506
529
|
const { getResource } = useEntityLoader();
|
|
507
530
|
const { status, data, error } = useQuery(queryKey, ()=>getResource(resourceType, urn, {
|
|
508
531
|
...options,
|
|
509
|
-
locale
|
|
532
|
+
locale,
|
|
533
|
+
referencingEntryId
|
|
510
534
|
}), {
|
|
511
535
|
enabled: options?.enabled
|
|
512
536
|
});
|
|
@@ -531,6 +555,8 @@ export function useResourceProvider(organizationId, appDefinitionId) {
|
|
|
531
555
|
};
|
|
532
556
|
}
|
|
533
557
|
function EntityProvider({ children, ...props }) {
|
|
534
|
-
return /*#__PURE__*/ React.createElement(SharedQueryClientProvider,
|
|
558
|
+
return /*#__PURE__*/ React.createElement(SharedQueryClientProvider, {
|
|
559
|
+
client: props.queryClient
|
|
560
|
+
}, /*#__PURE__*/ React.createElement(InternalServiceProvider, props, children));
|
|
535
561
|
}
|
|
536
562
|
export { EntityProvider, useEntityLoader };
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
|
+
import { useContentTypes } from '@contentful/field-editor-shared';
|
|
3
4
|
import { arrayMove } from '@dnd-kit/sortable';
|
|
4
5
|
import { LinkEntityActions } from '../components';
|
|
5
6
|
import { useLinkActionsProps } from '../components/LinkActions/LinkEntityActions';
|
|
6
7
|
import { useSortIDs } from '../utils/useSortIDs';
|
|
8
|
+
import { SharedQueryClientProvider } from './queryClient';
|
|
7
9
|
import { ReferenceEditor } from './ReferenceEditor';
|
|
8
10
|
import { useEditorPermissions } from './useEditorPermissions';
|
|
9
11
|
function onLinkOrCreate(setValue, entityType, items, ids, index = items.length) {
|
|
@@ -95,7 +97,10 @@ function Editor(props) {
|
|
|
95
97
|
}));
|
|
96
98
|
}
|
|
97
99
|
export function MultipleReferenceEditor(props) {
|
|
98
|
-
|
|
100
|
+
return /*#__PURE__*/ React.createElement(SharedQueryClientProvider, null, /*#__PURE__*/ React.createElement(MultipleReferenceEditorInner, props));
|
|
101
|
+
}
|
|
102
|
+
function MultipleReferenceEditorInner(props) {
|
|
103
|
+
const { contentTypes: allContentTypes } = useContentTypes(props.sdk);
|
|
99
104
|
return /*#__PURE__*/ React.createElement(ReferenceEditor, props, ({ value, disabled, setValue, externalReset })=>{
|
|
100
105
|
return /*#__PURE__*/ React.createElement(Editor, {
|
|
101
106
|
...props,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
|
+
import { useContentTypes } from '@contentful/field-editor-shared';
|
|
3
4
|
import { LinkEntityActions } from '../components';
|
|
4
5
|
import { useLinkActionsProps } from '../components/LinkActions/LinkEntityActions';
|
|
6
|
+
import { SharedQueryClientProvider } from './queryClient';
|
|
5
7
|
import { ReferenceEditor } from './ReferenceEditor';
|
|
6
8
|
import { useEditorPermissions } from './useEditorPermissions';
|
|
7
9
|
function Editor(props) {
|
|
@@ -48,11 +50,15 @@ function Editor(props) {
|
|
|
48
50
|
}
|
|
49
51
|
return props.children({
|
|
50
52
|
...props,
|
|
51
|
-
renderCustomCard: props.renderCustomCard && customCardRenderer
|
|
53
|
+
renderCustomCard: props.renderCustomCard && customCardRenderer,
|
|
54
|
+
addReferenceToRelease: props.addReferenceToRelease
|
|
52
55
|
});
|
|
53
56
|
}
|
|
54
57
|
export function SingleReferenceEditor(props) {
|
|
55
|
-
|
|
58
|
+
return /*#__PURE__*/ React.createElement(SharedQueryClientProvider, null, /*#__PURE__*/ React.createElement(SingleReferenceEditorInner, props));
|
|
59
|
+
}
|
|
60
|
+
function SingleReferenceEditorInner(props) {
|
|
61
|
+
const { contentTypes: allContentTypes } = useContentTypes(props.sdk);
|
|
56
62
|
return /*#__PURE__*/ React.createElement(ReferenceEditor, props, ({ value, setValue, disabled, externalReset })=>{
|
|
57
63
|
return /*#__PURE__*/ React.createElement(Editor, {
|
|
58
64
|
...props,
|
|
@@ -1,47 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { QueryClient, useQuery as useRQ, useQueryClient as useHostQueryClient } from '@tanstack/react-query';
|
|
3
|
-
const clientContext = /*#__PURE__*/ React.createContext(undefined);
|
|
4
|
-
function useMaybeHostQueryClient() {
|
|
5
|
-
try {
|
|
6
|
-
return useHostQueryClient();
|
|
7
|
-
} catch {
|
|
8
|
-
return undefined;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export function useQueryClient() {
|
|
12
|
-
const client = React.useContext(clientContext);
|
|
13
|
-
const hostClient = useMaybeHostQueryClient();
|
|
14
|
-
return React.useMemo(()=>{
|
|
15
|
-
if (client) {
|
|
16
|
-
return client;
|
|
17
|
-
}
|
|
18
|
-
if (hostClient) return hostClient;
|
|
19
|
-
return new QueryClient({
|
|
20
|
-
defaultOptions: {
|
|
21
|
-
queries: {
|
|
22
|
-
useErrorBoundary: false,
|
|
23
|
-
refetchOnWindowFocus: false,
|
|
24
|
-
refetchOnReconnect: true,
|
|
25
|
-
refetchOnMount: false,
|
|
26
|
-
staleTime: Infinity,
|
|
27
|
-
retry: false
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}, [
|
|
32
|
-
client,
|
|
33
|
-
hostClient
|
|
34
|
-
]);
|
|
35
|
-
}
|
|
36
|
-
export const useQuery = (key, fn, opt)=>{
|
|
37
|
-
return useRQ(key, fn, {
|
|
38
|
-
...opt,
|
|
39
|
-
context: clientContext
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
export function SharedQueryClientProvider({ children }) {
|
|
43
|
-
const client = useQueryClient();
|
|
44
|
-
return /*#__PURE__*/ React.createElement(clientContext.Provider, {
|
|
45
|
-
value: client
|
|
46
|
-
}, children);
|
|
47
|
-
}
|
|
1
|
+
export { SharedQueryClientProvider, useQueryClient, useQuery } from '@contentful/field-editor-shared';
|
|
@@ -11,6 +11,9 @@ export function useContentTypePermissions({ entityType, validations, sdk, allCon
|
|
|
11
11
|
if (entityType === 'Asset') {
|
|
12
12
|
return [];
|
|
13
13
|
}
|
|
14
|
+
if (validations.contentTypes && allContentTypes.length === 0) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
14
17
|
if (validations.contentTypes) {
|
|
15
18
|
return allContentTypes.filter((ct)=>validations.contentTypes?.includes(ct.sys.id));
|
|
16
19
|
}
|
|
@@ -23,21 +26,15 @@ export function useContentTypePermissions({ entityType, validations, sdk, allCon
|
|
|
23
26
|
const [creatableContentTypes, setCreatableContentTypes] = useState(availableContentTypes);
|
|
24
27
|
const { canPerformActionOnEntryOfType } = useAccessApi(sdk.access);
|
|
25
28
|
useEffect(()=>{
|
|
26
|
-
function getContentTypes(action) {
|
|
27
|
-
return filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType(action, ct.sys.id));
|
|
28
|
-
}
|
|
29
29
|
async function checkContentTypeAccess() {
|
|
30
|
-
const creatable = await
|
|
31
|
-
|
|
32
|
-
setCreatableContentTypes(creatable);
|
|
33
|
-
}
|
|
30
|
+
const creatable = await filter(availableContentTypes, (ct)=>canPerformActionOnEntryOfType('create', ct.sys.id));
|
|
31
|
+
setCreatableContentTypes((creatableContentTypes)=>isEqual(creatable, creatableContentTypes) ? creatableContentTypes : creatable);
|
|
34
32
|
}
|
|
35
33
|
if (availableContentTypes.length > 0) {
|
|
36
34
|
void checkContentTypeAccess();
|
|
37
35
|
}
|
|
38
36
|
}, [
|
|
39
|
-
availableContentTypes
|
|
40
|
-
creatableContentTypes
|
|
37
|
+
availableContentTypes
|
|
41
38
|
]);
|
|
42
39
|
return {
|
|
43
40
|
creatableContentTypes,
|
|
@@ -3,8 +3,12 @@ import { fromFieldValidations } from '../utils/fromFieldValidations';
|
|
|
3
3
|
import { useAccessApi } from './useAccessApi';
|
|
4
4
|
import { useContentTypePermissions } from './useContentTypePermissions';
|
|
5
5
|
export function useEditorPermissions({ sdk, entityType, parameters, allContentTypes }) {
|
|
6
|
+
const fieldValidations = sdk.field.validations;
|
|
7
|
+
const itemsValidations = sdk.field.type === 'Array' ? sdk.field.items?.validations : undefined;
|
|
6
8
|
const validations = useMemo(()=>fromFieldValidations(sdk.field), [
|
|
7
|
-
sdk.field
|
|
9
|
+
sdk.field,
|
|
10
|
+
JSON.stringify(fieldValidations),
|
|
11
|
+
JSON.stringify(itemsValidations)
|
|
8
12
|
]);
|
|
9
13
|
const [canCreateEntity, setCanCreateEntity] = useState(true);
|
|
10
14
|
const [canLinkEntity, setCanLinkEntity] = useState(true);
|
|
@@ -69,6 +69,7 @@ export function useLinkActionsProps(props) {
|
|
|
69
69
|
}, [
|
|
70
70
|
sdk,
|
|
71
71
|
entityType,
|
|
72
|
+
editorPermissions,
|
|
72
73
|
onLinkedExisting
|
|
73
74
|
]);
|
|
74
75
|
const onLinkSeveralExisting = React.useCallback(async (index)=>{
|
|
@@ -84,6 +85,7 @@ export function useLinkActionsProps(props) {
|
|
|
84
85
|
}, [
|
|
85
86
|
sdk,
|
|
86
87
|
entityType,
|
|
88
|
+
editorPermissions,
|
|
87
89
|
onLinkedExisting
|
|
88
90
|
]);
|
|
89
91
|
return useMemo(()=>({
|
|
@@ -34,7 +34,8 @@ export function MultipleEntryReferenceEditor(props) {
|
|
|
34
34
|
onMoveTop: index !== 0 ? ()=>childrenProps.onMove(index, 0) : undefined,
|
|
35
35
|
onMoveBottom: index !== lastIndex ? ()=>childrenProps.onMove(index, lastIndex) : undefined,
|
|
36
36
|
renderDragHandle: DragHandle,
|
|
37
|
-
isBeingDragged: index === indexToUpdate
|
|
37
|
+
isBeingDragged: index === indexToUpdate,
|
|
38
|
+
addReferenceToRelease: props.addReferenceToRelease
|
|
38
39
|
});
|
|
39
40
|
}));
|
|
40
41
|
}
|