strapi-plugin-navigation 2.1.0 → 2.2.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 (116) hide show
  1. package/README.md +17 -7
  2. package/admin/src/components/AdditionalFieldInput/index.d.ts +5 -0
  3. package/admin/src/components/AdditionalFieldInput/index.js +71 -0
  4. package/admin/src/components/AdditionalFieldInput/types.d.ts +14 -0
  5. package/admin/src/components/AdditionalFieldInput/types.js +3 -0
  6. package/admin/src/components/Item/index.js +2 -3
  7. package/admin/src/components/RestartAlert/index.d.ts +1 -1
  8. package/admin/src/components/TextArrayInput/index.d.ts +14 -0
  9. package/admin/src/components/TextArrayInput/index.js +45 -0
  10. package/admin/src/hooks/useAllContentTypes.d.ts +1 -4
  11. package/admin/src/hooks/useAllContentTypes.js +3 -7
  12. package/admin/src/hooks/useNavigationConfig.d.ts +1 -1
  13. package/admin/src/hooks/useNavigationConfig.js +6 -6
  14. package/admin/src/pages/DataManagerProvider/index.d.ts +1 -1
  15. package/admin/src/pages/DataManagerProvider/index.js +9 -11
  16. package/admin/src/pages/SettingsPage/components/CustomFieldForm/index.d.ts +12 -0
  17. package/admin/src/pages/SettingsPage/components/CustomFieldForm/index.js +112 -0
  18. package/admin/src/pages/SettingsPage/components/CustomFieldModal/index.d.ts +12 -0
  19. package/admin/src/pages/SettingsPage/components/CustomFieldModal/index.js +20 -0
  20. package/admin/src/pages/SettingsPage/components/CustomFieldTable/index.d.ts +11 -0
  21. package/admin/src/pages/SettingsPage/components/CustomFieldTable/index.js +105 -0
  22. package/admin/src/pages/SettingsPage/index.d.ts +2 -1
  23. package/admin/src/pages/SettingsPage/index.js +109 -74
  24. package/admin/src/pages/SettingsPage/types.d.ts +32 -0
  25. package/admin/src/pages/SettingsPage/types.js +3 -0
  26. package/admin/src/pages/SettingsPage/utils/form.d.ts +18 -0
  27. package/admin/src/pages/SettingsPage/utils/form.js +34 -0
  28. package/admin/src/pages/SettingsPage/utils/functions.d.ts +2 -2
  29. package/admin/src/pages/SettingsPage/utils/functions.js +1 -1
  30. package/admin/src/pages/View/components/NavigationItemForm/index.d.ts +3 -55
  31. package/admin/src/pages/View/components/NavigationItemForm/index.js +162 -177
  32. package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +90 -0
  33. package/admin/src/pages/View/components/NavigationItemForm/types.js +3 -0
  34. package/admin/src/pages/View/components/NavigationItemForm/utils/form.d.ts +24 -43
  35. package/admin/src/pages/View/components/NavigationItemForm/utils/form.js +78 -45
  36. package/admin/src/pages/View/components/NavigationItemPopup/index.js +1 -2
  37. package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.d.ts +4 -0
  38. package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.js +11 -0
  39. package/admin/src/pages/View/components/NavigationManager/AllNavigations/index.d.ts +9 -0
  40. package/admin/src/pages/View/components/NavigationManager/{List → AllNavigations}/index.js +32 -31
  41. package/admin/src/pages/View/components/NavigationManager/DeletionConfirm/index.d.ts +9 -0
  42. package/admin/src/pages/View/components/NavigationManager/{Delete → DeletionConfirm}/index.js +18 -12
  43. package/admin/src/pages/View/components/NavigationManager/ErrorDetails/index.d.ts +9 -0
  44. package/admin/src/pages/View/components/NavigationManager/{Error → ErrorDetails}/index.js +10 -10
  45. package/admin/src/pages/View/components/NavigationManager/Footer/index.d.ts +24 -0
  46. package/admin/src/pages/View/components/NavigationManager/Footer/index.js +13 -0
  47. package/admin/src/pages/View/components/NavigationManager/Form/index.d.ts +3 -2
  48. package/admin/src/pages/View/components/NavigationManager/Form/index.js +7 -2
  49. package/admin/src/pages/View/components/NavigationManager/NavigationUpdate/index.d.ts +9 -0
  50. package/admin/src/pages/View/components/NavigationManager/{Edit → NavigationUpdate}/index.js +16 -11
  51. package/admin/src/pages/View/components/NavigationManager/NewNavigation/index.d.ts +10 -0
  52. package/admin/src/pages/View/components/NavigationManager/{Create → NewNavigation}/index.js +16 -11
  53. package/admin/src/pages/View/components/NavigationManager/index.d.ts +3 -2
  54. package/admin/src/pages/View/components/NavigationManager/index.js +22 -21
  55. package/admin/src/pages/View/components/NavigationManager/types.d.ts +2 -15
  56. package/admin/src/pages/View/index.d.ts +1 -1
  57. package/admin/src/pages/View/index.js +1 -1
  58. package/admin/src/pages/View/utils/parsers.d.ts +1 -0
  59. package/admin/src/pages/View/utils/parsers.js +8 -7
  60. package/admin/src/translations/en.json +37 -0
  61. package/admin/src/translations/index.d.ts +2 -1
  62. package/admin/src/translations/index.js +1 -1
  63. package/admin/src/utils/api.d.ts +8 -7
  64. package/admin/src/utils/api.js +6 -41
  65. package/admin/src/utils/enums.d.ts +25 -0
  66. package/admin/src/utils/enums.js +30 -0
  67. package/admin/src/utils/functions.d.ts +16 -0
  68. package/admin/src/utils/functions.js +46 -0
  69. package/admin/src/utils/index.d.ts +3 -17
  70. package/admin/src/utils/index.js +16 -39
  71. package/package.json +5 -5
  72. package/server/config/index.js +6 -4
  73. package/server/config/setupStrategy.js +13 -1
  74. package/server/content-types/index.d.ts +5 -25
  75. package/server/content-types/navigation/index.d.ts +0 -7
  76. package/server/content-types/navigation/index.js +0 -2
  77. package/server/content-types/navigation-item/index.d.ts +5 -13
  78. package/server/content-types/navigation-item/index.js +0 -2
  79. package/server/content-types/navigation-item/schema.d.ts +5 -0
  80. package/server/content-types/navigation-item/schema.js +5 -0
  81. package/server/content-types/navigations-items-related/index.d.ts +0 -5
  82. package/server/content-types/navigations-items-related/index.js +0 -2
  83. package/server/controllers/admin.js +1 -1
  84. package/server/controllers/client.js +2 -1
  85. package/server/graphql/types/navigation-item.d.ts +2 -1
  86. package/server/graphql/types/navigation-item.js +26 -2
  87. package/server/index.d.ts +5 -25
  88. package/server/services/admin.js +26 -14
  89. package/server/services/client.js +64 -21
  90. package/server/services/common.js +25 -6
  91. package/server/utils/constant.d.ts +0 -3
  92. package/server/utils/constant.js +1 -2
  93. package/server/utils/functions.d.ts +12 -12
  94. package/server/utils/functions.js +60 -22
  95. package/strapi-server.d.ts +5 -25
  96. package/tsconfig.tsbuildinfo +1 -1
  97. package/types/config.d.ts +6 -2
  98. package/types/contentTypes.d.ts +22 -1
  99. package/types/services.d.ts +14 -5
  100. package/types/utils.d.ts +6 -1
  101. package/types/utils.js +15 -1
  102. package/admin/src/pages/View/components/NavigationManager/Create/index.d.ts +0 -9
  103. package/admin/src/pages/View/components/NavigationManager/Delete/index.d.ts +0 -8
  104. package/admin/src/pages/View/components/NavigationManager/Edit/index.d.ts +0 -8
  105. package/admin/src/pages/View/components/NavigationManager/Error/index.d.ts +0 -8
  106. package/admin/src/pages/View/components/NavigationManager/List/index.d.ts +0 -8
  107. package/admin/src/pages/View/utils/enums.d.ts +0 -9
  108. package/admin/src/pages/View/utils/enums.js +0 -12
  109. package/admin/src/utils/getTrad.d.ts +0 -3
  110. package/admin/src/utils/getTrad.js +0 -9
  111. package/server/content-types/navigation/lifecycle.d.ts +0 -9
  112. package/server/content-types/navigation/lifecycle.js +0 -10
  113. package/server/content-types/navigation-item/lifecycle.d.ts +0 -16
  114. package/server/content-types/navigation-item/lifecycle.js +0 -31
  115. package/server/content-types/navigations-items-related/lifecycle.d.ts +0 -8
  116. package/server/content-types/navigations-items-related/lifecycle.js +0 -22
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const lodash_1 = require("lodash");
7
- const slugify_1 = __importDefault(require("slugify"));
7
+ const slugify_1 = __importDefault(require("@sindresorhus/slugify"));
8
8
  const uuid_1 = require("uuid");
9
9
  const types_1 = require("../../types");
10
10
  const utils_1 = require("../utils");
@@ -12,13 +12,13 @@ const utils_2 = require("@strapi/utils");
12
12
  const i18n_1 = require("../i18n");
13
13
  const NavigationError_1 = require("../../utils/NavigationError");
14
14
  const clientService = ({ strapi }) => ({
15
- async render({ idOrSlug, type = utils_1.RENDER_TYPES.FLAT, menuOnly = false, rootPath = null, wrapRelated = false, locale, }) {
15
+ async render({ idOrSlug, type = utils_1.RENDER_TYPES.FLAT, menuOnly = false, rootPath = null, wrapRelated = false, locale, populate, }) {
16
16
  const clientService = (0, utils_1.getPluginService)('client');
17
17
  const findById = !isNaN((0, lodash_1.toNumber)(idOrSlug)) || (0, uuid_1.validate)(idOrSlug);
18
18
  const criteria = findById ? { id: idOrSlug } : { slug: idOrSlug };
19
19
  const itemCriteria = menuOnly ? { menuAttached: true } : {};
20
20
  return await clientService.renderType({
21
- type, criteria, itemCriteria, filter: null, rootPath, wrapRelated, locale,
21
+ type, criteria, itemCriteria, filter: null, rootPath, wrapRelated, locale, populate
22
22
  });
23
23
  },
24
24
  async renderChildren({ idOrSlug, childUIKey, type = utils_1.RENDER_TYPES.FLAT, menuOnly = false, wrapRelated = false, locale, }) {
@@ -32,7 +32,7 @@ const clientService = ({ strapi }) => ({
32
32
  };
33
33
  return clientService.renderType({ type, criteria, itemCriteria, filter, rootPath: null, wrapRelated, locale });
34
34
  },
35
- renderRFR(items, parent = null, parentNavItem = null, contentTypes = []) {
35
+ renderRFR({ items, parent = null, parentNavItem = null, contentTypes = [], enabledCustomFieldsNames, }) {
36
36
  const clientService = (0, utils_1.getPluginService)('client');
37
37
  let pages = {};
38
38
  let nav = {};
@@ -40,8 +40,8 @@ const clientService = ({ strapi }) => ({
40
40
  items.forEach(item => {
41
41
  const { items: itemChilds, ...itemProps } = item;
42
42
  const itemNav = clientService.renderRFRNav(itemProps);
43
- const itemPage = clientService.renderRFRPage(itemProps, parent);
44
- if (item.type === "INTERNAL") {
43
+ const itemPage = clientService.renderRFRPage(itemProps, parent, enabledCustomFieldsNames);
44
+ if (item.type !== "EXTERNAL") {
45
45
  pages = {
46
46
  ...pages,
47
47
  [itemPage.id]: {
@@ -60,7 +60,7 @@ const clientService = ({ strapi }) => ({
60
60
  }
61
61
  else {
62
62
  const navLevel = navItems
63
- .filter(navItem => navItem.type === "INTERNAL");
63
+ .filter(navItem => navItem.type !== "EXTERNAL");
64
64
  if (!(0, lodash_1.isEmpty)(navLevel))
65
65
  nav = {
66
66
  ...nav,
@@ -68,8 +68,20 @@ const clientService = ({ strapi }) => ({
68
68
  };
69
69
  }
70
70
  if (!(0, lodash_1.isEmpty)(itemChilds)) {
71
- const { nav: nestedNavs } = clientService.renderRFR(itemChilds, itemPage.id, itemNav, contentTypes);
72
- const { pages: nestedPages } = clientService.renderRFR((itemChilds).filter(child => child.type === "INTERNAL"), itemPage.id, itemNav, contentTypes);
71
+ const { nav: nestedNavs } = clientService.renderRFR({
72
+ items: itemChilds,
73
+ parent: itemPage.id,
74
+ parentNavItem: itemNav,
75
+ contentTypes,
76
+ enabledCustomFieldsNames,
77
+ });
78
+ const { pages: nestedPages } = clientService.renderRFR({
79
+ items: (itemChilds).filter(child => child.type !== "EXTERNAL"),
80
+ parent: itemPage.id,
81
+ parentNavItem: itemNav,
82
+ contentTypes,
83
+ enabledCustomFieldsNames,
84
+ });
73
85
  pages = {
74
86
  ...pages,
75
87
  ...nestedPages,
@@ -105,9 +117,14 @@ const clientService = ({ strapi }) => ({
105
117
  page: uiRouterKey,
106
118
  };
107
119
  }
120
+ if (type === "WRAPPER") {
121
+ return {
122
+ ...itemCommon,
123
+ };
124
+ }
108
125
  throw new NavigationError_1.NavigationError("Unknown item type", item);
109
126
  },
110
- renderRFRPage(item, parent) {
127
+ renderRFRPage(item, parent, enabledCustomFieldsNames) {
111
128
  const { uiRouterKey, title, path, slug, related, type, audience, menuAttached } = item;
112
129
  const { __contentType, id, __templateName } = related || {};
113
130
  const contentType = __contentType || '';
@@ -124,6 +141,7 @@ const clientService = ({ strapi }) => ({
124
141
  parent,
125
142
  audience,
126
143
  menuAttached,
144
+ ...enabledCustomFieldsNames.reduce((acc, field) => ({ ...acc, [field]: (0, lodash_1.get)(item, field) }), {})
127
145
  };
128
146
  },
129
147
  renderTree(items = [], id = null, field = 'parent', path = '', itemParser = (i) => i) {
@@ -152,7 +170,7 @@ const clientService = ({ strapi }) => ({
152
170
  return 0;
153
171
  });
154
172
  },
155
- async renderType({ type = utils_1.RENDER_TYPES.FLAT, criteria = {}, itemCriteria = {}, filter = null, rootPath = null, wrapRelated = false, locale, }) {
173
+ async renderType({ type = utils_1.RENDER_TYPES.FLAT, criteria = {}, itemCriteria = {}, filter = null, rootPath = null, wrapRelated = false, locale, populate, }) {
156
174
  const clientService = (0, utils_1.getPluginService)('client');
157
175
  const adminService = (0, utils_1.getPluginService)('admin');
158
176
  const commonService = (0, utils_1.getPluginService)('common');
@@ -160,7 +178,7 @@ const clientService = ({ strapi }) => ({
160
178
  ...criteria,
161
179
  visible: true,
162
180
  };
163
- const { masterModel, itemModel } = (0, utils_1.extractMeta)(strapi.plugins);
181
+ const { masterModel, itemModel } = (0, utils_1.getPluginModels)();
164
182
  const entity = await (0, i18n_1.i18nAwareEntityReadHandler)({
165
183
  entity: await strapi
166
184
  .query(masterModel.uid)
@@ -185,8 +203,10 @@ const clientService = ({ strapi }) => ({
185
203
  if (!entities) {
186
204
  return [];
187
205
  }
188
- const items = await commonService.getRelatedItems(entities);
189
- const { contentTypes, contentTypesNameFields } = await adminService.config(false);
206
+ const items = await commonService.getRelatedItems(entities, populate);
207
+ const { contentTypes, contentTypesNameFields, additionalFields, slugify: customSlugifyConfig } = await adminService.config(false);
208
+ const enabledCustomFieldsNames = (0, utils_1.getCustomFields)(additionalFields)
209
+ .reduce((acc, curr) => curr.enabled ? [...acc, curr.name] : acc, []);
190
210
  const wrapContentType = (itemContentType) => wrapRelated && itemContentType ? {
191
211
  id: itemContentType.id,
192
212
  attributes: { ...itemContentType }
@@ -200,7 +220,7 @@ const clientService = ({ strapi }) => ({
200
220
  const parentPath = isExternal ? undefined : `${path === '/' ? '' : path}/${(0, lodash_1.first)(item.path) === '/'
201
221
  ? item.path.substring(1)
202
222
  : item.path}`;
203
- const slug = (0, lodash_1.isString)(parentPath) ? (0, slugify_1.default)(((0, lodash_1.first)(parentPath) === '/' ? parentPath.substring(1) : parentPath).replace(/\//g, '-')) : undefined;
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;
204
224
  const lastRelated = (0, lodash_1.isArray)(item.related) ? (0, lodash_1.last)(item.related) : item.related;
205
225
  const relatedContentType = wrapContentType(lastRelated);
206
226
  return {
@@ -211,14 +231,15 @@ const clientService = ({ strapi }) => ({
211
231
  path: isExternal ? item.externalPath : parentPath,
212
232
  type: item.type,
213
233
  uiRouterKey: item.uiRouterKey,
214
- slug: !slug && item.uiRouterKey ? (0, slugify_1.default)(item.uiRouterKey) : slug,
234
+ slug: !slug && item.uiRouterKey ? (0, slugify_1.default)(item.uiRouterKey, customSlugifyConfig) : slug,
215
235
  external: isExternal,
216
236
  related: isExternal || !lastRelated ? undefined : {
217
237
  ...relatedContentType,
218
238
  __templateName: getTemplateName((lastRelated.relatedType || lastRelated.__contentType), lastRelated.id),
219
239
  },
220
- audience: !(0, lodash_1.isEmpty)(item.audience) ? item.audience.map(aItem => (aItem).key) : undefined,
240
+ audience: !(0, lodash_1.isEmpty)(item.audience) ? item.audience.map(({ key }) => key) : undefined,
221
241
  items: isExternal ? undefined : clientService.renderTree(items, item.id, field, parentPath, itemParser),
242
+ ...enabledCustomFieldsNames.reduce((acc, field) => ({ ...acc, [field]: (0, lodash_1.get)(item, `additionalFields.${field}`) }), {}),
222
243
  };
223
244
  };
224
245
  const { items: itemsFilteredByPath, root: rootElement, } = (0, utils_1.filterByPath)(items, rootPath);
@@ -227,19 +248,41 @@ const clientService = ({ strapi }) => ({
227
248
  ? treeStructure.filter((item) => item.uiRouterKey === filter)
228
249
  : treeStructure;
229
250
  if (type === utils_1.RENDER_TYPES.RFR) {
230
- return clientService.renderRFR(filteredStructure, null, null, contentTypes);
251
+ return clientService.renderRFR({
252
+ items: filteredStructure,
253
+ contentTypes,
254
+ enabledCustomFieldsNames,
255
+ });
231
256
  }
232
257
  return filteredStructure;
233
258
  default:
234
259
  const publishedItems = items.filter(utils_1.filterOutUnpublished);
235
260
  const result = (0, lodash_1.isNil)(rootPath) ? items : (0, utils_1.filterByPath)(publishedItems, rootPath).items;
236
- return result.map((item) => ({
261
+ const defaultCache = new Map();
262
+ const getNestedOrders = (id, cache = defaultCache) => {
263
+ const cached = cache.get(id);
264
+ if (!(0, lodash_1.isNil)(cached))
265
+ return cached;
266
+ const item = result.find(item => item.id === id);
267
+ if ((0, lodash_1.isNil)(item))
268
+ throw new Error("Item not found");
269
+ const { order, parent } = item;
270
+ const nestedOrders = parent
271
+ ? getNestedOrders(parent.id, cache).concat(order)
272
+ : [order];
273
+ cache.set(id, nestedOrders);
274
+ return nestedOrders;
275
+ };
276
+ return result
277
+ .map(({ additionalFields, ...item }) => ({
237
278
  ...item,
238
279
  audience: item.audience?.map(_ => (_).key),
239
- title: (0, utils_1.composeItemTitle)(item, contentTypesNameFields, contentTypes) || '',
280
+ title: (0, utils_1.composeItemTitle)({ ...item, additionalFields }, contentTypesNameFields, contentTypes) || '',
240
281
  related: wrapContentType(item.related),
241
282
  items: null,
242
- }));
283
+ ...enabledCustomFieldsNames.reduce((acc, name) => ({ ...acc, [name]: (0, lodash_1.get)(additionalFields, name, undefined) }), {}),
284
+ }))
285
+ .sort((a, b) => (0, utils_1.compareArraysOfNumbers)(getNestedOrders(a.id), getNestedOrders(b.id)));
243
286
  }
244
287
  }
245
288
  throw new utils_2.errors.NotFoundError();
@@ -110,7 +110,7 @@ const commonService = ({ strapi }) => ({
110
110
  },
111
111
  async createBranch(items, masterEntity, parentItem, operations) {
112
112
  const commonService = (0, utils_2.getPluginService)('common');
113
- const { itemModel } = (0, utils_2.extractMeta)(strapi.plugins);
113
+ const { itemModel } = (0, utils_2.getPluginModels)();
114
114
  return await Promise.all(items.map(async (item) => {
115
115
  operations.create = true;
116
116
  const { parent, master, related, ...params } = item;
@@ -197,7 +197,7 @@ const commonService = ({ strapi }) => ({
197
197
  async getPluginStore() {
198
198
  return await strapi.store({ type: 'plugin', name: 'navigation' });
199
199
  },
200
- async getRelatedItems(entityItems) {
200
+ async getRelatedItems(entityItems, populate) {
201
201
  const commonService = (0, utils_2.getPluginService)('common');
202
202
  const pluginStore = await commonService.getPluginStore();
203
203
  const config = await pluginStore.get({ key: 'config' });
@@ -207,7 +207,7 @@ const commonService = ({ strapi }) => ({
207
207
  ...(acc[relatedType] || []),
208
208
  ...entityItems
209
209
  .filter((item => (0, lodash_1.get)(item.related, 'related_type') === relatedType))
210
- .flatMap((item) => Object.assign(item.related, { navigationItemId: item.id })),
210
+ .flatMap((item) => Object.assign(item.related || {}, { navigationItemId: item.id })),
211
211
  ],
212
212
  }), {});
213
213
  const data = new Map((await Promise.all(Object.entries(groupedItems)
@@ -218,7 +218,7 @@ const commonService = ({ strapi }) => ({
218
218
  where: {
219
219
  id: { $in: (0, lodash_1.map)(related, 'related_id') },
220
220
  },
221
- populate: config.contentTypesPopulate[model] || []
221
+ populate: (0, lodash_1.isNil)(populate) ? config.contentTypesPopulate[model] || [] : (0, utils_2.parsePopulateQuery)(populate)
222
222
  });
223
223
  return relationData
224
224
  .flatMap(_ => Object.assign(_, {
@@ -239,7 +239,7 @@ const commonService = ({ strapi }) => ({
239
239
  },
240
240
  removeBranch(items = [], operations = {}) {
241
241
  const commonService = (0, utils_2.getPluginService)('common');
242
- const { itemModel } = (0, utils_2.extractMeta)(strapi.plugins);
242
+ const { itemModel } = (0, utils_2.getPluginModels)();
243
243
  return Promise.all(items
244
244
  .filter(item => item.id)
245
245
  .map(async (item) => {
@@ -273,7 +273,7 @@ const commonService = ({ strapi }) => ({
273
273
  },
274
274
  async updateBranch(toUpdate, masterEntity, parentItem, operations) {
275
275
  const commonService = (0, utils_2.getPluginService)('common');
276
- const { itemModel } = (0, utils_2.extractMeta)(strapi.plugins);
276
+ const { itemModel } = (0, utils_2.getPluginModels)();
277
277
  const databaseModel = strapi.query(itemModel.uid);
278
278
  return Promise.all(toUpdate.map(async (item) => {
279
279
  operations.update = true;
@@ -307,6 +307,25 @@ const commonService = ({ strapi }) => ({
307
307
  model: model.modelName,
308
308
  entry: sanitizedEntity,
309
309
  });
310
+ },
311
+ async pruneCustomFields(removedFields) {
312
+ const { itemModel } = (0, utils_2.getPluginModels)();
313
+ const databaseModel = strapi.query(itemModel.uid);
314
+ const removedFieldsNames = removedFields.map(({ name }) => name);
315
+ const navigationItems = await databaseModel.findMany({
316
+ where: {
317
+ additionalFields: {
318
+ $contains: [removedFieldsNames]
319
+ }
320
+ }
321
+ });
322
+ const navigationItemsToUpdate = removedFields.reduce((acc, curr) => {
323
+ return acc.map((item) => (0, lodash_1.omit)(item, [`additionalFields.${curr.name}`]));
324
+ }, navigationItems);
325
+ await Promise.all(navigationItemsToUpdate.map(async (item) => await databaseModel.update({
326
+ where: { id: item.id },
327
+ data: { additionalFields: item.additionalFields },
328
+ })));
310
329
  }
311
330
  });
312
331
  exports.default = commonService;
@@ -10,9 +10,6 @@ export declare const ALLOWED_CONTENT_TYPES: readonly ["api::", "plugin::"];
10
10
  export declare const RESTRICTED_CONTENT_TYPES: readonly ["plugin::users-permissions", "plugin::i18n.locale", "plugin::navigation"];
11
11
  export declare const EXCLUDED_CONTENT_TYPES: string[];
12
12
  export declare const CONTENT_TYPES_NAME_FIELDS_DEFAULTS: string[];
13
- export declare const ADDITIONAL_FIELDS: {
14
- AUDIENCE: string;
15
- };
16
13
  export declare const DEFAULT_POPULATE: "localizations"[];
17
14
  export declare const DEFAULT_NAVIGATION_ITEM: {
18
15
  readonly name: "Main navigation";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RENDER_TYPES = exports.DEFAULT_NAVIGATION_ITEM = exports.DEFAULT_POPULATE = exports.ADDITIONAL_FIELDS = exports.CONTENT_TYPES_NAME_FIELDS_DEFAULTS = exports.EXCLUDED_CONTENT_TYPES = exports.RESTRICTED_CONTENT_TYPES = exports.ALLOWED_CONTENT_TYPES = exports.KIND_TYPES = exports.MODEL_TYPES = exports.TEMPLATE_DEFAULT = void 0;
3
+ exports.RENDER_TYPES = exports.DEFAULT_NAVIGATION_ITEM = exports.DEFAULT_POPULATE = exports.CONTENT_TYPES_NAME_FIELDS_DEFAULTS = exports.EXCLUDED_CONTENT_TYPES = exports.RESTRICTED_CONTENT_TYPES = exports.ALLOWED_CONTENT_TYPES = exports.KIND_TYPES = exports.MODEL_TYPES = exports.TEMPLATE_DEFAULT = void 0;
4
4
  const i18n_1 = require("../i18n");
5
5
  exports.TEMPLATE_DEFAULT = 'Generic';
6
6
  exports.MODEL_TYPES = { CONTENT_TYPE: 'contentType' };
@@ -9,7 +9,6 @@ exports.ALLOWED_CONTENT_TYPES = ['api::', 'plugin::'];
9
9
  exports.RESTRICTED_CONTENT_TYPES = ['plugin::users-permissions', 'plugin::i18n.locale', 'plugin::navigation'];
10
10
  exports.EXCLUDED_CONTENT_TYPES = ['strapi::'];
11
11
  exports.CONTENT_TYPES_NAME_FIELDS_DEFAULTS = ['title', 'subject', 'name'];
12
- exports.ADDITIONAL_FIELDS = { AUDIENCE: 'audience' };
13
12
  exports.DEFAULT_POPULATE = [...i18n_1.I18N_DEFAULT_POPULATE];
14
13
  exports.DEFAULT_NAVIGATION_ITEM = {
15
14
  name: "Main navigation",
@@ -1,8 +1,10 @@
1
- import { Id, IStrapi, Primitive, StrapiContentType, StrapiPlugin, StringMap } from "strapi-typed";
2
- import { AuditLogContext, AuditLogParams, ContentTypeEntity, NavigationActions, NavigationItem, NavigationItemEntity, NavigationService, NavigationServiceName, NestedPath, NestedStructure, PluginConfigNameFields, ToBeFixed } from "../../types";
1
+ import { PopulateClause } from 'strapi-typed';
2
+ import { Id, IStrapi, Primitive, StrapiContentType, StringMap, StrapiContentTypeFullSchema } from "strapi-typed";
3
+ import { AuditLogContext, AuditLogParams, ContentTypeEntity, NavigationActions, NavigationItem, NavigationItemAdditionalField, NavigationItemCustomField, NavigationItemEntity, NavigationService, NavigationServiceName, NestedPath, NestedStructure, PluginConfigNameFields, PopulateQueryParam, ToBeFixed } from "../../types";
3
4
  import { NavigationError } from '../../utils/NavigationError';
4
5
  export declare const getPluginService: <T extends NavigationService>(name: NavigationServiceName) => T;
5
6
  export declare const errorHandler: (ctx: ToBeFixed) => (error: NavigationError | string) => any;
7
+ export declare const getCustomFields: (additionalFields: NavigationItemAdditionalField[]) => NavigationItemCustomField[];
6
8
  export declare const parseParams: <TParams extends StringMap<string> = StringMap<string>, TResult extends StringMap<Primitive> = StringMap<Primitive>>(params: TParams) => TResult;
7
9
  export declare const templateNameFactory: (items: import("strapi-typed").TypeResult<{
8
10
  path: string | null;
@@ -46,11 +48,13 @@ export declare const templateNameFactory: (items: import("strapi-typed").TypeRes
46
48
  audience: import("../../types").Audience[];
47
49
  externalPath: string | null;
48
50
  related: import("../../types").NavigationItemRelated | null;
51
+ additionalFields: StringMap<string | boolean>;
49
52
  }> | null;
50
53
  master: import("../../types").Navigation;
51
54
  audience: import("../../types").Audience[];
52
55
  externalPath: string | null;
53
56
  related: ContentTypeEntity | ContentTypeEntity[] | null;
57
+ additionalFields: StringMap<string | boolean>;
54
58
  }>[] | undefined, strapi: IStrapi, contentTypes?: StrapiContentType<ToBeFixed>[]) => Promise<(contentType: ToBeFixed, id: Id) => any>;
55
59
  export declare const getTemplateComponentFromTemplate: (strapi: IStrapi, template?: ToBeFixed[]) => any;
56
60
  export declare const prepareAuditLog: (actions: NavigationActions[]) => string;
@@ -60,16 +64,6 @@ export declare const extractItemRelationTitle: (relatedItem: ContentTypeEntity,
60
64
  export declare const filterOutUnpublished: (item: NavigationItemEntity<ContentTypeEntity | ContentTypeEntity[]>) => unknown;
61
65
  export declare const checkDuplicatePath: (parentItem: ToBeFixed | null, checkData: NavigationItem[]) => Promise<void>;
62
66
  export declare const singularize: (value?: string) => string;
63
- export declare const extractMeta: (plugins: {
64
- [uid: string]: StrapiPlugin;
65
- }) => {
66
- masterModel: any;
67
- itemModel: any;
68
- relatedModel: any;
69
- audienceModel: any;
70
- plugin: StrapiPlugin;
71
- pluginName: string;
72
- };
73
67
  export declare const buildNestedStructure: (entities: NavigationItemEntity<ContentTypeEntity>[], id?: Id | null, field?: keyof NavigationItemEntity) => NestedStructure<NavigationItemEntity<ContentTypeEntity>>[];
74
68
  export declare const buildNestedPaths: <T extends Pick<import("strapi-typed").TypeResult<{
75
69
  path: string | null;
@@ -100,6 +94,7 @@ export declare const buildNestedPaths: <T extends Pick<import("strapi-typed").Ty
100
94
  audience: import("../../types").Audience[];
101
95
  externalPath: string | null;
102
96
  related: import("../../types").NavigationItemRelated | null;
97
+ additionalFields: StringMap<string | boolean>;
103
98
  }>, "id" | "path" | "parent">>(items: T[], id?: Id | null, parentPath?: string | null) => NestedPath[];
104
99
  export declare const filterByPath: <T extends Pick<import("strapi-typed").TypeResult<{
105
100
  path: string | null;
@@ -130,10 +125,15 @@ export declare const filterByPath: <T extends Pick<import("strapi-typed").TypeRe
130
125
  audience: import("../../types").Audience[];
131
126
  externalPath: string | null;
132
127
  related: import("../../types").NavigationItemRelated | null;
128
+ additionalFields: StringMap<string | boolean>;
133
129
  }>, "id" | "path" | "parent">>(items: T[], path: string | null) => {
134
130
  root?: NestedPath | undefined;
135
131
  items: T[];
136
132
  };
137
133
  export declare const isContentTypeEligible: (uid?: string) => boolean | "";
138
134
  export declare const intercalate: <T, U extends T>(glue: T, arr: U[]) => (T | U)[];
135
+ export declare const compareArraysOfNumbers: (arrA: number[], arrB: number[]) => number;
136
+ export declare const getPluginModels: () => Record<'masterModel' | 'itemModel' | 'relatedModel' | 'audienceModel', StrapiContentTypeFullSchema>;
137
+ export declare const validateAdditionalFields: (additionalFields: NavigationItemAdditionalField[]) => void;
138
+ export declare const parsePopulateQuery: (populate: PopulateQueryParam) => PopulateClause;
139
139
  //# sourceMappingURL=functions.d.ts.map
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.intercalate = exports.isContentTypeEligible = exports.filterByPath = exports.buildNestedPaths = exports.buildNestedStructure = exports.extractMeta = exports.singularize = exports.checkDuplicatePath = exports.filterOutUnpublished = exports.extractItemRelationTitle = exports.composeItemTitle = exports.sendAuditLog = exports.prepareAuditLog = exports.getTemplateComponentFromTemplate = exports.templateNameFactory = exports.parseParams = exports.errorHandler = exports.getPluginService = void 0;
3
+ exports.parsePopulateQuery = exports.validateAdditionalFields = exports.getPluginModels = exports.compareArraysOfNumbers = exports.intercalate = exports.isContentTypeEligible = exports.filterByPath = exports.buildNestedPaths = exports.buildNestedStructure = exports.singularize = exports.checkDuplicatePath = exports.filterOutUnpublished = exports.extractItemRelationTitle = exports.composeItemTitle = exports.sendAuditLog = exports.prepareAuditLog = exports.getTemplateComponentFromTemplate = exports.templateNameFactory = exports.parseParams = exports.getCustomFields = exports.errorHandler = exports.getPluginService = void 0;
4
4
  const lodash_1 = require("lodash");
5
+ const types_1 = require("../../types");
5
6
  const NavigationError_1 = require("../../utils/NavigationError");
6
7
  const constant_1 = require("./constant");
7
8
  const getPluginService = (name) => strapi.plugin("navigation").service(name);
@@ -13,6 +14,8 @@ const errorHandler = (ctx) => (error) => {
13
14
  throw error;
14
15
  };
15
16
  exports.errorHandler = errorHandler;
17
+ const getCustomFields = (additionalFields) => additionalFields.filter(field => typeof field !== 'string');
18
+ exports.getCustomFields = getCustomFields;
16
19
  const parseParams = (params) => Object.keys(params).reduce((prev, curr) => {
17
20
  const value = params[curr];
18
21
  const parsedValue = isNaN(Number(value)) ? value : parseInt(value, 10);
@@ -25,24 +28,21 @@ exports.parseParams = parseParams;
25
28
  const templateNameFactory = async (items = [], strapi, contentTypes = []) => {
26
29
  const flatRelated = (0, lodash_1.flatten)(items.map(i => i.related)).filter(_ => !!_);
27
30
  const relatedMap = (flatRelated).reduce((acc, curr) => {
28
- if (curr === null)
31
+ if ((0, lodash_1.isNil)(curr) || typeof curr.__contentType !== "string")
29
32
  return acc;
30
33
  const index = curr.__contentType;
31
- if (typeof index !== 'string')
32
- return acc;
33
- if (!acc[index]) {
34
+ if ((0, lodash_1.isNil)(acc[index]))
34
35
  acc[index] = [];
35
- }
36
- acc[index].push(curr.id);
37
- return acc;
36
+ return { ...acc, [index]: [...acc[index], curr.id] };
38
37
  }, {});
39
38
  const responses = await Promise.all(Object.entries(relatedMap)
40
39
  .map(([contentType, ids]) => {
41
- const contentTypeUid = (0, lodash_1.get)((0, lodash_1.find)(contentTypes, cnt => cnt.uid === contentType), 'uid');
42
- return strapi.query(contentTypeUid)
40
+ (0, types_1.assertNotEmpty)((0, lodash_1.find)(contentTypes, cnt => cnt.uid === contentType));
41
+ return strapi.query(contentType)
43
42
  .findMany({
44
43
  where: { id: { $in: ids } },
45
44
  limit: Number.MAX_SAFE_INTEGER,
45
+ populate: ["template"],
46
46
  })
47
47
  .then(res => ({ [contentType]: res }));
48
48
  }));
@@ -141,18 +141,6 @@ const singularize = (value = '') => {
141
141
  return (0, lodash_1.last)(value) === 's' ? value.substr(0, value.length - 1) : value;
142
142
  };
143
143
  exports.singularize = singularize;
144
- const extractMeta = (plugins) => {
145
- const { navigation: plugin } = plugins;
146
- return {
147
- masterModel: plugin.contentType('navigation'),
148
- itemModel: plugin.contentType('navigation-item'),
149
- relatedModel: plugin.contentType('navigations-items-related'),
150
- audienceModel: plugin.contentType('audience'),
151
- plugin,
152
- pluginName: 'navigation',
153
- };
154
- };
155
- exports.extractMeta = extractMeta;
156
144
  const buildNestedStructure = (entities, id = null, field = 'parent') => {
157
145
  return entities
158
146
  .filter(entity => {
@@ -223,4 +211,54 @@ const isContentTypeEligible = (uid = '') => {
223
211
  exports.isContentTypeEligible = isContentTypeEligible;
224
212
  const intercalate = (glue, arr) => arr.slice(1).reduce((acc, element) => acc.concat([glue, element]), arr.slice(0, 1));
225
213
  exports.intercalate = intercalate;
214
+ const compareArraysOfNumbers = (arrA, arrB) => {
215
+ const diff = (0, lodash_1.zipWith)(arrA, arrB, (a, b) => {
216
+ if ((0, lodash_1.isNil)(a))
217
+ return -1;
218
+ if ((0, lodash_1.isNil)(b))
219
+ return 1;
220
+ return a - b;
221
+ });
222
+ return (0, lodash_1.find)(diff, a => a !== 0) || 0;
223
+ };
224
+ exports.compareArraysOfNumbers = compareArraysOfNumbers;
225
+ const getPluginModels = () => {
226
+ const plugin = strapi.plugin('navigation');
227
+ return {
228
+ masterModel: plugin.contentType('navigation'),
229
+ itemModel: plugin.contentType('navigation-item'),
230
+ relatedModel: plugin.contentType('navigations-items-related'),
231
+ audienceModel: plugin.contentType('audience'),
232
+ };
233
+ };
234
+ exports.getPluginModels = getPluginModels;
235
+ const validateAdditionalFields = (additionalFields) => {
236
+ const forbiddenNames = [
237
+ 'title', 'type', 'path',
238
+ 'externalPath', 'uiRouterKey', 'menuAttached',
239
+ 'order', 'collapsed', 'related',
240
+ 'parent', 'master', 'audience',
241
+ 'additionalFields',
242
+ ];
243
+ const customFields = (0, exports.getCustomFields)(additionalFields);
244
+ if (customFields.length !== (0, lodash_1.uniqBy)(customFields, 'name').length) {
245
+ throw new Error('All names of custom fields must be unique.');
246
+ }
247
+ if (!(0, lodash_1.isNil)((0, lodash_1.find)(customFields, item => (0, lodash_1.includes)(forbiddenNames, item.name)))) {
248
+ throw new Error(`Name of custom field cannot be one of: ${forbiddenNames.join(', ')}`);
249
+ }
250
+ };
251
+ exports.validateAdditionalFields = validateAdditionalFields;
252
+ const parsePopulateQuery = (populate) => {
253
+ if (populate === "*") {
254
+ return true;
255
+ }
256
+ else if (typeof populate === "string") {
257
+ return [populate];
258
+ }
259
+ else {
260
+ return populate;
261
+ }
262
+ };
263
+ exports.parsePopulateQuery = parsePopulateQuery;
226
264
  //# sourceMappingURL=functions.js.map
@@ -28,13 +28,6 @@ declare const _default: () => {
28
28
  };
29
29
  };
30
30
  navigation: {
31
- lifecycle: {
32
- renderType: {
33
- FLAT: string;
34
- TREE: string;
35
- RFR: string;
36
- };
37
- };
38
31
  schema: {
39
32
  collectionName: string;
40
33
  info: {
@@ -90,19 +83,6 @@ declare const _default: () => {
90
83
  };
91
84
  };
92
85
  "navigation-item": {
93
- lifecycle: {
94
- type: {
95
- INTERNAL: string;
96
- EXTERNAL: string;
97
- WRAPPER: string;
98
- };
99
- additionalFields: {
100
- AUDIENCE: string;
101
- };
102
- lifecycles: {
103
- afterFind(results: any): void;
104
- };
105
- };
106
86
  schema: {
107
87
  collectionName: string;
108
88
  info: {
@@ -196,15 +176,15 @@ declare const _default: () => {
196
176
  relation: string;
197
177
  target: string;
198
178
  };
179
+ additionalFields: {
180
+ type: string;
181
+ require: boolean;
182
+ default: {};
183
+ };
199
184
  };
200
185
  };
201
186
  };
202
187
  "navigations-items-related": {
203
- lifecycle: {
204
- lifecycles: {
205
- afterFind(results: any): void;
206
- };
207
- };
208
188
  schema: {
209
189
  collectionName: string;
210
190
  info: {