strapi-plugin-navigation 2.2.1 → 2.3.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -5
- package/admin/src/pages/DataManagerProvider/index.js +2 -0
- package/admin/src/pages/DataManagerProvider/reducer.d.ts +1 -0
- package/admin/src/pages/DataManagerProvider/reducer.js +1 -0
- package/admin/src/pages/SettingsPage/components/CustomFieldForm/index.js +2 -0
- package/admin/src/pages/SettingsPage/index.js +17 -8
- package/admin/src/pages/SettingsPage/types.d.ts +2 -1
- package/admin/src/pages/SettingsPage/utils/form.d.ts +2 -0
- package/admin/src/pages/SettingsPage/utils/form.js +3 -1
- package/admin/src/pages/View/components/NavigationItemForm/index.js +36 -20
- package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +6 -0
- package/admin/src/pages/View/components/NavigationItemForm/utils/form.js +2 -2
- package/admin/src/pages/View/components/NavigationItemPopup/index.d.ts +3 -1
- package/admin/src/pages/View/components/NavigationItemPopup/index.js +3 -2
- package/admin/src/pages/View/index.js +7 -2
- package/admin/src/pages/View/utils/parsers.js +1 -1
- package/admin/src/translations/en.json +3 -0
- package/package.json +2 -2
- package/server/config/index.js +1 -1
- package/server/config/setupStrategy.js +1 -9
- package/server/content-types/index.d.ts +2 -0
- package/server/content-types/navigation/index.d.ts +1 -0
- package/server/content-types/navigation/schema.d.ts +1 -0
- package/server/content-types/navigation/schema.js +2 -1
- package/server/content-types/navigation-item/index.d.ts +1 -0
- package/server/content-types/navigation-item/schema.d.ts +1 -0
- package/server/content-types/navigation-item/schema.js +2 -1
- package/server/controllers/admin.js +13 -0
- package/server/index.d.ts +2 -0
- package/server/routes/admin.js +10 -0
- package/server/services/admin.js +4 -10
- package/server/services/client.js +10 -14
- package/server/services/common.js +27 -1
- package/strapi-server.d.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/config.d.ts +1 -1
- package/types/controllers.d.ts +5 -0
- package/types/services.d.ts +1 -0
package/README.md
CHANGED
|
@@ -149,6 +149,9 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
149
149
|
> *Note v2.0.3 and newer only*
|
|
150
150
|
> Changing this file will not automatically change plugin configuration. To synchronize plugin's config with plugins.js file, it is necessary to restore configuration through the settings page
|
|
151
151
|
|
|
152
|
+
> *Note for newer than v2.2.0*
|
|
153
|
+
> `slugify` as been removed. **THIS A BREAKING CHANGE**
|
|
154
|
+
|
|
152
155
|
```js
|
|
153
156
|
module.exports = ({ env }) => ({
|
|
154
157
|
// ...
|
|
@@ -162,11 +165,6 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
162
165
|
},
|
|
163
166
|
allowedLevels: 2,
|
|
164
167
|
gql: {...},
|
|
165
|
-
slugify: {
|
|
166
|
-
customReplacements: [
|
|
167
|
-
["🤔", "thinking"],
|
|
168
|
-
],
|
|
169
|
-
}
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
});
|
|
@@ -179,6 +177,7 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
179
177
|
- `contentTypesNameFields` - Definition of content type title fields like `'api::<collection name>.<content type name>': ['field_name_1', 'field_name_2']`, if not set titles are pulled from fields like `['title', 'subject', 'name']`. **TIP** - Proper content type uid you can find in the URL of Content Manager where you're managing relevant entities like: `admin/content-manager/collectionType/< THE UID HERE >?page=1&pageSize=10&sort=Title:ASC&plugins[i18n][locale]=en`
|
|
180
178
|
- `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
|
|
181
179
|
- `i18nEnabled` - should you want to manage multi-locale content via navigation set this value `Enabled`. More **[ here ](#i18n-internationalization)**
|
|
180
|
+
- `cascadeMenuAttached` - If you don't want "Menu attached" to cascade on child items set this value `Disabled`.
|
|
182
181
|
- `slugify` - allows to extend configuration of our "slugging" solution of choice. To learn more visit the [documentation](https://github.com/sindresorhus/slugify#api). It can be left unset since it's optional. **This option can only be handled by configuration in config file**.
|
|
183
182
|
|
|
184
183
|
### Properties
|
|
@@ -631,6 +630,33 @@ module.exports = {
|
|
|
631
630
|
|
|
632
631
|
If you already got it, make sure that `navigation` plugin is inserted before `graphql`. That should do the job.
|
|
633
632
|
|
|
633
|
+
### Slug generation
|
|
634
|
+
|
|
635
|
+
#### Customisation
|
|
636
|
+
|
|
637
|
+
Slug generation is available as a controller and service. If you have custom requirements outside of what this plugin provides you can add your own logic with [plugins extensions](https://docs.strapi.io/developer-docs/latest/development/plugins-extension.html).
|
|
638
|
+
|
|
639
|
+
For example:
|
|
640
|
+
|
|
641
|
+
```ts
|
|
642
|
+
// path: ./src/index.js
|
|
643
|
+
|
|
644
|
+
module.exports = {
|
|
645
|
+
// ...
|
|
646
|
+
bootstrap({ strapi }) {
|
|
647
|
+
const navigationCommonService = strapi.plugin("navigation").service("common");
|
|
648
|
+
const originalGetSlug = navigationCommonService.getSlug;
|
|
649
|
+
const preprocess = (q) => {
|
|
650
|
+
return q + "suffix";
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
navigationCommonService.getSlug = (query) => {
|
|
654
|
+
return originalGetSlug(preprocess(query));
|
|
655
|
+
};
|
|
656
|
+
},
|
|
657
|
+
};
|
|
658
|
+
```
|
|
659
|
+
|
|
634
660
|
## 🤝 Contributing
|
|
635
661
|
|
|
636
662
|
<div>
|
|
@@ -287,6 +287,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
287
287
|
method: "DELETE",
|
|
288
288
|
signal,
|
|
289
289
|
});
|
|
290
|
+
const slugify = (query) => (0, helper_plugin_1.request)(`/${pluginId_1.default}/slug?q=${query}`, { method: "GET", signal });
|
|
290
291
|
const hardReset = () => getDataRef.current();
|
|
291
292
|
return (react_1.default.createElement(DataManagerContext_1.default.Provider, { value: {
|
|
292
293
|
items: passedActiveItems,
|
|
@@ -316,6 +317,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
316
317
|
readNavigationItemFromLocale,
|
|
317
318
|
handleNavigationsDeletion,
|
|
318
319
|
hardReset,
|
|
320
|
+
slugify,
|
|
319
321
|
} }, isLoading ? react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null) : children));
|
|
320
322
|
};
|
|
321
323
|
DataManagerProvider.propTypes = {
|
|
@@ -64,6 +64,7 @@ const CustomFieldForm = ({ isEditForm, customField, onSubmit, onClose, usedCusto
|
|
|
64
64
|
required: customField.required || formDefinition.defaultValues.required,
|
|
65
65
|
options: customField.options || formDefinition.defaultValues.options,
|
|
66
66
|
multi: customField.multi || formDefinition.defaultValues.multi,
|
|
67
|
+
enabled: customField.enabled,
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
else {
|
|
@@ -74,6 +75,7 @@ const CustomFieldForm = ({ isEditForm, customField, onSubmit, onClose, usedCusto
|
|
|
74
75
|
required: customField.required || formDefinition.defaultValues.required,
|
|
75
76
|
options: [],
|
|
76
77
|
multi: false,
|
|
78
|
+
enabled: customField.enabled,
|
|
77
79
|
};
|
|
78
80
|
}
|
|
79
81
|
}, [customField]);
|
|
@@ -83,6 +83,7 @@ const SettingsPage = () => {
|
|
|
83
83
|
const formikInitialValues = (0, react_1.useMemo)(() => ({
|
|
84
84
|
allowedLevels: (0, lodash_1.get)(navigationConfigData, "allowedLevels", 2),
|
|
85
85
|
audienceFieldChecked: (0, lodash_1.get)(navigationConfigData, "additionalFields", []).includes(utils_1.navigationItemAdditionalFields.AUDIENCE),
|
|
86
|
+
cascadeMenuAttachedChecked: (0, lodash_1.get)(navigationConfigData, "cascadeMenuAttached", true),
|
|
86
87
|
i18nEnabled: (0, lodash_1.get)(navigationConfigData, "i18nEnabled", false),
|
|
87
88
|
nameFields: (0, lodash_1.get)(navigationConfigData, "contentTypesNameFields", {}),
|
|
88
89
|
pathDefaultFields: (0, lodash_1.get)(navigationConfigData, "pathDefaultFields", {}),
|
|
@@ -97,9 +98,10 @@ const SettingsPage = () => {
|
|
|
97
98
|
?.filter((field) => field !== utils_1.navigationItemAdditionalFields.AUDIENCE);
|
|
98
99
|
setCustomFields(additionalFields || []);
|
|
99
100
|
}, [navigationConfigData]);
|
|
100
|
-
const preparePayload = (0, react_1.useCallback)(({ form: { allowedLevels, audienceFieldChecked, i18nEnabled, nameFields, pathDefaultFields, populate, selectedContentTypes, }, pruneObsoleteI18nNavigations }) => ({
|
|
101
|
+
const preparePayload = (0, react_1.useCallback)(({ form: { allowedLevels, audienceFieldChecked, cascadeMenuAttachedChecked, i18nEnabled, nameFields, pathDefaultFields, populate, selectedContentTypes, }, pruneObsoleteI18nNavigations }) => ({
|
|
101
102
|
additionalFields: audienceFieldChecked ? ['audience', ...customFields] : [...customFields],
|
|
102
103
|
allowedLevels,
|
|
104
|
+
cascadeMenuAttached: cascadeMenuAttachedChecked,
|
|
103
105
|
contentTypes: selectedContentTypes,
|
|
104
106
|
contentTypesNameFields: nameFields,
|
|
105
107
|
contentTypesPopulate: populate,
|
|
@@ -158,7 +160,7 @@ const SettingsPage = () => {
|
|
|
158
160
|
react_1.default.createElement(helper_plugin_1.SettingsPageTitle, { name: (0, utils_2.getMessage)('Settings.email.plugin.title', 'Configuration') }),
|
|
159
161
|
react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null, "Fetching plugin config...")));
|
|
160
162
|
}
|
|
161
|
-
const allContentTypes = !isLoading ? Object.values(allContentTypesData).filter(({ uid }) => (0, functions_1.isContentTypeEligible)(uid, {
|
|
163
|
+
const allContentTypes = !isLoading ? (0, lodash_1.sortBy)(Object.values(allContentTypesData).filter(({ uid }) => (0, functions_1.isContentTypeEligible)(uid, {
|
|
162
164
|
allowedContentTypes: navigationConfigData?.allowedContentTypes,
|
|
163
165
|
restrictedContentTypes: navigationConfigData?.restrictedContentTypes,
|
|
164
166
|
})).map(ct => {
|
|
@@ -172,7 +174,7 @@ const SettingsPage = () => {
|
|
|
172
174
|
};
|
|
173
175
|
}
|
|
174
176
|
return ct;
|
|
175
|
-
}) : [];
|
|
177
|
+
}), ct => ct.info.displayName) : [];
|
|
176
178
|
const isI18NPluginEnabled = navigationConfigData?.isI18NPluginEnabled;
|
|
177
179
|
const defaultLocale = navigationConfigData?.defaultLocale;
|
|
178
180
|
const handleSubmitCustomField = (field) => {
|
|
@@ -221,9 +223,10 @@ const SettingsPage = () => {
|
|
|
221
223
|
const contentType = allContentTypes.find(item => item.uid == uid);
|
|
222
224
|
if (!contentType)
|
|
223
225
|
return;
|
|
224
|
-
const {
|
|
225
|
-
const
|
|
226
|
-
const
|
|
226
|
+
const { info: { displayName }, available, isSingle } = contentType;
|
|
227
|
+
const attributeKeys = Object.keys(contentType.attributes).sort();
|
|
228
|
+
const stringAttributes = attributeKeys.filter(key => STRING_ATTRIBUTE_TYPES.includes(contentType.attributes[key].type));
|
|
229
|
+
const relationAttributes = attributeKeys.filter(key => RELATION_ATTRIBUTE_TYPES.includes(contentType.attributes[key].type));
|
|
227
230
|
const key = `collectionSettings-${uid}`;
|
|
228
231
|
return (react_1.default.createElement(Accordion_1.Accordion, { expanded: contentTypeExpanded === key, toggle: () => handleSetContentTypeExpanded(key), key: key, id: key, size: "S" },
|
|
229
232
|
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 }),
|
|
@@ -239,8 +242,14 @@ const SettingsPage = () => {
|
|
|
239
242
|
react_1.default.createElement(Stack_1.Stack, { size: 4 },
|
|
240
243
|
react_1.default.createElement(Typography_1.Typography, { variant: "delta", as: "h2" }, (0, utils_2.getMessage)('pages.settings.additional.title')),
|
|
241
244
|
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
242
|
-
react_1.default.createElement(Grid_1.GridItem, { col:
|
|
243
|
-
react_1.default.createElement(
|
|
245
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 4, s: 6, xs: 12 },
|
|
246
|
+
react_1.default.createElement(Box_1.Box, { style: { maxWidth: 257 } },
|
|
247
|
+
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 }))),
|
|
248
|
+
react_1.default.createElement(Grid_1.GridItem, { col: 4, s: 12, xs: 12 },
|
|
249
|
+
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 } }) => {
|
|
250
|
+
setFieldValue('cascadeMenuAttachedChecked', checked, true);
|
|
251
|
+
}, onLabel: "Enabled", offLabel: "Disabled", disabled: restartStatus.required }))),
|
|
252
|
+
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
244
253
|
react_1.default.createElement(Grid_1.GridItem, { col: 4, s: 12, xs: 12 },
|
|
245
254
|
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 })),
|
|
246
255
|
isI18NPluginEnabled && (react_1.default.createElement(Grid_1.GridItem, { col: 4, s: 12, xs: 12 },
|
|
@@ -3,6 +3,7 @@ import { Effect, NavigationPluginConfig } from "../../../../types";
|
|
|
3
3
|
export declare type RawPayload = {
|
|
4
4
|
allowedLevels: number;
|
|
5
5
|
audienceFieldChecked: boolean;
|
|
6
|
+
cascadeMenuAttachedChecked: boolean;
|
|
6
7
|
i18nEnabled: boolean;
|
|
7
8
|
nameFields: Record<string, string[]>;
|
|
8
9
|
pathDefaultFields: Record<string, string[]>;
|
|
@@ -18,7 +19,7 @@ export declare type StrapiContentTypeSchema = StrapiContentTypeFullSchema & {
|
|
|
18
19
|
export declare type PreparePayload = (payload: {
|
|
19
20
|
form: RawPayload;
|
|
20
21
|
pruneObsoleteI18nNavigations: boolean;
|
|
21
|
-
}) =>
|
|
22
|
+
}) => NavigationPluginConfig;
|
|
22
23
|
export declare type OnSave = Effect<RawPayload>;
|
|
23
24
|
export declare type OnPopupClose = Effect<boolean>;
|
|
24
25
|
export declare type HandleSetContentTypeExpanded = Effect<string | undefined>;
|
|
@@ -6,6 +6,7 @@ export declare const schemaFactory: (usedCustomFieldNames: string[]) => import("
|
|
|
6
6
|
required: import("yup/lib/boolean").RequiredBooleanSchema<boolean | undefined, Record<string, any>>;
|
|
7
7
|
multi: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
8
8
|
options: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
9
|
+
enabled: import("yup").BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
9
10
|
}, Record<string, any>, import("yup/lib/object").TypeOfShape<{
|
|
10
11
|
name: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
11
12
|
label: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
@@ -13,6 +14,7 @@ export declare const schemaFactory: (usedCustomFieldNames: string[]) => import("
|
|
|
13
14
|
required: import("yup/lib/boolean").RequiredBooleanSchema<boolean | undefined, Record<string, any>>;
|
|
14
15
|
multi: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
15
16
|
options: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
17
|
+
enabled: import("yup").BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
16
18
|
}>>;
|
|
17
19
|
export declare const defaultValues: NavigationItemCustomField;
|
|
18
20
|
//# sourceMappingURL=form.d.ts.map
|
|
@@ -19,7 +19,8 @@ const schemaFactory = (usedCustomFieldNames) => {
|
|
|
19
19
|
is: (val) => val === 'select',
|
|
20
20
|
then: (0, yup_1.array)().of((0, yup_1.string)()),
|
|
21
21
|
otherwise: (0, yup_1.mixed)().notRequired(),
|
|
22
|
-
})
|
|
22
|
+
}),
|
|
23
|
+
enabled: (0, yup_1.bool)().notRequired(),
|
|
23
24
|
});
|
|
24
25
|
};
|
|
25
26
|
exports.schemaFactory = schemaFactory;
|
|
@@ -30,5 +31,6 @@ exports.defaultValues = {
|
|
|
30
31
|
required: false,
|
|
31
32
|
multi: false,
|
|
32
33
|
options: [],
|
|
34
|
+
enabled: true,
|
|
33
35
|
};
|
|
34
36
|
//# sourceMappingURL=form.js.map
|
|
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
30
|
const lodash_1 = require("lodash");
|
|
31
|
-
const
|
|
31
|
+
const fp_1 = require("lodash/fp");
|
|
32
32
|
const formik_1 = require("formik");
|
|
33
33
|
const ModalLayout_1 = require("@strapi/design-system/ModalLayout");
|
|
34
34
|
const Select_1 = require("@strapi/design-system/Select");
|
|
@@ -44,8 +44,7 @@ const translations_1 = require("../../../../translations");
|
|
|
44
44
|
const types_1 = require("../../../../../../types");
|
|
45
45
|
const AdditionalFieldInput_1 = __importDefault(require("../../../../components/AdditionalFieldInput"));
|
|
46
46
|
const utils_2 = require("../../../../utils");
|
|
47
|
-
const
|
|
48
|
-
const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading, inputsPrefix, data, contentTypes = [], contentTypeEntities = [], usedContentTypeEntities = [], availableAudience = [], additionalFields = [], contentTypesNameFields = {}, onSubmit, onCancel, getContentTypeEntities, usedContentTypesData, appendLabelPublicationStatus = appendLabelPublicationStatusFallback, locale, readNavigationItemFromLocale, }) => {
|
|
47
|
+
const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading, inputsPrefix, data, contentTypes = [], contentTypeEntities = [], usedContentTypeEntities = [], availableAudience = [], additionalFields = [], contentTypesNameFields = {}, onSubmit, onCancel, getContentTypeEntities, usedContentTypesData, appendLabelPublicationStatus = appendLabelPublicationStatusFallback, locale, readNavigationItemFromLocale, slugify, }) => {
|
|
49
48
|
const [isLoading, setIsLoading] = (0, react_1.useState)(isPreloading);
|
|
50
49
|
const [hasBeenInitialized, setInitializedState] = (0, react_1.useState)(false);
|
|
51
50
|
const [hasChanged, setChangedState] = (0, react_1.useState)(false);
|
|
@@ -53,8 +52,8 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
53
52
|
const [contentTypeSearchInputValue, setContentTypeSearchInputValue] = (0, react_1.useState)(undefined);
|
|
54
53
|
const formik = (0, formik_1.useFormik)({
|
|
55
54
|
initialValues: formDefinition.defaultValues,
|
|
56
|
-
onSubmit: (payload) => onSubmit(sanitizePayload(payload, data)),
|
|
57
|
-
validate: (values) => (0, form_1.checkFormValidity)(sanitizePayload(values, {}), formDefinition.schemaFactory(isSingleSelected, additionalFields)),
|
|
55
|
+
onSubmit: loadingAware(async (payload) => onSubmit(await sanitizePayload(slugify, payload, data)), setIsLoading),
|
|
56
|
+
validate: loadingAware(async (values) => (0, form_1.checkFormValidity)(await sanitizePayload(slugify, values, {}), formDefinition.schemaFactory(isSingleSelected, additionalFields)), setIsLoading),
|
|
58
57
|
validateOnChange: false,
|
|
59
58
|
});
|
|
60
59
|
const initialRelatedTypeSelected = (0, lodash_1.get)(data, 'relatedType.value');
|
|
@@ -97,7 +96,10 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
97
96
|
})), [availableAudience]);
|
|
98
97
|
const generatePreviewPath = () => {
|
|
99
98
|
if (!isExternal) {
|
|
100
|
-
const
|
|
99
|
+
const itemPath = (0, lodash_1.isEmpty)(formik.values.path) || formik.values.path === '/'
|
|
100
|
+
? getDefaultPath()
|
|
101
|
+
: formik.values.path || "";
|
|
102
|
+
const value = `${data.levelPath !== '/' ? `${data.levelPath}` : ''}/${itemPath}`;
|
|
101
103
|
return {
|
|
102
104
|
id: (0, translations_1.getTradId)('popup.item.form.type.external.description'),
|
|
103
105
|
defaultMessage: '',
|
|
@@ -117,7 +119,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
117
119
|
}, contentTypesNameFields, { contentTypes });
|
|
118
120
|
}
|
|
119
121
|
}, [contentTypeEntities, contentTypesNameFields, contentTypes]);
|
|
120
|
-
const sanitizePayload = (payload, data) => {
|
|
122
|
+
const sanitizePayload = async (slugify, payload, data) => {
|
|
121
123
|
const { related, relatedType, menuAttached, type, ...purePayload } = payload;
|
|
122
124
|
const relatedId = related;
|
|
123
125
|
const singleRelatedItem = isSingleSelected ? (0, lodash_1.first)(contentTypeEntities) : undefined;
|
|
@@ -125,6 +127,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
125
127
|
const title = !!payload.title?.trim()
|
|
126
128
|
? payload.title
|
|
127
129
|
: getDefaultTitle(related, relatedType, isSingleSelected);
|
|
130
|
+
const uiRouterKey = await generateUiRouterKey(slugify, title, relatedId, relatedCollectionType);
|
|
128
131
|
return {
|
|
129
132
|
...data,
|
|
130
133
|
...purePayload,
|
|
@@ -137,7 +140,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
137
140
|
relatedType: type === utils_1.navigationItemType.INTERNAL ? relatedCollectionType : undefined,
|
|
138
141
|
isSingle: isSingleSelected,
|
|
139
142
|
singleRelatedItem,
|
|
140
|
-
uiRouterKey
|
|
143
|
+
uiRouterKey,
|
|
141
144
|
};
|
|
142
145
|
};
|
|
143
146
|
const onChange = ({ name, value }) => {
|
|
@@ -159,11 +162,13 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
159
162
|
(0, types_1.assertString)(relatedTypeSelectValue);
|
|
160
163
|
const pathDefaultFields = (0, lodash_1.get)(config, ["pathDefaultFields", relatedTypeSelectValue], []);
|
|
161
164
|
if ((0, lodash_1.isEmpty)(formik.values.path) && !(0, lodash_1.isEmpty)(pathDefaultFields)) {
|
|
162
|
-
const selectedEntity =
|
|
165
|
+
const selectedEntity = isSingleSelected
|
|
166
|
+
? (0, lodash_1.first)(contentTypeEntities)
|
|
167
|
+
: contentTypeEntities.find(i => i.id === relatedSelectValue);
|
|
163
168
|
const pathDefaultValues = pathDefaultFields
|
|
164
169
|
.map((field) => (0, lodash_1.get)(selectedEntity, field, ""))
|
|
165
170
|
.filter(value => !(0, lodash_1.isNil)(value) && String(value).match(/^\S+$/));
|
|
166
|
-
return String((0, lodash_1.first)(pathDefaultValues));
|
|
171
|
+
return String((0, lodash_1.first)(pathDefaultValues) || "");
|
|
167
172
|
}
|
|
168
173
|
return "";
|
|
169
174
|
}, [relatedTypeSelectValue, formik, config]);
|
|
@@ -178,17 +183,16 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
178
183
|
value,
|
|
179
184
|
});
|
|
180
185
|
};
|
|
181
|
-
const generateUiRouterKey = (title, related, relatedType) => {
|
|
182
|
-
const { slugify: customSlugifyConfig } = config;
|
|
186
|
+
const generateUiRouterKey = async (slugify, title, related, relatedType) => {
|
|
183
187
|
if (title) {
|
|
184
|
-
return (0, lodash_1.isString)(title) && !(0, lodash_1.isEmpty)(title) ? (0,
|
|
188
|
+
return (0, lodash_1.isString)(title) && !(0, lodash_1.isEmpty)(title) ? await slugify(title).then((0, fp_1.prop)("slug")) : undefined;
|
|
185
189
|
}
|
|
186
190
|
else if (related) {
|
|
187
191
|
const relationTitle = (0, parsers_1.extractRelatedItemLabel)({
|
|
188
192
|
...contentTypeEntities.find(_ => _.id === related),
|
|
189
193
|
__collectionUid: relatedType
|
|
190
194
|
}, contentTypesNameFields, { contentTypes });
|
|
191
|
-
return (0, lodash_1.isString)(relationTitle) && !(0, lodash_1.isEmpty)(relationTitle) ? (0,
|
|
195
|
+
return (0, lodash_1.isString)(relationTitle) && !(0, lodash_1.isEmpty)(relationTitle) ? await slugify(relationTitle).then((0, fp_1.prop)("slug")) : undefined;
|
|
192
196
|
}
|
|
193
197
|
return undefined;
|
|
194
198
|
};
|
|
@@ -206,7 +210,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
206
210
|
}
|
|
207
211
|
};
|
|
208
212
|
});
|
|
209
|
-
const relatedSelectOptions = contentTypeEntities
|
|
213
|
+
const relatedSelectOptions = (0, lodash_1.sortBy)(contentTypeEntities
|
|
210
214
|
.filter((item) => {
|
|
211
215
|
const usedContentTypeEntitiesOfSameType = usedContentTypeEntities
|
|
212
216
|
.filter(uctItem => relatedTypeSelectValue === uctItem.__collectionUid);
|
|
@@ -228,10 +232,10 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
228
232
|
value: item.id,
|
|
229
233
|
label: label,
|
|
230
234
|
});
|
|
231
|
-
});
|
|
235
|
+
}), item => item.metadatas.intlLabel.id);
|
|
232
236
|
const isExternal = formik.values.type === utils_1.navigationItemType.EXTERNAL;
|
|
233
237
|
const pathSourceName = isExternal ? 'externalPath' : 'path';
|
|
234
|
-
const submitDisabled = (formik.values.type === utils_1.navigationItemType.INTERNAL && !isSingleSelected && (0, lodash_1.isNil)(formik.values.related));
|
|
238
|
+
const submitDisabled = (formik.values.type === utils_1.navigationItemType.INTERNAL && !isSingleSelected && (0, lodash_1.isNil)(formik.values.related)) || isLoading;
|
|
235
239
|
const debouncedSearch = (0, react_1.useCallback)((0, lodash_1.debounce)(nextValue => setContentTypeSearchQuery(nextValue), 500), []);
|
|
236
240
|
const debounceContentTypeSearchQuery = (value) => {
|
|
237
241
|
setContentTypeSearchInputValue(value);
|
|
@@ -251,7 +255,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
251
255
|
setChangedState(true);
|
|
252
256
|
}
|
|
253
257
|
};
|
|
254
|
-
const relatedTypeSelectOptions = (0, react_1.useMemo)(() => contentTypes
|
|
258
|
+
const relatedTypeSelectOptions = (0, react_1.useMemo)(() => (0, lodash_1.sortBy)(contentTypes
|
|
255
259
|
.filter((contentType) => {
|
|
256
260
|
if (contentType.isSingle) {
|
|
257
261
|
if (relatedTypeSelectValue && [relatedTypeSelectValue, initialRelatedTypeSelected].includes(contentType.uid)) {
|
|
@@ -271,7 +275,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
271
275
|
},
|
|
272
276
|
value: (0, lodash_1.get)(item, 'uid'),
|
|
273
277
|
label: (0, lodash_1.get)(item, 'label', (0, lodash_1.get)(item, 'name')),
|
|
274
|
-
})), [contentTypes, usedContentTypesData, relatedTypeSelectValue]);
|
|
278
|
+
})), item => item.metadatas.intlLabel.id), [contentTypes, usedContentTypesData, relatedTypeSelectValue]);
|
|
275
279
|
const thereAreNoMoreContentTypes = (0, lodash_1.isEmpty)(relatedSelectOptions) && !contentTypeSearchQuery;
|
|
276
280
|
(0, react_1.useEffect)(() => {
|
|
277
281
|
const value = (0, lodash_1.get)(relatedSelectOptions, '0');
|
|
@@ -380,7 +384,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
380
384
|
react_1.default.createElement(Grid_1.GridItem, { key: "type", col: 4, lg: 12 },
|
|
381
385
|
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.type.label', 'Internal link'), name: "type", options: navigationItemTypeOptions, type: "select", error: formik.errors.type, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.type })),
|
|
382
386
|
react_1.default.createElement(Grid_1.GridItem, { key: "menuAttached", col: 4, lg: 12 },
|
|
383
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.menuAttached.label', 'MenuAttached'), name: "menuAttached", type: "bool", error: formik.errors.menuAttached, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.menuAttached, disabled: !(data.isMenuAllowedLevel && data.parentAttachedToMenu) })),
|
|
387
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.menuAttached.label', 'MenuAttached'), name: "menuAttached", type: "bool", error: formik.errors.menuAttached, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.menuAttached, disabled: config.cascadeMenuAttached ? !(data.isMenuAllowedLevel && data.parentAttachedToMenu) : false })),
|
|
384
388
|
react_1.default.createElement(Grid_1.GridItem, { key: "path", col: 12 },
|
|
385
389
|
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", error: formik.errors[pathSourceName], onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values[pathSourceName], description: generatePreviewPath() })),
|
|
386
390
|
formik.values.type === utils_1.navigationItemType.INTERNAL && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
@@ -415,5 +419,17 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
415
419
|
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: onCopyFromLocale, disabled: isLoading || !itemLocaleCopyValue }, (0, utils_2.getMessage)('popup.item.form.i18n.locale.button'))))) : null)),
|
|
416
420
|
react_1.default.createElement(NavigationItemPopupFooter_1.NavigationItemPopupFooter, { handleSubmit: formik.handleSubmit, handleCancel: onCancel, submitDisabled: submitDisabled })));
|
|
417
421
|
};
|
|
422
|
+
const appendLabelPublicationStatusFallback = () => "";
|
|
423
|
+
const loadingAware = (action, isLoading) => async (input) => {
|
|
424
|
+
try {
|
|
425
|
+
isLoading(true);
|
|
426
|
+
return await action(input);
|
|
427
|
+
}
|
|
428
|
+
catch (_) {
|
|
429
|
+
}
|
|
430
|
+
finally {
|
|
431
|
+
isLoading(false);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
418
434
|
exports.default = NavigationItemForm;
|
|
419
435
|
//# sourceMappingURL=index.js.map
|
|
@@ -60,6 +60,9 @@ export declare type NavigationItemFormProps = {
|
|
|
60
60
|
availableLocale: string[];
|
|
61
61
|
readNavigationItemFromLocale: ToBeFixed;
|
|
62
62
|
inputsPrefix: string;
|
|
63
|
+
slugify: (q: string) => Promise<{
|
|
64
|
+
slug: string;
|
|
65
|
+
}>;
|
|
63
66
|
};
|
|
64
67
|
export declare type ContentTypeSearchQuery = ToBeFixed;
|
|
65
68
|
export declare type RawFormPayload = {
|
|
@@ -86,5 +89,8 @@ export declare type SanitizedFormPayload = {
|
|
|
86
89
|
singleRelatedItem: ContentTypeEntity | undefined;
|
|
87
90
|
uiRouterKey: string | undefined;
|
|
88
91
|
};
|
|
92
|
+
export declare type Slugify = (q: string) => Promise<{
|
|
93
|
+
slug: string;
|
|
94
|
+
}>;
|
|
89
95
|
export {};
|
|
90
96
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -67,13 +67,13 @@ const schemaFactory = (isSingleSelected, additionalFields) => {
|
|
|
67
67
|
relatedType: yup.mixed()
|
|
68
68
|
.when('type', {
|
|
69
69
|
is: (val) => val === utils_1.navigationItemType.INTERNAL || (0, lodash_1.isNil)(val),
|
|
70
|
-
then:
|
|
70
|
+
then: yup.string().required(helper_plugin_1.translatedErrors.required).min(1, helper_plugin_1.translatedErrors.required),
|
|
71
71
|
otherwise: yup.mixed().notRequired(),
|
|
72
72
|
}),
|
|
73
73
|
related: yup.mixed()
|
|
74
74
|
.when('type', {
|
|
75
75
|
is: (val) => val === utils_1.navigationItemType.INTERNAL || (0, lodash_1.isNil)(val),
|
|
76
|
-
then: isSingleSelected ? yup.mixed().notRequired() : yup.
|
|
76
|
+
then: isSingleSelected ? yup.mixed().notRequired() : yup.string().required(helper_plugin_1.translatedErrors.required).min(1, helper_plugin_1.translatedErrors.required),
|
|
77
77
|
otherwise: yup.mixed().notRequired(),
|
|
78
78
|
}),
|
|
79
79
|
additionalFields: yup.object({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default NavigationItemPopUp;
|
|
2
|
-
declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data, config, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, }: {
|
|
2
|
+
declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data, config, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, slugify, }: {
|
|
3
3
|
availableLocale: any;
|
|
4
4
|
isOpen: any;
|
|
5
5
|
isLoading: any;
|
|
@@ -12,6 +12,7 @@ declare function NavigationItemPopUp({ availableLocale, isOpen, isLoading, data,
|
|
|
12
12
|
usedContentTypesData: any;
|
|
13
13
|
locale: any;
|
|
14
14
|
readNavigationItemFromLocale: any;
|
|
15
|
+
slugify: any;
|
|
15
16
|
}): JSX.Element;
|
|
16
17
|
declare namespace NavigationItemPopUp {
|
|
17
18
|
namespace propTypes {
|
|
@@ -24,6 +25,7 @@ declare namespace NavigationItemPopUp {
|
|
|
24
25
|
const getContentTypeItems: PropTypes.Validator<(...args: any[]) => any>;
|
|
25
26
|
const locale: PropTypes.Requireable<string>;
|
|
26
27
|
const readNavigationItemFromLocale: PropTypes.Validator<(...args: any[]) => any>;
|
|
28
|
+
const slugify: PropTypes.Validator<(...args: any[]) => any>;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
import PropTypes from "prop-types";
|
|
@@ -34,7 +34,7 @@ const NavigationItemForm_1 = __importDefault(require("../NavigationItemForm"));
|
|
|
34
34
|
const parsers_1 = require("../../utils/parsers");
|
|
35
35
|
const NavigationItemPopupHeader_1 = require("./NavigationItemPopupHeader");
|
|
36
36
|
const utils_1 = require("../../../../utils");
|
|
37
|
-
const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config = {}, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, }) => {
|
|
37
|
+
const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config = {}, onSubmit, onClose, usedContentTypeItems, getContentTypeItems, usedContentTypesData, locale, readNavigationItemFromLocale, slugify, }) => {
|
|
38
38
|
const handleOnSubmit = (payload) => {
|
|
39
39
|
onSubmit(payload);
|
|
40
40
|
};
|
|
@@ -71,7 +71,7 @@ const NavigationItemPopUp = ({ availableLocale, isOpen, isLoading, data, config
|
|
|
71
71
|
const hasViewId = !!data.viewId;
|
|
72
72
|
return (react_1.default.createElement(ModalLayout_1.ModalLayout, { labelledBy: "condition-modal-breadcrumbs", onClose: onClose, isOpen: isOpen },
|
|
73
73
|
react_1.default.createElement(NavigationItemPopupHeader_1.NavigationItemPopupHeader, { isNewItem: !hasViewId }),
|
|
74
|
-
react_1.default.createElement(NavigationItemForm_1.default, { availableLocale: availableLocale, config: config, data: preparedData, isLoading: isLoading, additionalFields: additionalFields, contentTypesNameFields: contentTypesNameFields, availableAudience: availableAudience, contentTypes: contentTypes, contentTypeEntities: contentTypeItems, usedContentTypeEntities: usedContentTypeItems, getContentTypeEntities: getContentTypeItems, usedContentTypesData: usedContentTypesData, onSubmit: handleOnSubmit, onCancel: onClose, appendLabelPublicationStatus: appendLabelPublicationStatus, locale: locale, readNavigationItemFromLocale: readNavigationItemFromLocale })));
|
|
74
|
+
react_1.default.createElement(NavigationItemForm_1.default, { availableLocale: availableLocale, config: config, data: preparedData, isLoading: isLoading, additionalFields: additionalFields, contentTypesNameFields: contentTypesNameFields, availableAudience: availableAudience, contentTypes: contentTypes, contentTypeEntities: contentTypeItems, usedContentTypeEntities: usedContentTypeItems, getContentTypeEntities: getContentTypeItems, usedContentTypesData: usedContentTypesData, onSubmit: handleOnSubmit, onCancel: onClose, appendLabelPublicationStatus: appendLabelPublicationStatus, locale: locale, readNavigationItemFromLocale: readNavigationItemFromLocale, slugify: slugify })));
|
|
75
75
|
};
|
|
76
76
|
NavigationItemPopUp.propTypes = {
|
|
77
77
|
data: prop_types_1.default.object.isRequired,
|
|
@@ -83,6 +83,7 @@ NavigationItemPopUp.propTypes = {
|
|
|
83
83
|
getContentTypeItems: prop_types_1.default.func.isRequired,
|
|
84
84
|
locale: prop_types_1.default.string,
|
|
85
85
|
readNavigationItemFromLocale: prop_types_1.default.func.isRequired,
|
|
86
|
+
slugify: prop_types_1.default.func.isRequired,
|
|
86
87
|
};
|
|
87
88
|
exports.default = NavigationItemPopUp;
|
|
88
89
|
//# sourceMappingURL=index.js.map
|
|
@@ -50,7 +50,8 @@ const useDataManager_1 = __importDefault(require("../../hooks/useDataManager"));
|
|
|
50
50
|
const translations_1 = require("../../translations");
|
|
51
51
|
const parsers_1 = require("./utils/parsers");
|
|
52
52
|
const View = () => {
|
|
53
|
-
const
|
|
53
|
+
const toggleNotification = (0, helper_plugin_1.useNotification)();
|
|
54
|
+
const { items: availableNavigations, activeItem: activeNavigation, changedActiveItem: changedActiveNavigation, config, navigationItemPopupOpened, isLoading, isLoadingForAdditionalDataToBeSet, isLoadingForSubmit, handleChangeNavigationItemPopupVisibility, handleChangeSelection, handleChangeNavigationData, handleResetNavigationData, handleSubmitNavigation, handleLocalizationSelection, handleI18nCopy, getContentTypeItems, error, availableLocale: allAvailableLocale, readNavigationItemFromLocale, slugify, } = (0, useDataManager_1.default)();
|
|
54
55
|
const availableLocale = (0, react_1.useMemo)(() => allAvailableLocale.filter(locale => locale !== changedActiveNavigation?.localeCode), [changedActiveNavigation, allAvailableLocale]);
|
|
55
56
|
const { i18nCopyItemsModal, i18nCopySourceLocale, setI18nCopyModalOpened, setI18nCopySourceLocale } = (0, useI18nCopyNavigationItemsModal_1.useI18nCopyNavigationItemsModal)((0, react_1.useCallback)((sourceLocale) => {
|
|
56
57
|
const source = activeNavigation?.localizations?.find(({ localeCode }) => localeCode === sourceLocale);
|
|
@@ -65,6 +66,10 @@ const View = () => {
|
|
|
65
66
|
const [structureChanged, setStructureChanged] = (0, react_1.useState)(false);
|
|
66
67
|
const isSearchEmpty = (0, lodash_1.isEmpty)(searchValue);
|
|
67
68
|
const structureHasErrors = !(0, parsers_1.validateNavigationStructure)((changedActiveNavigation || {}).items);
|
|
69
|
+
(0, react_1.useEffect)(() => structureHasErrors && toggleNotification({
|
|
70
|
+
type: 'warning',
|
|
71
|
+
message: (0, translations_1.getTrad)('notification.error.item.relation'),
|
|
72
|
+
}), [structureHasErrors]);
|
|
68
73
|
const navigationSelectValue = (0, lodash_1.get)(activeNavigation, "id", null);
|
|
69
74
|
const handleSave = () => isLoadingForSubmit || structureHasErrors
|
|
70
75
|
? null
|
|
@@ -227,7 +232,7 @@ const View = () => {
|
|
|
227
232
|
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: openI18nCopyModalOpened, disabled: !i18nCopySourceLocale, size: "S" }, formatMessage((0, translations_1.getTrad)('view.i18n.fill.cta.button'))))))) : null)),
|
|
228
233
|
!(0, lodash_1.isEmpty)(changedActiveNavigation.items || [])
|
|
229
234
|
&& react_1.default.createElement(NavigationItemList_1.default, { items: isSearchEmpty ? changedActiveNavigation.items || [] : filteredList, onItemLevelAdd: addNewNavigationItem, onItemRemove: handleItemRemove, onItemEdit: handleItemEdit, onItemRestore: handleItemRestore, onItemReOrder: handleItemReOrder, onItemToggleCollapse: handleItemToggleCollapse, displayFlat: !isSearchEmpty, root: true, error: error, allowedLevels: config.allowedLevels, contentTypes: config.contentTypes, isParentAttachedToMenu: true, contentTypesNameFields: config.contentTypesNameFields })))),
|
|
230
|
-
navigationItemPopupOpened && react_1.default.createElement(NavigationItemPopup_1.default, { availableLocale: availableLocale, isLoading: isLoadingForAdditionalDataToBeSet, data: activeNavigationItem, config: config, usedContentTypesData: usedContentTypesData, usedContentTypeItems: usedContentTypeItems, getContentTypeItems: getContentTypeItems, onSubmit: handleSubmitNavigationItem, onClose: onPopUpClose, locale: activeNavigation.localeCode, readNavigationItemFromLocale: readNavigationItemFromLocale }),
|
|
235
|
+
navigationItemPopupOpened && react_1.default.createElement(NavigationItemPopup_1.default, { availableLocale: availableLocale, isLoading: isLoadingForAdditionalDataToBeSet, data: activeNavigationItem, config: config, usedContentTypesData: usedContentTypesData, usedContentTypeItems: usedContentTypeItems, getContentTypeItems: getContentTypeItems, onSubmit: handleSubmitNavigationItem, onClose: onPopUpClose, locale: activeNavigation.localeCode, readNavigationItemFromLocale: readNavigationItemFromLocale, slugify: slugify }),
|
|
231
236
|
i18nCopyItemsModal));
|
|
232
237
|
};
|
|
233
238
|
exports.default = (0, react_1.memo)(View);
|
|
@@ -14,7 +14,7 @@ const transformItemToRESTPayload = (item, parent = undefined, master = undefined
|
|
|
14
14
|
const relatedContentType = relatedType ?
|
|
15
15
|
(0, lodash_1.find)(contentTypes, ct => ct.uid === relatedType) :
|
|
16
16
|
undefined;
|
|
17
|
-
const itemAttachedToMenu = menuAttached && parentAttachedToMenu;
|
|
17
|
+
const itemAttachedToMenu = config.cascadeMenuAttached ? menuAttached && parentAttachedToMenu : menuAttached;
|
|
18
18
|
return {
|
|
19
19
|
id,
|
|
20
20
|
parent,
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"notification.navigation.item.relation.status.published": "published",
|
|
83
83
|
"notification.error": "Error while processing request.",
|
|
84
84
|
"notification.error.customField.type": "Unsupported type of custom field",
|
|
85
|
+
"notification.error.item.relation": "Relations provided in some items are incorrect",
|
|
85
86
|
"pages.main.search.placeholder": "Type to start searching...",
|
|
86
87
|
"pages.main.header.localization.select.placeholder": "Select locale",
|
|
87
88
|
"pages.settings.general.title": "General settings",
|
|
@@ -122,6 +123,8 @@
|
|
|
122
123
|
"pages.settings.notification.submit.error": "Config update has failed",
|
|
123
124
|
"pages.settings.notification.restore.error": "Config restore has failed",
|
|
124
125
|
"pages.settings.notification.restart.error": "Failed to restart your application. Try to do it manually.",
|
|
126
|
+
"pages.settings.form.cascadeMenuAttached.label": "Cascade menu attached",
|
|
127
|
+
"pages.settings.form.cascadeMenuAttached.hint": "Disable if you don't want \"Menu attached\" to cascade on child items",
|
|
125
128
|
"pages.settings.form.contentTypes.label": "Enable navigation for",
|
|
126
129
|
"pages.settings.form.i18n.label": "i18n",
|
|
127
130
|
"pages.settings.form.i18n.hint": "Enable internationalisation",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-navigation",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0-beta.0",
|
|
4
4
|
"description": "Strapi - Navigation plugin",
|
|
5
5
|
"strapi": {
|
|
6
6
|
"name": "navigation",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"scripts": {},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@sindresorhus/slugify": "1.1.0",
|
|
18
|
-
"@strapi/utils": "^4.3.
|
|
18
|
+
"@strapi/utils": "^4.3.8",
|
|
19
19
|
"lodash": "^4.17.11",
|
|
20
20
|
"pluralize": "^8.0.0",
|
|
21
21
|
"react": "^16.9.0",
|
package/server/config/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.configSetupStrategy = void 0;
|
|
4
|
-
const lodash_1 = require("lodash");
|
|
5
4
|
const types_1 = require("../../types");
|
|
6
5
|
const utils_1 = require("../utils");
|
|
7
6
|
const configSetupStrategy = async ({ strapi }) => {
|
|
@@ -23,9 +22,9 @@ const configSetupStrategy = async ({ strapi }) => {
|
|
|
23
22
|
allowedLevels: getWithFallback("allowedLevels"),
|
|
24
23
|
gql: getWithFallback("gql"),
|
|
25
24
|
i18nEnabled: hasI18nPlugin && getWithFallback("i18nEnabled"),
|
|
26
|
-
slugify: (0, lodash_1.pick)(getWithFallback("slugify"), validSlugifyFields),
|
|
27
25
|
pruneObsoleteI18nNavigations: false,
|
|
28
26
|
pathDefaultFields: getWithFallback("pathDefaultFields"),
|
|
27
|
+
cascadeMenuAttached: getWithFallback("cascadeMenuAttached"),
|
|
29
28
|
};
|
|
30
29
|
(0, utils_1.validateAdditionalFields)(config.additionalFields);
|
|
31
30
|
await pluginStore.set({
|
|
@@ -40,11 +39,4 @@ const getWithFallbackFactory = (config, fallback) => (key) => {
|
|
|
40
39
|
(0, types_1.assertNotEmpty)(value, new Error(`[Navigation] Config "${key}" is undefined`));
|
|
41
40
|
return value;
|
|
42
41
|
};
|
|
43
|
-
const validSlugifyFields = [
|
|
44
|
-
"separator",
|
|
45
|
-
"lowercase",
|
|
46
|
-
"decamelize",
|
|
47
|
-
"customReplacements",
|
|
48
|
-
"preserveLeadingUnderscore",
|
|
49
|
-
];
|
|
50
42
|
//# sourceMappingURL=setupStrategy.js.map
|