@mattisvensson/strapi-plugin-webatlas 0.9.5 → 0.10.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 (117) hide show
  1. package/README.md +24 -36
  2. package/dist/_chunks/FullLoader-Cmsf8xS6.js +0 -1
  3. package/dist/_chunks/FullLoader-CrPED_dY.mjs +0 -1
  4. package/dist/_chunks/{SettingTitle-CiMKrd_1.mjs → SettingTitle-CdR3SVn_.mjs} +1 -2
  5. package/dist/_chunks/{SettingTitle-CAoYbTar.js → SettingTitle-RU1azFIM.js} +1 -1
  6. package/dist/_chunks/{de-C-uxto84.mjs → de-B5pRvs13.mjs} +13 -8
  7. package/dist/_chunks/{de-CGXL_3o_.js → de-CqU1FU8C.js} +13 -8
  8. package/dist/_chunks/{en-B1CHnIH7.mjs → en-BE-zzIv8.mjs} +13 -8
  9. package/dist/_chunks/{en-DWEd5BXK.js → en-C7I90FwV.js} +13 -8
  10. package/dist/_chunks/{index-Bqsd7oPS.mjs → index-B07UVUOa.mjs} +387 -230
  11. package/dist/_chunks/{index-DJBnQbrp.mjs → index-BmyxSosC.mjs} +3 -3
  12. package/dist/_chunks/{index-BOZDZiAv.js → index-BucL4va6.js} +38 -82
  13. package/dist/_chunks/{index-DU58LJ2w.mjs → index-BvcX9hcc.mjs} +61 -25
  14. package/dist/_chunks/{index-ezabqLEP.js → index-BxpDM360.js} +386 -228
  15. package/dist/_chunks/{index-qrC_n9-7.mjs → index-CIM-JzLK.mjs} +38 -82
  16. package/dist/_chunks/{index-qrrfKpw1.mjs → index-CNKWb8pn.mjs} +615 -321
  17. package/dist/_chunks/{index-m2ivL3ht.js → index-D-vJE_K8.js} +3 -3
  18. package/dist/_chunks/{index-BkB1x9Sn.js → index-IRSCe8PX.js} +610 -316
  19. package/dist/_chunks/{index-CC073vGB.js → index-d09V61nm.js} +61 -24
  20. package/dist/admin/index.js +1 -2
  21. package/dist/admin/index.mjs +1 -2
  22. package/dist/admin/src/components/CMEditViewAside/NewPathInfo.d.ts +2 -0
  23. package/dist/admin/src/components/CMEditViewAside/OverrideCheckbox.d.ts +7 -0
  24. package/dist/admin/src/components/CMEditViewAside/Panel.d.ts +5 -0
  25. package/dist/admin/src/components/CMEditViewAside/PathInput.d.ts +11 -0
  26. package/dist/admin/src/components/CMEditViewAside/RouteStructure.d.ts +3 -0
  27. package/dist/admin/src/components/CMEditViewAside/UidPathDisplay.d.ts +4 -0
  28. package/dist/admin/src/components/PathInfo.d.ts +2 -3
  29. package/dist/admin/src/components/modals/externalItem/index.d.ts +1 -1
  30. package/dist/admin/src/components/modals/internalItem/ItemDetails.d.ts +13 -0
  31. package/dist/admin/src/components/modals/internalItem/internalItemCreate.d.ts +1 -1
  32. package/dist/admin/src/components/modals/internalItem/internalItemEdit.d.ts +1 -1
  33. package/dist/admin/src/components/modals/useModalSharedLogic.d.ts +1 -1
  34. package/dist/admin/src/components/modals/wrapperItem/index.d.ts +1 -1
  35. package/dist/admin/src/hooks/useApi.d.ts +4 -3
  36. package/dist/admin/src/pages/Navigation/RouteItem.d.ts +1 -15
  37. package/dist/admin/src/pages/Navigation/RouteItemBadge.d.ts +4 -0
  38. package/dist/admin/src/pages/Navigation/RouteItemIcon.d.ts +5 -0
  39. package/dist/admin/src/pages/Navigation/RouteItemMenu.d.ts +10 -0
  40. package/dist/admin/src/pages/Navigation/RouteItemStatus.d.ts +5 -0
  41. package/dist/admin/src/pages/Navigation/SortableRouteItem.d.ts +1 -1
  42. package/dist/admin/src/types/index.d.ts +3 -0
  43. package/dist/admin/src/types/modal.d.ts +56 -0
  44. package/dist/admin/src/types/navigation.d.ts +18 -0
  45. package/dist/admin/src/types/panel.d.ts +41 -0
  46. package/dist/admin/src/types/route.d.ts +1 -1
  47. package/dist/admin/src/utils/buildBreadcrumbString.d.ts +16 -0
  48. package/dist/admin/src/utils/createTempNavItemObject.d.ts +6 -8
  49. package/dist/admin/src/utils/duplicateCheck.d.ts +10 -4
  50. package/dist/admin/src/utils/findParentNavItem.d.ts +13 -0
  51. package/dist/admin/src/utils/index.d.ts +3 -2
  52. package/dist/server/index.js +636 -209
  53. package/dist/server/index.mjs +636 -209
  54. package/dist/server/src/content-types/index.d.ts +18 -0
  55. package/dist/server/src/content-types/route/index.d.ts +18 -0
  56. package/dist/server/src/content-types/route/schema.d.ts +18 -0
  57. package/dist/server/src/controllers/admin.d.ts +3 -2
  58. package/dist/server/src/controllers/index.d.ts +3 -2
  59. package/dist/server/src/index.d.ts +24 -4
  60. package/dist/server/src/migrations/001-canonical-path.d.ts +7 -0
  61. package/dist/server/src/migrations/index.d.ts +3 -0
  62. package/dist/server/src/services/admin.d.ts +3 -2
  63. package/dist/server/src/services/index.d.ts +3 -2
  64. package/dist/server/src/utils/buildCanonicalPath.d.ts +1 -0
  65. package/dist/server/src/utils/buildNavigationPath.d.ts +5 -0
  66. package/dist/server/src/utils/cascadeCanonicalPathUpdates.d.ts +1 -0
  67. package/dist/server/src/utils/getNonInternalRouteIds.d.ts +1 -0
  68. package/dist/server/src/utils/getRouteAncestors.d.ts +1 -0
  69. package/dist/server/src/utils/getRouteDescendants.d.ts +1 -0
  70. package/dist/server/src/utils/index.d.ts +10 -2
  71. package/dist/server/src/utils/navigationItemStructure.d.ts +27 -0
  72. package/dist/server/src/utils/routeHandler.d.ts +4 -2
  73. package/dist/server/src/utils/validateRouteDependencies.d.ts +4 -0
  74. package/dist/types/index.d.ts +0 -1
  75. package/dist/types/navigation.d.ts +13 -12
  76. package/dist/types/route.d.ts +7 -2
  77. package/dist/types/strapi.d.ts +1 -2
  78. package/dist/utils/index.d.ts +1 -2
  79. package/package.json +1 -1
  80. package/dist/_chunks/FullLoader-Cmsf8xS6.js.map +0 -1
  81. package/dist/_chunks/FullLoader-CrPED_dY.mjs.map +0 -1
  82. package/dist/_chunks/SettingTitle-ByAhjihc.js +0 -68
  83. package/dist/_chunks/SettingTitle-ByAhjihc.js.map +0 -1
  84. package/dist/_chunks/SettingTitle-CiMKrd_1.mjs.map +0 -1
  85. package/dist/_chunks/SettingTitle-ZM5Yf2b4.mjs +0 -68
  86. package/dist/_chunks/de-C-uxto84.mjs.map +0 -1
  87. package/dist/_chunks/de-CGXL_3o_.js.map +0 -1
  88. package/dist/_chunks/en-B1CHnIH7.mjs.map +0 -1
  89. package/dist/_chunks/en-DWEd5BXK.js.map +0 -1
  90. package/dist/_chunks/index-BqceJPRl.js +0 -235
  91. package/dist/_chunks/index-BqceJPRl.js.map +0 -1
  92. package/dist/_chunks/index-Bqsd7oPS.mjs.map +0 -1
  93. package/dist/_chunks/index-CK1wisw5.mjs +0 -129
  94. package/dist/_chunks/index-CK1wisw5.mjs.map +0 -1
  95. package/dist/_chunks/index-CQ2raqxe.js +0 -129
  96. package/dist/_chunks/index-CQ2raqxe.js.map +0 -1
  97. package/dist/_chunks/index-Ca9T36AU.mjs +0 -263
  98. package/dist/_chunks/index-Ca9T36AU.mjs.map +0 -1
  99. package/dist/_chunks/index-DDN4T6c7.mjs +0 -4188
  100. package/dist/_chunks/index-DH4Rd7aA.mjs +0 -8311
  101. package/dist/_chunks/index-DH4Rd7aA.mjs.map +0 -1
  102. package/dist/_chunks/index-DU58LJ2w.mjs.map +0 -1
  103. package/dist/_chunks/index-DnE_cDwy.js +0 -8311
  104. package/dist/_chunks/index-DnE_cDwy.js.map +0 -1
  105. package/dist/_chunks/index-DzpXVfQ_.js +0 -263
  106. package/dist/_chunks/index-DzpXVfQ_.js.map +0 -1
  107. package/dist/_chunks/index-R7qsEu2N.js +0 -4205
  108. package/dist/_chunks/index-R7qsEu2N.js.map +0 -1
  109. package/dist/_chunks/index-fbC3magu.mjs +0 -234
  110. package/dist/admin/index.js.map +0 -1
  111. package/dist/admin/index.mjs.map +0 -1
  112. package/dist/admin/src/components/CMEditViewAside/Path.d.ts +0 -5
  113. package/dist/admin/src/utils/countChildren.d.ts +0 -2
  114. package/dist/server/index.js.map +0 -1
  115. package/dist/server/index.mjs.map +0 -1
  116. package/dist/types/modal.d.ts +0 -36
  117. package/dist/utils/getPath.d.ts +0 -1
@@ -1,10 +1,4 @@
1
1
  "use strict";
2
- function getPath(parentPath, slug) {
3
- if (!slug) return null;
4
- if (!parentPath) return slug;
5
- const newPath = parentPath.endsWith("/") ? parentPath : `${parentPath}/`;
6
- return `${newPath}${slug}`;
7
- }
8
2
  function transformToUrl(input) {
9
3
  const specialCharMap = {
10
4
  "ü": "ue",
@@ -16,6 +10,7 @@ function transformToUrl(input) {
16
10
  input = input.replace(/\/+/g, "/");
17
11
  input = input.startsWith("/") ? input.slice(1) : input;
18
12
  input = input.endsWith("/") ? input.slice(0, -1) : input;
13
+ input = input.replace(/\//g, "-");
19
14
  for (const char in specialCharMap) {
20
15
  const regex = new RegExp(char, "g");
21
16
  input = input.replace(regex, specialCharMap[char]);
@@ -26,7 +21,7 @@ function transformToUrl(input) {
26
21
  input = input.replace(/-+/g, "-");
27
22
  return input;
28
23
  }
29
- const version = "0.9.5";
24
+ const version = "0.9.6";
30
25
  const keywords = [];
31
26
  const type = "commonjs";
32
27
  const exports$1 = {
@@ -151,15 +146,10 @@ async function checkPathExists(path, targetRoutePath) {
151
146
  const entities = await strapi.documents(waRoute).findMany({
152
147
  filters: {
153
148
  $or: [
154
- {
155
- path
156
- },
157
- {
158
- slug: path
159
- },
160
- {
161
- uidPath: path
162
- }
149
+ { path },
150
+ { slug: path },
151
+ { uidPath: path },
152
+ { canonicalPath: path }
163
153
  ]
164
154
  }
165
155
  });
@@ -186,27 +176,12 @@ async function duplicateCheck(initialPath, targetRouteDocumentId) {
186
176
  }
187
177
  return uniquePath;
188
178
  } catch (e) {
189
- console.log(e);
179
+ strapi.log.error(e);
190
180
  }
191
181
  }
192
182
  async function createNavItem(data) {
193
183
  try {
194
184
  if (!data.route || !data.navigation) return null;
195
- const parent = data.parent ? await strapi.documents(waNavItem).findOne({
196
- documentId: data.parent,
197
- populate: ["route"]
198
- }) : null;
199
- const route2 = data.route ? await strapi.documents(waRoute).findOne({
200
- documentId: data.route
201
- }) : null;
202
- let path = route2.slug;
203
- if (route2.type === "internal" && !route2.isOverride && parent?.route.type === "internal") path = getPath(parent?.route?.path, route2.slug);
204
- await strapi.documents(waRoute).update({
205
- documentId: data.route,
206
- data: {
207
- path
208
- }
209
- });
210
185
  const entity = await strapi.documents(waNavItem).create({
211
186
  data: {
212
187
  navigation: data.navigation,
@@ -217,7 +192,7 @@ async function createNavItem(data) {
217
192
  });
218
193
  return entity;
219
194
  } catch (e) {
220
- console.log(e);
195
+ strapi.log.error(e);
221
196
  }
222
197
  }
223
198
  async function updateNavItem(documentId, data) {
@@ -230,7 +205,7 @@ async function updateNavItem(documentId, data) {
230
205
  data: updateData
231
206
  });
232
207
  } catch (e) {
233
- console.log(e);
208
+ strapi.log.error(e);
234
209
  }
235
210
  }
236
211
  async function deleteNavItem(documentId) {
@@ -240,7 +215,7 @@ async function deleteNavItem(documentId) {
240
215
  });
241
216
  return true;
242
217
  } catch (e) {
243
- console.log(e);
218
+ strapi.log.error(e);
244
219
  }
245
220
  }
246
221
  function getAdminService() {
@@ -282,7 +257,31 @@ async function createExternalRoute(data) {
282
257
  }
283
258
  });
284
259
  } catch (e) {
285
- console.log(e);
260
+ strapi.log.error(e);
261
+ }
262
+ }
263
+ async function updateRoute(documentId, data) {
264
+ try {
265
+ const entity = await strapi.documents(waRoute).update({
266
+ documentId,
267
+ data: {
268
+ ...data
269
+ }
270
+ });
271
+ return entity;
272
+ } catch (e) {
273
+ strapi.log.error(e);
274
+ }
275
+ }
276
+ async function deleteRoute(documentId) {
277
+ try {
278
+ await strapi.documents(waRoute).delete({
279
+ documentId
280
+ });
281
+ return true;
282
+ } catch (e) {
283
+ strapi.log.error(e);
284
+ return false;
286
285
  }
287
286
  }
288
287
  function buildStructuredNavigation(navigation2, variant = "nested") {
@@ -336,7 +335,7 @@ function buildStructuredNavigation(navigation2, variant = "nested") {
336
335
  return { ...navigation2, items: flattenedItems };
337
336
  }
338
337
  } catch (error) {
339
- console.error(error);
338
+ strapi.log.error(error);
340
339
  throw error;
341
340
  }
342
341
  }
@@ -377,8 +376,6 @@ function extractRouteAndItems(items) {
377
376
  delete route2.createdAt;
378
377
  delete route2.updatedAt;
379
378
  delete route2.isOverride;
380
- delete route2.internal;
381
- delete route2.wrapper;
382
379
  return {
383
380
  __component: route2.type === "wrapper" ? `${PLUGIN_ID}.wrapper` : `${PLUGIN_ID}.route`,
384
381
  type: route2.type,
@@ -4399,10 +4396,406 @@ function cleanRootKeys(obj) {
4399
4396
  function removeWaFields(obj) {
4400
4397
  delete obj["webatlas_path"];
4401
4398
  delete obj["webatlas_override"];
4399
+ delete obj["webatlas_parent"];
4402
4400
  return obj;
4403
4401
  }
4402
+ async function buildCanonicalPath(slug, parentDocumentId) {
4403
+ try {
4404
+ const parentRoute = await strapi.documents(waRoute).findOne({
4405
+ documentId: parentDocumentId
4406
+ });
4407
+ const parentCanonicalPath = parentRoute?.canonicalPath || "";
4408
+ const canonicalPath = `${parentCanonicalPath ? parentCanonicalPath + "/" : ""}${slug}`;
4409
+ return canonicalPath;
4410
+ } catch (err) {
4411
+ strapi.log.error("Error building canonical path:", err);
4412
+ return slug;
4413
+ }
4414
+ }
4415
+ async function cascadeCanonicalPathUpdates(parentRouteId, newParentCanonicalPath) {
4416
+ const children = await strapi.db.query(waRoute).findMany({
4417
+ where: {
4418
+ parent: {
4419
+ documentId: parentRouteId
4420
+ }
4421
+ }
4422
+ });
4423
+ for (const child of children) {
4424
+ const newCanonicalPath = `${newParentCanonicalPath}/${child.slug}`;
4425
+ const updateData = {
4426
+ canonicalPath: newCanonicalPath,
4427
+ // Only update path if not manually overridden
4428
+ ...child.isOverride ? {} : { path: newCanonicalPath }
4429
+ };
4430
+ await strapi.documents(waRoute).update({
4431
+ documentId: child.documentId,
4432
+ data: updateData
4433
+ });
4434
+ await cascadeCanonicalPathUpdates(child.documentId, newCanonicalPath);
4435
+ }
4436
+ }
4437
+ async function getRouteDescendants(routeId) {
4438
+ const descendants = [];
4439
+ const stack = [routeId];
4440
+ while (stack.length > 0) {
4441
+ const currentId = stack.pop();
4442
+ if (!currentId) continue;
4443
+ const children = await strapi.documents(waRoute).findMany({
4444
+ filters: {
4445
+ parent: {
4446
+ documentId: currentId
4447
+ }
4448
+ }
4449
+ });
4450
+ for (const child of children) {
4451
+ descendants.push(child.documentId);
4452
+ stack.push(child.documentId);
4453
+ }
4454
+ }
4455
+ return descendants;
4456
+ }
4457
+ async function getNonInternalRouteIds() {
4458
+ const routes2 = await strapi.documents(waRoute).findMany({
4459
+ filters: {
4460
+ type: {
4461
+ $ne: "internal"
4462
+ }
4463
+ }
4464
+ });
4465
+ const routeIds = routes2.map((route2) => route2.documentId);
4466
+ return routeIds;
4467
+ }
4468
+ async function validateRouteDependencies({
4469
+ routeId,
4470
+ newParentId
4471
+ }) {
4472
+ if (!newParentId) return true;
4473
+ const normalizedRouteId = routeId ?? void 0;
4474
+ const parentRoute = await strapi.documents(waRoute).findOne({
4475
+ documentId: newParentId
4476
+ });
4477
+ if (!parentRoute) {
4478
+ throw new Error(`Parent route not found: ${newParentId}`);
4479
+ }
4480
+ if (parentRoute?.type === "external") {
4481
+ throw new Error("External routes cannot have children");
4482
+ }
4483
+ if (!normalizedRouteId) return true;
4484
+ const descendants = await getRouteDescendants(normalizedRouteId);
4485
+ const nonInternalRouteIds = await getNonInternalRouteIds();
4486
+ if (normalizedRouteId === newParentId || descendants.includes(newParentId) || nonInternalRouteIds.includes(newParentId)) {
4487
+ throw new Error(`Circular dependency detected: Cannot set route ${newParentId} as parent of ${normalizedRouteId}`);
4488
+ }
4489
+ return true;
4490
+ }
4491
+ async function buildNavigationPath({
4492
+ slug,
4493
+ routeDocumentId,
4494
+ calculatedParent
4495
+ }) {
4496
+ let parentDocumentId = calculatedParent;
4497
+ let parent = null;
4498
+ if (parentDocumentId) {
4499
+ do {
4500
+ const navItem = await strapi.documents(waNavItem).findOne({
4501
+ documentId: parentDocumentId,
4502
+ populate: ["route", "parent"]
4503
+ });
4504
+ parent = navItem;
4505
+ parentDocumentId = navItem?.parent?.documentId || null;
4506
+ if (parent?.route?.type === "internal") break;
4507
+ } while (parentDocumentId);
4508
+ }
4509
+ if (parent?.route?.type !== "internal")
4510
+ parent = null;
4511
+ if (slug.startsWith("/")) slug = slug.substring(1);
4512
+ const newPath = parent?.route ? `${parent.route.path}/${slug}` : `${slug}`;
4513
+ const validatedPath = await duplicateCheck(newPath, routeDocumentId);
4514
+ return validatedPath;
4515
+ }
4516
+ async function handleItemDeletion(navigationItems) {
4517
+ const errors = [];
4518
+ let items = [...navigationItems];
4519
+ for (let i = 0; i < items.length; i++) {
4520
+ const item = items[i];
4521
+ if (item.clientModifications?.type === "delete") {
4522
+ try {
4523
+ if (item.documentId) {
4524
+ await deleteNavItem(item.documentId);
4525
+ }
4526
+ if (item.route.type !== "internal") {
4527
+ await deleteRoute(item.route.documentId);
4528
+ }
4529
+ const newItems = reduceDepthOfOrphanedItems(items, item.documentId);
4530
+ if (!newItems) {
4531
+ throw new Error("Failed to reduce depth of orphaned items");
4532
+ }
4533
+ items = newItems;
4534
+ i--;
4535
+ } catch (err) {
4536
+ const errorMsg = `Error deleting navigation item: ${err instanceof Error ? err.message : String(err)}`;
4537
+ errors.push(errorMsg);
4538
+ strapi.log.error(errorMsg, err);
4539
+ }
4540
+ continue;
4541
+ }
4542
+ if (!item.route && item.documentId) {
4543
+ try {
4544
+ strapi.log.warn("Navigation item without route found. Deleting it.", item);
4545
+ await deleteNavItem(item.documentId);
4546
+ items.splice(i, 1);
4547
+ i--;
4548
+ } catch (err) {
4549
+ const errorMsg = `Error deleting navigation item without route: ${err instanceof Error ? err.message : String(err)}`;
4550
+ errors.push(errorMsg);
4551
+ strapi.log.error(errorMsg, err);
4552
+ }
4553
+ continue;
4554
+ }
4555
+ }
4556
+ return {
4557
+ success: errors.length === 0,
4558
+ items,
4559
+ errors
4560
+ };
4561
+ }
4562
+ async function handleItemUpdate({
4563
+ item,
4564
+ calculatedParent,
4565
+ calculatedOrder,
4566
+ navigationId,
4567
+ newNavItemsMap
4568
+ }) {
4569
+ const errors = [];
4570
+ const isCreate = item.clientModifications?.type === "create";
4571
+ const isUpdate = item.clientModifications?.type === "update";
4572
+ const isInternal = item.route.type === "internal";
4573
+ if (isCreate && !item.clientModifications.route) {
4574
+ try {
4575
+ const newRoute = await createExternalRoute({
4576
+ title: item.route.title,
4577
+ slug: item.route.slug,
4578
+ path: item.route.path,
4579
+ type: item.route.type
4580
+ });
4581
+ const newNavItem = await createNavItem({
4582
+ route: newRoute.documentId,
4583
+ navigation: navigationId,
4584
+ parent: calculatedParent,
4585
+ order: calculatedOrder
4586
+ });
4587
+ if (newNavItem) newNavItemsMap.set(item.documentId, newNavItem);
4588
+ } catch (err) {
4589
+ errors.push(err instanceof Error ? err.message : String(err));
4590
+ strapi.log.error(`Error creating navigation item '${item.route.title}': `, err);
4591
+ }
4592
+ return { success: errors.length === 0, errors };
4593
+ }
4594
+ if (isCreate && item.clientModifications.route) {
4595
+ try {
4596
+ const route2 = await strapi.documents(waRoute).findOne({
4597
+ documentId: item.clientModifications.route
4598
+ });
4599
+ if (!route2) throw new Error(`Related route not found for new navigation item '${item.route.title}'`);
4600
+ const path = await buildNavigationPath({
4601
+ slug: item.route.slug,
4602
+ routeDocumentId: route2.documentId,
4603
+ calculatedParent
4604
+ });
4605
+ await updateRoute(route2.documentId, {
4606
+ title: item.route.title,
4607
+ slug: item.route.slug,
4608
+ path,
4609
+ isOverride: path !== route2.canonicalPath
4610
+ });
4611
+ const newNavItem = await createNavItem({
4612
+ route: item.clientModifications.route,
4613
+ navigation: item.clientModifications.navigation,
4614
+ parent: calculatedParent,
4615
+ order: calculatedOrder
4616
+ });
4617
+ if (newNavItem) newNavItemsMap.set(item.documentId, newNavItem);
4618
+ } catch (err) {
4619
+ errors.push(err instanceof Error ? err.message : String(err));
4620
+ strapi.log.error(`Error creating navigation item with existing route '${item.route.title}': `, err);
4621
+ }
4622
+ return { success: errors.length === 0, errors };
4623
+ }
4624
+ const needsRouteUpdate = isUpdate || isInternal;
4625
+ if (needsRouteUpdate || isInternal) {
4626
+ try {
4627
+ const route2 = await strapi.documents(waRoute).findOne({
4628
+ documentId: item.route.documentId
4629
+ });
4630
+ if (!route2) throw new Error(`Related route not found for navigation item '${item.route.title}'`);
4631
+ const slug = item.clientModifications?.slug || item.route.slug;
4632
+ const path = isInternal ? await buildNavigationPath({ slug, routeDocumentId: route2.documentId, calculatedParent }) : slug;
4633
+ if (needsRouteUpdate) {
4634
+ await updateRoute(route2.documentId, {
4635
+ title: item.clientModifications?.title || item.route.title,
4636
+ slug,
4637
+ path,
4638
+ isOverride: path !== route2.canonicalPath
4639
+ });
4640
+ }
4641
+ if (isInternal) {
4642
+ await strapi.entityService.update(item.route.relatedContentType, item.route.relatedDocumentId, {
4643
+ data: {
4644
+ webatlas_path: path,
4645
+ webatlas_override: path !== route2.canonicalPath
4646
+ }
4647
+ });
4648
+ }
4649
+ } catch (err) {
4650
+ errors.push(err instanceof Error ? err.message : String(err));
4651
+ strapi.log.error(`Error processing route for navigation item '${item.route.title}': `, err);
4652
+ }
4653
+ }
4654
+ await updateNavItem(item.documentId, {
4655
+ parent: calculatedParent,
4656
+ order: calculatedOrder
4657
+ });
4658
+ return {
4659
+ success: errors.length === 0,
4660
+ errors
4661
+ };
4662
+ }
4663
+ function calculateParentAndOrder({
4664
+ navigationItems,
4665
+ item,
4666
+ index: index2,
4667
+ parentIds,
4668
+ groupIndices,
4669
+ newNavItemsMap
4670
+ }) {
4671
+ if (item.depth === 0) {
4672
+ if (groupIndices[0] !== void 0) {
4673
+ groupIndices[0] = groupIndices[0] + 1;
4674
+ } else {
4675
+ groupIndices[0] = 0;
4676
+ }
4677
+ parentIds.length = 0;
4678
+ } else {
4679
+ const previousItem = navigationItems[index2 - 1];
4680
+ if (previousItem && typeof previousItem.depth === "number") {
4681
+ if (item.depth === previousItem.depth + 1) {
4682
+ parentIds.push(previousItem.documentId.startsWith("temp-") ? newNavItemsMap.get(previousItem.documentId)?.documentId || previousItem.documentId : previousItem.documentId);
4683
+ groupIndices[item.depth] = 0;
4684
+ } else if (item.depth <= previousItem.depth) {
4685
+ const diff = previousItem.depth - item.depth;
4686
+ for (let i = 0; i < diff; i++) {
4687
+ parentIds.pop();
4688
+ groupIndices.pop();
4689
+ }
4690
+ groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
4691
+ } else {
4692
+ groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
4693
+ }
4694
+ }
4695
+ }
4696
+ const calculatedParent = parentIds.at(-1) || null;
4697
+ const calculatedOrder = groupIndices[item.depth] || 0;
4698
+ return {
4699
+ calculatedParent,
4700
+ calculatedOrder
4701
+ };
4702
+ }
4703
+ const migration_001_canonical_path = {
4704
+ version: "001",
4705
+ description: "Migrate title field to canonicalPath using transformToUrl",
4706
+ async up(strapi2) {
4707
+ strapi2.log.info("[webatlas] Starting canonical path migration...");
4708
+ try {
4709
+ const routes2 = await strapi2.db?.query(waRoute).findMany({
4710
+ where: {
4711
+ title: {
4712
+ $notNull: true,
4713
+ $ne: ""
4714
+ },
4715
+ $or: [
4716
+ { canonicalPath: { $null: true } },
4717
+ { canonicalPath: "" }
4718
+ ]
4719
+ },
4720
+ populate: ["parent"]
4721
+ });
4722
+ if (!routes2 || routes2.length === 0) {
4723
+ strapi2.log.info("[webatlas] No routes found that need canonical path migration");
4724
+ return;
4725
+ }
4726
+ strapi2.log.info(`[webatlas] Found ${routes2.length} routes to migrate`);
4727
+ let migratedCount = 0;
4728
+ let errorCount = 0;
4729
+ const chunkSize = 50;
4730
+ for (let i = 0; i < routes2.length; i += chunkSize) {
4731
+ const chunk = routes2.slice(i, i + chunkSize);
4732
+ await Promise.all(chunk.map(async (route2) => {
4733
+ try {
4734
+ const transformedTitle = transformToUrl(route2.title);
4735
+ const parentId = route2.parent?.id || null;
4736
+ const canonicalPath = await buildCanonicalPath(transformedTitle, parentId);
4737
+ await strapi2.db?.query(waRoute).update({
4738
+ where: { id: route2.id },
4739
+ data: { canonicalPath }
4740
+ });
4741
+ migratedCount++;
4742
+ if (migratedCount % 25 === 0) {
4743
+ strapi2.log.info(`[webatlas] Migrated ${migratedCount}/${routes2.length} routes`);
4744
+ }
4745
+ } catch (error) {
4746
+ strapi2.log.error(`[webatlas] Failed to migrate route ${route2.id}:`, error);
4747
+ errorCount++;
4748
+ }
4749
+ }));
4750
+ }
4751
+ strapi2.log.info(`[webatlas] Canonical path migration completed. Migrated: ${migratedCount}, Errors: ${errorCount}`);
4752
+ if (errorCount > 0) {
4753
+ strapi2.log.warn(`[webatlas] ${errorCount} routes failed to migrate. Check logs for details.`);
4754
+ }
4755
+ } catch (error) {
4756
+ strapi2.log.error("[webatlas] Canonical path migration failed:", error);
4757
+ throw error;
4758
+ }
4759
+ }
4760
+ };
4761
+ const migrations = [
4762
+ migration_001_canonical_path
4763
+ ];
4764
+ const runMigrations = async (strapi2) => {
4765
+ const pluginStore = strapi2.store({ type: "plugin", name: PLUGIN_ID });
4766
+ let config2 = await pluginStore.get({ key: "config" });
4767
+ if (!config2) {
4768
+ config2 = { migrationVersion: "0" };
4769
+ }
4770
+ const currentVersion = config2.migrationVersion || "0";
4771
+ const pendingMigrations = migrations.filter((migration) => migration.version > currentVersion);
4772
+ if (pendingMigrations.length === 0) {
4773
+ strapi2.log.info("[webatlas] All migrations up to date");
4774
+ return;
4775
+ }
4776
+ strapi2.log.info(`[webatlas] Running ${pendingMigrations.length} migration(s)...`);
4777
+ for (const migration of pendingMigrations) {
4778
+ try {
4779
+ strapi2.log.info(`[webatlas] Running migration ${migration.version}: ${migration.description}`);
4780
+ await migration.up(strapi2);
4781
+ await pluginStore.set({
4782
+ key: "config",
4783
+ value: {
4784
+ ...config2,
4785
+ migrationVersion: migration.version
4786
+ }
4787
+ });
4788
+ strapi2.log.info(`[webatlas] Migration ${migration.version} completed successfully`);
4789
+ } catch (error) {
4790
+ strapi2.log.error(`[webatlas] Migration ${migration.version} failed:`, error);
4791
+ throw error;
4792
+ }
4793
+ }
4794
+ strapi2.log.info("[webatlas] All migrations completed successfully");
4795
+ };
4404
4796
  const bootstrap = async ({ strapi: strapi2 }) => {
4405
4797
  try {
4798
+ await runMigrations(strapi2);
4406
4799
  const actions = [
4407
4800
  {
4408
4801
  section: "plugins",
@@ -4454,22 +4847,20 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4454
4847
  });
4455
4848
  let newConfig = {
4456
4849
  ...config2,
4457
- selectedContentTypes: [...config2?.selectedContentTypes || []],
4850
+ selectedContentTypes: [],
4458
4851
  navigation: {
4459
4852
  maxDepth: config2?.navigation?.maxDepth || 1,
4460
4853
  ...config2?.navigation
4461
- }
4854
+ },
4855
+ migrationVersion: config2?.migrationVersion || "0"
4462
4856
  };
4463
4857
  enabledContentTypes.forEach((type2) => {
4464
- const exists = config2?.selectedContentTypes?.find((ct) => ct.uid === type2.uid);
4465
- if (!exists) {
4466
- newConfig.selectedContentTypes.push({
4467
- uid: type2.uid,
4468
- label: type2.info.displayName,
4469
- default: null,
4470
- pattern: null
4471
- });
4472
- }
4858
+ const existingConfig = config2?.selectedContentTypes?.find((ct) => ct.uid === type2.uid);
4859
+ newConfig.selectedContentTypes.push({
4860
+ uid: type2.uid,
4861
+ label: type2.info.displayName,
4862
+ default: existingConfig?.default || null
4863
+ });
4473
4864
  });
4474
4865
  if (JSON.stringify(newConfig) !== JSON.stringify(config2)) {
4475
4866
  await pluginStore.set({ key: "config", value: newConfig });
@@ -4491,7 +4882,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4491
4882
  if (!navItem || !navItem.route) return;
4492
4883
  event.state = navItem.route.id && navItem.route.type === "external" ? { id: navItem.route.id } : null;
4493
4884
  } catch (err) {
4494
- console.log(err);
4885
+ strapi2.log.error(err);
4495
4886
  }
4496
4887
  },
4497
4888
  async afterDelete(event) {
@@ -4504,15 +4895,13 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4504
4895
  }
4505
4896
  });
4506
4897
  } catch (err) {
4507
- console.log(err);
4898
+ strapi2.log.error(err);
4508
4899
  }
4509
4900
  }
4510
4901
  });
4511
4902
  strapi2.db?.lifecycles.subscribe({
4512
4903
  models: enabledContentTypes.map((type2) => type2.uid),
4513
4904
  async beforeCreate(event) {
4514
- const validContentTypes = config2.selectedContentTypes.filter((type2) => strapi2.contentTypes[type2.uid]);
4515
- await pluginStore.set({ key: "config", value: { selectedContentTypes: validContentTypes } });
4516
4905
  if (!event.params.data.webatlas_path) return;
4517
4906
  event.params.data.webatlas_path = transformToUrl(event.params.data.webatlas_path);
4518
4907
  },
@@ -4520,7 +4909,8 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4520
4909
  const ctSettings = config2.selectedContentTypes.find((type2) => type2.uid === event.model.uid);
4521
4910
  const {
4522
4911
  webatlas_path,
4523
- webatlas_override
4912
+ webatlas_override,
4913
+ webatlas_parent
4524
4914
  } = event.params.data;
4525
4915
  if (!webatlas_path) return;
4526
4916
  const relatedRoute = await strapi2.db?.query(waRoute).findOne({
@@ -4529,8 +4919,20 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4529
4919
  }
4530
4920
  });
4531
4921
  if (relatedRoute) return;
4532
- const title = ctSettings?.default ? event.params.data[ctSettings.default] : "";
4922
+ let parent = null;
4923
+ if (webatlas_parent) {
4924
+ try {
4925
+ const isValid = await validateRouteDependencies({
4926
+ newParentId: webatlas_parent
4927
+ });
4928
+ if (isValid) parent = webatlas_parent;
4929
+ } catch (err) {
4930
+ strapi2.log.error(`Route dependency validation failed: ${err.message}`);
4931
+ }
4932
+ }
4533
4933
  const path = await duplicateCheck(transformToUrl(webatlas_path));
4934
+ const canonicalPath = await buildCanonicalPath(path, parent);
4935
+ const title = event.params.data[ctSettings?.default]?.trim() || path;
4534
4936
  await strapi2.documents(waRoute).create({
4535
4937
  data: {
4536
4938
  relatedContentType: event.model.uid,
@@ -4540,7 +4942,9 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4540
4942
  path,
4541
4943
  uidPath: `${event.model.singularName}/${event.result.id}`,
4542
4944
  isOverride: webatlas_override || false,
4543
- title
4945
+ title,
4946
+ parent,
4947
+ canonicalPath
4544
4948
  }
4545
4949
  });
4546
4950
  },
@@ -4549,46 +4953,74 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4549
4953
  const {
4550
4954
  webatlas_path,
4551
4955
  webatlas_override,
4956
+ webatlas_parent,
4552
4957
  documentId
4553
4958
  } = event.params.data;
4554
4959
  if (!webatlas_path) return;
4555
- const relatedRoute = await strapi2.db?.query(waRoute).findOne({
4556
- where: {
4960
+ const relatedRoute = await strapi2.documents(waRoute).findFirst({
4961
+ filters: {
4557
4962
  relatedDocumentId: documentId
4558
4963
  }
4559
4964
  });
4560
- const title = ctSettings?.default ? event.params.data[ctSettings.default] : "";
4561
- const path = await duplicateCheck(transformToUrl(webatlas_path), relatedRoute ? relatedRoute.documentId : null);
4965
+ let parent = null;
4966
+ if (webatlas_parent) {
4967
+ try {
4968
+ const isValid = await validateRouteDependencies({
4969
+ routeId: relatedRoute ? relatedRoute.documentId : null,
4970
+ newParentId: webatlas_parent
4971
+ });
4972
+ if (isValid) {
4973
+ parent = await strapi2.documents(waRoute).findOne({
4974
+ documentId: webatlas_parent
4975
+ });
4976
+ }
4977
+ } catch (err) {
4978
+ strapi2.log.error(`Route dependency validation failed: ${err.message}`);
4979
+ }
4980
+ }
4981
+ const transformedPath = transformToUrl(webatlas_path);
4982
+ const rawPath = parent ? `${parent.path}/${transformedPath}` : transformedPath;
4983
+ const path = await duplicateCheck(rawPath, relatedRoute ? relatedRoute.documentId : null);
4984
+ const canonicalPath = await buildCanonicalPath(transformedPath, parent?.documentId);
4985
+ const title = event.params.data[ctSettings?.default]?.trim() || path;
4562
4986
  const routeData = {
4563
4987
  title,
4564
4988
  path,
4565
- slug: path,
4566
- isOverride: webatlas_override || false
4989
+ slug: transformedPath,
4990
+ isOverride: webatlas_override || false,
4991
+ parent: parent?.documentId || null
4567
4992
  };
4993
+ let routeDocumentId = relatedRoute?.documentId;
4568
4994
  if (!relatedRoute) {
4569
- await strapi2.documents(waRoute).create({
4995
+ const createdRoute = await strapi2.documents(waRoute).create({
4570
4996
  data: {
4571
4997
  relatedContentType: event.model.uid,
4572
4998
  relatedId: event.result.id,
4573
4999
  relatedDocumentId: event.result.documentId,
4574
5000
  uidPath: `${event.model.singularName}/${event.result.id}`,
5001
+ canonicalPath,
4575
5002
  ...routeData
4576
5003
  }
4577
5004
  });
5005
+ routeDocumentId = createdRoute?.documentId;
4578
5006
  } else {
4579
5007
  await strapi2.documents(waRoute).update({
4580
5008
  documentId: relatedRoute.documentId,
4581
5009
  data: {
4582
- ...routeData
5010
+ ...routeData,
5011
+ canonicalPath
4583
5012
  }
4584
5013
  });
4585
5014
  }
5015
+ if (routeDocumentId) {
5016
+ await cascadeCanonicalPathUpdates(routeDocumentId, canonicalPath);
5017
+ }
4586
5018
  },
4587
5019
  async afterDelete(event) {
4588
5020
  try {
4589
5021
  await findAndDeleteNavItem(event.result.id, event.model.uid);
4590
5022
  } catch (err) {
4591
- console.log(err);
5023
+ strapi2.log.error(err);
4592
5024
  }
4593
5025
  },
4594
5026
  async afterDeleteMany(event) {
@@ -4622,7 +5054,7 @@ async function findAndDeleteNavItem(relatedId, relatedContentType) {
4622
5054
  await strapi.documents(waRoute).delete({ documentId: route2.documentId });
4623
5055
  if (navItem?.documentId) await strapi.documents(waNavItem).delete({ documentId: navItem.documentId });
4624
5056
  } catch (err) {
4625
- console.log(err);
5057
+ strapi.log.error(err);
4626
5058
  }
4627
5059
  }
4628
5060
  const destroy = ({ strapi: strapi2 }) => {
@@ -5159,6 +5591,11 @@ const register = ({ strapi: strapi2 }) => {
5159
5591
  type: "boolean",
5160
5592
  private: true
5161
5593
  });
5594
+ set$1(attributes, "webatlas_parent", {
5595
+ ...fieldSettings,
5596
+ type: "string",
5597
+ private: true
5598
+ });
5162
5599
  });
5163
5600
  };
5164
5601
  const config = {
@@ -5217,6 +5654,10 @@ const schema$2 = {
5217
5654
  type: "string",
5218
5655
  configurable: false
5219
5656
  },
5657
+ canonicalPath: {
5658
+ type: "string",
5659
+ configurable: false
5660
+ },
5220
5661
  slug: {
5221
5662
  type: "string",
5222
5663
  configurable: false
@@ -5248,6 +5689,20 @@ const schema$2 = {
5248
5689
  default: "internal",
5249
5690
  configurable: false,
5250
5691
  required: true
5692
+ },
5693
+ parent: {
5694
+ type: "relation",
5695
+ relation: "manyToOne",
5696
+ target: "plugin::webatlas.route",
5697
+ inversedBy: "children",
5698
+ configurable: false
5699
+ },
5700
+ children: {
5701
+ type: "relation",
5702
+ relation: "oneToMany",
5703
+ target: "plugin::webatlas.route",
5704
+ mappedBy: "parent",
5705
+ configurable: false
5251
5706
  }
5252
5707
  }
5253
5708
  };
@@ -5376,19 +5831,18 @@ const admin$2 = () => ({
5376
5831
  return ctx.throw(500, e);
5377
5832
  }
5378
5833
  },
5379
- async getRoutes(ctx) {
5834
+ async getRoute(ctx) {
5380
5835
  try {
5381
- return await getAdminService().getRoutes();
5836
+ const { documentId } = ctx.params;
5837
+ if (!documentId) return ctx.throw(400, "Route documentId is required");
5838
+ return await getAdminService().getRoute(documentId);
5382
5839
  } catch (e) {
5383
5840
  return ctx.throw(500, e);
5384
5841
  }
5385
5842
  },
5386
- async updateRoute(ctx) {
5843
+ async getAllRoutes(ctx) {
5387
5844
  try {
5388
- const { documentId } = ctx.query;
5389
- if (!documentId) return ctx.throw(400, "Route documentId is required");
5390
- const { data } = ctx.request.body;
5391
- return await getAdminService().updateRoute(documentId, data);
5845
+ return await getAdminService().getAllRoutes();
5392
5846
  } catch (e) {
5393
5847
  return ctx.throw(500, e);
5394
5848
  }
@@ -5402,6 +5856,14 @@ const admin$2 = () => ({
5402
5856
  return ctx.throw(500, e);
5403
5857
  }
5404
5858
  },
5859
+ async getProhibitedRouteIds(ctx) {
5860
+ try {
5861
+ const { documentId } = ctx.params;
5862
+ return await getAdminService().getProhibitedRouteIds(documentId);
5863
+ } catch (e) {
5864
+ return ctx.throw(500, e);
5865
+ }
5866
+ },
5405
5867
  async getNavigation(ctx) {
5406
5868
  try {
5407
5869
  const { documentId, variant } = ctx.query;
@@ -5556,7 +6018,7 @@ const admin$1 = {
5556
6018
  {
5557
6019
  method: "GET",
5558
6020
  path: "/route",
5559
- handler: "admin.getRoutes",
6021
+ handler: "admin.getAllRoutes",
5560
6022
  config: {
5561
6023
  policies: [
5562
6024
  "admin::isAuthenticatedAdmin",
@@ -5573,9 +6035,9 @@ const admin$1 = {
5573
6035
  }
5574
6036
  },
5575
6037
  {
5576
- method: "PUT",
5577
- path: "/route",
5578
- handler: "admin.updateRoute",
6038
+ method: "GET",
6039
+ path: "/route/related",
6040
+ handler: "admin.getRelatedRoute",
5579
6041
  config: {
5580
6042
  policies: [
5581
6043
  "admin::isAuthenticatedAdmin",
@@ -5583,6 +6045,7 @@ const admin$1 = {
5583
6045
  name: `plugin::${PLUGIN_ID}.has-permissions`,
5584
6046
  config: {
5585
6047
  actions: [
6048
+ `plugin::${PLUGIN_ID}.cm.aside`,
5586
6049
  `plugin::${PLUGIN_ID}.page.navigation`
5587
6050
  ]
5588
6051
  }
@@ -5592,8 +6055,26 @@ const admin$1 = {
5592
6055
  },
5593
6056
  {
5594
6057
  method: "GET",
5595
- path: "/route/related",
5596
- handler: "admin.getRelatedRoute",
6058
+ path: "/route/prohibitedIds/:documentId?",
6059
+ handler: "admin.getProhibitedRouteIds",
6060
+ config: {
6061
+ policies: [
6062
+ "admin::isAuthenticatedAdmin",
6063
+ {
6064
+ name: `plugin::${PLUGIN_ID}.has-permissions`,
6065
+ config: {
6066
+ actions: [
6067
+ `plugin::${PLUGIN_ID}.cm.aside`
6068
+ ]
6069
+ }
6070
+ }
6071
+ ]
6072
+ }
6073
+ },
6074
+ {
6075
+ method: "GET",
6076
+ path: "/route/:documentId",
6077
+ handler: "admin.getRoute",
5597
6078
  config: {
5598
6079
  policies: [
5599
6080
  "admin::isAuthenticatedAdmin",
@@ -5601,7 +6082,6 @@ const admin$1 = {
5601
6082
  name: `plugin::${PLUGIN_ID}.has-permissions`,
5602
6083
  config: {
5603
6084
  actions: [
5604
- `plugin::${PLUGIN_ID}.cm.aside`,
5605
6085
  `plugin::${PLUGIN_ID}.page.navigation`
5606
6086
  ]
5607
6087
  }
@@ -5757,7 +6237,7 @@ const admin = ({ strapi: strapi2 }) => ({
5757
6237
  newConfigMerged = { ...config2, ...newConfig };
5758
6238
  await pluginStore.set({ key: "config", value: newConfigMerged });
5759
6239
  } catch (err) {
5760
- console.log(err);
6240
+ strapi2.log.error(err);
5761
6241
  return "Error. Couldn't update config";
5762
6242
  }
5763
6243
  return newConfigMerged;
@@ -5778,35 +6258,21 @@ const admin = ({ strapi: strapi2 }) => ({
5778
6258
  };
5779
6259
  return config2;
5780
6260
  },
5781
- async getRoutes() {
6261
+ async getRoute(documentId) {
5782
6262
  try {
5783
- const entities = await strapi2.documents(waRoute).findMany();
5784
- return entities;
6263
+ return await strapi2.documents(waRoute).findOne({
6264
+ documentId
6265
+ });
5785
6266
  } catch (e) {
5786
- console.log(e);
6267
+ strapi2.log.error(e);
5787
6268
  }
5788
6269
  },
5789
- // TODO: Types
5790
- async updateRoute(documentId, data) {
6270
+ async getAllRoutes() {
5791
6271
  try {
5792
- let checkedPath = data.path;
5793
- if (data.internal) {
5794
- const parent = data.parent ? await strapi2.documents(waNavItem).findOne({
5795
- documentId: data.parent
5796
- }) : null;
5797
- const path = data.isOverride ? data.slug : getPath(parent?.path, data.slug);
5798
- checkedPath = await duplicateCheck(path, documentId);
5799
- }
5800
- const entity = await strapi2.documents(waRoute).update({
5801
- documentId,
5802
- data: {
5803
- ...data,
5804
- path: checkedPath
5805
- }
5806
- });
5807
- return entity;
6272
+ const entities = await strapi2.documents(waRoute).findMany();
6273
+ return entities;
5808
6274
  } catch (e) {
5809
- console.log(e);
6275
+ strapi2.log.error(e);
5810
6276
  }
5811
6277
  },
5812
6278
  async getRelatedRoute(documentId) {
@@ -5814,10 +6280,28 @@ const admin = ({ strapi: strapi2 }) => ({
5814
6280
  return await strapi2.db?.query(waRoute).findOne({
5815
6281
  where: {
5816
6282
  relatedDocumentId: documentId
5817
- }
6283
+ },
6284
+ populate: ["parent"]
5818
6285
  });
5819
6286
  } catch (e) {
5820
- console.log(e);
6287
+ strapi2.log.error(e);
6288
+ }
6289
+ },
6290
+ async getProhibitedRouteIds(documentId) {
6291
+ try {
6292
+ let route2 = null;
6293
+ if (documentId) {
6294
+ route2 = await strapi2.documents(waRoute).findOne({
6295
+ documentId
6296
+ });
6297
+ }
6298
+ const descendants = route2?.documentId ? await getRouteDescendants(route2.documentId) : [];
6299
+ const nonInternalRouteIds = await getNonInternalRouteIds();
6300
+ const prohibitedRouteIds = [...descendants, ...nonInternalRouteIds];
6301
+ route2?.documentId && prohibitedRouteIds.push(route2.documentId);
6302
+ return prohibitedRouteIds;
6303
+ } catch (e) {
6304
+ strapi2.log.error(e);
5821
6305
  }
5822
6306
  },
5823
6307
  async getNavigation(documentId, variant) {
@@ -5853,7 +6337,7 @@ const admin = ({ strapi: strapi2 }) => ({
5853
6337
  }
5854
6338
  return navigation2;
5855
6339
  } catch (e) {
5856
- console.log(e);
6340
+ strapi2.log.error(e);
5857
6341
  }
5858
6342
  },
5859
6343
  async createNavigation(name2, visible) {
@@ -5866,7 +6350,7 @@ const admin = ({ strapi: strapi2 }) => ({
5866
6350
  }
5867
6351
  });
5868
6352
  } catch (e) {
5869
- console.log(e);
6353
+ strapi2.log.error(e);
5870
6354
  }
5871
6355
  },
5872
6356
  async updateNavigation(documentId, data) {
@@ -5880,7 +6364,7 @@ const admin = ({ strapi: strapi2 }) => ({
5880
6364
  });
5881
6365
  return entity;
5882
6366
  } catch (e) {
5883
- console.log(e);
6367
+ strapi2.log.error(e);
5884
6368
  }
5885
6369
  },
5886
6370
  async deleteNavigation(documentId) {
@@ -5899,115 +6383,46 @@ const admin = ({ strapi: strapi2 }) => ({
5899
6383
  documentId
5900
6384
  });
5901
6385
  } catch (e) {
5902
- console.log(e);
6386
+ strapi2.log.error(e);
5903
6387
  }
5904
6388
  },
5905
6389
  async updateNavigationItemStructure(navigationId, navigationItems) {
5906
6390
  if (!navigationId || !navigationItems) return;
5907
6391
  let error = false;
5908
- const newNavItemsMap = /* @__PURE__ */ new Map();
5909
- for (const [index2, item] of navigationItems.entries()) {
5910
- if (item.deleted) {
5911
- try {
5912
- item.documentId && await deleteNavItem(item.documentId);
5913
- const newItems = reduceDepthOfOrphanedItems(navigationItems, item.documentId);
5914
- if (!newItems) throw new Error("Failed to reduce depth of orphaned items");
5915
- navigationItems = newItems;
5916
- } catch (error2) {
5917
- error2 = true;
5918
- console.error("Error deleting navigation item ", error2);
5919
- }
5920
- continue;
5921
- }
5922
- if (!item.route && item.documentId) {
5923
- try {
5924
- console.warn("Navigation item without route found. Deleting it. ", item);
5925
- await deleteNavItem(item.documentId);
5926
- } catch (error2) {
5927
- console.error("Error deleting navigation item without route ", error2);
5928
- }
5929
- continue;
5930
- }
5931
- if (item.update && !item.isNew) {
5932
- try {
5933
- await this.updateRoute(item.route.documentId, {
5934
- title: item.update.title || item.route.title,
5935
- slug: item.update.slug || item.route.slug,
5936
- path: item.update.path || item.route.path,
5937
- isOverride: item.update.isOverride !== void 0 ? item.update.isOverride : item.route.isOverride
5938
- });
5939
- } catch (error2) {
5940
- error2 = true;
5941
- console.error("Error updating route ", error2);
5942
- }
5943
- }
6392
+ let newNavItemsMap = /* @__PURE__ */ new Map();
6393
+ const deletionResult = await handleItemDeletion(navigationItems);
6394
+ if (!deletionResult.success) {
6395
+ strapi2.log.error("Deletion errors:", deletionResult.errors);
5944
6396
  }
6397
+ navigationItems = deletionResult.items;
5945
6398
  let parentIds = [];
5946
6399
  let groupIndices = [];
5947
6400
  for (const [index2, item] of navigationItems.entries()) {
5948
6401
  if (typeof item.depth !== "number") {
5949
6402
  continue;
5950
6403
  }
5951
- if (item.depth === 0) {
5952
- if (groupIndices[0] !== void 0) {
5953
- groupIndices[0] = groupIndices[0] + 1;
5954
- } else {
5955
- groupIndices[0] = 0;
5956
- }
5957
- parentIds = [];
5958
- } else {
5959
- const previousItem = navigationItems[index2 - 1];
5960
- if (previousItem && typeof previousItem.depth === "number") {
5961
- if (item.depth === previousItem.depth + 1) {
5962
- parentIds.push(previousItem.documentId.startsWith("temp-") ? newNavItemsMap.get(previousItem.documentId)?.documentId || previousItem.documentId : previousItem.documentId);
5963
- groupIndices[item.depth] = 0;
5964
- } else if (item.depth <= previousItem.depth) {
5965
- const diff = previousItem.depth - item.depth;
5966
- for (let i = 0; i < diff; i++) {
5967
- parentIds.pop();
5968
- groupIndices.pop();
5969
- }
5970
- groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
5971
- } else {
5972
- groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
5973
- }
5974
- }
5975
- }
5976
- const calculatedParent = parentIds.at(-1) || null;
5977
- const calculatedOrder = groupIndices[item.depth] || 0;
5978
6404
  try {
5979
- if (item.isNew) {
5980
- if (item.isNew.route) {
5981
- await createNavItem({
5982
- route: item.isNew.route,
5983
- parent: calculatedParent,
5984
- navigation: item.isNew.navigation,
5985
- order: calculatedOrder
5986
- });
5987
- } else {
5988
- const newRoute = await createExternalRoute({
5989
- title: item.route.title,
5990
- slug: item.route.slug,
5991
- path: item.route.path,
5992
- type: item.route.type
5993
- });
5994
- const newNavItem = await createNavItem({
5995
- route: newRoute.documentId,
5996
- navigation: navigationId,
5997
- parent: calculatedParent,
5998
- order: calculatedOrder
5999
- });
6000
- if (newNavItem) newNavItemsMap.set(item.documentId, newNavItem);
6001
- }
6002
- } else {
6003
- await updateNavItem(item.documentId, {
6004
- order: calculatedOrder,
6005
- parent: calculatedParent
6006
- });
6405
+ const { calculatedParent, calculatedOrder } = calculateParentAndOrder({
6406
+ navigationItems,
6407
+ item,
6408
+ index: index2,
6409
+ parentIds,
6410
+ groupIndices,
6411
+ newNavItemsMap
6412
+ });
6413
+ const result = await handleItemUpdate({
6414
+ item,
6415
+ calculatedParent,
6416
+ calculatedOrder,
6417
+ navigationId,
6418
+ newNavItemsMap
6419
+ });
6420
+ if (!result.success) {
6421
+ strapi2.log.error("Error updating item: ", item);
6007
6422
  }
6008
6423
  } catch (errorMsg) {
6009
6424
  error = true;
6010
- console.error("Error updating navigation item ", errorMsg);
6425
+ strapi2.log.error("Error updating navigation item ", errorMsg);
6011
6426
  }
6012
6427
  }
6013
6428
  return !error;
@@ -6016,7 +6431,7 @@ const admin = ({ strapi: strapi2 }) => ({
6016
6431
  try {
6017
6432
  return await duplicateCheck(initialPath, targetRouteDocumentId);
6018
6433
  } catch (e) {
6019
- console.log(e);
6434
+ strapi2.log.error(e);
6020
6435
  }
6021
6436
  }
6022
6437
  });
@@ -6027,6 +6442,7 @@ const client = ({ strapi: strapi2 }) => ({
6027
6442
  filters: {
6028
6443
  $or: [
6029
6444
  { path: slug },
6445
+ { canonicalPath: slug },
6030
6446
  { uidPath: slug }
6031
6447
  ]
6032
6448
  }
@@ -6053,9 +6469,21 @@ const client = ({ strapi: strapi2 }) => ({
6053
6469
  if (!entity) return null;
6054
6470
  let cleanEntity = cleanRootKeys(entity);
6055
6471
  cleanEntity = removeWaFields(cleanEntity);
6056
- return { contentType: contentType.info.singularName, ...cleanEntity };
6472
+ const webatlasFields = {
6473
+ path: route2.path,
6474
+ canonicalPath: route2.canonicalPath,
6475
+ slug: route2.slug,
6476
+ uidPath: route2.uidPath
6477
+ };
6478
+ return {
6479
+ contentType: contentType.info.singularName,
6480
+ webatlas: {
6481
+ ...webatlasFields
6482
+ },
6483
+ ...cleanEntity
6484
+ };
6057
6485
  } catch (e) {
6058
- console.log(e);
6486
+ strapi2.log.error(e);
6059
6487
  return e;
6060
6488
  }
6061
6489
  },
@@ -6093,7 +6521,7 @@ const client = ({ strapi: strapi2 }) => ({
6093
6521
  try {
6094
6522
  navigation2 = await method.lookup();
6095
6523
  } catch (error) {
6096
- console.log(`Navigation lookup by ${method.name} failed:`, error);
6524
+ strapi2.log.error(`Navigation lookup by ${method.name} failed:`, error);
6097
6525
  }
6098
6526
  }
6099
6527
  }
@@ -6103,7 +6531,7 @@ const client = ({ strapi: strapi2 }) => ({
6103
6531
  const entityNavigation = extractRouteAndItems(structured.items);
6104
6532
  return { ...structured, items: entityNavigation };
6105
6533
  } catch (e) {
6106
- console.log(e);
6534
+ strapi2.log.error(e);
6107
6535
  return e;
6108
6536
  }
6109
6537
  }
@@ -6125,4 +6553,3 @@ const index = {
6125
6553
  middlewares
6126
6554
  };
6127
6555
  module.exports = index;
6128
- //# sourceMappingURL=index.js.map