@websolutespa/bom-mixer-store 1.7.8 → 1.7.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @websolutespa/bom-mixer-store
2
2
 
3
+ ## 1.7.9
4
+
5
+ ### Patch Changes
6
+
7
+ - Added: MenuCategory strategy
8
+ - Updated dependencies
9
+ - @websolutespa/bom-core@1.7.16
10
+
3
11
  ## 1.7.8
4
12
 
5
13
  ### Patch Changes
package/dist/index.js CHANGED
@@ -370,26 +370,44 @@ function collectUndecoratedPages(items, undecoratedPages = []) {
370
370
  return undecoratedPages;
371
371
  }
372
372
  var MAX_INT = 1e12;
373
- function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
374
- const decoratedItem = {
375
- abstract: item.abstract,
376
- category: "",
377
- customClass: item.customClass,
373
+ function makeCategoryMenuItem_(item, category) {
374
+ const id = item.id || (0, import_bom_core3.uuidv4)();
375
+ const title = item.title || category.title || "";
376
+ const abstract = item.abstract || void 0;
377
+ const customClass = item.customClass || void 0;
378
+ const media = item.media || category.media;
379
+ const items = [];
380
+ return category.isHidden ? {
381
+ type: "group",
382
+ id,
383
+ title,
384
+ abstract,
385
+ media,
386
+ customClass,
387
+ items
388
+ } : {
389
+ type: "category",
390
+ category: category.id,
391
+ id,
378
392
  href: "",
379
- id: item.id || (0, import_bom_core3.uuidv4)(),
380
- items: [],
381
- title: "",
382
- type: item.type
393
+ title,
394
+ abstract,
395
+ media,
396
+ customClass,
397
+ items
383
398
  };
384
- const category = (0, import_bom_core3.findCategoryInCategories)(categories, item.category);
399
+ }
400
+ function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
401
+ const strategy = item.strategy || import_bom_core3.MenuCategoryStrategy.Default;
402
+ const categoryId = (0, import_bom_core3.asCategoryId)(item.category);
403
+ const category = categoryId ? categories.find((x) => x.id === categoryId) : void 0;
385
404
  if (category) {
386
- decoratedItem.category = category.id;
387
- decoratedItem.title = item.title || category.title || "";
388
- decoratedItem.media = item.media || category.media;
389
- const route = (0, import_bom_core3.findRouteOfCategory)(routes, category.id);
390
- if (route) {
391
- decoratedItem.href = route.id;
392
- } else {
405
+ const decoratedItem = makeCategoryMenuItem_(item, category);
406
+ if (!category.isHidden) {
407
+ const route = routes.find((route2) => route2.isDefault && route2.resolvedCategory === category.id);
408
+ if (route) {
409
+ decoratedItem.href = route.id;
410
+ }
393
411
  }
394
412
  let maxDepth = item.maxDepth;
395
413
  if (typeof maxDepth === "number") {
@@ -398,33 +416,55 @@ function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
398
416
  }
399
417
  maxDepth--;
400
418
  }
401
- const childCategories = (0, import_bom_core3.findChildCategories)(categories, category.id).filter((x) => Boolean(x.isHidden) === false);
402
- if (childCategories.length) {
403
- childCategories.sort((a, b) => {
404
- return (a.order || MAX_INT) - (b.order || MAX_INT);
405
- });
406
- decoratedItem.items = childCategories.map((c) => decorateMenuCategory_({
407
- id: c.id,
408
- type: "category",
409
- category: c.id,
410
- maxDepth,
411
- items: []
412
- }, categories, routes, market, depth + 1));
413
- }
414
- const childRoutes = (0, import_bom_core3.findRoutesOfCategory)(routes, category.id, false);
419
+ const childCategories = (category.id ? categories.filter((x) => (0, import_bom_core3.asCategoryId)(x.category) === category.id) : []).filter((x) => {
420
+ switch (strategy) {
421
+ case import_bom_core3.MenuCategoryStrategy.ExcludeHidden:
422
+ return Boolean(x.isHidden) === false;
423
+ case import_bom_core3.MenuCategoryStrategy.Default:
424
+ return true;
425
+ }
426
+ });
427
+ childCategories.sort((a, b) => {
428
+ return (a.order || MAX_INT) - (b.order || MAX_INT);
429
+ });
430
+ const subStrategy = strategy;
431
+ const childCategoryItems = childCategories.map((c) => decorateMenuCategory_({
432
+ id: c.id,
433
+ type: "category",
434
+ category: c.id,
435
+ maxDepth,
436
+ strategy: subStrategy,
437
+ // dispatch sub strategy
438
+ items: []
439
+ }, categories, routes, market, depth + 1));
440
+ const childRoutes = routes.filter((route) => {
441
+ switch (strategy) {
442
+ case import_bom_core3.MenuCategoryStrategy.ExcludeHidden:
443
+ return route.resolvedCategory === category.id && Boolean(route.isDefault) === false;
444
+ case import_bom_core3.MenuCategoryStrategy.Default:
445
+ return route.category === category.id && (category.isHidden || Boolean(route.isDefault) === false);
446
+ }
447
+ });
415
448
  childRoutes.sort((a, b) => {
416
449
  return (a.order || MAX_INT) - (b.order || MAX_INT);
417
450
  });
451
+ const childRouteItems = childRoutes.map((x) => decorateMenuRoute_(x));
418
452
  decoratedItem.items = [
419
- ...decoratedItem.items || [],
420
- ...childRoutes.map((x) => decorateMenuRoute_(x))
421
- ];
453
+ ...childCategoryItems,
454
+ ...childRouteItems
455
+ ].filter((x) => Boolean(x));
456
+ return decoratedItem;
422
457
  }
423
- return decoratedItem;
458
+ return {
459
+ id: item.id || (0, import_bom_core3.uuidv4)(),
460
+ type: "group",
461
+ title: item.title || "",
462
+ items: []
463
+ };
424
464
  }
425
465
  function decorateMenuRoute_(item) {
426
466
  const decoratedItem = {
427
- id: item.page,
467
+ id: (0, import_bom_core3.uuidv4)(),
428
468
  type: "route",
429
469
  title: item.title,
430
470
  href: item.id,
@@ -2054,7 +2094,7 @@ async function getRouteLinkTree(market, locale) {
2054
2094
  }
2055
2095
  }
2056
2096
  });
2057
- const categories = await store.category.findMany();
2097
+ const categories = await store.category.findMany({ market, locale });
2058
2098
  const rootCategory = (0, import_bom_core16.getRootCategory)(categories);
2059
2099
  if (rootCategory) {
2060
2100
  const root = categoryToRouteLink(routes, categories, rootCategory, locale);
package/dist/index.mjs CHANGED
@@ -182,10 +182,11 @@ async function decorateLocalizables_(items, params = {}) {
182
182
 
183
183
  // src/decorators/menu.ts
184
184
  import {
185
+ MenuCategoryStrategy,
186
+ asCategoryId,
185
187
  findCategoryInCategories,
186
188
  findChildCategories,
187
189
  findRouteOfCategory as findRouteOfCategory2,
188
- findRoutesOfCategory,
189
190
  isEquatable,
190
191
  isUndecoratedMenuCategory,
191
192
  isUndecoratedMenuPage,
@@ -265,26 +266,44 @@ function collectUndecoratedPages(items, undecoratedPages = []) {
265
266
  return undecoratedPages;
266
267
  }
267
268
  var MAX_INT = 1e12;
268
- function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
269
- const decoratedItem = {
270
- abstract: item.abstract,
271
- category: "",
272
- customClass: item.customClass,
269
+ function makeCategoryMenuItem_(item, category) {
270
+ const id = item.id || uuidv4();
271
+ const title = item.title || category.title || "";
272
+ const abstract = item.abstract || void 0;
273
+ const customClass = item.customClass || void 0;
274
+ const media = item.media || category.media;
275
+ const items = [];
276
+ return category.isHidden ? {
277
+ type: "group",
278
+ id,
279
+ title,
280
+ abstract,
281
+ media,
282
+ customClass,
283
+ items
284
+ } : {
285
+ type: "category",
286
+ category: category.id,
287
+ id,
273
288
  href: "",
274
- id: item.id || uuidv4(),
275
- items: [],
276
- title: "",
277
- type: item.type
289
+ title,
290
+ abstract,
291
+ media,
292
+ customClass,
293
+ items
278
294
  };
279
- const category = findCategoryInCategories(categories, item.category);
295
+ }
296
+ function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
297
+ const strategy = item.strategy || MenuCategoryStrategy.Default;
298
+ const categoryId = asCategoryId(item.category);
299
+ const category = categoryId ? categories.find((x) => x.id === categoryId) : void 0;
280
300
  if (category) {
281
- decoratedItem.category = category.id;
282
- decoratedItem.title = item.title || category.title || "";
283
- decoratedItem.media = item.media || category.media;
284
- const route = findRouteOfCategory2(routes, category.id);
285
- if (route) {
286
- decoratedItem.href = route.id;
287
- } else {
301
+ const decoratedItem = makeCategoryMenuItem_(item, category);
302
+ if (!category.isHidden) {
303
+ const route = routes.find((route2) => route2.isDefault && route2.resolvedCategory === category.id);
304
+ if (route) {
305
+ decoratedItem.href = route.id;
306
+ }
288
307
  }
289
308
  let maxDepth = item.maxDepth;
290
309
  if (typeof maxDepth === "number") {
@@ -293,33 +312,55 @@ function decorateMenuCategory_(item, categories, routes, market, depth = 0) {
293
312
  }
294
313
  maxDepth--;
295
314
  }
296
- const childCategories = findChildCategories(categories, category.id).filter((x) => Boolean(x.isHidden) === false);
297
- if (childCategories.length) {
298
- childCategories.sort((a, b) => {
299
- return (a.order || MAX_INT) - (b.order || MAX_INT);
300
- });
301
- decoratedItem.items = childCategories.map((c) => decorateMenuCategory_({
302
- id: c.id,
303
- type: "category",
304
- category: c.id,
305
- maxDepth,
306
- items: []
307
- }, categories, routes, market, depth + 1));
308
- }
309
- const childRoutes = findRoutesOfCategory(routes, category.id, false);
315
+ const childCategories = (category.id ? categories.filter((x) => asCategoryId(x.category) === category.id) : []).filter((x) => {
316
+ switch (strategy) {
317
+ case MenuCategoryStrategy.ExcludeHidden:
318
+ return Boolean(x.isHidden) === false;
319
+ case MenuCategoryStrategy.Default:
320
+ return true;
321
+ }
322
+ });
323
+ childCategories.sort((a, b) => {
324
+ return (a.order || MAX_INT) - (b.order || MAX_INT);
325
+ });
326
+ const subStrategy = strategy;
327
+ const childCategoryItems = childCategories.map((c) => decorateMenuCategory_({
328
+ id: c.id,
329
+ type: "category",
330
+ category: c.id,
331
+ maxDepth,
332
+ strategy: subStrategy,
333
+ // dispatch sub strategy
334
+ items: []
335
+ }, categories, routes, market, depth + 1));
336
+ const childRoutes = routes.filter((route) => {
337
+ switch (strategy) {
338
+ case MenuCategoryStrategy.ExcludeHidden:
339
+ return route.resolvedCategory === category.id && Boolean(route.isDefault) === false;
340
+ case MenuCategoryStrategy.Default:
341
+ return route.category === category.id && (category.isHidden || Boolean(route.isDefault) === false);
342
+ }
343
+ });
310
344
  childRoutes.sort((a, b) => {
311
345
  return (a.order || MAX_INT) - (b.order || MAX_INT);
312
346
  });
347
+ const childRouteItems = childRoutes.map((x) => decorateMenuRoute_(x));
313
348
  decoratedItem.items = [
314
- ...decoratedItem.items || [],
315
- ...childRoutes.map((x) => decorateMenuRoute_(x))
316
- ];
349
+ ...childCategoryItems,
350
+ ...childRouteItems
351
+ ].filter((x) => Boolean(x));
352
+ return decoratedItem;
317
353
  }
318
- return decoratedItem;
354
+ return {
355
+ id: item.id || uuidv4(),
356
+ type: "group",
357
+ title: item.title || "",
358
+ items: []
359
+ };
319
360
  }
320
361
  function decorateMenuRoute_(item) {
321
362
  const decoratedItem = {
322
- id: item.page,
363
+ id: uuidv4(),
323
364
  type: "route",
324
365
  title: item.title,
325
366
  href: item.id,
@@ -1936,7 +1977,7 @@ async function storeApiDelete(url, options = {}) {
1936
1977
  import { getHost, getOrigin, isDevelopment as isDevelopment2, isProduction } from "@websolutespa/bom-core";
1937
1978
 
1938
1979
  // ../models/src/route/route.service.ts
1939
- import { asCategoryId, defaultLocale as defaultLocale2, defaultMarket as defaultMarket2, findRouteOfCategory as findRouteOfCategory3, getRootCategory, localize } from "@websolutespa/bom-core";
1980
+ import { asCategoryId as asCategoryId2, defaultLocale as defaultLocale2, defaultMarket as defaultMarket2, findRouteOfCategory as findRouteOfCategory3, getRootCategory, localize } from "@websolutespa/bom-core";
1940
1981
  async function getRouteLinkTree(market, locale) {
1941
1982
  const store = await getStore();
1942
1983
  const routes = await store.route.findMany({
@@ -1949,7 +1990,7 @@ async function getRouteLinkTree(market, locale) {
1949
1990
  }
1950
1991
  }
1951
1992
  });
1952
- const categories = await store.category.findMany();
1993
+ const categories = await store.category.findMany({ market, locale });
1953
1994
  const rootCategory = getRootCategory(categories);
1954
1995
  if (rootCategory) {
1955
1996
  const root = categoryToRouteLink(routes, categories, rootCategory, locale);
@@ -1964,7 +2005,7 @@ function categoryToRouteLink(routes, categories, category, locale) {
1964
2005
  }
1965
2006
  const rootCategory = getRootCategory(categories);
1966
2007
  const childCategories = categories.filter((x) => {
1967
- const parentId = asCategoryId(x.category);
2008
+ const parentId = asCategoryId2(x.category);
1968
2009
  return rootCategory && rootCategory.id === category.id ? x.id !== rootCategory.id && (parentId === category.id || !parentId) : parentId === category.id;
1969
2010
  });
1970
2011
  const routeLink = newRouteLink(category, route, locale);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@websolutespa/bom-mixer-store",
3
- "version": "1.7.8",
3
+ "version": "1.7.9",
4
4
  "description": "Mixer Store module of the BOM Repository",
5
5
  "keywords": [
6
6
  "bom",
@@ -1,9 +1,11 @@
1
1
  import {
2
- ICategorized, ICategory, IMenu, IMenuCategory, IMenuItem, IMenuPage, IMenuRoute, IRoute, IStore,
3
- IUndecoratedMenu, IUndecoratedMenuCategory, IUndecoratedMenuItem, IUndecoratedMenuPage, QueryParams,
2
+ ICategorized, ICategory, IMenu, IMenuCategory, IMenuGroup, IMenuItem, IMenuPage, IMenuRoute, IRoute, IStore,
3
+ IUndecoratedMenu, IUndecoratedMenuCategory, IUndecoratedMenuItem, IUndecoratedMenuPage, MenuCategoryStrategy, QueryParams,
4
+ asCategoryId,
4
5
  findCategoryInCategories,
5
6
  findChildCategories,
6
- findRouteOfCategory, findRoutesOfCategory, isEquatable, isUndecoratedMenuCategory, isUndecoratedMenuPage,
7
+ findRouteOfCategory,
8
+ isEquatable, isUndecoratedMenuCategory, isUndecoratedMenuPage,
7
9
  uuidv4
8
10
  } from '@websolutespa/bom-core';
9
11
 
@@ -91,12 +93,125 @@ function collectUndecoratedPages(items: IUndecoratedMenuItem[], undecoratedPages
91
93
 
92
94
  export const MAX_INT = 1000000000000; // 9007199254740991
93
95
 
96
+ function makeCategoryMenuItem_(item: IUndecoratedMenuCategory, category: ICategory): IMenuCategory | IMenuGroup {
97
+ const id = item.id || uuidv4();
98
+ const title = item.title || category.title || '';
99
+ const abstract = item.abstract || undefined;
100
+ const customClass = item.customClass || undefined;
101
+ const media = item.media || category.media;
102
+ const items: IMenuItem[] = [];
103
+ return category.isHidden ?
104
+ {
105
+ type: 'group',
106
+ id,
107
+ title,
108
+ abstract,
109
+ media,
110
+ customClass,
111
+ items,
112
+ } : {
113
+ type: 'category',
114
+ category: category.id,
115
+ id,
116
+ href: '',
117
+ title,
118
+ abstract,
119
+ media,
120
+ customClass,
121
+ items,
122
+ };
123
+ }
124
+
94
125
  function decorateMenuCategory_(
95
126
  item: IUndecoratedMenuCategory,
96
127
  categories: ICategory[],
97
128
  routes: IRoute[],
98
129
  market: string,
99
130
  depth: number = 0
131
+ ): IMenuItem | undefined {
132
+ const strategy = item.strategy || MenuCategoryStrategy.Default;
133
+ const categoryId = asCategoryId(item.category);
134
+ // find category
135
+ const category = categoryId ? categories.find(x => x.id === categoryId) : undefined;
136
+ if (category) {
137
+ const decoratedItem = makeCategoryMenuItem_(item, category);
138
+ if (!category.isHidden) {
139
+ const route = routes.find((route: IRoute) => route.isDefault && route.resolvedCategory === category.id);
140
+ if (route) {
141
+ (decoratedItem as IMenuCategory).href = route.id;
142
+ }
143
+ }
144
+ // checking for max depth recursion
145
+ let maxDepth = item.maxDepth;
146
+ if (typeof maxDepth === 'number') {
147
+ if (depth > maxDepth) {
148
+ return decoratedItem;
149
+ }
150
+ maxDepth--;
151
+ }
152
+ // search child categories
153
+ const childCategories = (category.id ?
154
+ categories.filter(x => asCategoryId(x.category) === category.id) : []
155
+ ).filter(x => {
156
+ switch (strategy) {
157
+ case MenuCategoryStrategy.ExcludeHidden:
158
+ return Boolean(x.isHidden) === false;
159
+ case MenuCategoryStrategy.Default:
160
+ return true;
161
+ }
162
+ });
163
+ // sort child categories
164
+ childCategories.sort((a, b) => {
165
+ return (a.order || MAX_INT) - (b.order || MAX_INT);
166
+ });
167
+ // define sub strategy (!!! todo)
168
+ const subStrategy = strategy;
169
+ // decorate child categories
170
+ const childCategoryItems = childCategories.map(c => decorateMenuCategory_({
171
+ id: c.id,
172
+ type: 'category',
173
+ category: c.id,
174
+ maxDepth,
175
+ strategy: subStrategy, // dispatch sub strategy
176
+ items: [],
177
+ } as IUndecoratedMenuCategory, categories, routes, market, depth + 1));
178
+ // find child routes
179
+ const childRoutes = routes.filter((route: IRoute) => {
180
+ switch (strategy) {
181
+ case MenuCategoryStrategy.ExcludeHidden:
182
+ return route.resolvedCategory === category.id && Boolean(route.isDefault) === false;
183
+ case MenuCategoryStrategy.Default:
184
+ return route.category === category.id && (category.isHidden || Boolean(route.isDefault) === false);
185
+ }
186
+ });
187
+ // sort child routes
188
+ childRoutes.sort((a, b) => {
189
+ return (a.order || MAX_INT) - (b.order || MAX_INT);
190
+ });
191
+ // decorate child routes
192
+ const childRouteItems: IMenuItem[] = childRoutes.map(x => decorateMenuRoute_(x));
193
+ // filter items
194
+ decoratedItem.items = [
195
+ ...childCategoryItems,
196
+ ...childRouteItems,
197
+ ].filter(x => Boolean(x)) as IMenuItem[];
198
+ return decoratedItem;
199
+ }
200
+ // return unresolved category as group
201
+ return {
202
+ id: item.id || uuidv4(),
203
+ type: 'group',
204
+ title: item.title || '',
205
+ items: [],
206
+ };
207
+ }
208
+
209
+ function decorateMenuCategoryWithHiddenSubCategories_(
210
+ item: IUndecoratedMenuCategory,
211
+ categories: ICategory[],
212
+ routes: IRoute[],
213
+ market: string,
214
+ depth: number = 0
100
215
  ): IMenuItem {
101
216
  const decoratedItem: IMenuCategory = {
102
217
  abstract: item.abstract,
@@ -108,6 +223,10 @@ function decorateMenuCategory_(
108
223
  title: '',
109
224
  type: item.type,
110
225
  };
226
+ /*
227
+ const categoryId = asCategoryId(item.category);
228
+ const category = categoryId ? categories.find(x => x.id === categoryId) : undefined;
229
+ */
111
230
  const category = findCategoryInCategories(categories, item.category);
112
231
  if (category) {
113
232
  // assigning category id
@@ -133,22 +252,59 @@ function decorateMenuCategory_(
133
252
  maxDepth--;
134
253
  }
135
254
  // search child categories
136
- const childCategories = findChildCategories(categories, category.id).filter(x => Boolean(x.isHidden) === false);
255
+ const childCategories = findChildCategories(categories, category.id);
137
256
  if (childCategories.length) {
138
257
  // sort child categories
139
258
  childCategories.sort((a, b) => {
140
259
  return (a.order || MAX_INT) - (b.order || MAX_INT);
141
260
  });
142
- decoratedItem.items = childCategories.map(c => decorateMenuCategory_({
143
- id: c.id,
144
- type: 'category',
145
- category: c.id,
146
- maxDepth,
147
- items: [],
148
- } as IUndecoratedMenuCategory, categories, routes, market, depth + 1));
261
+ decoratedItem.items = childCategories.map(c => {
262
+ const menuCategory = decorateMenuCategoryWithHiddenSubCategories_({
263
+ id: c.id,
264
+ type: 'category',
265
+ category: c.id,
266
+ maxDepth,
267
+ items: [],
268
+ } as IUndecoratedMenuCategory, categories, routes, market, depth + 1);
269
+ if (c.isHidden) {
270
+ const group: IMenuGroup = {
271
+ id: c.id,
272
+ type: 'group',
273
+ title: c.title,
274
+ items: [
275
+ ...(menuCategory.items || []),
276
+ ],
277
+ };
278
+ // find child routes
279
+ // const childRoutes = findRoutesOfCategory(routes, c.id, false);
280
+ const childRoutes = routes.filter((route: IRoute) =>
281
+ route.category === c.id &&
282
+ Boolean(route.isDefault) === false
283
+ );
284
+ // sort child routes
285
+ childRoutes.sort((a, b) => {
286
+ return (a.order || MAX_INT) - (b.order || MAX_INT);
287
+ });
288
+ const routeLinks = childRoutes.map(x => decorateMenuRoute_(x));
289
+ group.items?.push(...routeLinks);
290
+ return group;
291
+ } else {
292
+ return decorateMenuCategoryWithHiddenSubCategories_({
293
+ id: c.id,
294
+ type: 'category',
295
+ category: c.id,
296
+ maxDepth,
297
+ items: [],
298
+ } as IUndecoratedMenuCategory, categories, routes, market, depth + 1);
299
+ }
300
+ });
149
301
  }
150
302
  // find child routes
151
- const childRoutes = findRoutesOfCategory(routes, category.id, false);
303
+ // const childRoutes = findRoutesOfCategory(routes, category.id, false);
304
+ const childRoutes = routes.filter((route: IRoute) =>
305
+ route.category === category.id &&
306
+ Boolean(route.isDefault) === false
307
+ );
152
308
  // console.log('childRoutes', childRoutes, category.id);
153
309
  // sort child routes
154
310
  childRoutes.sort((a, b) => {
@@ -158,6 +314,7 @@ function decorateMenuCategory_(
158
314
  ...(decoratedItem.items || []),
159
315
  ...childRoutes.map(x => decorateMenuRoute_(x)),
160
316
  ];
317
+
161
318
  }
162
319
  return decoratedItem;
163
320
  }
@@ -166,7 +323,7 @@ function decorateMenuRoute_(
166
323
  item: IRoute
167
324
  ): IMenuItem {
168
325
  const decoratedItem: IMenuRoute = {
169
- id: item.page,
326
+ id: uuidv4(),
170
327
  type: 'route',
171
328
  title: item.title,
172
329
  href: item.id,