@contentful/field-editor-reference 5.13.3 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/common/EntityStore.js +13 -26
- package/dist/cjs/common/queryClient.js +97 -0
- package/dist/cjs/components/SpaceName/SpaceName.js +6 -4
- package/dist/cjs/entries/WrappedEntryCard/WrappedEntryCard.js +2 -1
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/resources/Cards/ResourceCard.spec.js +40 -3
- package/dist/esm/common/EntityStore.js +10 -23
- package/dist/esm/common/queryClient.js +37 -0
- package/dist/esm/components/SpaceName/SpaceName.js +6 -4
- package/dist/esm/entries/WrappedEntryCard/WrappedEntryCard.js +2 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/resources/Cards/ResourceCard.spec.js +41 -4
- package/dist/types/common/EntityStore.d.ts +1 -1
- package/dist/types/common/queryClient.d.ts +9 -0
- package/dist/types/components/SpaceName/SpaceName.d.ts +3 -2
- package/dist/types/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -29,10 +29,10 @@ _export(exports, {
|
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
const _react = _interop_require_wildcard(require("react"));
|
|
32
|
-
const _reactquery = require("@tanstack/react-query");
|
|
33
32
|
const _constate = _interop_require_default(require("constate"));
|
|
34
33
|
const _contentfulmanagement = require("contentful-management");
|
|
35
34
|
const _pqueue = _interop_require_default(require("p-queue"));
|
|
35
|
+
const _queryClient = require("./queryClient");
|
|
36
36
|
function _define_property(obj, key, value) {
|
|
37
37
|
if (key in obj) {
|
|
38
38
|
Object.defineProperty(obj, key, {
|
|
@@ -109,8 +109,14 @@ const isEntityQueryKey = (queryKey)=>{
|
|
|
109
109
|
async function fetchContentfulEntry(params) {
|
|
110
110
|
const { urn , fetch , options } = params;
|
|
111
111
|
const resourceId = urn.split(':', 6)[5];
|
|
112
|
-
const
|
|
113
|
-
const
|
|
112
|
+
const ENTITY_RESOURCE_ID_REGEX = RegExp("^spaces\\/(?<spaceId>[^/]+)(?:\\/environments\\/(?<environmentId>[^/]+))?\\/entries\\/(?<entityId>[^/]+)$");
|
|
113
|
+
const resourceIdMatch = resourceId.match(ENTITY_RESOURCE_ID_REGEX);
|
|
114
|
+
if (!resourceIdMatch || !resourceIdMatch?.groups?.spaceId || !resourceIdMatch?.groups?.entityId) {
|
|
115
|
+
throw new Error('Not a valid crn');
|
|
116
|
+
}
|
|
117
|
+
const spaceId = resourceIdMatch.groups.spaceId;
|
|
118
|
+
const environmentId = resourceIdMatch?.groups?.environmentId || 'master';
|
|
119
|
+
const entryId = resourceIdMatch.groups.entityId;
|
|
114
120
|
const [space, entry] = await Promise.all([
|
|
115
121
|
fetch([
|
|
116
122
|
'space',
|
|
@@ -174,7 +180,7 @@ const [InternalServiceProvider, useFetch, useEntityLoader, useCurrentIds] = (0,
|
|
|
174
180
|
props.sdk.ids.environmentAlias,
|
|
175
181
|
props.sdk.ids.environment
|
|
176
182
|
]);
|
|
177
|
-
const queryClient = (0,
|
|
183
|
+
const queryClient = (0, _queryClient.useQueryClient)();
|
|
178
184
|
const queryCache = queryClient.getQueryCache();
|
|
179
185
|
const entityChangeUnsubscribers = (0, _react.useRef)({});
|
|
180
186
|
const cmaClient = (0, _react.useMemo)(()=>(0, _contentfulmanagement.createClient)({
|
|
@@ -372,7 +378,7 @@ function useEntity(entityType, entityId, options) {
|
|
|
372
378
|
options?.spaceId ?? space,
|
|
373
379
|
options?.environmentId ?? environment
|
|
374
380
|
];
|
|
375
|
-
const { status , data } = (0,
|
|
381
|
+
const { status , data } = (0, _queryClient.useQuery)(queryKey, ()=>getEntity(entityType, entityId, options), {
|
|
376
382
|
enabled: options?.enabled
|
|
377
383
|
});
|
|
378
384
|
return {
|
|
@@ -387,7 +393,7 @@ function useResource(resourceType, urn, options) {
|
|
|
387
393
|
urn
|
|
388
394
|
];
|
|
389
395
|
const { getResource } = useEntityLoader();
|
|
390
|
-
const { status , data , error } = (0,
|
|
396
|
+
const { status , data , error } = (0, _queryClient.useQuery)(queryKey, ()=>getResource(resourceType, urn, options), {
|
|
391
397
|
enabled: options?.enabled
|
|
392
398
|
});
|
|
393
399
|
return {
|
|
@@ -397,24 +403,5 @@ function useResource(resourceType, urn, options) {
|
|
|
397
403
|
};
|
|
398
404
|
}
|
|
399
405
|
function EntityProvider({ children , ...props }) {
|
|
400
|
-
|
|
401
|
-
const queryCache = new _reactquery.QueryCache();
|
|
402
|
-
const queryClient = new _reactquery.QueryClient({
|
|
403
|
-
queryCache,
|
|
404
|
-
defaultOptions: {
|
|
405
|
-
queries: {
|
|
406
|
-
useErrorBoundary: false,
|
|
407
|
-
refetchOnWindowFocus: false,
|
|
408
|
-
refetchOnReconnect: true,
|
|
409
|
-
refetchOnMount: false,
|
|
410
|
-
staleTime: Infinity,
|
|
411
|
-
retry: false
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
return queryClient;
|
|
416
|
-
}, []);
|
|
417
|
-
return _react.default.createElement(_reactquery.QueryClientProvider, {
|
|
418
|
-
client: reactQueryClient
|
|
419
|
-
}, _react.default.createElement(InternalServiceProvider, props, children));
|
|
406
|
+
return _react.default.createElement(_queryClient.SharedQueryClientProvider, null, _react.default.createElement(InternalServiceProvider, props, children));
|
|
420
407
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
useQueryClient: function() {
|
|
13
|
+
return useQueryClient;
|
|
14
|
+
},
|
|
15
|
+
useQuery: function() {
|
|
16
|
+
return useQuery;
|
|
17
|
+
},
|
|
18
|
+
SharedQueryClientProvider: function() {
|
|
19
|
+
return SharedQueryClientProvider;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const _react = _interop_require_wildcard(require("react"));
|
|
23
|
+
const _reactquery = require("@tanstack/react-query");
|
|
24
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
25
|
+
if (typeof WeakMap !== "function") return null;
|
|
26
|
+
var cacheBabelInterop = new WeakMap();
|
|
27
|
+
var cacheNodeInterop = new WeakMap();
|
|
28
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
29
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
30
|
+
})(nodeInterop);
|
|
31
|
+
}
|
|
32
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
33
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
34
|
+
return obj;
|
|
35
|
+
}
|
|
36
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
37
|
+
return {
|
|
38
|
+
default: obj
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
42
|
+
if (cache && cache.has(obj)) {
|
|
43
|
+
return cache.get(obj);
|
|
44
|
+
}
|
|
45
|
+
var newObj = {};
|
|
46
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
47
|
+
for(var key in obj){
|
|
48
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
49
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
50
|
+
if (desc && (desc.get || desc.set)) {
|
|
51
|
+
Object.defineProperty(newObj, key, desc);
|
|
52
|
+
} else {
|
|
53
|
+
newObj[key] = obj[key];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
newObj.default = obj;
|
|
58
|
+
if (cache) {
|
|
59
|
+
cache.set(obj, newObj);
|
|
60
|
+
}
|
|
61
|
+
return newObj;
|
|
62
|
+
}
|
|
63
|
+
const clientContext = _react.createContext(undefined);
|
|
64
|
+
function useQueryClient() {
|
|
65
|
+
const client = _react.useContext(clientContext);
|
|
66
|
+
return _react.useMemo(()=>{
|
|
67
|
+
if (client) {
|
|
68
|
+
return client;
|
|
69
|
+
}
|
|
70
|
+
return new _reactquery.QueryClient({
|
|
71
|
+
defaultOptions: {
|
|
72
|
+
queries: {
|
|
73
|
+
useErrorBoundary: false,
|
|
74
|
+
refetchOnWindowFocus: false,
|
|
75
|
+
refetchOnReconnect: true,
|
|
76
|
+
refetchOnMount: false,
|
|
77
|
+
staleTime: Infinity,
|
|
78
|
+
retry: false
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}, [
|
|
83
|
+
client
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
const useQuery = (key, fn, opt)=>{
|
|
87
|
+
return (0, _reactquery.useQuery)(key, fn, {
|
|
88
|
+
...opt,
|
|
89
|
+
context: clientContext
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
function SharedQueryClientProvider({ children }) {
|
|
93
|
+
const client = useQueryClient();
|
|
94
|
+
return _react.createElement(clientContext.Provider, {
|
|
95
|
+
value: client
|
|
96
|
+
}, children);
|
|
97
|
+
}
|
|
@@ -60,12 +60,12 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
60
60
|
const styles = {
|
|
61
61
|
spaceIcon: (0, _emotion.css)({
|
|
62
62
|
flexShrink: 0,
|
|
63
|
-
fill: _f36tokens.default.
|
|
63
|
+
fill: _f36tokens.default.gray600
|
|
64
64
|
}),
|
|
65
65
|
spaceName: (0, _emotion.css)({
|
|
66
|
-
color: _f36tokens.default.
|
|
66
|
+
color: _f36tokens.default.gray600,
|
|
67
67
|
fontSize: _f36tokens.default.fontSizeS,
|
|
68
|
-
fontWeight: _f36tokens.default.
|
|
68
|
+
fontWeight: _f36tokens.default.fontWeightMedium,
|
|
69
69
|
maxWidth: '80px',
|
|
70
70
|
textOverflow: 'ellipsis',
|
|
71
71
|
overflow: 'hidden',
|
|
@@ -73,10 +73,12 @@ const styles = {
|
|
|
73
73
|
})
|
|
74
74
|
};
|
|
75
75
|
function SpaceName(props) {
|
|
76
|
+
let content = `Space: ${props.spaceName}`;
|
|
77
|
+
if (props.environmentName) content += ` (Env.: ${props.environmentName})`;
|
|
76
78
|
return _react.createElement(_f36components.Tooltip, {
|
|
77
79
|
placement: "top",
|
|
78
80
|
as: "div",
|
|
79
|
-
content:
|
|
81
|
+
content: content
|
|
80
82
|
}, _react.createElement(_f36components.Flex, {
|
|
81
83
|
alignItems: "center",
|
|
82
84
|
gap: "spacingXs",
|
|
@@ -126,7 +126,8 @@ function WrappedEntryCard(props) {
|
|
|
126
126
|
isSelected: props.isSelected,
|
|
127
127
|
status: status,
|
|
128
128
|
icon: props.spaceName ? _react.createElement(_SpaceName.SpaceName, {
|
|
129
|
-
spaceName: props.spaceName
|
|
129
|
+
spaceName: props.spaceName,
|
|
130
|
+
environmentName: props.entry.sys.environment.sys.id
|
|
130
131
|
}) : _react.createElement(_components.ScheduledIconWithTooltip, {
|
|
131
132
|
getEntityScheduledActions: props.getEntityScheduledActions,
|
|
132
133
|
entityType: "Entry",
|
package/dist/cjs/index.js
CHANGED
|
@@ -66,6 +66,9 @@ _export(exports, {
|
|
|
66
66
|
useResource: function() {
|
|
67
67
|
return _EntityStore.useResource;
|
|
68
68
|
},
|
|
69
|
+
EntityCacheProvider: function() {
|
|
70
|
+
return _queryClient.SharedQueryClientProvider;
|
|
71
|
+
},
|
|
69
72
|
SingleResourceReferenceEditor: function() {
|
|
70
73
|
return _resources.SingleResourceReferenceEditor;
|
|
71
74
|
},
|
|
@@ -78,6 +81,7 @@ const _entries = require("./entries");
|
|
|
78
81
|
const _assets = require("./assets");
|
|
79
82
|
const _SortableLinkList = require("./common/SortableLinkList");
|
|
80
83
|
const _EntityStore = require("./common/EntityStore");
|
|
84
|
+
const _queryClient = require("./common/queryClient");
|
|
81
85
|
const _resources = require("./resources");
|
|
82
86
|
_export_star(require("./types"), exports);
|
|
83
87
|
function _export_star(from, to) {
|
|
@@ -7,6 +7,7 @@ require("@testing-library/jest-dom");
|
|
|
7
7
|
const _fieldeditortestutils = require("@contentful/field-editor-test-utils");
|
|
8
8
|
const _react1 = require("@testing-library/react");
|
|
9
9
|
const _published_content_typejson = _interop_require_default(require("../../__fixtures__/content-type/published_content_type.json"));
|
|
10
|
+
const _published_entry_non_masterjson = _interop_require_default(require("../../__fixtures__/entry/published_entry_non_master.json"));
|
|
10
11
|
const _published_entryjson = _interop_require_default(require("../../__fixtures__/entry/published_entry.json"));
|
|
11
12
|
const _indifferent_spacejson = _interop_require_default(require("../../__fixtures__/space/indifferent_space.json"));
|
|
12
13
|
const _EntityStore = require("../../common/EntityStore");
|
|
@@ -62,6 +63,8 @@ jest.mock('react-intersection-observer', ()=>({
|
|
|
62
63
|
useInView: jest.fn().mockReturnValue({})
|
|
63
64
|
}));
|
|
64
65
|
const resolvableEntryUrn = 'crn:contentful:::content:spaces/space-id/entries/linked-entry-urn';
|
|
66
|
+
const resolvableEntryUrnWithExplicitMaster = 'crn:contentful:::content:spaces/space-id/environments/master/entries/linked-entry-urn';
|
|
67
|
+
const resolvableEntryUrnWithAnotherEnvironment = 'crn:contentful:::content:spaces/space-id/environments/my-test-environment/entries/linked-entry-urn';
|
|
65
68
|
const unknownEntryUrn = 'crn:contentful:::content:spaces/space-id/entries/unknown-entry-urn';
|
|
66
69
|
const sdk = {
|
|
67
70
|
locales: {
|
|
@@ -72,10 +75,13 @@ const sdk = {
|
|
|
72
75
|
get: jest.fn().mockReturnValue(_published_content_typejson.default)
|
|
73
76
|
},
|
|
74
77
|
Entry: {
|
|
75
|
-
get: jest.fn().mockImplementation(({ entryId })=>{
|
|
76
|
-
if (entryId === 'linked-entry-urn') {
|
|
78
|
+
get: jest.fn().mockImplementation(({ spaceId , environmentId , entryId })=>{
|
|
79
|
+
if (spaceId === 'space-id' && environmentId === 'master' && entryId === 'linked-entry-urn') {
|
|
77
80
|
return Promise.resolve(_published_entryjson.default);
|
|
78
81
|
}
|
|
82
|
+
if (spaceId === 'space-id' && environmentId === 'my-test-environment' && entryId === 'linked-entry-urn') {
|
|
83
|
+
return Promise.resolve(_published_entry_non_masterjson.default);
|
|
84
|
+
}
|
|
79
85
|
return Promise.reject(new Error());
|
|
80
86
|
})
|
|
81
87
|
},
|
|
@@ -124,11 +130,36 @@ function renderResourceCard({ linkType ='Contentful:Entry' , entryUrn =resolvabl
|
|
|
124
130
|
})));
|
|
125
131
|
}
|
|
126
132
|
describe('ResourceCard', ()=>{
|
|
127
|
-
it('renders entry card', async ()=>{
|
|
133
|
+
it('renders entry card with implicit master crn', async ()=>{
|
|
128
134
|
const { getByTestId , getByText } = renderResourceCard();
|
|
135
|
+
const tooltipContent = `Space: ${_indifferent_spacejson.default.name} (Env.: ${_published_entryjson.default.sys.environment.sys.id})`;
|
|
129
136
|
await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
130
137
|
expect(getByText(_published_entryjson.default.fields.exField['en-US'])).toBeDefined();
|
|
131
138
|
expect(getByText(_indifferent_spacejson.default.name)).toBeDefined();
|
|
139
|
+
_react1.fireEvent.mouseEnter(getByText(_indifferent_spacejson.default.name));
|
|
140
|
+
await (0, _react1.waitFor)(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
141
|
+
});
|
|
142
|
+
it('renders entry card with explicit master crn', async ()=>{
|
|
143
|
+
const { getByTestId , getByText } = renderResourceCard({
|
|
144
|
+
entryUrn: resolvableEntryUrnWithExplicitMaster
|
|
145
|
+
});
|
|
146
|
+
const tooltipContent = `Space: ${_indifferent_spacejson.default.name} (Env.: ${_published_entryjson.default.sys.environment.sys.id})`;
|
|
147
|
+
await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
148
|
+
expect(getByText(_published_entryjson.default.fields.exField['en-US'])).toBeDefined();
|
|
149
|
+
expect(getByText(_indifferent_spacejson.default.name)).toBeDefined();
|
|
150
|
+
_react1.fireEvent.mouseEnter(getByText(_indifferent_spacejson.default.name));
|
|
151
|
+
await (0, _react1.waitFor)(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
152
|
+
});
|
|
153
|
+
it('renders entry card with a non master environment', async ()=>{
|
|
154
|
+
const { getByTestId , getByText } = renderResourceCard({
|
|
155
|
+
entryUrn: resolvableEntryUrnWithAnotherEnvironment
|
|
156
|
+
});
|
|
157
|
+
await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
158
|
+
const tooltipContent = `Space: ${_indifferent_spacejson.default.name} (Env.: ${_published_entry_non_masterjson.default.sys.environment.sys.id})`;
|
|
159
|
+
expect(getByText(_published_entry_non_masterjson.default.fields.exField['en-US'])).toBeDefined();
|
|
160
|
+
expect(getByText(_indifferent_spacejson.default.name)).toBeDefined();
|
|
161
|
+
_react1.fireEvent.mouseEnter(getByText(_indifferent_spacejson.default.name));
|
|
162
|
+
await (0, _react1.waitFor)(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
132
163
|
});
|
|
133
164
|
it('renders skeleton when no data is provided', ()=>{
|
|
134
165
|
const { getByTestId } = renderResourceCard();
|
|
@@ -146,4 +177,10 @@ describe('ResourceCard', ()=>{
|
|
|
146
177
|
});
|
|
147
178
|
await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-missing-entry-card')).toBeDefined());
|
|
148
179
|
});
|
|
180
|
+
it('renders missing entity card when crn is invalid', async ()=>{
|
|
181
|
+
const { getByTestId } = renderResourceCard({
|
|
182
|
+
entryUrn: ''
|
|
183
|
+
});
|
|
184
|
+
await (0, _react1.waitFor)(()=>expect(getByTestId('cf-ui-missing-entry-card')).toBeDefined());
|
|
185
|
+
});
|
|
149
186
|
});
|
|
@@ -12,10 +12,10 @@ 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
19
|
const globalQueue = new PQueue({
|
|
20
20
|
concurrency: 50
|
|
21
21
|
});
|
|
@@ -35,8 +35,14 @@ const isEntityQueryKey = (queryKey)=>{
|
|
|
35
35
|
async function fetchContentfulEntry(params) {
|
|
36
36
|
const { urn , fetch , options } = params;
|
|
37
37
|
const resourceId = urn.split(':', 6)[5];
|
|
38
|
-
const
|
|
39
|
-
const
|
|
38
|
+
const ENTITY_RESOURCE_ID_REGEX = RegExp("^spaces\\/(?<spaceId>[^/]+)(?:\\/environments\\/(?<environmentId>[^/]+))?\\/entries\\/(?<entityId>[^/]+)$");
|
|
39
|
+
const resourceIdMatch = resourceId.match(ENTITY_RESOURCE_ID_REGEX);
|
|
40
|
+
if (!resourceIdMatch || !resourceIdMatch?.groups?.spaceId || !resourceIdMatch?.groups?.entityId) {
|
|
41
|
+
throw new Error('Not a valid crn');
|
|
42
|
+
}
|
|
43
|
+
const spaceId = resourceIdMatch.groups.spaceId;
|
|
44
|
+
const environmentId = resourceIdMatch?.groups?.environmentId || 'master';
|
|
45
|
+
const entryId = resourceIdMatch.groups.entityId;
|
|
40
46
|
const [space, entry] = await Promise.all([
|
|
41
47
|
fetch([
|
|
42
48
|
'space',
|
|
@@ -323,25 +329,6 @@ export function useResource(resourceType, urn, options) {
|
|
|
323
329
|
};
|
|
324
330
|
}
|
|
325
331
|
function EntityProvider({ children , ...props }) {
|
|
326
|
-
|
|
327
|
-
const queryCache = new QueryCache();
|
|
328
|
-
const queryClient = new QueryClient({
|
|
329
|
-
queryCache,
|
|
330
|
-
defaultOptions: {
|
|
331
|
-
queries: {
|
|
332
|
-
useErrorBoundary: false,
|
|
333
|
-
refetchOnWindowFocus: false,
|
|
334
|
-
refetchOnReconnect: true,
|
|
335
|
-
refetchOnMount: false,
|
|
336
|
-
staleTime: Infinity,
|
|
337
|
-
retry: false
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
return queryClient;
|
|
342
|
-
}, []);
|
|
343
|
-
return React.createElement(QueryClientProvider, {
|
|
344
|
-
client: reactQueryClient
|
|
345
|
-
}, React.createElement(InternalServiceProvider, props, children));
|
|
332
|
+
return React.createElement(SharedQueryClientProvider, null, React.createElement(InternalServiceProvider, props, children));
|
|
346
333
|
}
|
|
347
334
|
export { EntityProvider, useEntityLoader };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { QueryClient, useQuery as useRQ } from '@tanstack/react-query';
|
|
3
|
+
const clientContext = React.createContext(undefined);
|
|
4
|
+
export function useQueryClient() {
|
|
5
|
+
const client = React.useContext(clientContext);
|
|
6
|
+
return React.useMemo(()=>{
|
|
7
|
+
if (client) {
|
|
8
|
+
return client;
|
|
9
|
+
}
|
|
10
|
+
return new QueryClient({
|
|
11
|
+
defaultOptions: {
|
|
12
|
+
queries: {
|
|
13
|
+
useErrorBoundary: false,
|
|
14
|
+
refetchOnWindowFocus: false,
|
|
15
|
+
refetchOnReconnect: true,
|
|
16
|
+
refetchOnMount: false,
|
|
17
|
+
staleTime: Infinity,
|
|
18
|
+
retry: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}, [
|
|
23
|
+
client
|
|
24
|
+
]);
|
|
25
|
+
}
|
|
26
|
+
export const useQuery = (key, fn, opt)=>{
|
|
27
|
+
return useRQ(key, fn, {
|
|
28
|
+
...opt,
|
|
29
|
+
context: clientContext
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
export function SharedQueryClientProvider({ children }) {
|
|
33
|
+
const client = useQueryClient();
|
|
34
|
+
return React.createElement(clientContext.Provider, {
|
|
35
|
+
value: client
|
|
36
|
+
}, children);
|
|
37
|
+
}
|
|
@@ -6,12 +6,12 @@ import { css } from 'emotion';
|
|
|
6
6
|
const styles = {
|
|
7
7
|
spaceIcon: css({
|
|
8
8
|
flexShrink: 0,
|
|
9
|
-
fill: tokens.
|
|
9
|
+
fill: tokens.gray600
|
|
10
10
|
}),
|
|
11
11
|
spaceName: css({
|
|
12
|
-
color: tokens.
|
|
12
|
+
color: tokens.gray600,
|
|
13
13
|
fontSize: tokens.fontSizeS,
|
|
14
|
-
fontWeight: tokens.
|
|
14
|
+
fontWeight: tokens.fontWeightMedium,
|
|
15
15
|
maxWidth: '80px',
|
|
16
16
|
textOverflow: 'ellipsis',
|
|
17
17
|
overflow: 'hidden',
|
|
@@ -19,10 +19,12 @@ const styles = {
|
|
|
19
19
|
})
|
|
20
20
|
};
|
|
21
21
|
export function SpaceName(props) {
|
|
22
|
+
let content = `Space: ${props.spaceName}`;
|
|
23
|
+
if (props.environmentName) content += ` (Env.: ${props.environmentName})`;
|
|
22
24
|
return React.createElement(Tooltip, {
|
|
23
25
|
placement: "top",
|
|
24
26
|
as: "div",
|
|
25
|
-
content:
|
|
27
|
+
content: content
|
|
26
28
|
}, React.createElement(Flex, {
|
|
27
29
|
alignItems: "center",
|
|
28
30
|
gap: "spacingXs",
|
|
@@ -72,7 +72,8 @@ export function WrappedEntryCard(props) {
|
|
|
72
72
|
isSelected: props.isSelected,
|
|
73
73
|
status: status,
|
|
74
74
|
icon: props.spaceName ? React.createElement(SpaceName, {
|
|
75
|
-
spaceName: props.spaceName
|
|
75
|
+
spaceName: props.spaceName,
|
|
76
|
+
environmentName: props.entry.sys.environment.sys.id
|
|
76
77
|
}) : React.createElement(ScheduledIconWithTooltip, {
|
|
77
78
|
getEntityScheduledActions: props.getEntityScheduledActions,
|
|
78
79
|
entityType: "Entry",
|
package/dist/esm/index.js
CHANGED
|
@@ -3,5 +3,6 @@ export { SingleEntryReferenceEditor, MultipleEntryReferenceEditor, WrappedEntryC
|
|
|
3
3
|
export { SingleMediaEditor, MultipleMediaEditor, WrappedAssetCard } from './assets';
|
|
4
4
|
export { SortableLinkList } from './common/SortableLinkList';
|
|
5
5
|
export { EntityProvider, useEntityLoader, useEntity, useResource } from './common/EntityStore';
|
|
6
|
+
export { SharedQueryClientProvider as EntityCacheProvider } from './common/queryClient';
|
|
6
7
|
export { SingleResourceReferenceEditor, MultipleResourceReferenceEditor } from './resources';
|
|
7
8
|
export * from './types';
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import '@testing-library/jest-dom';
|
|
3
3
|
import { createFakeCMAAdapter } from '@contentful/field-editor-test-utils';
|
|
4
|
-
import { configure, render, waitFor } from '@testing-library/react';
|
|
4
|
+
import { configure, fireEvent, render, waitFor } from '@testing-library/react';
|
|
5
5
|
import publishedCT from '../../__fixtures__/content-type/published_content_type.json';
|
|
6
|
+
import publishedEntryNonMasterEnvironment from '../../__fixtures__/entry/published_entry_non_master.json';
|
|
6
7
|
import publishedEntry from '../../__fixtures__/entry/published_entry.json';
|
|
7
8
|
import space from '../../__fixtures__/space/indifferent_space.json';
|
|
8
9
|
import { EntityProvider } from '../../common/EntityStore';
|
|
@@ -14,6 +15,8 @@ jest.mock('react-intersection-observer', ()=>({
|
|
|
14
15
|
useInView: jest.fn().mockReturnValue({})
|
|
15
16
|
}));
|
|
16
17
|
const resolvableEntryUrn = 'crn:contentful:::content:spaces/space-id/entries/linked-entry-urn';
|
|
18
|
+
const resolvableEntryUrnWithExplicitMaster = 'crn:contentful:::content:spaces/space-id/environments/master/entries/linked-entry-urn';
|
|
19
|
+
const resolvableEntryUrnWithAnotherEnvironment = 'crn:contentful:::content:spaces/space-id/environments/my-test-environment/entries/linked-entry-urn';
|
|
17
20
|
const unknownEntryUrn = 'crn:contentful:::content:spaces/space-id/entries/unknown-entry-urn';
|
|
18
21
|
const sdk = {
|
|
19
22
|
locales: {
|
|
@@ -24,10 +27,13 @@ const sdk = {
|
|
|
24
27
|
get: jest.fn().mockReturnValue(publishedCT)
|
|
25
28
|
},
|
|
26
29
|
Entry: {
|
|
27
|
-
get: jest.fn().mockImplementation(({ entryId })=>{
|
|
28
|
-
if (entryId === 'linked-entry-urn') {
|
|
30
|
+
get: jest.fn().mockImplementation(({ spaceId , environmentId , entryId })=>{
|
|
31
|
+
if (spaceId === 'space-id' && environmentId === 'master' && entryId === 'linked-entry-urn') {
|
|
29
32
|
return Promise.resolve(publishedEntry);
|
|
30
33
|
}
|
|
34
|
+
if (spaceId === 'space-id' && environmentId === 'my-test-environment' && entryId === 'linked-entry-urn') {
|
|
35
|
+
return Promise.resolve(publishedEntryNonMasterEnvironment);
|
|
36
|
+
}
|
|
31
37
|
return Promise.reject(new Error());
|
|
32
38
|
})
|
|
33
39
|
},
|
|
@@ -76,11 +82,36 @@ function renderResourceCard({ linkType ='Contentful:Entry' , entryUrn =resolvabl
|
|
|
76
82
|
})));
|
|
77
83
|
}
|
|
78
84
|
describe('ResourceCard', ()=>{
|
|
79
|
-
it('renders entry card', async ()=>{
|
|
85
|
+
it('renders entry card with implicit master crn', async ()=>{
|
|
80
86
|
const { getByTestId , getByText } = renderResourceCard();
|
|
87
|
+
const tooltipContent = `Space: ${space.name} (Env.: ${publishedEntry.sys.environment.sys.id})`;
|
|
81
88
|
await waitFor(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
82
89
|
expect(getByText(publishedEntry.fields.exField['en-US'])).toBeDefined();
|
|
83
90
|
expect(getByText(space.name)).toBeDefined();
|
|
91
|
+
fireEvent.mouseEnter(getByText(space.name));
|
|
92
|
+
await waitFor(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
93
|
+
});
|
|
94
|
+
it('renders entry card with explicit master crn', async ()=>{
|
|
95
|
+
const { getByTestId , getByText } = renderResourceCard({
|
|
96
|
+
entryUrn: resolvableEntryUrnWithExplicitMaster
|
|
97
|
+
});
|
|
98
|
+
const tooltipContent = `Space: ${space.name} (Env.: ${publishedEntry.sys.environment.sys.id})`;
|
|
99
|
+
await waitFor(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
100
|
+
expect(getByText(publishedEntry.fields.exField['en-US'])).toBeDefined();
|
|
101
|
+
expect(getByText(space.name)).toBeDefined();
|
|
102
|
+
fireEvent.mouseEnter(getByText(space.name));
|
|
103
|
+
await waitFor(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
104
|
+
});
|
|
105
|
+
it('renders entry card with a non master environment', async ()=>{
|
|
106
|
+
const { getByTestId , getByText } = renderResourceCard({
|
|
107
|
+
entryUrn: resolvableEntryUrnWithAnotherEnvironment
|
|
108
|
+
});
|
|
109
|
+
await waitFor(()=>expect(getByTestId('cf-ui-entry-card')).toBeDefined());
|
|
110
|
+
const tooltipContent = `Space: ${space.name} (Env.: ${publishedEntryNonMasterEnvironment.sys.environment.sys.id})`;
|
|
111
|
+
expect(getByText(publishedEntryNonMasterEnvironment.fields.exField['en-US'])).toBeDefined();
|
|
112
|
+
expect(getByText(space.name)).toBeDefined();
|
|
113
|
+
fireEvent.mouseEnter(getByText(space.name));
|
|
114
|
+
await waitFor(()=>expect(getByText(tooltipContent)).toBeDefined());
|
|
84
115
|
});
|
|
85
116
|
it('renders skeleton when no data is provided', ()=>{
|
|
86
117
|
const { getByTestId } = renderResourceCard();
|
|
@@ -98,4 +129,10 @@ describe('ResourceCard', ()=>{
|
|
|
98
129
|
});
|
|
99
130
|
await waitFor(()=>expect(getByTestId('cf-ui-missing-entry-card')).toBeDefined());
|
|
100
131
|
});
|
|
132
|
+
it('renders missing entity card when crn is invalid', async ()=>{
|
|
133
|
+
const { getByTestId } = renderResourceCard({
|
|
134
|
+
entryUrn: ''
|
|
135
|
+
});
|
|
136
|
+
await waitFor(()=>expect(getByTestId('cf-ui-missing-entry-card')).toBeDefined());
|
|
137
|
+
});
|
|
101
138
|
});
|
|
@@ -54,7 +54,7 @@ declare const useEntityLoader: () => {
|
|
|
54
54
|
};
|
|
55
55
|
export declare function useEntity<E extends FetchableEntity>(entityType: FetchableEntityType, entityId: string, options?: UseEntityOptions): UseEntityResult<E>;
|
|
56
56
|
export declare function useResource(resourceType: ResourceType, urn: string, options?: UseResourceOptions): {
|
|
57
|
-
status: "
|
|
57
|
+
status: "error" | "success" | "loading";
|
|
58
58
|
data: ResourceInfo<Resource> | undefined;
|
|
59
59
|
error: unknown;
|
|
60
60
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { QueryClient, useQuery as useRQ } from '@tanstack/react-query';
|
|
3
|
+
export declare function useQueryClient(): QueryClient;
|
|
4
|
+
export declare const useQuery: typeof useRQ;
|
|
5
|
+
/**
|
|
6
|
+
* Provides access to a query client either by sharing an existing client or
|
|
7
|
+
* creating a new one.
|
|
8
|
+
*/
|
|
9
|
+
export declare function SharedQueryClientProvider({ children }: React.PropsWithChildren<{}>): React.JSX.Element;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
interface
|
|
2
|
+
interface SourceProps {
|
|
3
3
|
spaceName: string;
|
|
4
|
+
environmentName?: string;
|
|
4
5
|
}
|
|
5
|
-
export declare function SpaceName(props:
|
|
6
|
+
export declare function SpaceName(props: SourceProps): React.JSX.Element;
|
|
6
7
|
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export type { CustomActionProps } from './common/ReferenceEditor';
|
|
|
5
5
|
export type { CustomEntityCardProps, DefaultCardRenderer, MissingEntityCardProps, RenderCustomMissingEntityCard, } from './common/customCardTypes';
|
|
6
6
|
export { SortableLinkList } from './common/SortableLinkList';
|
|
7
7
|
export { EntityProvider, useEntityLoader, useEntity, useResource } from './common/EntityStore';
|
|
8
|
+
export { SharedQueryClientProvider as EntityCacheProvider } from './common/queryClient';
|
|
8
9
|
export type { ResourceInfo } from './common/EntityStore';
|
|
9
10
|
export { SingleResourceReferenceEditor, MultipleResourceReferenceEditor } from './resources';
|
|
10
11
|
export * from './types';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/field-editor-reference",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.15.0",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/esm/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"@contentful/app-sdk": "^4.2.0",
|
|
64
64
|
"react": ">=16.8.0"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "780d4eb1450f777c2d2396a86d0b1a10268b3c13"
|
|
67
67
|
}
|