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.
Files changed (38) hide show
  1. package/README.md +31 -5
  2. package/admin/src/pages/DataManagerProvider/index.js +2 -0
  3. package/admin/src/pages/DataManagerProvider/reducer.d.ts +1 -0
  4. package/admin/src/pages/DataManagerProvider/reducer.js +1 -0
  5. package/admin/src/pages/SettingsPage/components/CustomFieldForm/index.js +2 -0
  6. package/admin/src/pages/SettingsPage/index.js +17 -8
  7. package/admin/src/pages/SettingsPage/types.d.ts +2 -1
  8. package/admin/src/pages/SettingsPage/utils/form.d.ts +2 -0
  9. package/admin/src/pages/SettingsPage/utils/form.js +3 -1
  10. package/admin/src/pages/View/components/NavigationItemForm/index.js +36 -20
  11. package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +6 -0
  12. package/admin/src/pages/View/components/NavigationItemForm/utils/form.js +2 -2
  13. package/admin/src/pages/View/components/NavigationItemPopup/index.d.ts +3 -1
  14. package/admin/src/pages/View/components/NavigationItemPopup/index.js +3 -2
  15. package/admin/src/pages/View/index.js +7 -2
  16. package/admin/src/pages/View/utils/parsers.js +1 -1
  17. package/admin/src/translations/en.json +3 -0
  18. package/package.json +2 -2
  19. package/server/config/index.js +1 -1
  20. package/server/config/setupStrategy.js +1 -9
  21. package/server/content-types/index.d.ts +2 -0
  22. package/server/content-types/navigation/index.d.ts +1 -0
  23. package/server/content-types/navigation/schema.d.ts +1 -0
  24. package/server/content-types/navigation/schema.js +2 -1
  25. package/server/content-types/navigation-item/index.d.ts +1 -0
  26. package/server/content-types/navigation-item/schema.d.ts +1 -0
  27. package/server/content-types/navigation-item/schema.js +2 -1
  28. package/server/controllers/admin.js +13 -0
  29. package/server/index.d.ts +2 -0
  30. package/server/routes/admin.js +10 -0
  31. package/server/services/admin.js +4 -10
  32. package/server/services/client.js +10 -14
  33. package/server/services/common.js +27 -1
  34. package/strapi-server.d.ts +2 -0
  35. package/tsconfig.tsbuildinfo +1 -1
  36. package/types/config.d.ts +1 -1
  37. package/types/controllers.d.ts +5 -0
  38. package/types/services.d.ts +1 -0
@@ -67,6 +67,7 @@ declare const _default: {
67
67
  relation: string;
68
68
  target: string;
69
69
  configurable: boolean;
70
+ mappedBy: string;
70
71
  };
71
72
  localizations: {
72
73
  type: string;
@@ -167,6 +168,7 @@ declare const _default: {
167
168
  relation: string;
168
169
  target: string;
169
170
  configurable: boolean;
171
+ inversedBy: string;
170
172
  };
171
173
  audience: {
172
174
  type: string;
@@ -41,6 +41,7 @@ declare const _default: {
41
41
  relation: string;
42
42
  target: string;
43
43
  configurable: boolean;
44
+ mappedBy: string;
44
45
  };
45
46
  localizations: {
46
47
  type: string;
@@ -40,6 +40,7 @@ declare const _default: {
40
40
  relation: string;
41
41
  target: string;
42
42
  configurable: boolean;
43
+ mappedBy: string;
43
44
  };
44
45
  localizations: {
45
46
  type: string;
@@ -41,7 +41,8 @@ exports.default = {
41
41
  type: "relation",
42
42
  relation: "oneToMany",
43
43
  target: "plugin::navigation.navigation-item",
44
- configurable: false
44
+ configurable: false,
45
+ mappedBy: "master"
45
46
  },
46
47
  localizations: {
47
48
  type: "relation",
@@ -86,6 +86,7 @@ declare const _default: {
86
86
  relation: string;
87
87
  target: string;
88
88
  configurable: boolean;
89
+ inversedBy: string;
89
90
  };
90
91
  audience: {
91
92
  type: string;
@@ -85,6 +85,7 @@ declare const _default: {
85
85
  relation: string;
86
86
  target: string;
87
87
  configurable: boolean;
88
+ inversedBy: string;
88
89
  };
89
90
  audience: {
90
91
  type: string;
@@ -90,7 +90,8 @@ exports.default = {
90
90
  type: "relation",
91
91
  relation: "manyToOne",
92
92
  target: "plugin::navigation.navigation",
93
- configurable: false
93
+ configurable: false,
94
+ inversedBy: "items",
94
95
  },
95
96
  audience: {
96
97
  type: "relation",
@@ -121,6 +121,19 @@ const adminControllers = {
121
121
  throw error;
122
122
  }
123
123
  },
124
+ getSlug(ctx) {
125
+ const { query: { q } } = ctx;
126
+ try {
127
+ (0, types_1.assertNotEmpty)(q);
128
+ return this.getService("common").getSlug(q).then((slug) => ({ slug }));
129
+ }
130
+ catch (error) {
131
+ if (error instanceof Error) {
132
+ return ctx.badRequest(error.message);
133
+ }
134
+ throw error;
135
+ }
136
+ },
124
137
  };
125
138
  const assertCopyParams = (source, target) => {
126
139
  (0, types_1.assertIsNumber)(source, new InvalidParamNavigationError_1.InvalidParamNavigationError("Source's id is not a number"));
package/server/index.d.ts CHANGED
@@ -70,6 +70,7 @@ declare const _default: {
70
70
  relation: string;
71
71
  target: string;
72
72
  configurable: boolean;
73
+ mappedBy: string;
73
74
  };
74
75
  localizations: {
75
76
  type: string;
@@ -170,6 +171,7 @@ declare const _default: {
170
171
  relation: string;
171
172
  target: string;
172
173
  configurable: boolean;
174
+ inversedBy: string;
173
175
  };
174
176
  audience: {
175
177
  type: string;
@@ -28,6 +28,16 @@ const routes = {
28
28
  path: '/config',
29
29
  handler: 'admin.restoreConfig',
30
30
  },
31
+ {
32
+ method: 'GET',
33
+ path: '/slug',
34
+ handler: 'admin.getSlug',
35
+ config: {
36
+ policies: [
37
+ 'admin::isAuthenticatedAdmin'
38
+ ]
39
+ }
40
+ },
31
41
  {
32
42
  method: 'GET',
33
43
  path: '/:id',
@@ -1,10 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const utils_1 = require("@strapi/utils");
7
- const slugify_1 = __importDefault(require("@sindresorhus/slugify"));
8
4
  const lodash_1 = require("lodash");
9
5
  const utils_2 = require("../utils");
10
6
  const i18n_1 = require("../i18n");
@@ -16,11 +12,11 @@ const adminService = ({ strapi }) => ({
16
12
  const pluginStore = await commonService.getPluginStore();
17
13
  const config = await pluginStore.get({ key: 'config' });
18
14
  const additionalFields = config.additionalFields;
15
+ const cascadeMenuAttached = config.cascadeMenuAttached;
19
16
  const contentTypesNameFields = config.contentTypesNameFields;
20
17
  const contentTypesPopulate = config.contentTypesPopulate;
21
18
  const pathDefaultFields = config.pathDefaultFields;
22
19
  const allowedLevels = config.allowedLevels;
23
- const slugify = config.slugify;
24
20
  const isGQLPluginEnabled = !(0, lodash_1.isNil)(strapi.plugin('graphql'));
25
21
  let extendedResult = {
26
22
  allowedContentTypes: utils_2.ALLOWED_CONTENT_TYPES,
@@ -43,7 +39,7 @@ const adminService = ({ strapi }) => ({
43
39
  navigationItemRelated: configContentTypes.map(({ labelSingular }) => labelSingular.replace(/\s+/g, ''))
44
40
  },
45
41
  isGQLPluginEnabled: viaSettingsPage ? isGQLPluginEnabled : undefined,
46
- slugify,
42
+ cascadeMenuAttached,
47
43
  };
48
44
  const i18nConfig = await (0, i18n_1.addI18NConfigFields)({ strapi, viaSettingsPage, previousConfig: {} });
49
45
  if (additionalFields.includes('audience')) {
@@ -99,12 +95,11 @@ const adminService = ({ strapi }) => ({
99
95
  const commonService = (0, utils_2.getPluginService)('common');
100
96
  const adminService = (0, utils_2.getPluginService)('admin');
101
97
  const { enabled: i18nEnabled, defaultLocale } = await (0, i18n_1.getI18nStatus)({ strapi });
102
- const { slugify: customSlugifyConfig } = await adminService.config(false);
103
98
  const { masterModel } = (0, utils_2.getPluginModels)();
104
99
  const { name, visible } = payload;
105
100
  const data = {
106
101
  name,
107
- slug: (0, slugify_1.default)(name, customSlugifyConfig).toLowerCase(),
102
+ slug: await commonService.getSlug(name),
108
103
  visible,
109
104
  };
110
105
  const existingEntity = await strapi
@@ -127,14 +122,13 @@ const adminService = ({ strapi }) => ({
127
122
  const adminService = (0, utils_2.getPluginService)('admin');
128
123
  const commonService = (0, utils_2.getPluginService)('common');
129
124
  const { enabled: i18nEnabled } = await (0, i18n_1.getI18nStatus)({ strapi });
130
- const { slugify: customSlugifyConfig } = await adminService.config(false);
131
125
  const { masterModel } = (0, utils_2.getPluginModels)();
132
126
  const { name, visible } = payload;
133
127
  const existingEntity = await adminService.getById(id);
134
128
  const detailsHaveChanged = existingEntity.name !== name || existingEntity.visible !== visible;
135
129
  if (detailsHaveChanged) {
136
130
  const newName = detailsHaveChanged ? name : existingEntity.name;
137
- const newSlug = detailsHaveChanged ? (0, slugify_1.default)(name, customSlugifyConfig).toLowerCase() : existingEntity.slug;
131
+ const newSlug = detailsHaveChanged ? await commonService.getSlug(name) : existingEntity.slug;
138
132
  await strapi.query(masterModel.uid).update({
139
133
  where: { id },
140
134
  data: {
@@ -1,10 +1,6 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  const lodash_1 = require("lodash");
7
- const slugify_1 = __importDefault(require("@sindresorhus/slugify"));
8
4
  const uuid_1 = require("uuid");
9
5
  const types_1 = require("../../types");
10
6
  const utils_1 = require("../utils");
@@ -144,8 +140,8 @@ const clientService = ({ strapi }) => ({
144
140
  ...enabledCustomFieldsNames.reduce((acc, field) => ({ ...acc, [field]: (0, lodash_1.get)(item, field) }), {})
145
141
  };
146
142
  },
147
- renderTree(items = [], id = null, field = 'parent', path = '', itemParser = (i) => i) {
148
- return items
143
+ async renderTree(items = [], id = null, field = 'parent', path = '', itemParser = (i) => i) {
144
+ return (await Promise.all(items
149
145
  .filter((item) => {
150
146
  if (item[field] === null && id === null) {
151
147
  return true;
@@ -160,9 +156,9 @@ const clientService = ({ strapi }) => ({
160
156
  return (data && data === id);
161
157
  })
162
158
  .filter(utils_1.filterOutUnpublished)
163
- .map(item => itemParser({
159
+ .map(async (item) => itemParser({
164
160
  ...item,
165
- }, path, field))
161
+ }, path, field))))
166
162
  .sort((x, y) => {
167
163
  if (x.order !== undefined && y.order !== undefined)
168
164
  return x.order - y.order;
@@ -204,7 +200,7 @@ const clientService = ({ strapi }) => ({
204
200
  return [];
205
201
  }
206
202
  const items = await commonService.getRelatedItems(entities, populate);
207
- const { contentTypes, contentTypesNameFields, additionalFields, slugify: customSlugifyConfig } = await adminService.config(false);
203
+ const { contentTypes, contentTypesNameFields, additionalFields } = await adminService.config(false);
208
204
  const enabledCustomFieldsNames = (0, utils_1.getCustomFields)(additionalFields)
209
205
  .reduce((acc, curr) => curr.enabled ? [...acc, curr.name] : acc, []);
210
206
  const wrapContentType = (itemContentType) => wrapRelated && itemContentType ? {
@@ -215,12 +211,12 @@ const clientService = ({ strapi }) => ({
215
211
  case utils_1.RENDER_TYPES.TREE:
216
212
  case utils_1.RENDER_TYPES.RFR:
217
213
  const getTemplateName = await (0, utils_1.templateNameFactory)(items, strapi, contentTypes);
218
- const itemParser = (item, path = '', field) => {
214
+ const itemParser = async (item, path = '', field) => {
219
215
  const isExternal = item.type === "EXTERNAL";
220
216
  const parentPath = isExternal ? undefined : `${path === '/' ? '' : path}/${(0, lodash_1.first)(item.path) === '/'
221
217
  ? item.path.substring(1)
222
218
  : item.path}`;
223
- const slug = (0, lodash_1.isString)(parentPath) ? (0, slugify_1.default)(((0, lodash_1.first)(parentPath) === '/' ? parentPath.substring(1) : parentPath).replace(/\//g, '-'), customSlugifyConfig) : undefined;
219
+ const slug = (0, lodash_1.isString)(parentPath) ? await commonService.getSlug(((0, lodash_1.first)(parentPath) === '/' ? parentPath.substring(1) : parentPath).replace(/\//g, '-')) : undefined;
224
220
  const lastRelated = (0, lodash_1.isArray)(item.related) ? (0, lodash_1.last)(item.related) : item.related;
225
221
  const relatedContentType = wrapContentType(lastRelated);
226
222
  return {
@@ -231,19 +227,19 @@ const clientService = ({ strapi }) => ({
231
227
  path: isExternal ? item.externalPath : parentPath,
232
228
  type: item.type,
233
229
  uiRouterKey: item.uiRouterKey,
234
- slug: !slug && item.uiRouterKey ? (0, slugify_1.default)(item.uiRouterKey, customSlugifyConfig) : slug,
230
+ slug: !slug && item.uiRouterKey ? commonService.getSlug(item.uiRouterKey) : slug,
235
231
  external: isExternal,
236
232
  related: isExternal || !lastRelated ? undefined : {
237
233
  ...relatedContentType,
238
234
  __templateName: getTemplateName((lastRelated.relatedType || lastRelated.__contentType), lastRelated.id),
239
235
  },
240
236
  audience: !(0, lodash_1.isEmpty)(item.audience) ? item.audience.map(({ key }) => key) : undefined,
241
- items: isExternal ? undefined : clientService.renderTree(items, item.id, field, parentPath, itemParser),
237
+ items: isExternal ? undefined : await clientService.renderTree(items, item.id, field, parentPath, itemParser),
242
238
  ...enabledCustomFieldsNames.reduce((acc, field) => ({ ...acc, [field]: (0, lodash_1.get)(item, `additionalFields.${field}`) }), {}),
243
239
  };
244
240
  };
245
241
  const { items: itemsFilteredByPath, root: rootElement, } = (0, utils_1.filterByPath)(items, rootPath);
246
- const treeStructure = clientService.renderTree((0, lodash_1.isNil)(rootPath) ? items : itemsFilteredByPath, (0, lodash_1.get)(rootElement, 'parent.id'), 'parent', (0, lodash_1.get)(rootElement, 'parent.path'), itemParser);
242
+ const treeStructure = await clientService.renderTree((0, lodash_1.isNil)(rootPath) ? items : itemsFilteredByPath, (0, lodash_1.get)(rootElement, 'parent.id'), 'parent', (0, lodash_1.get)(rootElement, 'parent.path'), itemParser);
247
243
  const filteredStructure = filter
248
244
  ? treeStructure.filter((item) => item.uiRouterKey === filter)
249
245
  : treeStructure;
@@ -9,6 +9,7 @@ const utils_1 = require("@strapi/utils");
9
9
  const config_1 = require("../config");
10
10
  const i18n_1 = require("../i18n");
11
11
  const utils_2 = require("../utils");
12
+ const slugify_1 = __importDefault(require("@sindresorhus/slugify"));
12
13
  const commonService = ({ strapi }) => ({
13
14
  analyzeBranch(items = [], masterEntity = null, parentItem = null, prevOperations = {}) {
14
15
  const commonService = (0, utils_2.getPluginService)('common');
@@ -326,7 +327,32 @@ const commonService = ({ strapi }) => ({
326
327
  where: { id: item.id },
327
328
  data: { additionalFields: item.additionalFields },
328
329
  })));
329
- }
330
+ },
331
+ async getSlug(query) {
332
+ let slug = (0, slugify_1.default)(query);
333
+ if (slug) {
334
+ const { itemModel } = (0, utils_2.getPluginModels)();
335
+ const existingItems = await strapi
336
+ .query(itemModel.uid)
337
+ .count({
338
+ where: {
339
+ $or: [
340
+ {
341
+ uiRouterKey: {
342
+ $startsWith: slug
343
+ }
344
+ },
345
+ { uiRouterKey: slug }
346
+ ]
347
+ },
348
+ limit: Number.MAX_SAFE_INTEGER,
349
+ });
350
+ if (existingItems) {
351
+ slug = `${slug}-${existingItems}`;
352
+ }
353
+ }
354
+ return slug.toLowerCase();
355
+ },
330
356
  });
331
357
  exports.default = commonService;
332
358
  //# sourceMappingURL=common.js.map
@@ -70,6 +70,7 @@ declare const _default: () => {
70
70
  relation: string;
71
71
  target: string;
72
72
  configurable: boolean;
73
+ mappedBy: string;
73
74
  };
74
75
  localizations: {
75
76
  type: string;
@@ -170,6 +171,7 @@ declare const _default: () => {
170
171
  relation: string;
171
172
  target: string;
172
173
  configurable: boolean;
174
+ inversedBy: string;
173
175
  };
174
176
  audience: {
175
177
  type: string;