@contentful/field-editor-slug 2.1.4 → 2.1.5-canary.6

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.
@@ -56,7 +56,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
56
56
  function isSupportedFieldTypes(val) {
57
57
  return val === 'Symbol';
58
58
  }
59
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, id }) {
59
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
60
60
  const safeSetValue = _react.useCallback(async (...args)=>{
61
61
  try {
62
62
  await setValue(...args);
@@ -70,6 +70,7 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
70
70
  locale: locale,
71
71
  createdAt: createdAt,
72
72
  performUniqueCheck: performUniqueCheck,
73
+ isUniqueValidationEnabled: isUniqueValidationEnabled,
73
74
  hasError: errors.length > 0,
74
75
  value: value,
75
76
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
@@ -87,6 +88,7 @@ function SlugEditor(props) {
87
88
  }
88
89
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
89
90
  const entrySys = entry.getSys();
91
+ const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
90
92
  const isLocaleOptional = locales.optional[field.locale];
91
93
  const localeFallbackCode = locales.fallbacks[field.locale];
92
94
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -135,6 +137,7 @@ function SlugEditor(props) {
135
137
  createdAt: entrySys.createdAt,
136
138
  locale: field.locale,
137
139
  performUniqueCheck: performUniqueCheck,
140
+ isUniqueValidationEnabled: isUniqueValidationEnabled,
138
141
  key: `slug-editor-${externalReset}`,
139
142
  id: id
140
143
  });
@@ -60,6 +60,11 @@ function createMocks(initialValues = {}) {
60
60
  const [field] = (0, _fieldeditortestutils.createFakeFieldAPI)((field)=>({
61
61
  ...field,
62
62
  id: 'slug-id',
63
+ validations: [
64
+ {
65
+ unique: true
66
+ }
67
+ ],
63
68
  onValueChanged: jest.fn().mockImplementation(field.onValueChanged),
64
69
  setValue: jest.fn().mockImplementation(field.setValue)
65
70
  }), initialValues.field || '');
@@ -269,6 +274,36 @@ describe('SlugEditor', ()=>{
269
274
  expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
270
275
  });
271
276
  });
277
+ it('shows warning instead of error when unique validation is disabled on content model', async ()=>{
278
+ const { field, sdk } = createMocks({
279
+ titleField: 'Slug value',
280
+ field: 'slug-value'
281
+ });
282
+ field.validations = [];
283
+ sdk.entry.getSys.mockReturnValue({
284
+ id: 'entry-id',
285
+ publishedVersion: undefined,
286
+ contentType: {
287
+ sys: {
288
+ id: 'content-type-id'
289
+ }
290
+ }
291
+ });
292
+ sdk.cma.entry.getMany.mockResolvedValue({
293
+ total: 2
294
+ });
295
+ const { queryByText, getByTestId } = (0, _react1.render)(/*#__PURE__*/ _react.createElement(_SlugEditor.SlugEditor, {
296
+ field: field,
297
+ baseSdk: sdk,
298
+ isInitiallyDisabled: false
299
+ }));
300
+ await (0, _react1.waitFor)(()=>{
301
+ expect(sdk.cma.entry.getMany).toHaveBeenCalledTimes(1);
302
+ expect(queryByText('Warning: This slug has already been published in another entry. Enable "Unique" validation in the content model to enforce this as an error.')).toBeInTheDocument();
303
+ expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
304
+ expect(getByTestId('cf-ui-text-input')).not.toHaveAttribute('aria-invalid');
305
+ });
306
+ });
272
307
  });
273
308
  describe('should react to title changes', ()=>{
274
309
  it('when field is disabled', async ()=>{
@@ -19,6 +19,7 @@ _export(exports, {
19
19
  const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
20
20
  const _f36components = require("@contentful/f36-components");
21
21
  const _f36icons = require("@contentful/f36-icons");
22
+ const _f36note = require("@contentful/f36-note");
22
23
  const _core = require("@lingui/core");
23
24
  const _usedebounce = require("use-debounce");
24
25
  const _makeSlug = require("./services/makeSlug");
@@ -110,15 +111,17 @@ function useUniqueChecker(props) {
110
111
  return status;
111
112
  }
112
113
  function SlugEditorFieldStatic(props) {
113
- const { hasError, isDisabled, value, setValue, onChange, onBlur, id } = props;
114
+ const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id } = props;
114
115
  const status = useUniqueChecker(props);
116
+ const hasDuplicate = status === 'duplicate';
117
+ const shouldShowDuplicateAsError = hasDuplicate && isUniqueValidationEnabled;
115
118
  return /*#__PURE__*/ _react.createElement("div", {
116
119
  className: _styles.inputContainer
117
120
  }, /*#__PURE__*/ _react.createElement(_f36icons.LinkSimpleIcon, {
118
121
  className: _styles.icon
119
122
  }), /*#__PURE__*/ _react.createElement(_f36components.TextInput, {
120
123
  className: _styles.input,
121
- isInvalid: hasError || status === 'duplicate',
124
+ isInvalid: hasError || shouldShowDuplicateAsError,
122
125
  isDisabled: isDisabled,
123
126
  value: value || '',
124
127
  id: id,
@@ -137,12 +140,19 @@ function SlugEditorFieldStatic(props) {
137
140
  className: _styles.spinnerContainer
138
141
  }, /*#__PURE__*/ _react.createElement(_f36components.Spinner, {
139
142
  testId: "slug-editor-spinner"
140
- })), status === 'duplicate' && /*#__PURE__*/ _react.createElement(_f36components.ValidationMessage, {
143
+ })), hasDuplicate && isUniqueValidationEnabled && /*#__PURE__*/ _react.createElement(_f36components.ValidationMessage, {
141
144
  testId: "slug-editor-duplicate-error",
142
145
  className: _styles.uniqueValidationError
143
146
  }, _core.i18n._({
144
147
  id: "FieldEditors.Slug.SlugEditorField.DuplicateSlugError",
145
148
  message: "This slug has already been published in another entry"
149
+ })), hasDuplicate && !isUniqueValidationEnabled && /*#__PURE__*/ _react.createElement(_f36note.Note, {
150
+ variant: "warning",
151
+ testId: "slug-editor-duplicate-warning",
152
+ className: _styles.uniqueValidationError
153
+ }, _core.i18n._({
154
+ id: "FieldEditors.Slug.SlugEditorField.DuplicateSlugWarning",
155
+ message: 'Warning: This slug has already been published in another entry. Enable "Unique" validation in the content model to enforce this as an error.'
146
156
  })));
147
157
  }
148
158
  function SlugEditorField(props) {
@@ -5,7 +5,7 @@ import { TrackingFieldConnector } from './TrackingFieldConnector';
5
5
  function isSupportedFieldTypes(val) {
6
6
  return val === 'Symbol';
7
7
  }
8
- function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, id }) {
8
+ function FieldConnectorCallback({ Component, value, disabled, setValue, errors, titleValue, isOptionalLocaleWithFallback, locale, createdAt, performUniqueCheck, isUniqueValidationEnabled, id }) {
9
9
  const safeSetValue = React.useCallback(async (...args)=>{
10
10
  try {
11
11
  await setValue(...args);
@@ -19,6 +19,7 @@ function FieldConnectorCallback({ Component, value, disabled, setValue, errors,
19
19
  locale: locale,
20
20
  createdAt: createdAt,
21
21
  performUniqueCheck: performUniqueCheck,
22
+ isUniqueValidationEnabled: isUniqueValidationEnabled,
22
23
  hasError: errors.length > 0,
23
24
  value: value,
24
25
  isOptionalLocaleWithFallback: isOptionalLocaleWithFallback,
@@ -36,6 +37,7 @@ export function SlugEditor(props) {
36
37
  }
37
38
  const trackingFieldId = parameters?.instance?.trackingFieldId ?? undefined;
38
39
  const entrySys = entry.getSys();
40
+ const isUniqueValidationEnabled = (field.validations || []).some((validation)=>'unique' in validation && validation.unique === true);
39
41
  const isLocaleOptional = locales.optional[field.locale];
40
42
  const localeFallbackCode = locales.fallbacks[field.locale];
41
43
  const isOptionalFieldLocale = Boolean(!field.required || isLocaleOptional);
@@ -84,6 +86,7 @@ export function SlugEditor(props) {
84
86
  createdAt: entrySys.createdAt,
85
87
  locale: field.locale,
86
88
  performUniqueCheck: performUniqueCheck,
89
+ isUniqueValidationEnabled: isUniqueValidationEnabled,
87
90
  key: `slug-editor-${externalReset}`,
88
91
  id: id
89
92
  });
@@ -15,6 +15,11 @@ function createMocks(initialValues = {}) {
15
15
  const [field] = createFakeFieldAPI((field)=>({
16
16
  ...field,
17
17
  id: 'slug-id',
18
+ validations: [
19
+ {
20
+ unique: true
21
+ }
22
+ ],
18
23
  onValueChanged: jest.fn().mockImplementation(field.onValueChanged),
19
24
  setValue: jest.fn().mockImplementation(field.setValue)
20
25
  }), initialValues.field || '');
@@ -224,6 +229,36 @@ describe('SlugEditor', ()=>{
224
229
  expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
225
230
  });
226
231
  });
232
+ it('shows warning instead of error when unique validation is disabled on content model', async ()=>{
233
+ const { field, sdk } = createMocks({
234
+ titleField: 'Slug value',
235
+ field: 'slug-value'
236
+ });
237
+ field.validations = [];
238
+ sdk.entry.getSys.mockReturnValue({
239
+ id: 'entry-id',
240
+ publishedVersion: undefined,
241
+ contentType: {
242
+ sys: {
243
+ id: 'content-type-id'
244
+ }
245
+ }
246
+ });
247
+ sdk.cma.entry.getMany.mockResolvedValue({
248
+ total: 2
249
+ });
250
+ const { queryByText, getByTestId } = render(/*#__PURE__*/ React.createElement(SlugEditor, {
251
+ field: field,
252
+ baseSdk: sdk,
253
+ isInitiallyDisabled: false
254
+ }));
255
+ await waitFor(()=>{
256
+ expect(sdk.cma.entry.getMany).toHaveBeenCalledTimes(1);
257
+ expect(queryByText('Warning: This slug has already been published in another entry. Enable "Unique" validation in the content model to enforce this as an error.')).toBeInTheDocument();
258
+ expect(queryByText('This slug has already been published in another entry')).not.toBeInTheDocument();
259
+ expect(getByTestId('cf-ui-text-input')).not.toHaveAttribute('aria-invalid');
260
+ });
261
+ });
227
262
  });
228
263
  describe('should react to title changes', ()=>{
229
264
  it('when field is disabled', async ()=>{
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { Spinner, TextInput, ValidationMessage } from '@contentful/f36-components';
3
3
  import { LinkSimpleIcon } from '@contentful/f36-icons';
4
+ import { Note } from '@contentful/f36-note';
4
5
  import { i18n as $_i18n } from "@lingui/core";
5
6
  import { useDebounce } from 'use-debounce';
6
7
  import { makeSlug } from './services/makeSlug';
@@ -51,15 +52,17 @@ function useUniqueChecker(props) {
51
52
  return status;
52
53
  }
53
54
  export function SlugEditorFieldStatic(props) {
54
- const { hasError, isDisabled, value, setValue, onChange, onBlur, id } = props;
55
+ const { hasError, isDisabled, value, setValue, onChange, onBlur, isUniqueValidationEnabled, id } = props;
55
56
  const status = useUniqueChecker(props);
57
+ const hasDuplicate = status === 'duplicate';
58
+ const shouldShowDuplicateAsError = hasDuplicate && isUniqueValidationEnabled;
56
59
  return /*#__PURE__*/ React.createElement("div", {
57
60
  className: styles.inputContainer
58
61
  }, /*#__PURE__*/ React.createElement(LinkSimpleIcon, {
59
62
  className: styles.icon
60
63
  }), /*#__PURE__*/ React.createElement(TextInput, {
61
64
  className: styles.input,
62
- isInvalid: hasError || status === 'duplicate',
65
+ isInvalid: hasError || shouldShowDuplicateAsError,
63
66
  isDisabled: isDisabled,
64
67
  value: value || '',
65
68
  id: id,
@@ -78,12 +81,19 @@ export function SlugEditorFieldStatic(props) {
78
81
  className: styles.spinnerContainer
79
82
  }, /*#__PURE__*/ React.createElement(Spinner, {
80
83
  testId: "slug-editor-spinner"
81
- })), status === 'duplicate' && /*#__PURE__*/ React.createElement(ValidationMessage, {
84
+ })), hasDuplicate && isUniqueValidationEnabled && /*#__PURE__*/ React.createElement(ValidationMessage, {
82
85
  testId: "slug-editor-duplicate-error",
83
86
  className: styles.uniqueValidationError
84
87
  }, $_i18n._({
85
88
  id: "FieldEditors.Slug.SlugEditorField.DuplicateSlugError",
86
89
  message: "This slug has already been published in another entry"
90
+ })), hasDuplicate && !isUniqueValidationEnabled && /*#__PURE__*/ React.createElement(Note, {
91
+ variant: "warning",
92
+ testId: "slug-editor-duplicate-warning",
93
+ className: styles.uniqueValidationError
94
+ }, $_i18n._({
95
+ id: "FieldEditors.Slug.SlugEditorField.DuplicateSlugWarning",
96
+ message: 'Warning: This slug has already been published in another entry. Enable "Unique" validation in the content model to enforce this as an error.'
87
97
  })));
88
98
  }
89
99
  export function SlugEditorField(props) {
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  interface SlugEditorFieldProps {
3
3
  hasError: boolean;
4
+ isUniqueValidationEnabled: boolean;
4
5
  isOptionalLocaleWithFallback: boolean;
5
6
  isDisabled: boolean;
6
7
  value: string | null | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/field-editor-slug",
3
- "version": "2.1.4",
3
+ "version": "2.1.5-canary.6+2bae425d",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",
@@ -38,6 +38,7 @@
38
38
  "dependencies": {
39
39
  "@contentful/f36-components": "^5.4.1",
40
40
  "@contentful/f36-icons": "^5.4.1",
41
+ "@contentful/f36-note": "^5.4.1",
41
42
  "@contentful/f36-tokens": "^5.1.0",
42
43
  "@contentful/field-editor-shared": "^2.18.1",
43
44
  "@types/speakingurl": "^13.0.2",
@@ -58,5 +59,5 @@
58
59
  "publishConfig": {
59
60
  "registry": "https://npm.pkg.github.com/"
60
61
  },
61
- "gitHead": "51e565419e82705b2e2db20e136f50c497f1e8e0"
62
+ "gitHead": "2bae425d639a833aea33f11ef8bd4082644a1250"
62
63
  }