strapi-plugin-navigation 1.1.3 → 2.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +61 -87
  2. package/admin/src/components/EmptyView/index.js +7 -16
  3. package/admin/src/components/Item/ItemCardBadge/index.js +8 -0
  4. package/admin/src/components/Item/ItemCardHeader/Wrapper.js +21 -0
  5. package/admin/src/components/Item/ItemCardHeader/index.js +59 -0
  6. package/admin/src/components/Item/Wrapper.js +39 -0
  7. package/admin/src/components/Item/index.js +78 -124
  8. package/admin/src/components/NavigationItemList/Wrapper.js +22 -0
  9. package/admin/src/components/NavigationItemList/index.js +56 -0
  10. package/admin/src/components/PluginIcon/index.js +6 -0
  11. package/admin/src/components/Search/index.js +46 -83
  12. package/admin/src/index.js +49 -45
  13. package/admin/src/pages/App/index.js +31 -0
  14. package/admin/src/{containers → pages}/DataManagerProvider/actions.js +0 -0
  15. package/admin/src/{containers → pages}/DataManagerProvider/index.js +77 -84
  16. package/admin/src/{containers → pages}/DataManagerProvider/init.js +0 -0
  17. package/admin/src/pages/DataManagerProvider/reducer.js +125 -0
  18. package/admin/src/pages/View/components/NavigationContentHeader/index.js +18 -0
  19. package/admin/src/pages/View/components/NavigationHeader/index.js +60 -0
  20. package/admin/src/pages/View/components/NavigationItemForm/index.js +403 -0
  21. package/admin/src/{containers → pages}/View/components/NavigationItemForm/utils/form.js +2 -2
  22. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.js +40 -0
  23. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +20 -0
  24. package/admin/src/{containers → pages}/View/components/NavigationItemPopup/index.js +16 -16
  25. package/admin/src/pages/View/index.js +221 -0
  26. package/admin/src/{containers → pages}/View/utils/enums.js +0 -0
  27. package/admin/src/{containers → pages}/View/utils/form.js +1 -1
  28. package/admin/src/{containers → pages}/View/utils/index.js +0 -0
  29. package/admin/src/{containers → pages}/View/utils/parsers.js +13 -12
  30. package/admin/src/pluginId.js +3 -2
  31. package/admin/src/translations/en.json +47 -38
  32. package/admin/src/translations/fr.json +7 -1
  33. package/admin/src/utils/getTrad.js +2 -2
  34. package/package.json +18 -7
  35. package/server/bootstrap.js +41 -0
  36. package/server/config/index.js +8 -0
  37. package/server/config.js +8 -0
  38. package/server/content-types/audience/index.js +9 -0
  39. package/{models/audience.js → server/content-types/audience/lifecycle.js} +0 -0
  40. package/{models/audience.settings.json → server/content-types/audience/schema.json} +4 -2
  41. package/server/content-types/index.js +13 -0
  42. package/server/content-types/navigation/index.js +9 -0
  43. package/{models/navigation.js → server/content-types/navigation/lifecycle.js} +0 -0
  44. package/server/content-types/navigation/schema.js +45 -0
  45. package/server/content-types/navigation-item/index.js +9 -0
  46. package/{models/navigationItem.js → server/content-types/navigation-item/lifecycle.js} +0 -0
  47. package/{models/navigationItem.settings.json → server/content-types/navigation-item/schema.json} +16 -12
  48. package/server/content-types/navigations-items-related/index.js +9 -0
  49. package/{models/navigations_items_related.js → server/content-types/navigations-items-related/lifecycle.js} +0 -0
  50. package/{models/navigations_items_related.settings.json → server/content-types/navigations-items-related/schema.json} +4 -2
  51. package/server/controllers/index.js +7 -0
  52. package/{controllers → server/controllers}/navigation.js +20 -31
  53. package/server/graphql/index.js +23 -0
  54. package/server/graphql/queries/index.js +17 -0
  55. package/server/graphql/queries/render-navigation-child.js +16 -0
  56. package/server/graphql/queries/render-navigation.js +15 -0
  57. package/server/graphql/resolvers-config.js +4 -0
  58. package/server/graphql/types/content-types-name-fields.js +8 -0
  59. package/server/graphql/types/content-types.js +16 -0
  60. package/server/graphql/types/create-navigation-item.js +17 -0
  61. package/server/graphql/types/create-navigation-related.js +8 -0
  62. package/server/graphql/types/create-navigation.js +7 -0
  63. package/server/graphql/types/index.js +15 -0
  64. package/server/graphql/types/navigation-config.js +9 -0
  65. package/server/graphql/types/navigation-details.js +10 -0
  66. package/server/graphql/types/navigation-item.js +29 -0
  67. package/server/graphql/types/navigation-related.js +23 -0
  68. package/server/graphql/types/navigation-render-type.js +4 -0
  69. package/server/graphql/types/navigation.js +9 -0
  70. package/server/register.js +5 -0
  71. package/server/routes/admin.js +38 -0
  72. package/server/routes/client.js +21 -0
  73. package/server/routes/index.js +4 -0
  74. package/{services → server/services}/__tests__/navigation.test.js +0 -0
  75. package/server/services/index.js +7 -0
  76. package/server/services/navigation.js +729 -0
  77. package/{services → server/services}/utils/constant.js +3 -1
  78. package/server/services/utils/functions.js +185 -0
  79. package/strapi-admin.js +1 -0
  80. package/strapi-server.js +20 -0
  81. package/__mocks__/helpers/another-plugin/blog-post.settings.json +0 -31
  82. package/__mocks__/helpers/another-plugin/pages.settings.json +0 -28
  83. package/__mocks__/helpers/blog-post.settings.json +0 -31
  84. package/__mocks__/helpers/home-page.settings.json +0 -4
  85. package/__mocks__/helpers/my-homepage.settings.json +0 -27
  86. package/__mocks__/helpers/pages.settings.json +0 -27
  87. package/__mocks__/helpers/strapi.js +0 -101
  88. package/admin/src/assets/images/icon-cross-blue.svg +0 -1
  89. package/admin/src/assets/images/icon_remove.svg +0 -19
  90. package/admin/src/components/Container/index.js +0 -7
  91. package/admin/src/components/Input/index.js +0 -41
  92. package/admin/src/components/Item/CardItem.js +0 -46
  93. package/admin/src/components/Item/CardItemLevelAdd.js +0 -41
  94. package/admin/src/components/Item/CardItemLevelWrapper.js +0 -27
  95. package/admin/src/components/Item/CardItemPath.js +0 -9
  96. package/admin/src/components/Item/CardItemRestore.js +0 -19
  97. package/admin/src/components/Item/CardItemTitle.js +0 -5
  98. package/admin/src/components/Item/CardWrapper.js +0 -78
  99. package/admin/src/components/ItemFooter/CardItemError.js +0 -11
  100. package/admin/src/components/ItemFooter/CardItemRelation.js +0 -18
  101. package/admin/src/components/ItemFooter/CardItemRelationStatus.js +0 -17
  102. package/admin/src/components/ItemFooter/CardItemType.js +0 -18
  103. package/admin/src/components/ItemFooter/Wrapper.js +0 -26
  104. package/admin/src/components/ItemFooter/index.js +0 -66
  105. package/admin/src/components/ItemOrdering/CardOrderingButton.js +0 -24
  106. package/admin/src/components/ItemOrdering/Wrapper.js +0 -24
  107. package/admin/src/components/ItemOrdering/index.js +0 -36
  108. package/admin/src/components/List/Container.js +0 -34
  109. package/admin/src/components/List/ListLevelRoot.js +0 -18
  110. package/admin/src/components/List/index.js +0 -81
  111. package/admin/src/components/Option/OptionButton.js +0 -18
  112. package/admin/src/components/Option/OptionSet.js +0 -14
  113. package/admin/src/components/Option/Wrapper.js +0 -15
  114. package/admin/src/components/Option/index.js +0 -47
  115. package/admin/src/components/Select/ClearIndicator.js +0 -15
  116. package/admin/src/components/Select/DropdownIndicator.js +0 -39
  117. package/admin/src/components/Select/ErrorMessage.js +0 -10
  118. package/admin/src/components/Select/IndicatorSeparator.js +0 -3
  119. package/admin/src/components/Select/MultiValueContainer.js +0 -43
  120. package/admin/src/components/Select/StyledOption.js +0 -11
  121. package/admin/src/components/Select/index.js +0 -68
  122. package/admin/src/components/Select/utils/styles.js +0 -92
  123. package/admin/src/containers/App/Wrapper.js +0 -14
  124. package/admin/src/containers/App/index.js +0 -34
  125. package/admin/src/containers/DataManagerProvider/reducer.js +0 -136
  126. package/admin/src/containers/DetailsView/Wrapper.js +0 -21
  127. package/admin/src/containers/DetailsView/index.js +0 -111
  128. package/admin/src/containers/Initializer/index.js +0 -26
  129. package/admin/src/containers/ListView/Footer.js +0 -56
  130. package/admin/src/containers/ListView/components.js +0 -138
  131. package/admin/src/containers/ListView/index.js +0 -54
  132. package/admin/src/containers/View/FadedWrapper.js +0 -51
  133. package/admin/src/containers/View/HeaderForm.js +0 -9
  134. package/admin/src/containers/View/HeaderFormCell.js +0 -25
  135. package/admin/src/containers/View/Wrapper.js +0 -17
  136. package/admin/src/containers/View/components/NavigationItemForm/ModalFooter.js +0 -45
  137. package/admin/src/containers/View/components/NavigationItemForm/index.js +0 -427
  138. package/admin/src/containers/View/components/NavigationItemPopup/MediumPopup.js +0 -6
  139. package/admin/src/containers/View/index.js +0 -240
  140. package/admin/src/lifecycles.js +0 -3
  141. package/admin/src/permissions.js +0 -14
  142. package/config/functions/bootstrap.js +0 -138
  143. package/config/routes.json +0 -60
  144. package/config/schema.graphql.js +0 -209
  145. package/examples/audit-log-integrations.js.md +0 -38
  146. package/models/navigation.settings.json +0 -43
  147. package/public/assets/preview.png +0 -0
  148. package/services/navigation.js +0 -732
  149. package/services/utils/functions.js +0 -186
@@ -0,0 +1,403 @@
1
+ import React, { useEffect, useMemo, useState, useCallback } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { debounce, find, get, isEmpty, isEqual, isNil, isString } from 'lodash';
4
+ import PropTypes from 'prop-types';
5
+ import { Formik } from 'formik'
6
+
7
+ // Design System
8
+ import { ModalBody } from '@strapi/design-system/ModalLayout';
9
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
10
+ import { Form, GenericInput } from '@strapi/helper-plugin';
11
+
12
+ import { NavigationItemPopupFooter } from '../NavigationItemPopup/NavigationItemPopupFooter';
13
+
14
+
15
+ import { navigationItemType } from '../../utils/enums';
16
+ import slugify from 'slugify';
17
+ import { extractRelatedItemLabel } from '../../utils/parsers';
18
+ import { form as formDefinition } from './utils/form';
19
+ import { checkFormValidity } from '../../utils/form';
20
+ import { getTradId } from '../../../../translations';
21
+
22
+ const NavigationItemForm = ({
23
+ isLoading,
24
+ inputsPrefix,
25
+ data = {},
26
+ contentTypes = [],
27
+ contentTypeEntities = [],
28
+ usedContentTypeEntities = [],
29
+ availableAudience = [],
30
+ additionalFields = [],
31
+ contentTypesNameFields = {},
32
+ onSubmit,
33
+ onCancel,
34
+ getContentTypeEntities,
35
+ usedContentTypesData,
36
+ appendLabelPublicationStatus = () => '',
37
+ }) => {
38
+ const [hasBeenInitialized, setInitializedState] = useState(false);
39
+ const [hasChanged, setChangedState] = useState(false);
40
+ const [contentTypeSearchQuery, setContentTypeSearchQuery] = useState(undefined);
41
+ const [contentTypeSearchInputValue, setContentTypeSearchInputValue] = useState(undefined);
42
+ const [form, setFormState] = useState({});
43
+ const [formErrors, setFormErrorsState] = useState({});
44
+ const { relatedType } = form;
45
+ const { formatMessage } = useIntl();
46
+
47
+ const relatedFieldName = `${inputsPrefix}related`;
48
+
49
+ if (!hasBeenInitialized && !isEmpty(data)) {
50
+ setInitializedState(true);
51
+ setFormState({
52
+ ...data,
53
+ type: data.type || navigationItemType.INTERNAL,
54
+ related: data.related?.value,
55
+ relatedType: data.relatedType?.value
56
+ });
57
+ }
58
+
59
+ const generatePreviewPath = () => {
60
+ if (!isExternal) {
61
+ return {
62
+ id: `${data.levelPath !== '/' ? `${data.levelPath}` : ''}/${form.path || ''}`,
63
+ defaultMessage: `${data.levelPath !== '/' ? `${data.levelPath}` : ''}/${form.path || ''}`
64
+ }
65
+ }
66
+ return null;
67
+ };
68
+
69
+ const sanitizePayload = (payload = {}) => {
70
+ const { onItemClick, onItemLevelAddClick, related, relatedType, menuAttached, ...purePayload } = payload;
71
+ const sanitizedType = purePayload.type || navigationItemType.INTERNAL;
72
+ const relatedId = related
73
+ const relatedCollectionType = relatedType;
74
+ return {
75
+ ...purePayload,
76
+ menuAttached: isNil(menuAttached) ? false : menuAttached,
77
+ type: sanitizedType,
78
+ path: sanitizedType === navigationItemType.INTERNAL ? purePayload.path : undefined,
79
+ externalPath: sanitizedType === navigationItemType.EXTERNAL ? purePayload.externalPath : undefined,
80
+ related: relatedId,
81
+ relatedType: relatedCollectionType,
82
+ isSingle: isSingleSelected,
83
+ uiRouterKey: generateUiRouterKey(purePayload.title, relatedId, relatedCollectionType),
84
+ };
85
+ };
86
+
87
+ const handleSubmit = async e => {
88
+ if (e) {
89
+ e.preventDefault();
90
+ }
91
+
92
+ const payload = sanitizePayload(form);
93
+ const errors = await checkFormValidity(payload, formDefinition.schema(isSingleSelected));
94
+ if (!errors || isEmpty(errors)) {
95
+ return onSubmit(payload);
96
+ } else {
97
+ setFormErrorsState(errors);
98
+ }
99
+ };
100
+
101
+ const onTypeChange = ({ target: { name, value } }) =>
102
+ onChange({ target: { name, value: value ? navigationItemType.INTERNAL : navigationItemType.EXTERNAL } });
103
+
104
+ const onChange = ({ target: { name, value } }) => {
105
+ setFormState(prevState => ({
106
+ ...prevState,
107
+ updated: true,
108
+ [name]: value,
109
+ }));
110
+ if (!hasChanged) {
111
+ setChangedState(true);
112
+ }
113
+ };
114
+
115
+ const generateUiRouterKey = (title, related, relatedType) => {
116
+ if (title) {
117
+ return isString(title) && !isEmpty(title) ? slugify(title).toLowerCase() : undefined;
118
+ } else if (related) {
119
+ const relationTitle = extractRelatedItemLabel({
120
+ ...contentTypeEntities.find(_ => _.id === related),
121
+ __collectionUid: relatedType
122
+ }, contentTypesNameFields, { contentTypes });
123
+ return isString(relationTitle) && !isEmpty(relationTitle) ? slugify(relationTitle).toLowerCase() : undefined;
124
+ }
125
+ return undefined;
126
+ };
127
+
128
+ const relatedTypeSelectValue = form.relatedType;
129
+ const relatedSelectValue = form.related;
130
+
131
+ const isSingleSelected = useMemo(
132
+ () => relatedTypeSelectValue ? contentTypes.find(_ => _.uid === relatedTypeSelectValue)?.isSingle || false : false,
133
+ [relatedTypeSelectValue, contentTypes],
134
+ );
135
+
136
+ const relatedSelectOptions = contentTypeEntities
137
+ .filter((item) => {
138
+ const usedContentTypeEntitiesOfSameType = usedContentTypeEntities
139
+ .filter(uctItem => relatedTypeSelectValue === uctItem.__collectionUid);
140
+ return !find(usedContentTypeEntitiesOfSameType, uctItem => (item.id === uctItem.id && uctItem.id !== form.related));
141
+ })
142
+ .map((item) => {
143
+ const label = appendLabelPublicationStatus(
144
+ extractRelatedItemLabel({
145
+ ...item,
146
+ __collectionUid: get(relatedTypeSelectValue, 'value', relatedTypeSelectValue),
147
+ }, contentTypesNameFields, { contentTypes }),
148
+ item
149
+ );
150
+ return ({
151
+ key: get(item, 'id'),
152
+ metadatas: {
153
+ intlLabel: {
154
+ id: label || " ",
155
+ defaultMessage: label || " ",
156
+ }
157
+ },
158
+ value: item.id,
159
+ label: label,
160
+ })
161
+ });
162
+
163
+ const isExternal = form.type === navigationItemType.EXTERNAL;
164
+ const pathSourceName = isExternal ? 'externalPath' : 'path';
165
+
166
+ const submitDisabled = (form.type !== navigationItemType.EXTERNAL) && isNil(form.related);
167
+
168
+ const debouncedSearch = useCallback(
169
+ debounce(nextValue => setContentTypeSearchQuery(nextValue), 500),
170
+ [],
171
+ );
172
+
173
+ const debounceContentTypeSearchQuery = value => {
174
+ setContentTypeSearchInputValue(value);
175
+ debouncedSearch(value);
176
+ };
177
+
178
+ const onChangeRelatedType = ({ target: { name, value } }) => {
179
+ const relatedTypeBeingReverted = data.relatedType && (data.relatedType.value === get(value, 'value', value));
180
+ setContentTypeSearchQuery(undefined);
181
+ setContentTypeSearchInputValue(undefined);
182
+ setFormState(prevState => ({
183
+ ...prevState,
184
+ updated: true,
185
+ related: relatedTypeBeingReverted ? data.related?.value : undefined,
186
+ [name]: value,
187
+ }));
188
+ if (!hasChanged) {
189
+ setChangedState(true);
190
+ }
191
+ };
192
+
193
+ const relatedTypeSelectOptions = useMemo(
194
+ () => contentTypes
195
+ .filter((contentType) => {
196
+ if (contentType.isSingle) {
197
+ return !usedContentTypesData.some((_) => _.__collectionUid === contentType.uid && _.__collectionUid !== form.relatedType);
198
+ }
199
+ return true;
200
+ })
201
+ .map((item) => ({
202
+ key: get(item, 'uid'),
203
+ metadatas: {
204
+ intlLabel: {
205
+ id: get(item, 'label', get(item, 'name')),
206
+ defaultMessage: get(item, 'label', get(item, 'name')),
207
+ }
208
+ },
209
+ value: get(item, 'uid'),
210
+ label: appendLabelPublicationStatus(get(item, 'label', get(item, 'name')), item, true),
211
+ })),
212
+ [contentTypes, usedContentTypesData],
213
+ );
214
+
215
+ const thereAreNoMoreContentTypes = isEmpty(relatedSelectOptions) && !contentTypeSearchQuery;
216
+
217
+ useEffect(
218
+ () => {
219
+ const value = get(relatedSelectOptions, '0');
220
+ if (isSingleSelected && relatedSelectOptions.length === 1 && !isEqual(value, relatedSelectValue)) {
221
+ onChange({ target: { name: relatedFieldName, value } });
222
+ }
223
+ },
224
+ [isSingleSelected, relatedSelectOptions],
225
+ );
226
+
227
+ useEffect(() => {
228
+ const value = relatedType;
229
+ const fetchContentTypeEntities = async () => {
230
+ if (value) {
231
+ const item = find(
232
+ contentTypes,
233
+ (_) => _.uid === value,
234
+ );
235
+ if (item) {
236
+ await getContentTypeEntities({
237
+ modelUID: item.uid,
238
+ query: contentTypeSearchQuery,
239
+ }, item.plugin);
240
+ }
241
+ }
242
+ };
243
+ fetchContentTypeEntities();
244
+ }, [relatedType, contentTypeSearchQuery]);
245
+ return (
246
+ <>
247
+ <Formik>
248
+ <Form>
249
+ <ModalBody>
250
+ <Grid gap={5}>
251
+ <GridItem key={`${inputsPrefix}title`} col={12}>
252
+ <GenericInput
253
+ autoFocused={true}
254
+ intlLabel={{
255
+ id: getTradId('popup.item.form.title.label'),
256
+ defaultMessage: 'Title',
257
+ }}
258
+ name={`${inputsPrefix}title`}
259
+ placeholder={{
260
+ id: getTradId('popup.item.form.title.placeholder'),
261
+ defaultMessage: 'e.g. Blog',
262
+ }}
263
+ type='text'
264
+ error={get(formErrors, `${inputsPrefix}title.id`)}
265
+ onChange={onChange}
266
+ value={get(form, `${inputsPrefix}title`, '')}
267
+ />
268
+ </GridItem>
269
+ <GridItem key={`${inputsPrefix}menuAttached`} col={6} lg={12}>
270
+ <GenericInput
271
+ intlLabel={{
272
+ id: getTradId('popup.item.form.menuAttached.label'),
273
+ defaultMessage: 'MenuAttached',
274
+ }}
275
+ name={`${inputsPrefix}menuAttached`}
276
+ type='bool'
277
+ error={get(formErrors, `${inputsPrefix}menuAttached.id`)}
278
+ onChange={onChange}
279
+ value={get(form, `${inputsPrefix}menuAttached`, '')}
280
+ disabled={!(data.isMenuAllowedLevel && data.parentAttachedToMenu)}
281
+ />
282
+ </GridItem>
283
+ <GridItem key={`${inputsPrefix}type`} col={6} lg={12}>
284
+ <GenericInput
285
+ intlLabel={{
286
+ id: getTradId('popup.item.form.type.label'),
287
+ defaultMessage: 'Internal link',
288
+ }}
289
+ name={`${inputsPrefix}type`}
290
+ type='bool'
291
+ error={get(formErrors, `${inputsPrefix}type.id`)}
292
+ onChange={onTypeChange}
293
+ value={get(form, `${inputsPrefix}type`, '') === navigationItemType.INTERNAL}
294
+ />
295
+ </GridItem>
296
+ <GridItem key={`${inputsPrefix}path`} col={12}>
297
+ <GenericInput
298
+ intlLabel={{
299
+ id: getTradId(`popup.item.form.${pathSourceName}.label`),
300
+ defaultMessage: 'Path',
301
+ }}
302
+ name={`${inputsPrefix}${pathSourceName}`}
303
+ placeholder={{
304
+ id: getTradId(`popup.item.form.${pathSourceName}.placeholder`),
305
+ defaultMessage: 'e.g. Blog',
306
+ }}
307
+ type='text'
308
+ error={get(formErrors, `${inputsPrefix}${pathSourceName}.id`)}
309
+ onChange={onChange}
310
+ value={get(form, `${inputsPrefix}${pathSourceName}`, '')}
311
+ description={generatePreviewPath()}
312
+ />
313
+ </GridItem>
314
+ {!isExternal && (
315
+ <>
316
+ <GridItem col={6} lg={12}>
317
+ <GenericInput
318
+ type="select"
319
+ intlLabel={{
320
+ id: getTradId('popup.item.form.relatedType.label'),
321
+ defaultMessage: 'Related Type'
322
+ }}
323
+ placeholder={{
324
+ id: getTradId('popup.item.form.relatedType.placeholder'),
325
+ defaultMessage: 'Related Type'
326
+ }}
327
+ name={`${inputsPrefix}relatedType`}
328
+ error={get(formErrors, `${inputsPrefix}relatedType.id`)}
329
+ onChange={onChangeRelatedType}
330
+ options={relatedTypeSelectOptions}
331
+ value={relatedTypeSelectValue}
332
+ />
333
+ </GridItem>
334
+ {relatedTypeSelectValue && !isSingleSelected && (
335
+ <GridItem col={6} lg={12}>
336
+ <GenericInput
337
+ type="select"
338
+ intlLabel={{
339
+ id: getTradId('popup.item.form.related.label'),
340
+ defaultMessage: 'Related'
341
+ }}
342
+ placeholder={{
343
+ id: getTradId('popup.item.form.related.label'),
344
+ defaultMessage: 'Related'
345
+ }}
346
+ name={relatedFieldName}
347
+ error={get(formErrors, `${relatedFieldName}.id`)}
348
+ onChange={onChange}
349
+ onInputChange={debounceContentTypeSearchQuery}
350
+ inputValue={contentTypeSearchInputValue}
351
+ options={relatedSelectOptions}
352
+ value={relatedSelectValue}
353
+ disabled={isLoading || thereAreNoMoreContentTypes}
354
+ description={
355
+ !isLoading && thereAreNoMoreContentTypes
356
+ ? {
357
+ id: getTradId('popup.item.form.related.empty'),
358
+ defaultMessage: 'There are no more entities',
359
+ values: { contentTypeName: relatedTypeSelectValue },
360
+ }
361
+ : undefined
362
+ }
363
+ />
364
+ </GridItem>
365
+ )}
366
+ </>
367
+ )}
368
+ </Grid>
369
+ </ModalBody>
370
+ </Form>
371
+ </Formik>
372
+ <NavigationItemPopupFooter handleSubmit={handleSubmit} handleCancel={onCancel} submitDisabled={submitDisabled} />
373
+ </>
374
+ );
375
+ };
376
+
377
+ NavigationItemForm.defaultProps = {
378
+ fieldsToDisable: [],
379
+ formErrors: {},
380
+ inputsPrefix: '',
381
+ onSubmit: (e) => e.preventDefault(),
382
+ requestError: null,
383
+ };
384
+
385
+ NavigationItemForm.propTypes = {
386
+ isLoading: PropTypes.bool,
387
+ fieldsToDisable: PropTypes.array,
388
+ formErrors: PropTypes.object.isRequired,
389
+ inputsPrefix: PropTypes.string,
390
+ data: PropTypes.object.isRequired,
391
+ onSubmit: PropTypes.func,
392
+ requestError: PropTypes.object,
393
+ contentTypes: PropTypes.array,
394
+ contentTypeEntities: PropTypes.array,
395
+ usedContentTypeEntities: PropTypes.array,
396
+ availableAudience: PropTypes.array,
397
+ additionalFields: PropTypes.array,
398
+ getContentTypeEntities: PropTypes.func.isRequired,
399
+ appendLabelPublicationStatus: PropTypes.func,
400
+ onCancel: PropTypes.func,
401
+ };
402
+
403
+ export default NavigationItemForm;
@@ -1,6 +1,6 @@
1
1
  import * as yup from "yup";
2
2
  import { isNil } from "lodash";
3
- import { translatedErrors } from "strapi-helper-plugin";
3
+ import { translatedErrors } from "@strapi/helper-plugin";
4
4
  import { navigationItemType } from "../../../utils/enums";
5
5
  import pluginId from "../../../../../pluginId";
6
6
 
@@ -29,7 +29,7 @@ export const form = {
29
29
  is: val => val === navigationItemType.EXTERNAL,
30
30
  then: yup.string()
31
31
  .required(translatedErrors.required)
32
- .matches(/(#.*)|(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}|mailto:.+@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)+[^.\s]{2,})/, {
32
+ .matches(/(#.*)|(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/, {
33
33
  excludeEmptyString: true,
34
34
  message: `${pluginId}.popup.item.form.externalPath.validation.type`,
35
35
  }),
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useIntl } from 'react-intl';
4
+
5
+ import { Button } from '@strapi/design-system/Button';
6
+ import { ModalFooter } from '@strapi/design-system/ModalLayout';
7
+
8
+ import { getTrad } from '../../../../translations';
9
+
10
+ export const NavigationItemPopupFooter = ({ handleCancel, handleSubmit, submitDisabled, formViewId }) => {
11
+ const { formatMessage } = useIntl();
12
+
13
+ return (
14
+ <ModalFooter
15
+ startActions={
16
+ <Button onClick={handleCancel} variant="tertiary">
17
+ {formatMessage(getTrad('popup.item.form.button.cancel'))}
18
+ </Button>
19
+ }
20
+ endActions={
21
+ <Button onClick={handleSubmit} disabled={submitDisabled}>
22
+ {formatMessage(getTrad(`popup.item.form.button.save`))}
23
+ </Button>
24
+ }
25
+ />
26
+ );
27
+ };
28
+
29
+ NavigationItemPopupFooter.defaultProps = {
30
+ onValidate: undefined,
31
+ submitDisabled: false,
32
+ formViewId: undefined,
33
+ };
34
+
35
+ NavigationItemPopupFooter.propTypes = {
36
+ handleCancel: PropTypes.func.isRequired,
37
+ handleSubmit: PropTypes.func,
38
+ submitDisabled: PropTypes.bool,
39
+ formViewId: PropTypes.object,
40
+ };
@@ -0,0 +1,20 @@
1
+
2
+
3
+ import React from 'react';
4
+ import { ButtonText } from '@strapi/design-system/Text';
5
+ import { ModalHeader } from '@strapi/design-system/ModalLayout';
6
+ import { useIntl } from 'react-intl';
7
+ import { getTrad } from '../../../../translations';
8
+
9
+ export const NavigationItemPopupHeader = () => {
10
+ const { formatMessage } = useIntl();
11
+ return (
12
+ <ModalHeader>
13
+ <ButtonText textColor="neutral800" as="h2" id="asset-dialog-title">
14
+ {formatMessage(
15
+ getTrad('popup.item.header'),
16
+ )}
17
+ </ButtonText>
18
+ </ModalHeader>
19
+ );
20
+ };
@@ -5,15 +5,18 @@
5
5
  */
6
6
 
7
7
  import React from 'react';
8
- import { FormattedMessage, useIntl } from 'react-intl';
8
+ import { useIntl } from 'react-intl';
9
9
  import PropTypes from 'prop-types';
10
- import { HeaderModal, HeaderModalTitle } from 'strapi-helper-plugin';
11
10
  import { find } from 'lodash';
11
+
12
+ //Design System
13
+ import { ModalLayout } from '@strapi/design-system/ModalLayout';
14
+
12
15
  import NavigationItemForm from '../NavigationItemForm';
13
16
  import { extractRelatedItemLabel, isRelationCorrect, isRelationPublished } from '../../utils/parsers';
14
- import { MediumPopup } from './MediumPopup';
15
17
  import { navigationItemType } from '../../utils/enums';
16
- import { getTrad, getTradId } from '../../../../translations';
18
+ import { getTrad } from '../../../../translations';
19
+ import { NavigationItemPopupHeader } from './NavigationItemPopupHeader';
17
20
 
18
21
  const NavigationItemPopUp = ({
19
22
  isOpen,
@@ -26,6 +29,7 @@ const NavigationItemPopUp = ({
26
29
  getContentTypeItems,
27
30
  usedContentTypesData,
28
31
  }) => {
32
+
29
33
  const { formatMessage } = useIntl();
30
34
 
31
35
  const handleOnSubmit = (payload) => {
@@ -45,7 +49,7 @@ const NavigationItemPopUp = ({
45
49
  const appendLabelPublicationStatus = (label = '', item = {}, isCollection = false) => {
46
50
  const appendix = isRelationPublished({
47
51
  relatedRef: item,
48
- type: item.isSingle ? navigationItemType.INTERNAL : item.type,
52
+ type: item.isSingle ? navigationItemType.INTERNAL : item.type,
49
53
  isCollection,
50
54
  }) ? '' : `[${formatMessage(getTrad('notification.navigation.item.relation.status.draft'))}] `.toUpperCase();
51
55
  return `${appendix}${label}`;
@@ -60,9 +64,9 @@ const NavigationItemPopUp = ({
60
64
  related: related && isRelationCorrect(data) ? {
61
65
  value: related,
62
66
  label: appendLabelPublicationStatus(
63
- extractRelatedItemLabel({
67
+ extractRelatedItemLabel({
64
68
  ...relatedItem,
65
- __collectionName: relatedType,
69
+ __collectionUid: relatedType,
66
70
  }, contentTypesNameFields, config),
67
71
  relatedItem,
68
72
  ),
@@ -75,14 +79,8 @@ const NavigationItemPopUp = ({
75
79
  };
76
80
 
77
81
  return (
78
- <MediumPopup isOpen={isOpen} onToggle={onClose}>
79
- <HeaderModal>
80
- <section>
81
- <HeaderModalTitle>
82
- <FormattedMessage id={getTradId('popup.item.header')} />
83
- </HeaderModalTitle>
84
- </section>
85
- </HeaderModal>
82
+ <ModalLayout labelledBy="condition-modal-breadcrumbs" onClose={onClose} isOpen={isOpen}>
83
+ <NavigationItemPopupHeader />
86
84
  <NavigationItemForm
87
85
  data={prepareFormData(data)}
88
86
  isLoading={isLoading}
@@ -95,9 +93,11 @@ const NavigationItemPopUp = ({
95
93
  getContentTypeEntities={getContentTypeItems}
96
94
  usedContentTypesData={usedContentTypesData}
97
95
  onSubmit={handleOnSubmit}
96
+ onCancel={onClose}
98
97
  appendLabelPublicationStatus={appendLabelPublicationStatus}
99
98
  />
100
- </MediumPopup>
99
+ </ModalLayout>
100
+
101
101
  );
102
102
  };
103
103