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