@mattisvensson/strapi-plugin-webatlas 0.10.1 → 0.11.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 (48) hide show
  1. package/README.md +2 -1
  2. package/dist/admin/FullLoader-Cmsf8xS6.js +1 -0
  3. package/dist/admin/FullLoader-Cmsf8xS6.js.map +1 -0
  4. package/dist/admin/FullLoader-CrPED_dY.mjs +1 -0
  5. package/dist/admin/FullLoader-CrPED_dY.mjs.map +1 -0
  6. package/dist/admin/{SettingTitle-DbsxB1V9.mjs → SettingTitle-B1IaU3qs.mjs} +2 -1
  7. package/dist/admin/SettingTitle-B1IaU3qs.mjs.map +1 -0
  8. package/dist/admin/{SettingTitle-uw1S5OmC.js → SettingTitle-BjE_2u6R.js} +2 -1
  9. package/dist/admin/SettingTitle-BjE_2u6R.js.map +1 -0
  10. package/dist/admin/de-B5pRvs13.mjs +1 -0
  11. package/dist/admin/de-B5pRvs13.mjs.map +1 -0
  12. package/dist/admin/de-CqU1FU8C.js +1 -0
  13. package/dist/admin/de-CqU1FU8C.js.map +1 -0
  14. package/dist/admin/en-BE-zzIv8.mjs +1 -0
  15. package/dist/admin/en-BE-zzIv8.mjs.map +1 -0
  16. package/dist/admin/en-C7I90FwV.js +1 -0
  17. package/dist/admin/en-C7I90FwV.js.map +1 -0
  18. package/dist/admin/{index-BXt-QjKo.js → index-AVI3QJ0R.js} +2 -1
  19. package/dist/admin/index-AVI3QJ0R.js.map +1 -0
  20. package/dist/admin/{index-CGsC8P9P.js → index-B90eSO4a.js} +3 -2
  21. package/dist/admin/index-B90eSO4a.js.map +1 -0
  22. package/dist/admin/{index-tPrfjOIn.mjs → index-BIEUXWe7.mjs} +2 -1
  23. package/dist/admin/index-BIEUXWe7.mjs.map +1 -0
  24. package/dist/admin/{index-CUaBX_v-.mjs → index-BbnlyBrZ.mjs} +3 -2
  25. package/dist/admin/index-BbnlyBrZ.mjs.map +1 -0
  26. package/dist/admin/{index-BKWY9Ta-.mjs → index-Cf9j0bn2.mjs} +2 -1
  27. package/dist/admin/index-Cf9j0bn2.mjs.map +1 -0
  28. package/dist/admin/{index-BYlmJycd.js → index-D8bG0YFB.js} +3 -2
  29. package/dist/admin/index-D8bG0YFB.js.map +1 -0
  30. package/dist/admin/{index-CIr8o1RP.mjs → index-DCYCtKrj.mjs} +118 -106
  31. package/dist/admin/index-DCYCtKrj.mjs.map +1 -0
  32. package/dist/admin/{index-DkqiqVx2.js → index-JLpXBQVL.js} +2 -1
  33. package/dist/admin/index-JLpXBQVL.js.map +1 -0
  34. package/dist/admin/{index-B07KlG03.mjs → index-Y_PYIiRA.mjs} +3 -2
  35. package/dist/admin/index-Y_PYIiRA.mjs.map +1 -0
  36. package/dist/admin/{index-DC5WwNdi.js → index-Yq-QR8t0.js} +118 -106
  37. package/dist/admin/index-Yq-QR8t0.js.map +1 -0
  38. package/dist/admin/index.js +2 -1
  39. package/dist/admin/index.js.map +1 -0
  40. package/dist/admin/index.mjs +2 -1
  41. package/dist/admin/index.mjs.map +1 -0
  42. package/dist/server/index.js +384 -259
  43. package/dist/server/index.js.map +1 -0
  44. package/dist/server/index.mjs +384 -259
  45. package/dist/server/index.mjs.map +1 -0
  46. package/package.json +1 -1
  47. package/dist/admin/src/index.d.ts +0 -12
  48. package/dist/server/src/index.d.ts +0 -301
@@ -1,17 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- function transformToUrl(input) {
3
+ function transformToUrl(input, replaceSlash = true) {
4
4
  const specialCharMap = {
5
5
  "ü": "ue",
6
6
  "ä": "ae",
7
- "ö": "oe"
7
+ "ö": "oe",
8
+ "ß": "ss"
8
9
  };
9
10
  if (!input || typeof input !== "string") return "";
10
11
  input = input.toLowerCase();
11
12
  input = input.replace(/\/+/g, "/");
12
13
  input = input.startsWith("/") ? input.slice(1) : input;
13
14
  input = input.endsWith("/") ? input.slice(0, -1) : input;
14
- input = input.replace(/\//g, "-");
15
+ if (replaceSlash) {
16
+ input = input.replace(/\//g, "-");
17
+ } else {
18
+ input = input.replace(/\/+/g, "/");
19
+ input = input.startsWith("/") ? input.slice(1) : input;
20
+ input = input.endsWith("/") ? input.slice(0, -1) : input;
21
+ }
15
22
  for (const char in specialCharMap) {
16
23
  const regex = new RegExp(char, "g");
17
24
  input = input.replace(regex, specialCharMap[char]);
@@ -30,36 +37,28 @@ const PLUGIN_ID = pluginPkg.strapi.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plug
30
37
  const waNavigation = `plugin::${PLUGIN_ID}.navigation`;
31
38
  const waNavItem = `plugin::${PLUGIN_ID}.navitem`;
32
39
  const waRoute = `plugin::${PLUGIN_ID}.route`;
33
- async function checkPathExists(path, targetRoutePath) {
34
- const entities = await strapi.documents(waRoute).findMany({
35
- filters: {
36
- $or: [
37
- { path },
38
- { slug: path },
39
- { uidPath: path },
40
- { canonicalPath: path }
41
- ]
42
- }
43
- });
44
- if (targetRoutePath && entities && entities[0]?.path === targetRoutePath)
45
- return false;
46
- return entities?.length > 0;
40
+ async function checkPathExists(path, excludeDocumentId) {
41
+ const filters = {
42
+ $or: [
43
+ { path },
44
+ { uidPath: path },
45
+ { canonicalPath: path }
46
+ ]
47
+ };
48
+ if (excludeDocumentId) {
49
+ filters.documentId = { $ne: excludeDocumentId };
50
+ }
51
+ const entity = await strapi.documents(waRoute).findFirst({ filters });
52
+ return !!entity;
47
53
  }
48
54
  async function duplicateCheck(initialPath, targetRouteDocumentId) {
49
55
  try {
50
56
  let uniquePath = initialPath;
51
- let targetRoutePath = null;
52
57
  let counter = 1;
53
- if (targetRouteDocumentId) {
54
- const route2 = await strapi.documents(waRoute).findOne({
55
- documentId: targetRouteDocumentId
56
- });
57
- if (route2) targetRoutePath = route2.path;
58
- }
59
- let exists = await checkPathExists(uniquePath, targetRoutePath);
58
+ let exists = await checkPathExists(uniquePath, targetRouteDocumentId);
60
59
  while (exists) {
61
60
  uniquePath = `${initialPath}-${counter}`;
62
- exists = await checkPathExists(uniquePath);
61
+ exists = await checkPathExists(uniquePath, targetRouteDocumentId);
63
62
  counter++;
64
63
  }
65
64
  return uniquePath;
@@ -251,12 +250,14 @@ function extractRouteAndItems(items) {
251
250
  return items.map((item) => {
252
251
  const route2 = { ...item.route };
253
252
  if (!route2) return null;
254
- if (item.depth) {
255
- route2.depth = item.depth;
253
+ let depth = null;
254
+ if (item.depth !== void 0) {
255
+ depth = item.depth;
256
256
  }
257
+ let children = null;
257
258
  if (item.items?.length > 0) {
258
259
  const items2 = extractRouteAndItems(item.items);
259
- if (items2.length > 0) route2.items = items2;
260
+ if (items2.length > 0) children = items2;
260
261
  }
261
262
  delete route2.relatedContentType;
262
263
  delete route2.relatedDocumentId;
@@ -267,7 +268,9 @@ function extractRouteAndItems(items) {
267
268
  return {
268
269
  __component: route2.type === "wrapper" ? `${PLUGIN_ID}.wrapper` : `${PLUGIN_ID}.route`,
269
270
  type: route2.type,
270
- ...route2
271
+ ...route2,
272
+ depth: depth !== null ? depth : void 0,
273
+ items: children !== null ? children : void 0
271
274
  };
272
275
  });
273
276
  }
@@ -4318,6 +4321,7 @@ function removeWaFields(obj) {
4318
4321
  delete obj["webatlas_path"];
4319
4322
  delete obj["webatlas_override"];
4320
4323
  delete obj["webatlas_parent"];
4324
+ delete obj["webatlas"];
4321
4325
  return obj;
4322
4326
  }
4323
4327
  async function buildCanonicalPath(slug, parentDocumentId) {
@@ -4333,26 +4337,55 @@ async function buildCanonicalPath(slug, parentDocumentId) {
4333
4337
  return slug;
4334
4338
  }
4335
4339
  }
4336
- async function cascadeCanonicalPathUpdates(parentRouteId, newParentCanonicalPath) {
4337
- const children = await strapi.db.query(waRoute).findMany({
4338
- where: {
4339
- parent: {
4340
- documentId: parentRouteId
4340
+ async function cascadePathUpdates({
4341
+ validatedParentPath,
4342
+ parentRouteDocumentId,
4343
+ canonicalPath,
4344
+ isOverride
4345
+ }) {
4346
+ try {
4347
+ const children = await strapi.db.query(waRoute).findMany({
4348
+ where: {
4349
+ parent: {
4350
+ documentId: parentRouteDocumentId
4351
+ }
4341
4352
  }
4342
- }
4343
- });
4344
- for (const child of children) {
4345
- const newCanonicalPath = `${newParentCanonicalPath}/${child.slug}`;
4346
- const updateData = {
4347
- canonicalPath: newCanonicalPath,
4348
- // Only update path if not manually overridden
4349
- ...child.isOverride ? {} : { path: newCanonicalPath }
4350
- };
4351
- await strapi.documents(waRoute).update({
4352
- documentId: child.documentId,
4353
- data: updateData
4354
4353
  });
4355
- await cascadeCanonicalPathUpdates(child.documentId, newCanonicalPath);
4354
+ for (const child of children) {
4355
+ const newCanonicalPath = `${canonicalPath}/${child.slug}`;
4356
+ const newPath = isOverride ? `${validatedParentPath}/${child.slug}` : newCanonicalPath;
4357
+ const validatedCanonicalPath = await duplicateCheck(newCanonicalPath, child.documentId);
4358
+ const validatedPath = isOverride ? await duplicateCheck(newPath, child.documentId) : validatedCanonicalPath;
4359
+ await strapi.db.query(waRoute).updateMany({
4360
+ where: { documentId: child.documentId },
4361
+ data: {
4362
+ canonicalPath: validatedCanonicalPath,
4363
+ path: validatedPath
4364
+ }
4365
+ });
4366
+ const existingEntry = await strapi.db.query(child.relatedContentType).findOne({
4367
+ where: { documentId: child.relatedDocumentId }
4368
+ });
4369
+ if (existingEntry) {
4370
+ await strapi.db.query(child.relatedContentType).updateMany({
4371
+ where: { documentId: child.relatedDocumentId },
4372
+ data: {
4373
+ webatlas: {
4374
+ ...existingEntry.webatlas,
4375
+ path: validatedPath
4376
+ }
4377
+ }
4378
+ });
4379
+ }
4380
+ await cascadePathUpdates({
4381
+ validatedParentPath: validatedPath,
4382
+ parentRouteDocumentId: child.documentId,
4383
+ canonicalPath: validatedCanonicalPath,
4384
+ isOverride
4385
+ });
4386
+ }
4387
+ } catch (err) {
4388
+ strapi.log.error(err);
4356
4389
  }
4357
4390
  }
4358
4391
  async function getRouteDescendants(routeId) {
@@ -4679,8 +4712,66 @@ const migration_001_canonical_path = {
4679
4712
  }
4680
4713
  }
4681
4714
  };
4715
+ const migration_002_webatlas_json_field = {
4716
+ version: "002",
4717
+ description: "Migrate webatlas_path, webatlas_parent and webatlas_override text fields into the webatlas JSON field",
4718
+ async up(strapi2) {
4719
+ const knex = strapi2.db.connection;
4720
+ const enabledContentTypes = Object.values(strapi2.contentTypes).filter(
4721
+ (ct) => ct.pluginOptions?.webatlas?.enabled === true
4722
+ );
4723
+ for (const contentType of enabledContentTypes) {
4724
+ const tableName = strapi2.db.metadata.get(contentType.uid)?.tableName ?? contentType.collectionName;
4725
+ strapi2.log.info(`[webatlas] Processing table: ${tableName} (${contentType.uid})`);
4726
+ const [hasPathCol, hasOverrideCol, hasParentCol, hasWebatlasCol] = await Promise.all([
4727
+ knex.schema.hasColumn(tableName, "webatlas_path"),
4728
+ knex.schema.hasColumn(tableName, "webatlas_override"),
4729
+ knex.schema.hasColumn(tableName, "webatlas_parent"),
4730
+ knex.schema.hasColumn(tableName, "webatlas")
4731
+ ]);
4732
+ const hasAnyOldCol = hasPathCol || hasOverrideCol || hasParentCol;
4733
+ if (!hasAnyOldCol) {
4734
+ strapi2.log.info(`[webatlas] No old fields found in ${tableName}, skipping data migration`);
4735
+ } else if (!hasWebatlasCol) {
4736
+ strapi2.log.warn(`[webatlas] New "webatlas" column not found in ${tableName} — schema may not have synced yet. Skipping data migration, old columns will still be dropped.`);
4737
+ } else {
4738
+ const selectCols = ["id"];
4739
+ if (hasPathCol) selectCols.push("webatlas_path");
4740
+ if (hasOverrideCol) selectCols.push("webatlas_override");
4741
+ if (hasParentCol) selectCols.push("webatlas_parent");
4742
+ const rows = await knex(tableName).select(selectCols);
4743
+ let migratedCount = 0;
4744
+ for (const row of rows) {
4745
+ const path = row.webatlas_path || "";
4746
+ const isOverride = Boolean(row.webatlas_override);
4747
+ const parentDocumentId = row.webatlas_parent || null;
4748
+ if (!path && !isOverride && !parentDocumentId) continue;
4749
+ const slug = path ? path.split("/").pop() || "" : "";
4750
+ await knex(tableName).where({ id: row.id }).update({
4751
+ webatlas: JSON.stringify({ path, slug, isOverride, parentDocumentId })
4752
+ });
4753
+ migratedCount++;
4754
+ }
4755
+ strapi2.log.info(`[webatlas] Migrated ${migratedCount} / ${rows.length} rows in ${tableName}`);
4756
+ }
4757
+ const colsToDrop = [
4758
+ hasPathCol && "webatlas_path",
4759
+ hasOverrideCol && "webatlas_override",
4760
+ hasParentCol && "webatlas_parent"
4761
+ ].filter(Boolean);
4762
+ if (colsToDrop.length > 0) {
4763
+ await knex.schema.table(tableName, (table) => {
4764
+ colsToDrop.forEach((col) => table.dropColumn(col));
4765
+ });
4766
+ strapi2.log.info(`[webatlas] Dropped columns [${colsToDrop.join(", ")}] from ${tableName}`);
4767
+ }
4768
+ }
4769
+ strapi2.log.info("[webatlas] webatlas JSON field migration completed");
4770
+ }
4771
+ };
4682
4772
  const migrations = [
4683
- migration_001_canonical_path
4773
+ migration_001_canonical_path,
4774
+ migration_002_webatlas_json_field
4684
4775
  ];
4685
4776
  const runMigrations = async (strapi2) => {
4686
4777
  const pluginStore = strapi2.store({ type: "plugin", name: PLUGIN_ID });
@@ -4714,54 +4805,47 @@ const runMigrations = async (strapi2) => {
4714
4805
  }
4715
4806
  strapi2.log.info("[webatlas] All migrations completed successfully");
4716
4807
  };
4717
- const bootstrap = async ({ strapi: strapi2 }) => {
4718
- try {
4719
- await runMigrations(strapi2);
4720
- const actions = [
4721
- {
4722
- section: "plugins",
4723
- displayName: "Navigation page",
4724
- uid: "page.navigation",
4725
- subCategory: "Pages",
4726
- pluginName: PLUGIN_ID
4727
- },
4728
- {
4729
- section: "plugins",
4730
- displayName: "Routes page",
4731
- uid: "page.routes",
4732
- subCategory: "Pages",
4733
- pluginName: PLUGIN_ID
4734
- },
4735
- {
4736
- section: "plugins",
4737
- displayName: "General page",
4738
- uid: "settings.general",
4739
- subCategory: "Settings",
4740
- pluginName: PLUGIN_ID
4741
- },
4742
- {
4743
- section: "plugins",
4744
- displayName: "Navigation page",
4745
- uid: "settings.navigation",
4746
- subCategory: "Settings",
4747
- pluginName: PLUGIN_ID
4748
- },
4749
- {
4750
- section: "plugins",
4751
- displayName: "Aside panel",
4752
- uid: "cm.aside",
4753
- subCategory: "Content Manager",
4754
- pluginName: PLUGIN_ID
4755
- }
4756
- ];
4757
- strapi2.admin.services.permission.actionProvider.registerMany(actions);
4758
- } catch (error) {
4759
- strapi2.log.error(`Bootstrap failed. ${String(error)}`);
4760
- }
4761
- const contentTypes2 = strapi2.contentTypes;
4762
- const enabledContentTypes = Object.values(contentTypes2).filter(
4763
- (type) => type.pluginOptions?.webatlas?.enabled === true
4764
- );
4808
+ function registerPermissions(strapi2) {
4809
+ const actions = [
4810
+ {
4811
+ section: "plugins",
4812
+ displayName: "Navigation page",
4813
+ uid: "page.navigation",
4814
+ subCategory: "Pages",
4815
+ pluginName: PLUGIN_ID
4816
+ },
4817
+ {
4818
+ section: "plugins",
4819
+ displayName: "Routes page",
4820
+ uid: "page.routes",
4821
+ subCategory: "Pages",
4822
+ pluginName: PLUGIN_ID
4823
+ },
4824
+ {
4825
+ section: "plugins",
4826
+ displayName: "General page",
4827
+ uid: "settings.general",
4828
+ subCategory: "Settings",
4829
+ pluginName: PLUGIN_ID
4830
+ },
4831
+ {
4832
+ section: "plugins",
4833
+ displayName: "Navigation page",
4834
+ uid: "settings.navigation",
4835
+ subCategory: "Settings",
4836
+ pluginName: PLUGIN_ID
4837
+ },
4838
+ {
4839
+ section: "plugins",
4840
+ displayName: "Aside panel",
4841
+ uid: "cm.aside",
4842
+ subCategory: "Content Manager",
4843
+ pluginName: PLUGIN_ID
4844
+ }
4845
+ ];
4846
+ strapi2.admin.services.permission.actionProvider.registerMany(actions);
4847
+ }
4848
+ async function syncConfig(strapi2, enabledContentTypes) {
4765
4849
  const pluginStore = strapi2.store({ type: "plugin", name: PLUGIN_ID });
4766
4850
  const config2 = await pluginStore.get({
4767
4851
  key: "config"
@@ -4786,140 +4870,117 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4786
4870
  if (JSON.stringify(newConfig) !== JSON.stringify(config2)) {
4787
4871
  await pluginStore.set({ key: "config", value: newConfig });
4788
4872
  }
4789
- if (!enabledContentTypes.length) return;
4790
- strapi2.db?.lifecycles.subscribe({
4791
- models: [waNavItem],
4792
- // TODO: is beforeDelete needed?
4793
- async beforeDelete(event) {
4794
- const id = event.params.where["id"];
4795
- if (!id) return;
4796
- try {
4797
- const navItem = await strapi2.db?.query(waNavItem).findOne({
4798
- where: {
4799
- id
4800
- },
4801
- populate: ["route"]
4802
- });
4803
- if (!navItem || !navItem.route) return;
4804
- event.state = navItem.route.id && navItem.route.type === "external" ? { id: navItem.route.id } : null;
4805
- } catch (err) {
4806
- strapi2.log.error(err);
4807
- }
4808
- },
4809
- async afterDelete(event) {
4810
- const { id } = event.state;
4811
- if (!id) return;
4812
- try {
4813
- await strapi2.db?.query(waRoute).delete({
4814
- where: {
4815
- id
4816
- }
4817
- });
4818
- } catch (err) {
4819
- strapi2.log.error(err);
4820
- }
4873
+ return newConfig;
4874
+ }
4875
+ function documentMiddleware(strapi2, enabledContentTypes, config2) {
4876
+ const actions = ["create", "update", "delete"];
4877
+ strapi2.documents.use(async (context, next) => {
4878
+ if (!enabledContentTypes.map((type) => type.uid).includes(context.uid) || !actions.includes(context.action)) {
4879
+ return next();
4821
4880
  }
4822
- });
4823
- strapi2.db?.lifecycles.subscribe({
4824
- models: enabledContentTypes.map((type) => type.uid),
4825
- async beforeCreate(event) {
4826
- if (!event.params.data.webatlas_path) return;
4827
- event.params.data.webatlas_path = transformToUrl(event.params.data.webatlas_path);
4828
- },
4829
- async afterCreate(event) {
4830
- const ctSettings = config2.selectedContentTypes.find((type) => type.uid === event.model.uid);
4831
- const {
4832
- webatlas_path,
4833
- webatlas_override,
4834
- webatlas_parent
4835
- } = event.params.data;
4836
- if (!webatlas_path) return;
4837
- const relatedRoute = await strapi2.db?.query(waRoute).findOne({
4838
- where: {
4839
- relatedDocumentId: event.result.documentId
4840
- }
4881
+ const ctSettings = config2.selectedContentTypes.find((ct) => ct.uid === context.uid);
4882
+ if (context.action === "create") {
4883
+ const data = context.params.data;
4884
+ const { webatlas } = data;
4885
+ const { slug, parentDocumentId, isOverride } = webatlas || {};
4886
+ const transformedSlug = slug ? transformToUrl(slug) : null;
4887
+ if (transformedSlug) {
4888
+ data.webatlas.slug = transformedSlug;
4889
+ }
4890
+ const result2 = await next();
4891
+ if (!transformedSlug) return result2;
4892
+ const existing = await strapi2.db?.query(waRoute).findOne({
4893
+ where: { relatedDocumentId: result2.documentId }
4841
4894
  });
4842
- if (relatedRoute) return;
4895
+ if (existing) return result2;
4843
4896
  let parent = null;
4844
- if (webatlas_parent) {
4845
- try {
4846
- const isValid = await validateRouteDependencies({
4847
- newParentId: webatlas_parent
4897
+ let isValid = false;
4898
+ if (parentDocumentId) {
4899
+ isValid = await validateRouteDependencies({ newParentId: parentDocumentId });
4900
+ if (isValid) {
4901
+ parent = await strapi2.documents(waRoute).findOne({
4902
+ documentId: parentDocumentId
4848
4903
  });
4849
- if (isValid) parent = webatlas_parent;
4850
- } catch (err) {
4851
- strapi2.log.error(`Route dependency validation failed: ${err.message}`);
4852
4904
  }
4853
4905
  }
4854
- const path = await duplicateCheck(transformToUrl(webatlas_path));
4855
- const canonicalPath = await buildCanonicalPath(path, parent);
4856
- const title = event.params.data[ctSettings?.default]?.trim() || path;
4906
+ let rawPath = transformedSlug;
4907
+ if (!isOverride) rawPath = parent ? `${parent.path}/${transformedSlug}` : transformedSlug;
4908
+ const validatedPath = await duplicateCheck(rawPath);
4909
+ if (!validatedPath) throw new Error(`Failed to generate a unique path for slug: ${transformedSlug}`);
4910
+ const singularName = context.contentType.info.singularName;
4911
+ const title = context.params.data[ctSettings?.default]?.trim() || transformedSlug;
4912
+ const canonicalPath = await buildCanonicalPath(transformToUrl(title), isValid ? parent.documentId : null);
4857
4913
  await strapi2.documents(waRoute).create({
4858
4914
  data: {
4859
- relatedContentType: event.model.uid,
4860
- relatedId: event.result.id,
4861
- relatedDocumentId: event.result.documentId,
4862
- slug: path,
4863
- path,
4864
- uidPath: `${event.model.singularName}/${event.result.id}`,
4865
- isOverride: webatlas_override || false,
4915
+ relatedContentType: context.uid,
4916
+ relatedId: result2.id,
4917
+ relatedDocumentId: result2.documentId,
4918
+ slug: transformedSlug,
4919
+ path: validatedPath,
4920
+ uidPath: `${singularName}/${result2.id}`,
4921
+ isOverride: isOverride || false,
4866
4922
  title,
4867
- parent,
4923
+ parent: isValid ? parent?.documentId : null,
4868
4924
  canonicalPath
4869
4925
  }
4870
4926
  });
4871
- },
4872
- async afterUpdate(event) {
4873
- const ctSettings = config2.selectedContentTypes.find((type) => type.uid === event.model.uid);
4874
- const {
4875
- webatlas_path,
4876
- webatlas_override,
4877
- webatlas_parent,
4878
- documentId
4879
- } = event.params.data;
4880
- if (!webatlas_path) return;
4927
+ await strapi2.db?.query(context.uid).updateMany({
4928
+ where: { documentId: result2.documentId },
4929
+ data: { webatlas: { ...webatlas, slug: transformedSlug, path: validatedPath, parentDocumentId: isValid ? parent?.documentId : null } }
4930
+ });
4931
+ return result2;
4932
+ }
4933
+ if (context.action === "update") {
4934
+ const data = context.params.data;
4935
+ const { documentId } = context.params;
4936
+ const { webatlas } = data;
4937
+ const { slug, parentDocumentId, isOverride } = webatlas || {};
4938
+ if (!slug) return;
4881
4939
  const relatedRoute = await strapi2.documents(waRoute).findFirst({
4882
4940
  filters: {
4883
4941
  relatedDocumentId: documentId
4884
4942
  }
4885
4943
  });
4886
4944
  let parent = null;
4887
- if (webatlas_parent) {
4888
- try {
4889
- const isValid = await validateRouteDependencies({
4890
- routeId: relatedRoute ? relatedRoute.documentId : null,
4891
- newParentId: webatlas_parent
4945
+ let isValid = false;
4946
+ if (parentDocumentId) {
4947
+ isValid = await validateRouteDependencies({
4948
+ routeId: relatedRoute ? relatedRoute.documentId : null,
4949
+ newParentId: parentDocumentId
4950
+ });
4951
+ if (isValid) {
4952
+ parent = await strapi2.documents(waRoute).findOne({
4953
+ documentId: parentDocumentId
4892
4954
  });
4893
- if (isValid) {
4894
- parent = await strapi2.documents(waRoute).findOne({
4895
- documentId: webatlas_parent
4896
- });
4897
- }
4898
- } catch (err) {
4899
- strapi2.log.error(`Route dependency validation failed: ${err.message}`);
4900
4955
  }
4901
4956
  }
4902
- const transformedPath = transformToUrl(webatlas_path);
4903
- const rawPath = parent ? `${parent.path}/${transformedPath}` : transformedPath;
4904
- const path = await duplicateCheck(rawPath, relatedRoute ? relatedRoute.documentId : null);
4905
- const canonicalPath = await buildCanonicalPath(transformedPath, parent?.documentId);
4906
- const title = event.params.data[ctSettings?.default]?.trim() || path;
4957
+ const transformedSlug = transformToUrl(slug);
4958
+ let rawPath = transformedSlug;
4959
+ if (!isOverride) rawPath = parent ? `${parent.path}/${transformedSlug}` : transformedSlug;
4960
+ const validatedPath = await duplicateCheck(rawPath, relatedRoute?.documentId ?? null);
4961
+ data.webatlas.path = validatedPath;
4962
+ data.webatlas.slug = transformedSlug;
4963
+ if (relatedRoute) data.relatedRoute = relatedRoute;
4964
+ if (!isValid && parentDocumentId) data.webatlas.parent = null;
4965
+ const result2 = await next();
4966
+ const title = context.params.data[ctSettings?.default]?.trim() || slug;
4967
+ const canonicalPath = isOverride ? relatedRoute.path : await buildCanonicalPath(transformToUrl(title), parent?.documentId);
4907
4968
  const routeData = {
4908
4969
  title,
4909
- path,
4910
- slug: transformedPath,
4911
- isOverride: webatlas_override || false,
4912
- parent: parent?.documentId || null
4970
+ path: validatedPath,
4971
+ slug,
4972
+ isOverride: isOverride || false,
4973
+ parent: parent?.documentId || null,
4974
+ canonicalPath
4913
4975
  };
4914
4976
  let routeDocumentId = relatedRoute?.documentId;
4915
4977
  if (!relatedRoute) {
4916
4978
  const createdRoute = await strapi2.documents(waRoute).create({
4917
4979
  data: {
4918
- relatedContentType: event.model.uid,
4919
- relatedId: event.result.id,
4920
- relatedDocumentId: event.result.documentId,
4921
- uidPath: `${event.model.singularName}/${event.result.id}`,
4922
- canonicalPath,
4980
+ relatedContentType: context.uid,
4981
+ relatedId: result2.id,
4982
+ relatedDocumentId: result2.documentId,
4983
+ uidPath: `${context.contentType.info.singularName}/${result2.id}`,
4923
4984
  ...routeData
4924
4985
  }
4925
4986
  });
@@ -4927,57 +4988,121 @@ const bootstrap = async ({ strapi: strapi2 }) => {
4927
4988
  } else {
4928
4989
  await strapi2.documents(waRoute).update({
4929
4990
  documentId: relatedRoute.documentId,
4930
- data: {
4931
- ...routeData,
4932
- canonicalPath
4933
- }
4991
+ data: routeData
4934
4992
  });
4935
4993
  }
4936
4994
  if (routeDocumentId) {
4937
- await cascadeCanonicalPathUpdates(routeDocumentId, canonicalPath);
4995
+ await cascadePathUpdates({
4996
+ validatedParentPath: validatedPath,
4997
+ parentRouteDocumentId: routeDocumentId,
4998
+ canonicalPath,
4999
+ isOverride
5000
+ });
4938
5001
  }
4939
- },
4940
- async afterDelete(event) {
5002
+ }
5003
+ if (context.action === "delete") {
5004
+ const result2 = await next();
4941
5005
  try {
4942
- await findAndDeleteNavItem(event.result.id, event.model.uid);
5006
+ const relatedDocumentId = context.params.documentId;
5007
+ const deletedRoute = await strapi2.db.query(waRoute).delete({
5008
+ where: { relatedDocumentId },
5009
+ populate: ["navitem"]
5010
+ });
5011
+ if (!deletedRoute?.documentId) return result2;
5012
+ const navItemDocumentIds = Array.from(deletedRoute.navitem?.map((item) => item.documentId));
5013
+ for (const navItemDocumentId of navItemDocumentIds) {
5014
+ await strapi2.documents(waNavItem).delete({ documentId: navItemDocumentId });
5015
+ }
4943
5016
  } catch (err) {
4944
5017
  strapi2.log.error(err);
4945
5018
  }
4946
- },
4947
- async afterDeleteMany(event) {
4948
- const deletedArr = event.params.where["$and"];
4949
- deletedArr.map((item) => {
4950
- const ids = item.id["$in"];
4951
- ids.map(async (id) => {
4952
- await findAndDeleteNavItem(id, event.model.uid);
4953
- });
4954
- });
5019
+ return result2;
4955
5020
  }
5021
+ const result = await next();
5022
+ return result;
4956
5023
  });
4957
- };
4958
- async function findAndDeleteNavItem(relatedId, relatedContentType) {
4959
- if (!relatedId || !relatedContentType) return;
4960
- try {
4961
- const route2 = await strapi.db?.query(waRoute).findOne({
4962
- where: {
4963
- relatedId,
4964
- relatedContentType
5024
+ }
5025
+ function webatlasMiddleware(strapi2) {
5026
+ strapi2.documents.use(async (context, next) => {
5027
+ if (context.uid !== waNavItem) return next();
5028
+ if (context.action === "delete") {
5029
+ let externalRouteDocumentId = null;
5030
+ try {
5031
+ const navItem = await strapi2.db?.query(waNavItem).findOne({
5032
+ where: { documentId: context.params.documentId },
5033
+ populate: ["route"]
5034
+ });
5035
+ if (navItem?.route?.type === "external") {
5036
+ externalRouteDocumentId = navItem.route.documentId;
5037
+ }
5038
+ } catch (err) {
5039
+ strapi2.log.error(err);
4965
5040
  }
4966
- });
4967
- if (!route2?.documentId) return;
4968
- const navItem = await strapi.db?.query(waNavItem).findOne({
4969
- where: {
4970
- route: {
4971
- documentId: route2.documentId
5041
+ const result = await next();
5042
+ if (externalRouteDocumentId) {
5043
+ try {
5044
+ await strapi2.documents(waRoute).delete({ documentId: externalRouteDocumentId });
5045
+ } catch (err) {
5046
+ strapi2.log.error(err);
4972
5047
  }
4973
5048
  }
4974
- });
4975
- await strapi.documents(waRoute).delete({ documentId: route2.documentId });
4976
- if (navItem?.documentId) await strapi.documents(waNavItem).delete({ documentId: navItem.documentId });
4977
- } catch (err) {
4978
- strapi.log.error(err);
4979
- }
5049
+ return result;
5050
+ }
5051
+ return next();
5052
+ });
5053
+ }
5054
+ function contentTypeMiddleware(strapi2) {
5055
+ strapi2.documents.use(async (context, next) => {
5056
+ const pluginOptions = context.contentType?.pluginOptions;
5057
+ if (!pluginOptions?.webatlas?.enabled) {
5058
+ return next();
5059
+ }
5060
+ if (!["findOne", "findMany"].includes(context.action)) {
5061
+ return next();
5062
+ }
5063
+ const result = await next();
5064
+ if (context.action === "findOne") {
5065
+ if (!result || typeof result !== "object" || Array.isArray(result)) return result;
5066
+ const entry = result;
5067
+ const webatlasObj = entry.webatlas || {};
5068
+ const newWebatlasObj = {
5069
+ path: webatlasObj.path || "",
5070
+ slug: webatlasObj.slug || ""
5071
+ };
5072
+ return { ...entry, webatlas: newWebatlasObj };
5073
+ }
5074
+ if (context.action === "findMany") {
5075
+ if (!Array.isArray(result)) return result;
5076
+ return result.map(
5077
+ (entry) => {
5078
+ const webatlasObj = entry.webatlas || {};
5079
+ const newWebatlasObj = {
5080
+ path: webatlasObj.path || "",
5081
+ slug: webatlasObj.slug || ""
5082
+ };
5083
+ return { ...entry, webatlas: newWebatlasObj };
5084
+ }
5085
+ );
5086
+ }
5087
+ return result;
5088
+ });
4980
5089
  }
5090
+ const bootstrap = async ({ strapi: strapi2 }) => {
5091
+ try {
5092
+ await runMigrations(strapi2);
5093
+ registerPermissions(strapi2);
5094
+ const enabledContentTypes = Object.values(strapi2.contentTypes).filter(
5095
+ (type) => type.pluginOptions?.webatlas?.enabled === true
5096
+ );
5097
+ const config2 = await syncConfig(strapi2, enabledContentTypes);
5098
+ if (!enabledContentTypes.length) return;
5099
+ documentMiddleware(strapi2, enabledContentTypes, config2);
5100
+ webatlasMiddleware(strapi2);
5101
+ contentTypeMiddleware(strapi2);
5102
+ } catch (error) {
5103
+ strapi2.log.error(`Bootstrap failed. ${String(error)}`);
5104
+ }
5105
+ };
4981
5106
  const destroy = ({ strapi: strapi2 }) => {
4982
5107
  };
4983
5108
  var _freeGlobal;
@@ -5893,21 +6018,11 @@ const register = ({ strapi: strapi2 }) => {
5893
6018
  visible: true,
5894
6019
  default: null
5895
6020
  };
5896
- set(attributes, "webatlas_path", {
6021
+ set(attributes, "webatlas", {
5897
6022
  ...fieldSettings,
5898
- type: "string",
6023
+ type: "json",
5899
6024
  private: false
5900
6025
  });
5901
- set(attributes, "webatlas_override", {
5902
- ...fieldSettings,
5903
- type: "boolean",
5904
- private: true
5905
- });
5906
- set(attributes, "webatlas_parent", {
5907
- ...fieldSettings,
5908
- type: "string",
5909
- private: true
5910
- });
5911
6026
  });
5912
6027
  };
5913
6028
  const config = {
@@ -6246,9 +6361,9 @@ const client$2 = ({ strapi: strapi2 }) => ({
6246
6361
  },
6247
6362
  async getNavigation(ctx) {
6248
6363
  try {
6249
- const { id, name, documentId, variant } = ctx.query;
6250
- if (!id && !name && !documentId) return ctx.throw(400, "Navigation id, name or documentId is required");
6251
- const navigation2 = await getClientService().getNavigation(id, name, documentId, variant);
6364
+ const { id, name, slug, documentId, variant } = ctx.query;
6365
+ if (!id && !name && !slug && !documentId) return ctx.throw(400, "Navigation id, name, slug or documentId is required");
6366
+ const navigation2 = await getClientService().getNavigation(id, name, slug, documentId, variant);
6252
6367
  if (!navigation2) return ctx.throw(404, "Navigation not found");
6253
6368
  return ctx.send(navigation2);
6254
6369
  } catch (e) {
@@ -6799,23 +6914,32 @@ const client = ({ strapi: strapi2 }) => ({
6799
6914
  return e;
6800
6915
  }
6801
6916
  },
6802
- async getNavigation(id, name, documentId, variant = "nested") {
6917
+ async getNavigation(id, name, slug, documentId, variant = "nested") {
6803
6918
  try {
6804
6919
  let navigation2 = null;
6920
+ const populateObject = ["items", "items.parent", "items.route"];
6805
6921
  const lookupMethods = [
6806
6922
  {
6807
6923
  condition: documentId,
6808
6924
  lookup: () => strapi2.documents(waNavigation).findOne({
6809
6925
  documentId,
6810
- populate: ["items", "items.parent", "items.route"]
6926
+ populate: populateObject
6811
6927
  }),
6812
6928
  name: "documentId"
6813
6929
  },
6930
+ {
6931
+ condition: slug,
6932
+ lookup: () => strapi2.db?.query(waNavigation).findOne({
6933
+ where: { slug },
6934
+ populate: populateObject
6935
+ }),
6936
+ name: "slug"
6937
+ },
6814
6938
  {
6815
6939
  condition: name,
6816
6940
  lookup: () => strapi2.db?.query(waNavigation).findOne({
6817
6941
  where: { name },
6818
- populate: ["items", "items.parent", "items.route"]
6942
+ populate: populateObject
6819
6943
  }),
6820
6944
  name: "name"
6821
6945
  },
@@ -6823,7 +6947,7 @@ const client = ({ strapi: strapi2 }) => ({
6823
6947
  condition: id,
6824
6948
  lookup: () => strapi2.db?.query(waNavigation).findOne({
6825
6949
  where: { id },
6826
- populate: ["items", "items.parent", "items.route"]
6950
+ populate: populateObject
6827
6951
  }),
6828
6952
  name: "id"
6829
6953
  }
@@ -6865,3 +6989,4 @@ const index = {
6865
6989
  middlewares
6866
6990
  };
6867
6991
  exports.default = index;
6992
+ //# sourceMappingURL=index.js.map