@contentful/field-editor-validation-errors 2.0.7 → 2.0.8-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,7 @@ const _f36components = require("@contentful/f36-components");
13
13
  const _f36icons = require("@contentful/f36-icons");
14
14
  const _f36tokens = /*#__PURE__*/ _interop_require_default(require("@contentful/f36-tokens"));
15
15
  const _fieldeditorshared = require("@contentful/field-editor-shared");
16
+ const _reactquery = require("@contentful/field-editor-shared/react-query");
16
17
  const _core = require("@lingui/core");
17
18
  const _styles = /*#__PURE__*/ _interop_require_wildcard(require("./styles"));
18
19
  function _interop_require_default(obj) {
@@ -61,67 +62,75 @@ function _interop_require_wildcard(obj, nodeInterop) {
61
62
  }
62
63
  return newObj;
63
64
  }
64
- function UniquenessError(props) {
65
+ function UniquenessError({ error, cma, localeCode, defaultLocaleCode, getEntryURL }) {
65
66
  const [state, setState] = _react.useState({
66
67
  loading: true,
67
68
  entries: []
68
69
  });
69
- const contentTypesById = _react.useMemo(()=>props.space.getCachedContentTypes().reduce((prev, ct)=>({
70
+ const { contentTypes: allContentTypes } = (0, _reactquery.useContentTypes)(cma);
71
+ const contentTypesById = _react.useMemo(()=>allContentTypes.reduce((prev, ct)=>({
70
72
  ...prev,
71
73
  [ct.sys.id]: ct
72
74
  }), {}), [
73
- props.space
75
+ allContentTypes
74
76
  ]);
75
- const getTitle = _react.useCallback((entry)=>_fieldeditorshared.entityHelpers.getEntryTitle({
76
- entry,
77
- defaultTitle: _core.i18n._({
78
- id: "FieldEditors.ValidationErrors.UniquenessError.DefaultTitle",
79
- message: "Untitled"
80
- }),
81
- localeCode: props.localeCode,
82
- defaultLocaleCode: props.defaultLocaleCode,
83
- contentType: contentTypesById[entry.sys.contentType.sys.id]
84
- }), [
85
- props.localeCode,
86
- props.defaultLocaleCode,
87
- contentTypesById
77
+ const conflictKey = _react.useMemo(()=>{
78
+ const conflicting = 'conflicting' in error ? error.conflicting : [];
79
+ return conflicting.map((entry)=>entry.sys.id).sort().join(',');
80
+ }, [
81
+ error
88
82
  ]);
89
- let conflicting = [];
90
- if ('conflicting' in props.error) {
91
- conflicting = props.error.conflicting;
92
- }
93
83
  _react.useEffect(()=>{
94
- const entryIds = state.entries.map((entry)=>entry.id);
95
- const conflictIds = conflicting.map((entry)=>entry.sys.id);
96
- if (conflictIds.every((id)=>entryIds.includes(id))) {
84
+ if (!conflictKey) {
85
+ setState({
86
+ loading: false,
87
+ entries: []
88
+ });
97
89
  return;
98
90
  }
99
- setState((state)=>({
100
- ...state,
101
- loading: true
102
- }));
103
- props.cma.entry.getMany({
91
+ setState({
92
+ loading: true,
93
+ entries: []
94
+ });
95
+ const conflicting = 'conflicting' in error ? error.conflicting : [];
96
+ const conflictIds = conflicting.map((entry)=>entry.sys.id);
97
+ cma.entry.getMany({
104
98
  query: {
105
99
  'sys.id[in]': conflictIds.join(',')
106
100
  },
107
101
  releaseId: undefined
108
102
  }).then(({ items })=>{
109
- const entries = items.map((entry)=>({
110
- id: entry.sys.id,
111
- title: getTitle(entry),
112
- href: props.getEntryURL(entry)
113
- }));
114
103
  setState({
115
104
  loading: false,
116
- entries
105
+ entries: items
117
106
  });
118
107
  });
119
108
  }, [
120
- getTitle,
109
+ conflictKey,
110
+ error,
111
+ cma
112
+ ]);
113
+ const displayEntries = _react.useMemo(()=>{
114
+ return state.entries.map((entry)=>({
115
+ id: entry.sys.id,
116
+ title: _fieldeditorshared.entityHelpers.getEntryTitle({
117
+ entry,
118
+ defaultTitle: _core.i18n._({
119
+ id: "FieldEditors.ValidationErrors.UniquenessError.DefaultTitle",
120
+ message: "Untitled"
121
+ }),
122
+ localeCode,
123
+ defaultLocaleCode,
124
+ contentType: contentTypesById[entry.sys.contentType.sys.id]
125
+ }),
126
+ href: getEntryURL(entry)
127
+ }));
128
+ }, [
121
129
  state.entries,
122
- conflicting,
123
- props.cma,
124
- props.getEntryURL
130
+ contentTypesById,
131
+ localeCode,
132
+ defaultLocaleCode,
133
+ getEntryURL
125
134
  ]);
126
135
  return /*#__PURE__*/ _react.createElement(_f36components.List, {
127
136
  className: _styles.errorList,
@@ -131,7 +140,7 @@ function UniquenessError(props) {
131
140
  }, state.loading ? /*#__PURE__*/ _react.createElement("div", null, _core.i18n._({
132
141
  id: "FieldEditors.ValidationErrors.UniquenessError.LoadingMessage",
133
142
  message: "Loading title for conflicting entry…"
134
- })) : state.entries.map((entry)=>/*#__PURE__*/ _react.createElement(_f36components.TextLink, {
143
+ })) : displayEntries.map((entry)=>/*#__PURE__*/ _react.createElement(_f36components.TextLink, {
135
144
  key: entry.id,
136
145
  href: entry.href,
137
146
  icon: /*#__PURE__*/ _react.createElement(_f36icons.ArrowSquareOutIcon, null),
@@ -141,7 +150,7 @@ function UniquenessError(props) {
141
150
  rel: "noopener noreferrer"
142
151
  }, entry.title))));
143
152
  }
144
- function ValidationErrors({ field, space, cma, locales, errorMessageOverride, getEntryURL }) {
153
+ function ValidationErrorsInternal({ field, cma, locales, errorMessageOverride, getEntryURL }) {
145
154
  const [errors, setErrors] = _react.useState([]);
146
155
  _react.useEffect(()=>{
147
156
  const onErrors = (errors)=>{
@@ -171,10 +180,12 @@ function ValidationErrors({ field, space, cma, locales, errorMessageOverride, ge
171
180
  }, errorMessageOverride?.(error.message) ?? error.message, error.name === 'unique' && /*#__PURE__*/ _react.createElement(UniquenessError, {
172
181
  cma: cma,
173
182
  error: error,
174
- space: space,
175
183
  localeCode: field.locale,
176
184
  defaultLocaleCode: locales.default,
177
185
  getEntryURL: getEntryURL
178
186
  })));
179
187
  }));
180
188
  }
189
+ function ValidationErrors(props) {
190
+ return /*#__PURE__*/ _react.createElement(_reactquery.SharedQueryClientProvider, null, /*#__PURE__*/ _react.createElement(ValidationErrorsInternal, props));
191
+ }
@@ -53,19 +53,6 @@ function _interop_require_wildcard(obj, nodeInterop) {
53
53
  });
54
54
  const displayField = 'my-title';
55
55
  const contentTypeId = 'my-content-type';
56
- const getCachedContentTypes = ()=>[
57
- {
58
- displayField,
59
- fields: [
60
- {
61
- id: displayField
62
- }
63
- ],
64
- sys: {
65
- id: 'my-content-type'
66
- }
67
- }
68
- ];
69
56
  const createEntry = (id)=>({
70
57
  fields: {
71
58
  [displayField]: {
@@ -86,6 +73,26 @@ const cma = {
86
73
  getMany: jest.fn().mockReturnValue({
87
74
  items: []
88
75
  })
76
+ },
77
+ contentType: {
78
+ getMany: jest.fn().mockResolvedValue({
79
+ items: [
80
+ {
81
+ sys: {
82
+ id: contentTypeId
83
+ },
84
+ name: 'My Content Type',
85
+ displayField,
86
+ fields: [
87
+ {
88
+ id: displayField,
89
+ name: 'Title',
90
+ type: 'Symbol'
91
+ }
92
+ ]
93
+ }
94
+ ]
95
+ })
89
96
  }
90
97
  };
91
98
  describe('ValidationErrors', ()=>{
@@ -95,7 +102,6 @@ describe('ValidationErrors', ()=>{
95
102
  const { container } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_ValidationErrors.ValidationErrors, {
96
103
  field: field,
97
104
  cma: cma,
98
- space: _fieldeditortestutils.createFakeSpaceAPI(),
99
105
  locales: _fieldeditortestutils.createFakeLocalesAPI(),
100
106
  getEntryURL: (entry)=>`url.${entry.sys.id}`
101
107
  }));
@@ -113,7 +119,6 @@ describe('ValidationErrors', ()=>{
113
119
  const { findByText } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_ValidationErrors.ValidationErrors, {
114
120
  field: field,
115
121
  cma: cma,
116
- space: _fieldeditortestutils.createFakeSpaceAPI(),
117
122
  locales: _fieldeditortestutils.createFakeLocalesAPI(),
118
123
  getEntryURL: (entry)=>`url.${entry.sys.id}`
119
124
  }));
@@ -149,17 +154,12 @@ describe('ValidationErrors', ()=>{
149
154
  }
150
155
  ];
151
156
  const [field, emitter] = _fieldeditortestutils.createFakeFieldAPI();
152
- const space = _fieldeditortestutils.createFakeSpaceAPI((api)=>({
153
- ...api,
154
- getCachedContentTypes
155
- }));
156
157
  cma.entry.getMany.mockResolvedValue({
157
158
  items: ids.map(createEntry)
158
159
  });
159
160
  const { findByText, findAllByTestId } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_ValidationErrors.ValidationErrors, {
160
161
  field: field,
161
162
  cma: cma,
162
- space: space,
163
163
  locales: _fieldeditortestutils.createFakeLocalesAPI(),
164
164
  getEntryURL: (entry)=>`url.${entry.sys.id}`
165
165
  }));
@@ -3,69 +3,78 @@ import { List, ListItem, TextLink } from '@contentful/f36-components';
3
3
  import { ArrowSquareOutIcon, InfoIcon } from '@contentful/f36-icons';
4
4
  import tokens from '@contentful/f36-tokens';
5
5
  import { entityHelpers } from '@contentful/field-editor-shared';
6
+ import { SharedQueryClientProvider, useContentTypes } from '@contentful/field-editor-shared/react-query';
6
7
  import { i18n as $_i18n } from "@lingui/core";
7
8
  import * as styles from './styles';
8
- function UniquenessError(props) {
9
+ function UniquenessError({ error, cma, localeCode, defaultLocaleCode, getEntryURL }) {
9
10
  const [state, setState] = React.useState({
10
11
  loading: true,
11
12
  entries: []
12
13
  });
13
- const contentTypesById = React.useMemo(()=>props.space.getCachedContentTypes().reduce((prev, ct)=>({
14
+ const { contentTypes: allContentTypes } = useContentTypes(cma);
15
+ const contentTypesById = React.useMemo(()=>allContentTypes.reduce((prev, ct)=>({
14
16
  ...prev,
15
17
  [ct.sys.id]: ct
16
18
  }), {}), [
17
- props.space
19
+ allContentTypes
18
20
  ]);
19
- const getTitle = React.useCallback((entry)=>entityHelpers.getEntryTitle({
20
- entry,
21
- defaultTitle: $_i18n._({
22
- id: "FieldEditors.ValidationErrors.UniquenessError.DefaultTitle",
23
- message: "Untitled"
24
- }),
25
- localeCode: props.localeCode,
26
- defaultLocaleCode: props.defaultLocaleCode,
27
- contentType: contentTypesById[entry.sys.contentType.sys.id]
28
- }), [
29
- props.localeCode,
30
- props.defaultLocaleCode,
31
- contentTypesById
21
+ const conflictKey = React.useMemo(()=>{
22
+ const conflicting = 'conflicting' in error ? error.conflicting : [];
23
+ return conflicting.map((entry)=>entry.sys.id).sort().join(',');
24
+ }, [
25
+ error
32
26
  ]);
33
- let conflicting = [];
34
- if ('conflicting' in props.error) {
35
- conflicting = props.error.conflicting;
36
- }
37
27
  React.useEffect(()=>{
38
- const entryIds = state.entries.map((entry)=>entry.id);
39
- const conflictIds = conflicting.map((entry)=>entry.sys.id);
40
- if (conflictIds.every((id)=>entryIds.includes(id))) {
28
+ if (!conflictKey) {
29
+ setState({
30
+ loading: false,
31
+ entries: []
32
+ });
41
33
  return;
42
34
  }
43
- setState((state)=>({
44
- ...state,
45
- loading: true
46
- }));
47
- props.cma.entry.getMany({
35
+ setState({
36
+ loading: true,
37
+ entries: []
38
+ });
39
+ const conflicting = 'conflicting' in error ? error.conflicting : [];
40
+ const conflictIds = conflicting.map((entry)=>entry.sys.id);
41
+ cma.entry.getMany({
48
42
  query: {
49
43
  'sys.id[in]': conflictIds.join(',')
50
44
  },
51
45
  releaseId: undefined
52
46
  }).then(({ items })=>{
53
- const entries = items.map((entry)=>({
54
- id: entry.sys.id,
55
- title: getTitle(entry),
56
- href: props.getEntryURL(entry)
57
- }));
58
47
  setState({
59
48
  loading: false,
60
- entries
49
+ entries: items
61
50
  });
62
51
  });
63
52
  }, [
64
- getTitle,
53
+ conflictKey,
54
+ error,
55
+ cma
56
+ ]);
57
+ const displayEntries = React.useMemo(()=>{
58
+ return state.entries.map((entry)=>({
59
+ id: entry.sys.id,
60
+ title: entityHelpers.getEntryTitle({
61
+ entry,
62
+ defaultTitle: $_i18n._({
63
+ id: "FieldEditors.ValidationErrors.UniquenessError.DefaultTitle",
64
+ message: "Untitled"
65
+ }),
66
+ localeCode,
67
+ defaultLocaleCode,
68
+ contentType: contentTypesById[entry.sys.contentType.sys.id]
69
+ }),
70
+ href: getEntryURL(entry)
71
+ }));
72
+ }, [
65
73
  state.entries,
66
- conflicting,
67
- props.cma,
68
- props.getEntryURL
74
+ contentTypesById,
75
+ localeCode,
76
+ defaultLocaleCode,
77
+ getEntryURL
69
78
  ]);
70
79
  return /*#__PURE__*/ React.createElement(List, {
71
80
  className: styles.errorList,
@@ -75,7 +84,7 @@ function UniquenessError(props) {
75
84
  }, state.loading ? /*#__PURE__*/ React.createElement("div", null, $_i18n._({
76
85
  id: "FieldEditors.ValidationErrors.UniquenessError.LoadingMessage",
77
86
  message: "Loading title for conflicting entry…"
78
- })) : state.entries.map((entry)=>/*#__PURE__*/ React.createElement(TextLink, {
87
+ })) : displayEntries.map((entry)=>/*#__PURE__*/ React.createElement(TextLink, {
79
88
  key: entry.id,
80
89
  href: entry.href,
81
90
  icon: /*#__PURE__*/ React.createElement(ArrowSquareOutIcon, null),
@@ -85,7 +94,7 @@ function UniquenessError(props) {
85
94
  rel: "noopener noreferrer"
86
95
  }, entry.title))));
87
96
  }
88
- export function ValidationErrors({ field, space, cma, locales, errorMessageOverride, getEntryURL }) {
97
+ function ValidationErrorsInternal({ field, cma, locales, errorMessageOverride, getEntryURL }) {
89
98
  const [errors, setErrors] = React.useState([]);
90
99
  React.useEffect(()=>{
91
100
  const onErrors = (errors)=>{
@@ -115,10 +124,12 @@ export function ValidationErrors({ field, space, cma, locales, errorMessageOverr
115
124
  }, errorMessageOverride?.(error.message) ?? error.message, error.name === 'unique' && /*#__PURE__*/ React.createElement(UniquenessError, {
116
125
  cma: cma,
117
126
  error: error,
118
- space: space,
119
127
  localeCode: field.locale,
120
128
  defaultLocaleCode: locales.default,
121
129
  getEntryURL: getEntryURL
122
130
  })));
123
131
  }));
124
132
  }
133
+ export function ValidationErrors(props) {
134
+ return /*#__PURE__*/ React.createElement(SharedQueryClientProvider, null, /*#__PURE__*/ React.createElement(ValidationErrorsInternal, props));
135
+ }
@@ -8,19 +8,6 @@ configure({
8
8
  });
9
9
  const displayField = 'my-title';
10
10
  const contentTypeId = 'my-content-type';
11
- const getCachedContentTypes = ()=>[
12
- {
13
- displayField,
14
- fields: [
15
- {
16
- id: displayField
17
- }
18
- ],
19
- sys: {
20
- id: 'my-content-type'
21
- }
22
- }
23
- ];
24
11
  const createEntry = (id)=>({
25
12
  fields: {
26
13
  [displayField]: {
@@ -41,6 +28,26 @@ const cma = {
41
28
  getMany: jest.fn().mockReturnValue({
42
29
  items: []
43
30
  })
31
+ },
32
+ contentType: {
33
+ getMany: jest.fn().mockResolvedValue({
34
+ items: [
35
+ {
36
+ sys: {
37
+ id: contentTypeId
38
+ },
39
+ name: 'My Content Type',
40
+ displayField,
41
+ fields: [
42
+ {
43
+ id: displayField,
44
+ name: 'Title',
45
+ type: 'Symbol'
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ })
44
51
  }
45
52
  };
46
53
  describe('ValidationErrors', ()=>{
@@ -50,7 +57,6 @@ describe('ValidationErrors', ()=>{
50
57
  const { container } = render(/*#__PURE__*/ React.createElement(ValidationErrors, {
51
58
  field: field,
52
59
  cma: cma,
53
- space: utils.createFakeSpaceAPI(),
54
60
  locales: utils.createFakeLocalesAPI(),
55
61
  getEntryURL: (entry)=>`url.${entry.sys.id}`
56
62
  }));
@@ -68,7 +74,6 @@ describe('ValidationErrors', ()=>{
68
74
  const { findByText } = render(/*#__PURE__*/ React.createElement(ValidationErrors, {
69
75
  field: field,
70
76
  cma: cma,
71
- space: utils.createFakeSpaceAPI(),
72
77
  locales: utils.createFakeLocalesAPI(),
73
78
  getEntryURL: (entry)=>`url.${entry.sys.id}`
74
79
  }));
@@ -104,17 +109,12 @@ describe('ValidationErrors', ()=>{
104
109
  }
105
110
  ];
106
111
  const [field, emitter] = utils.createFakeFieldAPI();
107
- const space = utils.createFakeSpaceAPI((api)=>({
108
- ...api,
109
- getCachedContentTypes
110
- }));
111
112
  cma.entry.getMany.mockResolvedValue({
112
113
  items: ids.map(createEntry)
113
114
  });
114
115
  const { findByText, findAllByTestId } = render(/*#__PURE__*/ React.createElement(ValidationErrors, {
115
116
  field: field,
116
117
  cma: cma,
117
- space: space,
118
118
  locales: utils.createFakeLocalesAPI(),
119
119
  getEntryURL: (entry)=>`url.${entry.sys.id}`
120
120
  }));
@@ -1,12 +1,11 @@
1
1
  import * as React from 'react';
2
- import type { Entry, FieldAPI, LocalesAPI, SpaceAPI } from '@contentful/field-editor-shared';
2
+ import type { Entry, FieldAPI, LocalesAPI } from '@contentful/field-editor-shared';
3
3
  import type { PlainClientAPI } from 'contentful-management';
4
4
  export interface ValidationErrorsProps {
5
5
  field: FieldAPI;
6
- space: SpaceAPI;
7
6
  cma: PlainClientAPI;
8
7
  locales: LocalesAPI;
9
8
  errorMessageOverride?: (message: string | undefined) => React.ReactNode;
10
9
  getEntryURL: (entry: Entry) => string;
11
10
  }
12
- export declare function ValidationErrors({ field, space, cma, locales, errorMessageOverride, getEntryURL, }: ValidationErrorsProps): React.JSX.Element | null;
11
+ export declare function ValidationErrors(props: ValidationErrorsProps): React.JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/field-editor-validation-errors",
3
- "version": "2.0.7",
3
+ "version": "2.0.8-canary.1+168bff6f",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -39,19 +39,20 @@
39
39
  "@contentful/f36-components": "^5.4.1",
40
40
  "@contentful/f36-icons": "^5.4.1",
41
41
  "@contentful/f36-tokens": "^5.1.0",
42
- "@contentful/field-editor-shared": "^2.17.1",
42
+ "@contentful/field-editor-shared": "^2.17.2-canary.1+168bff6f",
43
43
  "emotion": "^10.0.17"
44
44
  },
45
45
  "devDependencies": {
46
- "@contentful/field-editor-test-utils": "^1.7.0",
46
+ "@contentful/field-editor-test-utils": "^1.7.1-canary.76+168bff6f",
47
47
  "@lingui/core": "5.3.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@lingui/core": "^5.3.0",
51
+ "@tanstack/react-query": "^4.3.9",
51
52
  "react": ">=16.8.0"
52
53
  },
53
54
  "publishConfig": {
54
55
  "registry": "https://npm.pkg.github.com/"
55
56
  },
56
- "gitHead": "c8fbf95fbb880df05fd011b8892523c135c2a5fd"
57
+ "gitHead": "168bff6f172e483def0432b3095e8f0a2af37b1f"
57
58
  }