strapi-plugin-navigation 2.5.1 → 2.5.2
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/admin/src/pages/SettingsPage/index.js +112 -102
- package/admin/src/pages/SettingsPage/types.d.ts +1 -0
- package/admin/src/pages/SettingsPage/utils/functions.js +2 -1
- package/admin/src/pages/View/components/NavigationItemForm/index.js +17 -18
- package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +1 -0
- package/admin/src/pages/View/components/NavigationItemForm/utils/form.d.ts +2 -0
- package/admin/src/pages/View/components/NavigationItemForm/utils/form.js +2 -0
- package/admin/src/pages/View/utils/parsers.d.ts +1 -0
- package/admin/src/pages/View/utils/parsers.js +2 -1
- package/admin/src/translations/en.json +2 -0
- package/package.json +3 -3
- package/server/config/index.js +1 -0
- package/server/config/setupStrategy.js +1 -0
- package/server/content-types/index.d.ts +5 -0
- package/server/content-types/navigation-item/index.d.ts +5 -0
- package/server/content-types/navigation-item/schema.d.ts +5 -0
- package/server/content-types/navigation-item/schema.js +5 -0
- package/server/index.d.ts +5 -0
- package/server/services/admin.js +2 -0
- package/server/services/client.js +1 -1
- package/server/utils/functions.d.ts +4 -0
- package/strapi-server.d.ts +5 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/config.d.ts +1 -0
- package/types/contentTypes.d.ts +1 -0
|
@@ -97,6 +97,7 @@ const SettingsPage = () => {
|
|
|
97
97
|
populate: (0, lodash_1.get)(navigationConfigData, "contentTypesPopulate", {}),
|
|
98
98
|
selectedContentTypes: configContentTypes.map(item => item.uid),
|
|
99
99
|
isCacheEnabled: (0, lodash_1.get)(navigationConfigData, "isCacheEnabled", false),
|
|
100
|
+
preferCustomContentTypes: (0, lodash_1.get)(navigationConfigData, "preferCustomContentTypes", true) ?? true,
|
|
100
101
|
}), [configContentTypes, navigationConfigData, utils_1.navigationItemAdditionalFields]);
|
|
101
102
|
const { disableI18nModal, setDisableI18nModalOpened, setI18nModalOnCancel, } = (0, DisableI18nModal_1.useDisableI18nModal)(({ pruneNavigations }) => {
|
|
102
103
|
setPruneObsoleteI18nNavigations(pruneNavigations);
|
|
@@ -106,7 +107,7 @@ const SettingsPage = () => {
|
|
|
106
107
|
?.filter((field) => field !== utils_1.navigationItemAdditionalFields.AUDIENCE);
|
|
107
108
|
setCustomFields(additionalFields || []);
|
|
108
109
|
}, [navigationConfigData]);
|
|
109
|
-
const preparePayload = (0, react_1.useCallback)(({ form: { allowedLevels, audienceFieldChecked, cascadeMenuAttachedChecked, i18nEnabled, nameFields, pathDefaultFields, populate, selectedContentTypes, isCacheEnabled, }, pruneObsoleteI18nNavigations }) => ({
|
|
110
|
+
const preparePayload = (0, react_1.useCallback)(({ form: { allowedLevels, audienceFieldChecked, cascadeMenuAttachedChecked, i18nEnabled, nameFields, pathDefaultFields, populate, selectedContentTypes, isCacheEnabled, preferCustomContentTypes, }, pruneObsoleteI18nNavigations }) => ({
|
|
110
111
|
additionalFields: audienceFieldChecked ? ['audience', ...customFields] : [...customFields],
|
|
111
112
|
allowedLevels,
|
|
112
113
|
cascadeMenuAttached: cascadeMenuAttachedChecked,
|
|
@@ -120,6 +121,7 @@ const SettingsPage = () => {
|
|
|
120
121
|
navigationItemRelated: selectedContentTypes.map((uid) => (0, functions_1.resolveGlobalLikeId)(uid)),
|
|
121
122
|
},
|
|
122
123
|
isCacheEnabled,
|
|
124
|
+
preferCustomContentTypes,
|
|
123
125
|
}), [customFields]);
|
|
124
126
|
const onSave = async (form) => {
|
|
125
127
|
lockApp();
|
|
@@ -176,21 +178,6 @@ const SettingsPage = () => {
|
|
|
176
178
|
react_1.default.createElement(helper_plugin_1.SettingsPageTitle, { name: (0, utils_2.getMessage)('Settings.email.plugin.title', 'Configuration') }),
|
|
177
179
|
react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null, "Fetching plugin config...")));
|
|
178
180
|
}
|
|
179
|
-
const allContentTypes = !isLoading ? (0, lodash_1.sortBy)(Object.values(allContentTypesData).filter(({ uid }) => (0, functions_1.isContentTypeEligible)(uid, {
|
|
180
|
-
allowedContentTypes: navigationConfigData?.allowedContentTypes,
|
|
181
|
-
restrictedContentTypes: navigationConfigData?.restrictedContentTypes,
|
|
182
|
-
})).map(ct => {
|
|
183
|
-
const type = configContentTypes.find(_ => _.uid === ct.uid);
|
|
184
|
-
if (type) {
|
|
185
|
-
const { available, isSingle } = type;
|
|
186
|
-
return {
|
|
187
|
-
...ct,
|
|
188
|
-
available,
|
|
189
|
-
isSingle,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
return ct;
|
|
193
|
-
}), ct => ct.info.displayName) : [];
|
|
194
181
|
const isI18NPluginEnabled = navigationConfigData?.isI18NPluginEnabled;
|
|
195
182
|
const isCachePluginEnabled = navigationConfigData?.isCachePluginEnabled;
|
|
196
183
|
const defaultLocale = navigationConfigData?.defaultLocale;
|
|
@@ -218,92 +205,115 @@ const SettingsPage = () => {
|
|
|
218
205
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
219
206
|
react_1.default.createElement(helper_plugin_1.SettingsPageTitle, { name: (0, utils_2.getMessage)('Settings.email.plugin.title', 'Configuration') }),
|
|
220
207
|
react_1.default.createElement(Main_1.Main, { labelledBy: "title" },
|
|
221
|
-
react_1.default.createElement(formik_1.Formik, { initialValues: formikInitialValues, onSubmit: onSave }, ({ handleSubmit, setFieldValue, values }) =>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
208
|
+
react_1.default.createElement(formik_1.Formik, { initialValues: formikInitialValues, onSubmit: onSave }, ({ handleSubmit, setFieldValue, values }) => {
|
|
209
|
+
const allContentTypes = !isLoading ? (0, lodash_1.sortBy)(Object.values(allContentTypesData).filter(({ uid }) => (0, functions_1.isContentTypeEligible)(uid, {
|
|
210
|
+
allowedContentTypes: navigationConfigData?.allowedContentTypes,
|
|
211
|
+
restrictedContentTypes: navigationConfigData?.restrictedContentTypes,
|
|
212
|
+
selectedContentTypes: values?.selectedContentTypes,
|
|
213
|
+
preferCustomContentTypes: values?.preferCustomContentTypes,
|
|
214
|
+
})).map(ct => {
|
|
215
|
+
const type = configContentTypes.find(_ => _.uid === ct.uid);
|
|
216
|
+
if (type) {
|
|
217
|
+
const { available, isSingle } = type;
|
|
218
|
+
return {
|
|
219
|
+
...ct,
|
|
220
|
+
available,
|
|
221
|
+
isSingle,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
return ct;
|
|
225
|
+
}), ct => ct.info.displayName) : [];
|
|
226
|
+
return (react_1.default.createElement(formik_1.Form, { noValidate: true, onSubmit: handleSubmit },
|
|
227
|
+
react_1.default.createElement(Layout_1.HeaderLayout, { title: (0, utils_2.getMessage)('pages.settings.header.title'), subtitle: (0, utils_2.getMessage)('pages.settings.header.description'), primaryAction: react_1.default.createElement(helper_plugin_1.CheckPermissions, { permissions: permissions_1.default.access },
|
|
228
|
+
react_1.default.createElement(Button_1.Button, { type: "submit", startIcon: react_1.default.createElement(icons_1.Check, null), disabled: restartStatus.required }, (0, utils_2.getMessage)('pages.settings.actions.submit'))) }),
|
|
229
|
+
react_1.default.createElement(Layout_1.ContentLayout, null,
|
|
230
|
+
react_1.default.createElement(Stack_1.Stack, { spacing: 7 },
|
|
231
|
+
restartStatus.required && (react_1.default.createElement(RestartAlert_1.default, { closeLabel: (0, utils_2.getMessage)('pages.settings.actions.restart.alert.cancel'), title: (0, utils_2.getMessage)('pages.settings.actions.restart.alert.title'), action: react_1.default.createElement(Box_1.Box, null,
|
|
232
|
+
react_1.default.createElement(Button_1.Button, { onClick: handleRestart, startIcon: react_1.default.createElement(icons_1.Play, null) }, (0, utils_2.getMessage)('pages.settings.actions.restart'))), onClose: handleRestartDiscard },
|
|
233
|
+
react_1.default.createElement(react_1.default.Fragment, null,
|
|
234
|
+
react_1.default.createElement(Box_1.Box, { paddingBottom: 1 }, (0, utils_2.getMessage)('pages.settings.actions.restart.alert.description')),
|
|
235
|
+
restartStatus.reasons?.map((reason, i) => react_1.default.createElement(Box_1.Box, { paddingBottom: 1, key: i, children: (0, utils_2.getMessage)(`pages.settings.actions.restart.alert.reason.${reason}`) }))))),
|
|
236
|
+
react_1.default.createElement(Box_1.Box, { ...BOX_DEFAULT_PROPS },
|
|
237
|
+
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
238
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "delta", as: "h2" }, (0, utils_2.getMessage)('pages.settings.general.title')),
|
|
239
|
+
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
240
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 12, s: 12, xs: 12 },
|
|
241
|
+
react_1.default.createElement(ToggleInput_1.ToggleInput, { name: "preferCustomContentTypes", label: (0, utils_2.getMessage)('pages.settings.form.preferCustomContentTypes.label', 'Prefer custom content types'), hint: (0, utils_2.getMessage)('pages.settings.form.preferCustomContentTypes.hint', 'Prefer if to use only api:: prefixed content types'), checked: values.preferCustomContentTypes, onChange: ({ target: { checked } }) => {
|
|
242
|
+
setFieldValue('preferCustomContentTypes', checked, true);
|
|
243
|
+
}, onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required })),
|
|
244
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 12, s: 12, xs: 12 },
|
|
245
|
+
react_1.default.createElement(Select_1.Select, { name: "selectedContentTypes", label: (0, utils_2.getMessage)('pages.settings.form.contentTypes.label'), placeholder: (0, utils_2.getMessage)('pages.settings.form.contentTypes.placeholder'), hint: (0, utils_2.getMessage)('pages.settings.form.contentTypes.hint'), onClear: () => setFieldValue('selectedContentTypes', [], false), value: values.selectedContentTypes, onChange: (value) => setFieldValue('selectedContentTypes', value, false), multi: true, withTags: true, disabled: restartStatus.required }, allContentTypes.map((item) => react_1.default.createElement(Select_1.Option, { key: item.uid, value: item.uid }, item.info.displayName)))),
|
|
246
|
+
!(0, lodash_1.isEmpty)(values.selectedContentTypes) && (react_1.default.createElement(Grid_1.GridItem, { col: 12 },
|
|
247
|
+
react_1.default.createElement(Accordion_1.AccordionGroup, { label: (0, utils_2.getMessage)('pages.settings.form.contentTypesSettings.label'), labelAction: react_1.default.createElement(Tooltip_1.Tooltip, { description: (0, utils_2.getMessage)('pages.settings.form.contentTypesSettings.tooltip') },
|
|
248
|
+
react_1.default.createElement(icons_1.Information, { "aria-hidden": true })) }, (0, lodash_1.orderBy)(values.selectedContentTypes).map(uid => {
|
|
249
|
+
const contentType = allContentTypes.find(item => item.uid == uid);
|
|
250
|
+
if (!contentType)
|
|
251
|
+
return;
|
|
252
|
+
const { info: { displayName }, available, isSingle } = contentType;
|
|
253
|
+
const attributeKeys = Object.keys(contentType.attributes).sort();
|
|
254
|
+
const stringAttributes = attributeKeys.filter(key => STRING_ATTRIBUTE_TYPES.includes(contentType.attributes[key].type));
|
|
255
|
+
const relationAttributes = attributeKeys.filter(key => RELATION_ATTRIBUTE_TYPES.includes(contentType.attributes[key].type));
|
|
256
|
+
const key = `collectionSettings-${uid}`;
|
|
257
|
+
return (react_1.default.createElement(Accordion_1.Accordion, { expanded: contentTypeExpanded === key, toggle: () => handleSetContentTypeExpanded(key), key: key, id: key, size: "S" },
|
|
258
|
+
react_1.default.createElement(Accordion_1.AccordionToggle, { title: displayName, togglePosition: "left", startIcon: (isSingle && !available) ? (react_1.default.createElement(icons_1.ExclamationMarkCircle, { "aria-hidden": true })) : null }),
|
|
259
|
+
react_1.default.createElement(Accordion_1.AccordionContent, null,
|
|
260
|
+
react_1.default.createElement(Box_1.Box, { padding: 6 },
|
|
261
|
+
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
262
|
+
(isSingle && !available) && (react_1.default.createElement(styles_1.PermanentAlert, { title: (0, utils_2.getMessage)('pages.settings.form.contentTypesSettings.initializationWarning.title'), variant: "danger", onClose: (e) => e.preventDefault() }, (0, utils_2.getMessage)('pages.settings.form.contentTypesSettings.initializationWarning.content'))),
|
|
263
|
+
react_1.default.createElement(Select_1.Select, { name: `collectionSettings-${uid}-entryLabel`, label: (0, utils_2.getMessage)('pages.settings.form.nameField.label'), hint: (0, utils_2.getMessage)(`pages.settings.form.nameField.${(0, lodash_1.isEmpty)(stringAttributes) ? 'empty' : 'hint'}`), placeholder: (0, utils_2.getMessage)('pages.settings.form.nameField.placeholder'), onClear: () => setFieldValue('nameFields', (0, utils_1.prepareNewValueForRecord)(uid, values.nameFields, [])), value: values.nameFields[uid] || [], onChange: (value) => setFieldValue('nameFields', (0, utils_1.prepareNewValueForRecord)(uid, values.nameFields, value)), multi: true, withTags: true, disabled: restartStatus.required || (0, lodash_1.isEmpty)(stringAttributes) }, stringAttributes.map(key => (react_1.default.createElement(Select_1.Option, { key: uid + key, value: key }, (0, lodash_1.capitalize)(key.split('_').join(' ')))))),
|
|
264
|
+
react_1.default.createElement(Select_1.Select, { name: `collectionSettings-${uid}-populate`, label: (0, utils_2.getMessage)('pages.settings.form.populate.label'), hint: (0, utils_2.getMessage)(`pages.settings.form.populate.${(0, lodash_1.isEmpty)(relationAttributes) ? 'empty' : 'hint'}`), placeholder: (0, utils_2.getMessage)('pages.settings.form.populate.placeholder'), onClear: () => setFieldValue('populate', (0, utils_1.prepareNewValueForRecord)(uid, values.populate, [])), value: values.populate[uid] || [], onChange: (value) => setFieldValue('populate', (0, utils_1.prepareNewValueForRecord)(uid, values.populate, value)), multi: true, withTags: true, disabled: restartStatus.required || (0, lodash_1.isEmpty)(relationAttributes) }, relationAttributes.map(key => (react_1.default.createElement(Select_1.Option, { key: uid + key, value: key }, (0, lodash_1.capitalize)(key.split('_').join(' ')))))),
|
|
265
|
+
react_1.default.createElement(Select_1.Select, { name: `collectionSettings-${uid}-pathDefaultFields`, label: (0, utils_2.getMessage)('pages.settings.form.pathDefaultFields.label'), hint: (0, utils_2.getMessage)(`pages.settings.form.pathDefaultFields.${(0, lodash_1.isEmpty)(stringAttributes) ? 'empty' : 'hint'}`), placeholder: (0, utils_2.getMessage)('pages.settings.form.pathDefaultFields.placeholder'), onClear: () => setFieldValue('pathDefaultFields', (0, utils_1.prepareNewValueForRecord)(uid, values.pathDefaultFields, [])), value: values.pathDefaultFields[uid] || [], onChange: (value) => setFieldValue('pathDefaultFields', (0, utils_1.prepareNewValueForRecord)(uid, values.pathDefaultFields, value)), multi: true, withTags: true, disabled: restartStatus.required || (0, lodash_1.isEmpty)(stringAttributes) }, stringAttributes.map(key => (react_1.default.createElement(Select_1.Option, { key: uid + key, value: key }, (0, lodash_1.capitalize)(key.split('_').join(' ')))))))))));
|
|
266
|
+
}))))))),
|
|
267
|
+
react_1.default.createElement(Box_1.Box, { ...BOX_DEFAULT_PROPS },
|
|
268
|
+
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
269
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "delta", as: "h2" }, (0, utils_2.getMessage)('pages.settings.additional.title')),
|
|
270
|
+
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
271
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 6, s: 6, xs: 12 },
|
|
272
|
+
react_1.default.createElement(Box_1.Box, { style: { maxWidth: 257 } },
|
|
273
|
+
react_1.default.createElement(NumberInput_1.NumberInput, { name: "allowedLevels", label: (0, utils_2.getMessage)('pages.settings.form.allowedLevels.label'), placeholder: (0, utils_2.getMessage)('pages.settings.form.allowedLevels.placeholder'), hint: (0, utils_2.getMessage)('pages.settings.form.allowedLevels.hint'), onValueChange: (value) => setFieldValue('allowedLevels', value, false), value: values.allowedLevels, disabled: restartStatus.required }))),
|
|
274
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 6, s: 12, xs: 12 },
|
|
275
|
+
react_1.default.createElement(ToggleInput_1.ToggleInput, { name: "cascadeMenuAttachedChecked", label: (0, utils_2.getMessage)('pages.settings.form.cascadeMenuAttached.label'), hint: (0, utils_2.getMessage)('pages.settings.form.cascadeMenuAttached.hint'), checked: values.cascadeMenuAttachedChecked, onChange: ({ target: { checked } }) => {
|
|
276
|
+
setFieldValue('cascadeMenuAttachedChecked', checked, true);
|
|
277
|
+
}, onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required }))),
|
|
278
|
+
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
279
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 6, s: 12, xs: 12 },
|
|
280
|
+
react_1.default.createElement(ToggleInput_1.ToggleInput, { name: "audienceFieldChecked", label: (0, utils_2.getMessage)('pages.settings.form.audience.label'), hint: (0, utils_2.getMessage)('pages.settings.form.audience.hint'), checked: values.audienceFieldChecked, onChange: () => setFieldValue('audienceFieldChecked', !values.audienceFieldChecked, false), onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required })),
|
|
281
|
+
isI18NPluginEnabled && (react_1.default.createElement(Grid_1.GridItem, { col: 6, s: 12, xs: 12 },
|
|
282
|
+
react_1.default.createElement(ToggleInput_1.ToggleInput, { name: "i18nEnabled", label: (0, utils_2.getMessage)('pages.settings.form.i18n.label'), hint: defaultLocale
|
|
283
|
+
? (0, utils_2.getMessage)('pages.settings.form.i18n.hint')
|
|
284
|
+
: (0, utils_2.getMessage)('pages.settings.form.i18n.hint.missingDefaultLocale'), checked: values.i18nEnabled, onChange: ({ target: { checked } }) => {
|
|
285
|
+
setFieldValue('i18nEnabled', checked, false);
|
|
286
|
+
if (checked) {
|
|
287
|
+
setPruneObsoleteI18nNavigations(false);
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
setDisableI18nModalOpened(true);
|
|
291
|
+
setI18nModalOnCancel(() => () => {
|
|
292
|
+
setFieldValue('i18nEnabled', true);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}, onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required || !defaultLocale })))),
|
|
296
|
+
isCachePluginEnabled && (react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
297
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 12, s: 12, xs: 12 },
|
|
298
|
+
react_1.default.createElement(ToggleInput_1.ToggleInput, { name: "cacheEnabled", label: (0, utils_2.getMessage)('pages.settings.form.cache.label'), hint: (0, utils_2.getMessage)('pages.settings.form.cache.hint'), checked: values.isCacheEnabled, onChange: ({ target: { checked } }) => {
|
|
299
|
+
setFieldValue('isCacheEnabled', checked, false);
|
|
300
|
+
}, onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required })))))),
|
|
301
|
+
react_1.default.createElement(Box_1.Box, { ...BOX_DEFAULT_PROPS },
|
|
302
|
+
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
303
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "delta", as: "h2" }, (0, utils_2.getMessage)('pages.settings.customFields.title')),
|
|
304
|
+
react_1.default.createElement(CustomFieldTable_1.default, { data: customFields, onOpenModal: handleOpenCustomFieldModal, onRemoveCustomField: handleRemoveCustomField, onToggleCustomField: handleToggleCustomField }))),
|
|
305
|
+
react_1.default.createElement(Box_1.Box, { ...BOX_DEFAULT_PROPS },
|
|
306
|
+
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
307
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "delta", as: "h2" }, (0, utils_2.getMessage)('pages.settings.restoring.title')),
|
|
308
|
+
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
309
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 12, s: 12, xs: 12 },
|
|
310
|
+
react_1.default.createElement(Typography_1.Typography, null, (0, utils_2.getMessage)('pages.settings.actions.restore.description'))),
|
|
311
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 6, s: 12, xs: 12 },
|
|
312
|
+
react_1.default.createElement(helper_plugin_1.CheckPermissions, { permissions: permissions_1.default.access },
|
|
313
|
+
react_1.default.createElement(Button_1.Button, { variant: "danger-light", startIcon: react_1.default.createElement(icons_1.Refresh, null), onClick: () => setIsRestorePopupOpen(true) }, (0, utils_2.getMessage)('pages.settings.actions.restore'))),
|
|
314
|
+
react_1.default.createElement(ConfirmationDialog_1.default, { isVisible: isRestorePopupOpen, header: (0, utils_2.getMessage)('pages.settings.actions.restore.confirmation.header'), labelConfirm: (0, utils_2.getMessage)('pages.settings.actions.restore.confirmation.confirm'), iconConfirm: react_1.default.createElement(icons_1.Refresh, null), onConfirm: () => onPopupClose(true), onCancel: () => onPopupClose(false) }, (0, utils_2.getMessage)('pages.settings.actions.restore.confirmation.description')),
|
|
315
|
+
disableI18nModal))))))));
|
|
316
|
+
})),
|
|
307
317
|
isCustomFieldModalOpen &&
|
|
308
318
|
react_1.default.createElement(CustomFieldModal_1.default, { onClose: () => setIsCustomFieldModalOpen(false), onSubmit: handleSubmitCustomField, isOpen: isCustomFieldModalOpen, data: customFieldSelected, usedCustomFieldNames: customFields.filter(f => f.name !== customFieldSelected?.name).map(f => f.name) })));
|
|
309
319
|
};
|
|
@@ -10,6 +10,7 @@ export type RawPayload = {
|
|
|
10
10
|
populate: Record<string, string[]>;
|
|
11
11
|
selectedContentTypes: string[];
|
|
12
12
|
isCacheEnabled: boolean;
|
|
13
|
+
preferCustomContentTypes: boolean;
|
|
13
14
|
};
|
|
14
15
|
export type StrapiContentTypeSchema = StrapiContentTypeFullSchema & {
|
|
15
16
|
available: boolean;
|
|
@@ -16,7 +16,8 @@ module.exports = {
|
|
|
16
16
|
return `${parse(scope)}${parse(contentTypeName)}`;
|
|
17
17
|
},
|
|
18
18
|
isContentTypeEligible(uid = '', config = {}) {
|
|
19
|
-
const { allowedContentTypes = [], restrictedContentTypes = [] } = config;
|
|
19
|
+
const { allowedContentTypes: baseAllowedContentTypes = [], restrictedContentTypes = [], preferCustomContentTypes = false, selectedContentTypes = [], } = config;
|
|
20
|
+
const allowedContentTypes = preferCustomContentTypes ? ["api::", ...selectedContentTypes] : baseAllowedContentTypes;
|
|
20
21
|
const isOneOfAllowedType = allowedContentTypes.filter(_ => uid.includes(_) || (uid === _)).length > 0;
|
|
21
22
|
const isNoneOfRestricted = restrictedContentTypes.filter(_ => uid.includes(_) || (uid === _)).length === 0;
|
|
22
23
|
return !!uid && isOneOfAllowedType && isNoneOfRestricted;
|
|
@@ -26,28 +26,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
const
|
|
29
|
+
const formik_1 = require("formik");
|
|
30
30
|
const lodash_1 = require("lodash");
|
|
31
31
|
const fp_1 = require("lodash/fp");
|
|
32
|
-
const
|
|
32
|
+
const react_1 = __importStar(require("react"));
|
|
33
33
|
const ModalLayout_1 = require("@strapi/design-system/ModalLayout");
|
|
34
34
|
const Select_1 = require("@strapi/design-system/Select");
|
|
35
35
|
const Grid_1 = require("@strapi/design-system/Grid");
|
|
36
36
|
const helper_plugin_1 = require("@strapi/helper-plugin");
|
|
37
37
|
const Button_1 = require("@strapi/design-system/Button");
|
|
38
|
-
const
|
|
38
|
+
const types_1 = require("../../../../../../types");
|
|
39
|
+
const AdditionalFieldInput_1 = __importDefault(require("../../../../components/AdditionalFieldInput"));
|
|
40
|
+
const translations_1 = require("../../../../translations");
|
|
39
41
|
const utils_1 = require("../../../../utils");
|
|
42
|
+
const form_1 = require("../../utils/form");
|
|
40
43
|
const parsers_1 = require("../../utils/parsers");
|
|
44
|
+
const NavigationItemPopupFooter_1 = require("../NavigationItemPopup/NavigationItemPopupFooter");
|
|
41
45
|
const formDefinition = __importStar(require("./utils/form"));
|
|
42
|
-
const form_1 = require("../../utils/form");
|
|
43
|
-
const translations_1 = require("../../../../translations");
|
|
44
|
-
const types_1 = require("../../../../../../types");
|
|
45
|
-
const AdditionalFieldInput_1 = __importDefault(require("../../../../components/AdditionalFieldInput"));
|
|
46
|
-
const utils_2 = require("../../../../utils");
|
|
47
46
|
const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading, inputsPrefix, data, contentTypes = [], contentTypeEntities = [], usedContentTypeEntities = [], availableAudience = [], additionalFields = [], contentTypesNameFields = {}, onSubmit, onCancel, getContentTypeEntities, usedContentTypesData, appendLabelPublicationStatus = appendLabelPublicationStatusFallback, locale, readNavigationItemFromLocale, slugify, permissions = {}, }) => {
|
|
48
47
|
const [isLoading, setIsLoading] = (0, react_1.useState)(isPreloading);
|
|
49
48
|
const [hasBeenInitialized, setInitializedState] = (0, react_1.useState)(false);
|
|
50
|
-
const [autoSync, setAutoSync] = (0, react_1.useState)(true);
|
|
51
49
|
const [hasChanged, setChangedState] = (0, react_1.useState)(false);
|
|
52
50
|
const [contentTypeSearchQuery, setContentTypeSearchQuery] = (0, react_1.useState)(undefined);
|
|
53
51
|
const { canUpdate } = permissions;
|
|
@@ -78,6 +76,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
78
76
|
if (!hasBeenInitialized && !(0, lodash_1.isEmpty)(data)) {
|
|
79
77
|
setInitializedState(true);
|
|
80
78
|
formik.setValues({
|
|
79
|
+
autoSync: (0, lodash_1.get)(data, "autoSync", formDefinition.defaultValues.autoSync) ?? true,
|
|
81
80
|
type: (0, lodash_1.get)(data, "type", formDefinition.defaultValues.type),
|
|
82
81
|
related: (0, lodash_1.get)(data, "related.value", formDefinition.defaultValues.related),
|
|
83
82
|
relatedType: (0, lodash_1.get)(data, "relatedType.value", formDefinition.defaultValues.relatedType),
|
|
@@ -158,7 +157,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
158
157
|
updated: true,
|
|
159
158
|
[name]: value,
|
|
160
159
|
}));
|
|
161
|
-
if (name === "related" && relatedTypeSelectValue && autoSync) {
|
|
160
|
+
if (name === "related" && relatedTypeSelectValue && formik.values.autoSync) {
|
|
162
161
|
const { contentTypesNameFields, pathDefaultFields } = config;
|
|
163
162
|
const selectedRelated = contentTypeEntities.find(({ id, __collectionUid }) => `${id}` === `${value}` && __collectionUid === relatedTypeSelectValue);
|
|
164
163
|
const newPath = pathDefaultFields[relatedTypeSelectValue]?.reduce((acc, field) => {
|
|
@@ -348,7 +347,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
348
347
|
locale: itemLocaleCopyValue,
|
|
349
348
|
structureId: data.structureId
|
|
350
349
|
});
|
|
351
|
-
if (result.type ===
|
|
350
|
+
if (result.type === utils_1.ResourceState.RESOLVED) {
|
|
352
351
|
const { value: { related, ...rest } } = result;
|
|
353
352
|
formik.setValues((prevState) => ({
|
|
354
353
|
...prevState,
|
|
@@ -364,17 +363,17 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
364
363
|
}));
|
|
365
364
|
}
|
|
366
365
|
}
|
|
367
|
-
if (result.type ===
|
|
366
|
+
if (result.type === utils_1.ResourceState.ERROR) {
|
|
368
367
|
formik.setErrors({
|
|
369
368
|
...formik.errors,
|
|
370
|
-
[itemLocaleCopyField]: (0,
|
|
369
|
+
[itemLocaleCopyField]: (0, utils_1.getMessage)(result.errors[0]),
|
|
371
370
|
});
|
|
372
371
|
}
|
|
373
372
|
}
|
|
374
373
|
catch (error) {
|
|
375
374
|
formik.setErrors({
|
|
376
375
|
...formik.errors,
|
|
377
|
-
[itemLocaleCopyField]: (0,
|
|
376
|
+
[itemLocaleCopyField]: (0, utils_1.getMessage)('popup.item.form.i18n.locale.error.generic'),
|
|
378
377
|
});
|
|
379
378
|
}
|
|
380
379
|
setIsLoading(false);
|
|
@@ -423,7 +422,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
423
422
|
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.label`, 'Path'), name: pathSourceName, placeholder: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.placeholder`, 'e.g. Blog'), type: "text", disabled: !canUpdate, error: formik.errors[pathSourceName], onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values[pathSourceName], description: generatePreviewPath() })),
|
|
424
423
|
formik.values.type === utils_1.navigationItemType.INTERNAL && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
425
424
|
react_1.default.createElement(Grid_1.GridItem, { key: "menuAttached", col: 12 },
|
|
426
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.autoSync.label', 'Read fields from related'), name: "autoSync", type: "bool", onChange: ({ target: { value } }) =>
|
|
425
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.autoSync.label', 'Read fields from related'), name: "autoSync", type: "bool", onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.autoSync })),
|
|
427
426
|
react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12 },
|
|
428
427
|
react_1.default.createElement(helper_plugin_1.GenericInput, { type: "select", intlLabel: (0, translations_1.getTrad)('popup.item.form.relatedType.label', 'Related Type'), placeholder: (0, translations_1.getTrad)('popup.item.form.relatedType.placeholder', 'Related Type'), name: "relatedType", error: formik.errors.relatedType, onChange: onChangeRelatedType, options: relatedTypeSelectOptions, value: formik.values.relatedType, disabled: isLoading || (0, lodash_1.isEmpty)(relatedTypeSelectOptions) || !canUpdate, description: !isLoading && (0, lodash_1.isEmpty)(relatedTypeSelectOptions)
|
|
429
428
|
? (0, translations_1.getTrad)('popup.item.form.relatedType.empty', 'There are no more content types')
|
|
@@ -439,8 +438,8 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
439
438
|
additionalFields.map((additionalField) => {
|
|
440
439
|
if (additionalField === 'audience') {
|
|
441
440
|
return (react_1.default.createElement(Grid_1.GridItem, { key: "audience", col: 6, lg: 12 },
|
|
442
|
-
react_1.default.createElement(Select_1.Select, { id: "audience", placeholder: (0,
|
|
443
|
-
? (0,
|
|
441
|
+
react_1.default.createElement(Select_1.Select, { id: "audience", placeholder: (0, utils_1.getMessage)('popup.item.form.audience.placeholder'), label: (0, utils_1.getMessage)('popup.item.form.audience.label'), onChange: onAudienceChange, value: formik.values.audience, hint: !isLoading && (0, lodash_1.isEmpty)(audienceOptions)
|
|
442
|
+
? (0, utils_1.getMessage)('popup.item.form.audience.empty', 'There are no more audiences')
|
|
444
443
|
: undefined, multi: true, withTags: true, disabled: (0, lodash_1.isEmpty)(audienceOptions) || !canUpdate }, audienceOptions.map(({ value, label }) => react_1.default.createElement(Select_1.Option, { key: value, value: value }, label)))));
|
|
445
444
|
}
|
|
446
445
|
else {
|
|
@@ -452,7 +451,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
452
451
|
react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12 },
|
|
453
452
|
react_1.default.createElement(helper_plugin_1.GenericInput, { ...itemCopyProps, type: "select", name: itemLocaleCopyField, error: (0, lodash_1.get)(formik.errors, itemLocaleCopyField), onChange: onChangeLocaleCopy, options: availableLocaleOptions, value: itemLocaleCopyValue, disabled: isLoading || !canUpdate })),
|
|
454
453
|
canUpdate && (react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12, paddingTop: 6 },
|
|
455
|
-
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: onCopyFromLocale, disabled: isLoading || !itemLocaleCopyValue }, (0,
|
|
454
|
+
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: onCopyFromLocale, disabled: isLoading || !itemLocaleCopyValue }, (0, utils_1.getMessage)('popup.item.form.i18n.locale.button')))))) : null)),
|
|
456
455
|
react_1.default.createElement(NavigationItemPopupFooter_1.NavigationItemPopupFooter, { handleSubmit: formik.handleSubmit, handleCancel: onCancel, submitDisabled: submitDisabled, canUpdate: canUpdate })));
|
|
457
456
|
};
|
|
458
457
|
const appendLabelPublicationStatusFallback = () => "";
|
|
@@ -2,6 +2,7 @@ import * as yup from "yup";
|
|
|
2
2
|
import { NavigationItemAdditionalField } from "../../../../../../../types";
|
|
3
3
|
import { RawFormPayload } from "../types";
|
|
4
4
|
export declare const schemaFactory: (isSingleSelected: boolean, additionalFields: NavigationItemAdditionalField[]) => import("yup/lib/object").OptionalObjectSchema<{
|
|
5
|
+
autoSync: yup.BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
5
6
|
title: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
6
7
|
uiRouterKey: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
7
8
|
type: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
@@ -12,6 +13,7 @@ export declare const schemaFactory: (isSingleSelected: boolean, additionalFields
|
|
|
12
13
|
related: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
13
14
|
additionalFields: import("yup/lib/object").OptionalObjectSchema<{}, Record<string, any>, import("yup/lib/object").TypeOfShape<{}>>;
|
|
14
15
|
}, Record<string, any>, import("yup/lib/object").TypeOfShape<{
|
|
16
|
+
autoSync: yup.BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
15
17
|
title: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
16
18
|
uiRouterKey: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
17
19
|
type: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
@@ -40,6 +40,7 @@ const externalPathRegexps = [
|
|
|
40
40
|
];
|
|
41
41
|
const schemaFactory = (isSingleSelected, additionalFields) => {
|
|
42
42
|
return yup.object({
|
|
43
|
+
autoSync: yup.bool().optional(),
|
|
43
44
|
title: yup.string()
|
|
44
45
|
.when('type', {
|
|
45
46
|
is: (val) => val !== utils_1.navigationItemType.INTERNAL,
|
|
@@ -104,6 +105,7 @@ const schemaFactory = (isSingleSelected, additionalFields) => {
|
|
|
104
105
|
};
|
|
105
106
|
exports.schemaFactory = schemaFactory;
|
|
106
107
|
exports.defaultValues = {
|
|
108
|
+
autoSync: true,
|
|
107
109
|
type: "INTERNAL",
|
|
108
110
|
related: "",
|
|
109
111
|
relatedType: "",
|
|
@@ -5,7 +5,7 @@ const uuid_1 = require("uuid");
|
|
|
5
5
|
const lodash_1 = require("lodash");
|
|
6
6
|
const utils_1 = require("../../../utils");
|
|
7
7
|
const transformItemToRESTPayload = (item, parent = undefined, master = undefined, config = {}, parentAttachedToMenu = true) => {
|
|
8
|
-
const { id, title, type = utils_1.navigationItemType.INTERNAL, updated = false, removed = false, uiRouterKey, menuAttached, path, externalPath, related, relatedType, order, audience = [], items = [], collapsed, isSingle, additionalFields = {}, } = item;
|
|
8
|
+
const { id, title, type = utils_1.navigationItemType.INTERNAL, updated = false, removed = false, uiRouterKey, menuAttached, path, externalPath, related, relatedType, order, audience = [], items = [], collapsed, isSingle, additionalFields = {}, autoSync, } = item;
|
|
9
9
|
const isExternal = type === utils_1.navigationItemType.EXTERNAL;
|
|
10
10
|
const isWrapper = type === utils_1.navigationItemType.WRAPPER;
|
|
11
11
|
const { contentTypes = [] } = config;
|
|
@@ -27,6 +27,7 @@ const transformItemToRESTPayload = (item, parent = undefined, master = undefined
|
|
|
27
27
|
uiRouterKey,
|
|
28
28
|
collapsed,
|
|
29
29
|
additionalFields,
|
|
30
|
+
autoSync,
|
|
30
31
|
menuAttached: itemAttachedToMenu,
|
|
31
32
|
audience: audience.map((audienceItem) => (0, lodash_1.isObject)(audienceItem)
|
|
32
33
|
? audienceItem.id || audienceItem.value
|
|
@@ -136,6 +136,8 @@
|
|
|
136
136
|
"pages.settings.notification.submit.error": "Config update has failed",
|
|
137
137
|
"pages.settings.notification.restore.error": "Config restore has failed",
|
|
138
138
|
"pages.settings.notification.restart.error": "Failed to restart your application. Try to do it manually.",
|
|
139
|
+
"pages.settings.form.preferCustomContentTypes.label": "Prefer custom content types",
|
|
140
|
+
"pages.settings.form.preferCustomContentTypes.hint": "Prefer if to use only api:: prefixed content types",
|
|
139
141
|
"pages.settings.form.cascadeMenuAttached.label": "Cascade menu attached",
|
|
140
142
|
"pages.settings.form.cascadeMenuAttached.hint": "Disable if you don't want \"Menu attached\" to cascade on child items",
|
|
141
143
|
"pages.settings.form.contentTypes.label": "Enable navigation for",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-navigation",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"description": "Strapi - Navigation plugin",
|
|
5
5
|
"strapi": {
|
|
6
6
|
"name": "navigation",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"types": "./types/index.d.ts",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@sindresorhus/slugify": "1.1.0",
|
|
19
|
-
"@strapi/utils": "^4.24.
|
|
19
|
+
"@strapi/utils": "^4.24.5",
|
|
20
20
|
"lodash": "^4.17.21",
|
|
21
21
|
"pluralize": "^8.0.0",
|
|
22
22
|
"react": "^17.0.0 || ^18.0.0",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@strapi/data-transfer": "4.24.
|
|
31
|
+
"@strapi/data-transfer": "4.24.5",
|
|
32
32
|
"@strapi/strapi": "4.x",
|
|
33
33
|
"react": "^17.0.0 || ^18.0.0",
|
|
34
34
|
"react-dom": "^17.0.0 || ^18.0.0",
|
package/server/config/index.js
CHANGED
|
@@ -26,6 +26,7 @@ const configSetupStrategy = async ({ strapi }) => {
|
|
|
26
26
|
pathDefaultFields: getWithFallback("pathDefaultFields"),
|
|
27
27
|
cascadeMenuAttached: getWithFallback("cascadeMenuAttached"),
|
|
28
28
|
isCacheEnabled: getWithFallback("isCacheEnabled"),
|
|
29
|
+
preferCustomContentTypes: getWithFallback("isCacheEnabled"),
|
|
29
30
|
};
|
|
30
31
|
handleDeletedContentTypes(config, { strapi });
|
|
31
32
|
(0, utils_1.validateAdditionalFields)(config.additionalFields);
|