strapi-plugin-navigation 2.2.14 → 2.2.16
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 +68 -1
- package/admin/src/pages/View/components/NavigationHeader/index.js +8 -1
- package/admin/src/pages/View/components/NavigationItemForm/utils/form.d.ts +6 -6
- package/admin/src/translations/ca.json +1 -0
- package/admin/src/translations/en.json +1 -0
- package/admin/src/translations/fr.json +1 -0
- package/package.json +7 -2
- package/server/controllers/client.js +15 -0
- package/server/i18n/navigationSetupStrategy.js +59 -39
- package/server/routes/client.js +8 -0
- package/server/services/admin.js +113 -56
- package/server/services/client.js +16 -0
- package/server/services/common.js +6 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/types/controllers.d.ts +1 -0
- package/types/services.d.ts +5 -1
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ Complete installation requirements are exact same as for Strapi itself and can b
|
|
|
122
122
|
|
|
123
123
|
**Supported Strapi versions**:
|
|
124
124
|
|
|
125
|
-
- Strapi v4.
|
|
125
|
+
- Strapi v4.14.x (recently tested)
|
|
126
126
|
- Strapi v4.x
|
|
127
127
|
|
|
128
128
|
> This plugin is designed for **Strapi v4** and is not working with v3.x. To get version for **Strapi v3** install version [v1.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-navigation/tree/strapi-v3).
|
|
@@ -377,6 +377,73 @@ Plugin supports both **REST API** and **GraphQL API** exposed by Strapi.
|
|
|
377
377
|
> Version `v2.0.13` introduced breaking change!
|
|
378
378
|
> All responses have changed their structure. Related field will now be of type ContentType instead of Array\<ContentType\>
|
|
379
379
|
|
|
380
|
+
`GET <host>/api/navigation/?locale=<locale>&orderBy=<orderBy>&orderDirection=<orderDirection>`
|
|
381
|
+
|
|
382
|
+
NOTE: All params are optional
|
|
383
|
+
|
|
384
|
+
**Example URL**: `https://localhost:1337/api/navigation?locale=en`
|
|
385
|
+
|
|
386
|
+
**Example response body**
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
[
|
|
390
|
+
{
|
|
391
|
+
"id": 383,
|
|
392
|
+
"name": "Floor",
|
|
393
|
+
"slug": "floor-pl",
|
|
394
|
+
"visible": true,
|
|
395
|
+
"createdAt": "2023-09-29T12:45:54.399Z",
|
|
396
|
+
"updatedAt": "2023-09-29T13:44:08.702Z",
|
|
397
|
+
"localeCode": "pl"
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
"id": 384,
|
|
401
|
+
"name": "Floor",
|
|
402
|
+
"slug": "floor-fr",
|
|
403
|
+
"visible": true,
|
|
404
|
+
"createdAt": "2023-09-29T12:45:54.399Z",
|
|
405
|
+
"updatedAt": "2023-09-29T13:44:08.725Z",
|
|
406
|
+
"localeCode": "fr"
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"id": 382,
|
|
410
|
+
"name": "Floor",
|
|
411
|
+
"slug": "floor",
|
|
412
|
+
"visible": true,
|
|
413
|
+
"createdAt": "2023-09-29T12:45:54.173Z",
|
|
414
|
+
"updatedAt": "2023-09-29T13:44:08.747Z",
|
|
415
|
+
"localeCode": "en"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"id": 374,
|
|
419
|
+
"name": "Main navigation",
|
|
420
|
+
"slug": "main-navigation-pl",
|
|
421
|
+
"visible": true,
|
|
422
|
+
"createdAt": "2023-09-29T12:22:30.373Z",
|
|
423
|
+
"updatedAt": "2023-09-29T13:44:08.631Z",
|
|
424
|
+
"localeCode": "pl"
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"id": 375,
|
|
428
|
+
"name": "Main navigation",
|
|
429
|
+
"slug": "main-navigation-fr",
|
|
430
|
+
"visible": true,
|
|
431
|
+
"createdAt": "2023-09-29T12:22:30.373Z",
|
|
432
|
+
"updatedAt": "2023-09-29T13:44:08.658Z",
|
|
433
|
+
"localeCode": "fr"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"id": 373,
|
|
437
|
+
"name": "Main navigation",
|
|
438
|
+
"slug": "main-navigation",
|
|
439
|
+
"visible": true,
|
|
440
|
+
"createdAt": "2023-09-29T12:22:30.356Z",
|
|
441
|
+
"updatedAt": "2023-09-29T13:44:08.680Z",
|
|
442
|
+
"localeCode": "en"
|
|
443
|
+
}
|
|
444
|
+
]
|
|
445
|
+
```
|
|
446
|
+
|
|
380
447
|
`GET <host>/api/navigation/render/<navigationIdOrSlug>?type=<type>`
|
|
381
448
|
|
|
382
449
|
Return a rendered navigation structure depends on passed type (`TREE`, `RFR` or nothing to render as `FLAT`).
|
|
@@ -33,6 +33,8 @@ const Stack_1 = require("@strapi/design-system/Stack");
|
|
|
33
33
|
const Button_1 = require("@strapi/design-system/Button");
|
|
34
34
|
const Check_1 = __importDefault(require("@strapi/icons/Check"));
|
|
35
35
|
const More_1 = __importDefault(require("@strapi/icons/More"));
|
|
36
|
+
const Information_1 = __importDefault(require("@strapi/icons/Information"));
|
|
37
|
+
const Tag_1 = require("@strapi/design-system/Tag");
|
|
36
38
|
const translations_1 = require("../../../../translations");
|
|
37
39
|
const styles_1 = require("./styles");
|
|
38
40
|
const Select_1 = require("@strapi/design-system/Select");
|
|
@@ -57,7 +59,12 @@ const NavigationHeader = ({ activeNavigation, availableNavigations, structureHas
|
|
|
57
59
|
const passedActiveNavigation = pickDefaultLocaleNavigation({ activeNavigation, config });
|
|
58
60
|
const { closeNavigationManagerModal, openNavigationManagerModal, navigationManagerModal } = (0, useNavigationManager_1.useNavigationManager)();
|
|
59
61
|
const { canUpdate } = permissions;
|
|
60
|
-
return (react_1.default.createElement(Layout_1.HeaderLayout, {
|
|
62
|
+
return (react_1.default.createElement(Layout_1.HeaderLayout, { secondaryAction: react_1.default.createElement(Tag_1.Tag, { icon: react_1.default.createElement(Information_1.default, { "aria-hidden": true }) }, activeNavigation
|
|
63
|
+
? formatMessage((0, translations_1.getTrad)('header.meta'), {
|
|
64
|
+
id: activeNavigation?.id,
|
|
65
|
+
key: activeNavigation?.slug
|
|
66
|
+
})
|
|
67
|
+
: null), primaryAction: react_1.default.createElement(Stack_1.Stack, { horizontal: true, size: 2 },
|
|
61
68
|
react_1.default.createElement(Box_1.Box, { marginRight: "8px" },
|
|
62
69
|
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
63
70
|
!hasLocalizations ? (react_1.default.createElement(Grid_1.GridItem, { col: 2 })) : null,
|
|
@@ -2,21 +2,21 @@ 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
|
-
title: yup.
|
|
5
|
+
title: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
6
6
|
uiRouterKey: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
7
7
|
type: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
8
|
-
path: yup.
|
|
9
|
-
externalPath: yup.
|
|
8
|
+
path: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
9
|
+
externalPath: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
10
10
|
menuAttached: yup.BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
11
11
|
relatedType: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
12
12
|
related: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
13
13
|
additionalFields: import("yup/lib/object").OptionalObjectSchema<{}, Record<string, any>, import("yup/lib/object").TypeOfShape<{}>>;
|
|
14
14
|
}, Record<string, any>, import("yup/lib/object").TypeOfShape<{
|
|
15
|
-
title: yup.
|
|
15
|
+
title: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
16
16
|
uiRouterKey: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
17
17
|
type: import("yup/lib/string").RequiredStringSchema<string | undefined, Record<string, any>>;
|
|
18
|
-
path: yup.
|
|
19
|
-
externalPath: yup.
|
|
18
|
+
path: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
19
|
+
externalPath: yup.default<string | undefined, Record<string, any>, string | undefined>;
|
|
20
20
|
menuAttached: yup.BooleanSchema<boolean | undefined, Record<string, any>, boolean | undefined>;
|
|
21
21
|
relatedType: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
22
22
|
related: import("yup/lib/mixed").MixedSchema<any, Record<string, any>, any>;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"header.action.manage": "Gestionar",
|
|
15
15
|
"header.action.newItem": "Element nou",
|
|
16
16
|
"header.description": "Definiu la vostra navegació del lloc web",
|
|
17
|
+
"header.meta": "ID: { id }, slug: { key }",
|
|
17
18
|
"header.title": "Navegació",
|
|
18
19
|
"notification.error": "S'ha produït un error en processar la sol·licitud.",
|
|
19
20
|
"notification.error.customField.type": "Tipus de camp personalitzat no compatible",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"plugin.name": "UI Navigation",
|
|
3
3
|
"header.title": "Navigation",
|
|
4
4
|
"header.description": "Define your portal navigation",
|
|
5
|
+
"header.meta": "ID: { id }, slug: { key }",
|
|
5
6
|
"header.action.newItem": "New Item",
|
|
6
7
|
"header.action.manage": "Manage",
|
|
7
8
|
"header.action.collapseAll": "Collapse All",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"plugin.name": "UI Navigation",
|
|
3
3
|
"header.title": "Navigation",
|
|
4
4
|
"header.description": "Définisser votre menu de navigation",
|
|
5
|
+
"header.meta": "ID: { id }, slug: { key }",
|
|
5
6
|
"submit.cta.cancel": "Annuler",
|
|
6
7
|
"submit.cta.save": "Sauvegarder",
|
|
7
8
|
"empty": "Le menu de navigation est vide",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-navigation",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.16",
|
|
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.
|
|
18
|
+
"@strapi/utils": "^4.14.2",
|
|
19
19
|
"lodash": "^4.17.21",
|
|
20
20
|
"pluralize": "^8.0.0",
|
|
21
21
|
"react": "^18.2.0",
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"name": "VirtusLab // Maciej Witkowski",
|
|
50
50
|
"email": "mwitkowski@virtuslab.com",
|
|
51
51
|
"url": "https://virtuslab.com"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "VirtusLab // Tomasz Puch",
|
|
55
|
+
"email": "tpuch@virtuslab.com",
|
|
56
|
+
"url": "https://virtuslab.com"
|
|
52
57
|
}
|
|
53
58
|
],
|
|
54
59
|
"engines": {
|
|
@@ -6,6 +6,21 @@ const clientControllers = {
|
|
|
6
6
|
getService(name = "client") {
|
|
7
7
|
return (0, utils_2.getPluginService)(name);
|
|
8
8
|
},
|
|
9
|
+
async readAll(ctx) {
|
|
10
|
+
const { query = {} } = ctx;
|
|
11
|
+
const { locale, orderBy, orderDirection } = query;
|
|
12
|
+
try {
|
|
13
|
+
return await this.getService().readAll({
|
|
14
|
+
locale, orderBy, orderDirection
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error instanceof Error) {
|
|
19
|
+
return ctx.badRequest(error.message);
|
|
20
|
+
}
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
9
24
|
async render(ctx) {
|
|
10
25
|
const { params, query = {} } = ctx;
|
|
11
26
|
const { type, menu: menuOnly, path: rootPath, locale, populate } = query;
|
|
@@ -4,6 +4,7 @@ exports.i18nNavigationSetupStrategy = void 0;
|
|
|
4
4
|
const types_1 = require("../../types");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const errors_1 = require("./errors");
|
|
7
|
+
const fp_1 = require("lodash/fp");
|
|
7
8
|
const i18nNavigationSetupStrategy = async ({ strapi, }) => {
|
|
8
9
|
const pluginStore = strapi.store({
|
|
9
10
|
type: "plugin",
|
|
@@ -24,48 +25,54 @@ const i18nNavigationSetupStrategy = async ({ strapi, }) => {
|
|
|
24
25
|
await createDefaultI18nNavigation({ strapi, defaultLocale }),
|
|
25
26
|
];
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
:
|
|
39
|
-
|
|
28
|
+
const noLocaleNavigations = currentNavigations.filter(hasNotAnyLocale);
|
|
29
|
+
if (noLocaleNavigations.length) {
|
|
30
|
+
await updateNavigations({
|
|
31
|
+
strapi,
|
|
32
|
+
ids: noLocaleNavigations.map((0, fp_1.prop)("id")).reduce((acc, id) => {
|
|
33
|
+
if (id && Number(id)) {
|
|
34
|
+
acc.push(Number(id));
|
|
35
|
+
}
|
|
36
|
+
return acc;
|
|
37
|
+
}, []),
|
|
38
|
+
payload: {
|
|
39
|
+
localeCode: defaultLocale,
|
|
40
|
+
},
|
|
41
|
+
populate: utils_1.DEFAULT_POPULATE,
|
|
42
|
+
});
|
|
43
|
+
currentNavigations = await getCurrentNavigations(strapi);
|
|
40
44
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const localizations = [
|
|
45
|
+
const navigationsToProcess = currentNavigations.filter(({ localeCode }) => defaultLocale === localeCode);
|
|
46
|
+
for (const rootNavigation of navigationsToProcess) {
|
|
47
|
+
let localizations = [
|
|
45
48
|
...(rootNavigation.localizations ?? []).map((localization) => (0, types_1.assertEntity)(localization, "Navigation")),
|
|
46
49
|
rootNavigation,
|
|
47
50
|
];
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
const missingLocale = allLocale.filter((locale) => !localizations.some(({ localeCode }) => localeCode === locale));
|
|
52
|
+
if (missingLocale.length) {
|
|
53
|
+
const { ids } = await createNavigations({
|
|
54
|
+
strapi,
|
|
55
|
+
payloads: missingLocale.map((locale) => ({
|
|
56
|
+
localeCode: locale,
|
|
57
|
+
slug: `${rootNavigation.slug}-${locale}`,
|
|
58
|
+
name: rootNavigation.name,
|
|
59
|
+
visible: true,
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
62
|
+
localizations = [...(await getCurrentNavigations(strapi, ids))].concat([
|
|
63
|
+
rootNavigation,
|
|
64
|
+
]);
|
|
60
65
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
for (const current of localizations) {
|
|
67
|
+
await updateNavigation({
|
|
68
|
+
strapi,
|
|
69
|
+
current,
|
|
70
|
+
payload: {
|
|
71
|
+
localizations: localizations.filter((localization) => localization.id !== current.id),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
69
76
|
}
|
|
70
77
|
else {
|
|
71
78
|
if (config.pruneObsoleteI18nNavigations) {
|
|
@@ -89,13 +96,17 @@ const i18nNavigationSetupStrategy = async ({ strapi, }) => {
|
|
|
89
96
|
return getCurrentNavigations(strapi);
|
|
90
97
|
};
|
|
91
98
|
exports.i18nNavigationSetupStrategy = i18nNavigationSetupStrategy;
|
|
92
|
-
const getCurrentNavigations = (strapi) => strapi.plugin("navigation").service("admin").get();
|
|
99
|
+
const getCurrentNavigations = (strapi, ids) => strapi.plugin("navigation").service("admin").get(ids);
|
|
93
100
|
const createNavigation = ({ strapi, payload, populate, }) => strapi.query("plugin::navigation.navigation").create({
|
|
94
101
|
data: {
|
|
95
102
|
...payload,
|
|
96
103
|
},
|
|
97
104
|
populate,
|
|
98
105
|
});
|
|
106
|
+
const createNavigations = ({ strapi, payloads, populate, }) => strapi.query("plugin::navigation.navigation").createMany({
|
|
107
|
+
data: payloads,
|
|
108
|
+
populate,
|
|
109
|
+
});
|
|
99
110
|
const updateNavigation = ({ strapi, current, payload, populate, }) => strapi.query("plugin::navigation.navigation").update({
|
|
100
111
|
data: {
|
|
101
112
|
...payload,
|
|
@@ -105,10 +116,19 @@ const updateNavigation = ({ strapi, current, payload, populate, }) => strapi.que
|
|
|
105
116
|
id: current.id,
|
|
106
117
|
},
|
|
107
118
|
});
|
|
119
|
+
const updateNavigations = ({ strapi, ids, payload, populate, }) => strapi.query("plugin::navigation.navigation").updateMany({
|
|
120
|
+
data: payload,
|
|
121
|
+
populate,
|
|
122
|
+
where: {
|
|
123
|
+
id: {
|
|
124
|
+
$in: ids,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
});
|
|
108
128
|
const deleteNavigations = ({ strapi, where, }) => strapi.query("plugin::navigation.navigation").deleteMany({
|
|
109
129
|
where,
|
|
110
130
|
});
|
|
111
|
-
const createDefaultI18nNavigation = ({ strapi, defaultLocale }) => createNavigation({
|
|
131
|
+
const createDefaultI18nNavigation = ({ strapi, defaultLocale, }) => createNavigation({
|
|
112
132
|
strapi,
|
|
113
133
|
payload: {
|
|
114
134
|
...utils_1.DEFAULT_NAVIGATION_ITEM,
|