@mattisvensson/strapi-plugin-webatlas 0.9.6 → 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.
- package/README.md +24 -36
- package/dist/_chunks/{SettingTitle-77mvMRg_.mjs → SettingTitle-CdR3SVn_.mjs} +1 -1
- package/dist/_chunks/{SettingTitle-DLj_Wwqy.js → SettingTitle-RU1azFIM.js} +1 -1
- package/dist/_chunks/{de-C-uxto84.mjs → de-B5pRvs13.mjs} +13 -7
- package/dist/_chunks/{de-CGXL_3o_.js → de-CqU1FU8C.js} +13 -7
- package/dist/_chunks/{en-B1CHnIH7.mjs → en-BE-zzIv8.mjs} +13 -7
- package/dist/_chunks/{en-DWEd5BXK.js → en-C7I90FwV.js} +13 -7
- package/dist/_chunks/{index-DwaKIwAz.mjs → index-B07UVUOa.mjs} +387 -229
- package/dist/_chunks/{index-3pYLMhui.mjs → index-BmyxSosC.mjs} +3 -3
- package/dist/_chunks/{index-Dt-AXdaw.js → index-BucL4va6.js} +38 -82
- package/dist/_chunks/{index-BRKi-K-v.mjs → index-BvcX9hcc.mjs} +61 -24
- package/dist/_chunks/{index-COfk3YSm.js → index-BxpDM360.js} +386 -228
- package/dist/_chunks/{index-5OG4i6qO.mjs → index-CIM-JzLK.mjs} +38 -82
- package/dist/_chunks/{index-BWzalvVi.mjs → index-CNKWb8pn.mjs} +614 -320
- package/dist/_chunks/{index-VXuAEnpX.js → index-D-vJE_K8.js} +3 -3
- package/dist/_chunks/{index-BOtvXSPU.js → index-IRSCe8PX.js} +609 -315
- package/dist/_chunks/{index-DTsHvlTa.js → index-d09V61nm.js} +61 -24
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/CMEditViewAside/NewPathInfo.d.ts +2 -0
- package/dist/admin/src/components/CMEditViewAside/OverrideCheckbox.d.ts +7 -0
- package/dist/admin/src/components/CMEditViewAside/Panel.d.ts +5 -0
- package/dist/admin/src/components/CMEditViewAside/PathInput.d.ts +11 -0
- package/dist/admin/src/components/CMEditViewAside/RouteStructure.d.ts +3 -0
- package/dist/admin/src/components/CMEditViewAside/UidPathDisplay.d.ts +4 -0
- package/dist/admin/src/components/PathInfo.d.ts +2 -3
- package/dist/admin/src/components/modals/externalItem/index.d.ts +1 -1
- package/dist/admin/src/components/modals/internalItem/ItemDetails.d.ts +13 -0
- package/dist/admin/src/components/modals/internalItem/internalItemCreate.d.ts +1 -1
- package/dist/admin/src/components/modals/internalItem/internalItemEdit.d.ts +1 -1
- package/dist/admin/src/components/modals/useModalSharedLogic.d.ts +1 -1
- package/dist/admin/src/components/modals/wrapperItem/index.d.ts +1 -1
- package/dist/admin/src/hooks/useApi.d.ts +4 -3
- package/dist/admin/src/pages/Navigation/RouteItem.d.ts +1 -15
- package/dist/admin/src/pages/Navigation/RouteItemBadge.d.ts +4 -0
- package/dist/admin/src/pages/Navigation/RouteItemIcon.d.ts +5 -0
- package/dist/admin/src/pages/Navigation/RouteItemMenu.d.ts +10 -0
- package/dist/admin/src/pages/Navigation/RouteItemStatus.d.ts +5 -0
- package/dist/admin/src/pages/Navigation/SortableRouteItem.d.ts +1 -1
- package/dist/admin/src/types/index.d.ts +3 -0
- package/dist/admin/src/types/modal.d.ts +56 -0
- package/dist/admin/src/types/navigation.d.ts +18 -0
- package/dist/admin/src/types/panel.d.ts +41 -0
- package/dist/admin/src/types/route.d.ts +1 -1
- package/dist/admin/src/utils/buildBreadcrumbString.d.ts +16 -0
- package/dist/admin/src/utils/createTempNavItemObject.d.ts +6 -8
- package/dist/admin/src/utils/duplicateCheck.d.ts +10 -4
- package/dist/admin/src/utils/findParentNavItem.d.ts +13 -0
- package/dist/admin/src/utils/index.d.ts +3 -2
- package/dist/server/index.js +630 -200
- package/dist/server/index.mjs +630 -200
- package/dist/server/src/content-types/index.d.ts +18 -0
- package/dist/server/src/content-types/route/index.d.ts +18 -0
- package/dist/server/src/content-types/route/schema.d.ts +18 -0
- package/dist/server/src/controllers/admin.d.ts +3 -2
- package/dist/server/src/controllers/index.d.ts +3 -2
- package/dist/server/src/index.d.ts +24 -4
- package/dist/server/src/migrations/001-canonical-path.d.ts +7 -0
- package/dist/server/src/migrations/index.d.ts +3 -0
- package/dist/server/src/services/admin.d.ts +3 -2
- package/dist/server/src/services/index.d.ts +3 -2
- package/dist/server/src/utils/buildCanonicalPath.d.ts +1 -0
- package/dist/server/src/utils/buildNavigationPath.d.ts +5 -0
- package/dist/server/src/utils/cascadeCanonicalPathUpdates.d.ts +1 -0
- package/dist/server/src/utils/getNonInternalRouteIds.d.ts +1 -0
- package/dist/server/src/utils/getRouteAncestors.d.ts +1 -0
- package/dist/server/src/utils/getRouteDescendants.d.ts +1 -0
- package/dist/server/src/utils/index.d.ts +10 -2
- package/dist/server/src/utils/navigationItemStructure.d.ts +27 -0
- package/dist/server/src/utils/routeHandler.d.ts +4 -2
- package/dist/server/src/utils/validateRouteDependencies.d.ts +4 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/navigation.d.ts +13 -12
- package/dist/types/route.d.ts +7 -2
- package/dist/types/strapi.d.ts +1 -2
- package/dist/utils/index.d.ts +1 -2
- package/package.json +1 -1
- package/dist/admin/src/components/CMEditViewAside/Path.d.ts +0 -5
- package/dist/admin/src/utils/countChildren.d.ts +0 -2
- package/dist/types/modal.d.ts +0 -36
- package/dist/utils/getPath.d.ts +0 -1
package/dist/server/index.mjs
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
@@ -4457,15 +4850,15 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
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
4857
|
const existingConfig = config2?.selectedContentTypes?.find((ct) => ct.uid === type2.uid);
|
|
4464
4858
|
newConfig.selectedContentTypes.push({
|
|
4465
4859
|
uid: type2.uid,
|
|
4466
4860
|
label: type2.info.displayName,
|
|
4467
|
-
default: existingConfig?.default || null
|
|
4468
|
-
pattern: existingConfig?.pattern || null
|
|
4861
|
+
default: existingConfig?.default || null
|
|
4469
4862
|
});
|
|
4470
4863
|
});
|
|
4471
4864
|
if (JSON.stringify(newConfig) !== JSON.stringify(config2)) {
|
|
@@ -4488,7 +4881,7 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4488
4881
|
if (!navItem || !navItem.route) return;
|
|
4489
4882
|
event.state = navItem.route.id && navItem.route.type === "external" ? { id: navItem.route.id } : null;
|
|
4490
4883
|
} catch (err) {
|
|
4491
|
-
|
|
4884
|
+
strapi2.log.error(err);
|
|
4492
4885
|
}
|
|
4493
4886
|
},
|
|
4494
4887
|
async afterDelete(event) {
|
|
@@ -4501,15 +4894,13 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4501
4894
|
}
|
|
4502
4895
|
});
|
|
4503
4896
|
} catch (err) {
|
|
4504
|
-
|
|
4897
|
+
strapi2.log.error(err);
|
|
4505
4898
|
}
|
|
4506
4899
|
}
|
|
4507
4900
|
});
|
|
4508
4901
|
strapi2.db?.lifecycles.subscribe({
|
|
4509
4902
|
models: enabledContentTypes.map((type2) => type2.uid),
|
|
4510
4903
|
async beforeCreate(event) {
|
|
4511
|
-
const validContentTypes = config2.selectedContentTypes.filter((type2) => strapi2.contentTypes[type2.uid]);
|
|
4512
|
-
await pluginStore.set({ key: "config", value: { selectedContentTypes: validContentTypes } });
|
|
4513
4904
|
if (!event.params.data.webatlas_path) return;
|
|
4514
4905
|
event.params.data.webatlas_path = transformToUrl(event.params.data.webatlas_path);
|
|
4515
4906
|
},
|
|
@@ -4517,7 +4908,8 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4517
4908
|
const ctSettings = config2.selectedContentTypes.find((type2) => type2.uid === event.model.uid);
|
|
4518
4909
|
const {
|
|
4519
4910
|
webatlas_path,
|
|
4520
|
-
webatlas_override
|
|
4911
|
+
webatlas_override,
|
|
4912
|
+
webatlas_parent
|
|
4521
4913
|
} = event.params.data;
|
|
4522
4914
|
if (!webatlas_path) return;
|
|
4523
4915
|
const relatedRoute = await strapi2.db?.query(waRoute).findOne({
|
|
@@ -4526,8 +4918,20 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4526
4918
|
}
|
|
4527
4919
|
});
|
|
4528
4920
|
if (relatedRoute) return;
|
|
4529
|
-
|
|
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
|
+
}
|
|
4530
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;
|
|
4531
4935
|
await strapi2.documents(waRoute).create({
|
|
4532
4936
|
data: {
|
|
4533
4937
|
relatedContentType: event.model.uid,
|
|
@@ -4537,7 +4941,9 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4537
4941
|
path,
|
|
4538
4942
|
uidPath: `${event.model.singularName}/${event.result.id}`,
|
|
4539
4943
|
isOverride: webatlas_override || false,
|
|
4540
|
-
title
|
|
4944
|
+
title,
|
|
4945
|
+
parent,
|
|
4946
|
+
canonicalPath
|
|
4541
4947
|
}
|
|
4542
4948
|
});
|
|
4543
4949
|
},
|
|
@@ -4546,46 +4952,74 @@ const bootstrap = async ({ strapi: strapi2 }) => {
|
|
|
4546
4952
|
const {
|
|
4547
4953
|
webatlas_path,
|
|
4548
4954
|
webatlas_override,
|
|
4955
|
+
webatlas_parent,
|
|
4549
4956
|
documentId
|
|
4550
4957
|
} = event.params.data;
|
|
4551
4958
|
if (!webatlas_path) return;
|
|
4552
|
-
const relatedRoute = await strapi2.
|
|
4553
|
-
|
|
4959
|
+
const relatedRoute = await strapi2.documents(waRoute).findFirst({
|
|
4960
|
+
filters: {
|
|
4554
4961
|
relatedDocumentId: documentId
|
|
4555
4962
|
}
|
|
4556
4963
|
});
|
|
4557
|
-
|
|
4558
|
-
|
|
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;
|
|
4559
4985
|
const routeData = {
|
|
4560
4986
|
title,
|
|
4561
4987
|
path,
|
|
4562
|
-
slug:
|
|
4563
|
-
isOverride: webatlas_override || false
|
|
4988
|
+
slug: transformedPath,
|
|
4989
|
+
isOverride: webatlas_override || false,
|
|
4990
|
+
parent: parent?.documentId || null
|
|
4564
4991
|
};
|
|
4992
|
+
let routeDocumentId = relatedRoute?.documentId;
|
|
4565
4993
|
if (!relatedRoute) {
|
|
4566
|
-
await strapi2.documents(waRoute).create({
|
|
4994
|
+
const createdRoute = await strapi2.documents(waRoute).create({
|
|
4567
4995
|
data: {
|
|
4568
4996
|
relatedContentType: event.model.uid,
|
|
4569
4997
|
relatedId: event.result.id,
|
|
4570
4998
|
relatedDocumentId: event.result.documentId,
|
|
4571
4999
|
uidPath: `${event.model.singularName}/${event.result.id}`,
|
|
5000
|
+
canonicalPath,
|
|
4572
5001
|
...routeData
|
|
4573
5002
|
}
|
|
4574
5003
|
});
|
|
5004
|
+
routeDocumentId = createdRoute?.documentId;
|
|
4575
5005
|
} else {
|
|
4576
5006
|
await strapi2.documents(waRoute).update({
|
|
4577
5007
|
documentId: relatedRoute.documentId,
|
|
4578
5008
|
data: {
|
|
4579
|
-
...routeData
|
|
5009
|
+
...routeData,
|
|
5010
|
+
canonicalPath
|
|
4580
5011
|
}
|
|
4581
5012
|
});
|
|
4582
5013
|
}
|
|
5014
|
+
if (routeDocumentId) {
|
|
5015
|
+
await cascadeCanonicalPathUpdates(routeDocumentId, canonicalPath);
|
|
5016
|
+
}
|
|
4583
5017
|
},
|
|
4584
5018
|
async afterDelete(event) {
|
|
4585
5019
|
try {
|
|
4586
5020
|
await findAndDeleteNavItem(event.result.id, event.model.uid);
|
|
4587
5021
|
} catch (err) {
|
|
4588
|
-
|
|
5022
|
+
strapi2.log.error(err);
|
|
4589
5023
|
}
|
|
4590
5024
|
},
|
|
4591
5025
|
async afterDeleteMany(event) {
|
|
@@ -4619,7 +5053,7 @@ async function findAndDeleteNavItem(relatedId, relatedContentType) {
|
|
|
4619
5053
|
await strapi.documents(waRoute).delete({ documentId: route2.documentId });
|
|
4620
5054
|
if (navItem?.documentId) await strapi.documents(waNavItem).delete({ documentId: navItem.documentId });
|
|
4621
5055
|
} catch (err) {
|
|
4622
|
-
|
|
5056
|
+
strapi.log.error(err);
|
|
4623
5057
|
}
|
|
4624
5058
|
}
|
|
4625
5059
|
const destroy = ({ strapi: strapi2 }) => {
|
|
@@ -5156,6 +5590,11 @@ const register = ({ strapi: strapi2 }) => {
|
|
|
5156
5590
|
type: "boolean",
|
|
5157
5591
|
private: true
|
|
5158
5592
|
});
|
|
5593
|
+
set$1(attributes, "webatlas_parent", {
|
|
5594
|
+
...fieldSettings,
|
|
5595
|
+
type: "string",
|
|
5596
|
+
private: true
|
|
5597
|
+
});
|
|
5159
5598
|
});
|
|
5160
5599
|
};
|
|
5161
5600
|
const config = {
|
|
@@ -5214,6 +5653,10 @@ const schema$2 = {
|
|
|
5214
5653
|
type: "string",
|
|
5215
5654
|
configurable: false
|
|
5216
5655
|
},
|
|
5656
|
+
canonicalPath: {
|
|
5657
|
+
type: "string",
|
|
5658
|
+
configurable: false
|
|
5659
|
+
},
|
|
5217
5660
|
slug: {
|
|
5218
5661
|
type: "string",
|
|
5219
5662
|
configurable: false
|
|
@@ -5245,6 +5688,20 @@ const schema$2 = {
|
|
|
5245
5688
|
default: "internal",
|
|
5246
5689
|
configurable: false,
|
|
5247
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
|
|
5248
5705
|
}
|
|
5249
5706
|
}
|
|
5250
5707
|
};
|
|
@@ -5373,19 +5830,18 @@ const admin$2 = () => ({
|
|
|
5373
5830
|
return ctx.throw(500, e);
|
|
5374
5831
|
}
|
|
5375
5832
|
},
|
|
5376
|
-
async
|
|
5833
|
+
async getRoute(ctx) {
|
|
5377
5834
|
try {
|
|
5378
|
-
|
|
5835
|
+
const { documentId } = ctx.params;
|
|
5836
|
+
if (!documentId) return ctx.throw(400, "Route documentId is required");
|
|
5837
|
+
return await getAdminService().getRoute(documentId);
|
|
5379
5838
|
} catch (e) {
|
|
5380
5839
|
return ctx.throw(500, e);
|
|
5381
5840
|
}
|
|
5382
5841
|
},
|
|
5383
|
-
async
|
|
5842
|
+
async getAllRoutes(ctx) {
|
|
5384
5843
|
try {
|
|
5385
|
-
|
|
5386
|
-
if (!documentId) return ctx.throw(400, "Route documentId is required");
|
|
5387
|
-
const { data } = ctx.request.body;
|
|
5388
|
-
return await getAdminService().updateRoute(documentId, data);
|
|
5844
|
+
return await getAdminService().getAllRoutes();
|
|
5389
5845
|
} catch (e) {
|
|
5390
5846
|
return ctx.throw(500, e);
|
|
5391
5847
|
}
|
|
@@ -5399,6 +5855,14 @@ const admin$2 = () => ({
|
|
|
5399
5855
|
return ctx.throw(500, e);
|
|
5400
5856
|
}
|
|
5401
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
|
+
},
|
|
5402
5866
|
async getNavigation(ctx) {
|
|
5403
5867
|
try {
|
|
5404
5868
|
const { documentId, variant } = ctx.query;
|
|
@@ -5553,7 +6017,7 @@ const admin$1 = {
|
|
|
5553
6017
|
{
|
|
5554
6018
|
method: "GET",
|
|
5555
6019
|
path: "/route",
|
|
5556
|
-
handler: "admin.
|
|
6020
|
+
handler: "admin.getAllRoutes",
|
|
5557
6021
|
config: {
|
|
5558
6022
|
policies: [
|
|
5559
6023
|
"admin::isAuthenticatedAdmin",
|
|
@@ -5570,9 +6034,9 @@ const admin$1 = {
|
|
|
5570
6034
|
}
|
|
5571
6035
|
},
|
|
5572
6036
|
{
|
|
5573
|
-
method: "
|
|
5574
|
-
path: "/route",
|
|
5575
|
-
handler: "admin.
|
|
6037
|
+
method: "GET",
|
|
6038
|
+
path: "/route/related",
|
|
6039
|
+
handler: "admin.getRelatedRoute",
|
|
5576
6040
|
config: {
|
|
5577
6041
|
policies: [
|
|
5578
6042
|
"admin::isAuthenticatedAdmin",
|
|
@@ -5580,6 +6044,7 @@ const admin$1 = {
|
|
|
5580
6044
|
name: `plugin::${PLUGIN_ID}.has-permissions`,
|
|
5581
6045
|
config: {
|
|
5582
6046
|
actions: [
|
|
6047
|
+
`plugin::${PLUGIN_ID}.cm.aside`,
|
|
5583
6048
|
`plugin::${PLUGIN_ID}.page.navigation`
|
|
5584
6049
|
]
|
|
5585
6050
|
}
|
|
@@ -5589,8 +6054,26 @@ const admin$1 = {
|
|
|
5589
6054
|
},
|
|
5590
6055
|
{
|
|
5591
6056
|
method: "GET",
|
|
5592
|
-
path: "/route/
|
|
5593
|
-
handler: "admin.
|
|
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",
|
|
5594
6077
|
config: {
|
|
5595
6078
|
policies: [
|
|
5596
6079
|
"admin::isAuthenticatedAdmin",
|
|
@@ -5598,7 +6081,6 @@ const admin$1 = {
|
|
|
5598
6081
|
name: `plugin::${PLUGIN_ID}.has-permissions`,
|
|
5599
6082
|
config: {
|
|
5600
6083
|
actions: [
|
|
5601
|
-
`plugin::${PLUGIN_ID}.cm.aside`,
|
|
5602
6084
|
`plugin::${PLUGIN_ID}.page.navigation`
|
|
5603
6085
|
]
|
|
5604
6086
|
}
|
|
@@ -5754,7 +6236,7 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5754
6236
|
newConfigMerged = { ...config2, ...newConfig };
|
|
5755
6237
|
await pluginStore.set({ key: "config", value: newConfigMerged });
|
|
5756
6238
|
} catch (err) {
|
|
5757
|
-
|
|
6239
|
+
strapi2.log.error(err);
|
|
5758
6240
|
return "Error. Couldn't update config";
|
|
5759
6241
|
}
|
|
5760
6242
|
return newConfigMerged;
|
|
@@ -5775,35 +6257,21 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5775
6257
|
};
|
|
5776
6258
|
return config2;
|
|
5777
6259
|
},
|
|
5778
|
-
async
|
|
6260
|
+
async getRoute(documentId) {
|
|
5779
6261
|
try {
|
|
5780
|
-
|
|
5781
|
-
|
|
6262
|
+
return await strapi2.documents(waRoute).findOne({
|
|
6263
|
+
documentId
|
|
6264
|
+
});
|
|
5782
6265
|
} catch (e) {
|
|
5783
|
-
|
|
6266
|
+
strapi2.log.error(e);
|
|
5784
6267
|
}
|
|
5785
6268
|
},
|
|
5786
|
-
|
|
5787
|
-
async updateRoute(documentId, data) {
|
|
6269
|
+
async getAllRoutes() {
|
|
5788
6270
|
try {
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
const parent = data.parent ? await strapi2.documents(waNavItem).findOne({
|
|
5792
|
-
documentId: data.parent
|
|
5793
|
-
}) : null;
|
|
5794
|
-
const path = data.isOverride ? data.slug : getPath(parent?.path, data.slug);
|
|
5795
|
-
checkedPath = await duplicateCheck(path, documentId);
|
|
5796
|
-
}
|
|
5797
|
-
const entity = await strapi2.documents(waRoute).update({
|
|
5798
|
-
documentId,
|
|
5799
|
-
data: {
|
|
5800
|
-
...data,
|
|
5801
|
-
path: checkedPath
|
|
5802
|
-
}
|
|
5803
|
-
});
|
|
5804
|
-
return entity;
|
|
6271
|
+
const entities = await strapi2.documents(waRoute).findMany();
|
|
6272
|
+
return entities;
|
|
5805
6273
|
} catch (e) {
|
|
5806
|
-
|
|
6274
|
+
strapi2.log.error(e);
|
|
5807
6275
|
}
|
|
5808
6276
|
},
|
|
5809
6277
|
async getRelatedRoute(documentId) {
|
|
@@ -5811,10 +6279,28 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5811
6279
|
return await strapi2.db?.query(waRoute).findOne({
|
|
5812
6280
|
where: {
|
|
5813
6281
|
relatedDocumentId: documentId
|
|
5814
|
-
}
|
|
6282
|
+
},
|
|
6283
|
+
populate: ["parent"]
|
|
5815
6284
|
});
|
|
5816
6285
|
} catch (e) {
|
|
5817
|
-
|
|
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);
|
|
5818
6304
|
}
|
|
5819
6305
|
},
|
|
5820
6306
|
async getNavigation(documentId, variant) {
|
|
@@ -5850,7 +6336,7 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5850
6336
|
}
|
|
5851
6337
|
return navigation2;
|
|
5852
6338
|
} catch (e) {
|
|
5853
|
-
|
|
6339
|
+
strapi2.log.error(e);
|
|
5854
6340
|
}
|
|
5855
6341
|
},
|
|
5856
6342
|
async createNavigation(name2, visible) {
|
|
@@ -5863,7 +6349,7 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5863
6349
|
}
|
|
5864
6350
|
});
|
|
5865
6351
|
} catch (e) {
|
|
5866
|
-
|
|
6352
|
+
strapi2.log.error(e);
|
|
5867
6353
|
}
|
|
5868
6354
|
},
|
|
5869
6355
|
async updateNavigation(documentId, data) {
|
|
@@ -5877,7 +6363,7 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5877
6363
|
});
|
|
5878
6364
|
return entity;
|
|
5879
6365
|
} catch (e) {
|
|
5880
|
-
|
|
6366
|
+
strapi2.log.error(e);
|
|
5881
6367
|
}
|
|
5882
6368
|
},
|
|
5883
6369
|
async deleteNavigation(documentId) {
|
|
@@ -5896,115 +6382,46 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
5896
6382
|
documentId
|
|
5897
6383
|
});
|
|
5898
6384
|
} catch (e) {
|
|
5899
|
-
|
|
6385
|
+
strapi2.log.error(e);
|
|
5900
6386
|
}
|
|
5901
6387
|
},
|
|
5902
6388
|
async updateNavigationItemStructure(navigationId, navigationItems) {
|
|
5903
6389
|
if (!navigationId || !navigationItems) return;
|
|
5904
6390
|
let error = false;
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
item.documentId && await deleteNavItem(item.documentId);
|
|
5910
|
-
const newItems = reduceDepthOfOrphanedItems(navigationItems, item.documentId);
|
|
5911
|
-
if (!newItems) throw new Error("Failed to reduce depth of orphaned items");
|
|
5912
|
-
navigationItems = newItems;
|
|
5913
|
-
} catch (error2) {
|
|
5914
|
-
error2 = true;
|
|
5915
|
-
console.error("Error deleting navigation item ", error2);
|
|
5916
|
-
}
|
|
5917
|
-
continue;
|
|
5918
|
-
}
|
|
5919
|
-
if (!item.route && item.documentId) {
|
|
5920
|
-
try {
|
|
5921
|
-
console.warn("Navigation item without route found. Deleting it. ", item);
|
|
5922
|
-
await deleteNavItem(item.documentId);
|
|
5923
|
-
} catch (error2) {
|
|
5924
|
-
console.error("Error deleting navigation item without route ", error2);
|
|
5925
|
-
}
|
|
5926
|
-
continue;
|
|
5927
|
-
}
|
|
5928
|
-
if (item.update && !item.isNew) {
|
|
5929
|
-
try {
|
|
5930
|
-
await this.updateRoute(item.route.documentId, {
|
|
5931
|
-
title: item.update.title || item.route.title,
|
|
5932
|
-
slug: item.update.slug || item.route.slug,
|
|
5933
|
-
path: item.update.path || item.route.path,
|
|
5934
|
-
isOverride: item.update.isOverride !== void 0 ? item.update.isOverride : item.route.isOverride
|
|
5935
|
-
});
|
|
5936
|
-
} catch (error2) {
|
|
5937
|
-
error2 = true;
|
|
5938
|
-
console.error("Error updating route ", error2);
|
|
5939
|
-
}
|
|
5940
|
-
}
|
|
6391
|
+
let newNavItemsMap = /* @__PURE__ */ new Map();
|
|
6392
|
+
const deletionResult = await handleItemDeletion(navigationItems);
|
|
6393
|
+
if (!deletionResult.success) {
|
|
6394
|
+
strapi2.log.error("Deletion errors:", deletionResult.errors);
|
|
5941
6395
|
}
|
|
6396
|
+
navigationItems = deletionResult.items;
|
|
5942
6397
|
let parentIds = [];
|
|
5943
6398
|
let groupIndices = [];
|
|
5944
6399
|
for (const [index2, item] of navigationItems.entries()) {
|
|
5945
6400
|
if (typeof item.depth !== "number") {
|
|
5946
6401
|
continue;
|
|
5947
6402
|
}
|
|
5948
|
-
if (item.depth === 0) {
|
|
5949
|
-
if (groupIndices[0] !== void 0) {
|
|
5950
|
-
groupIndices[0] = groupIndices[0] + 1;
|
|
5951
|
-
} else {
|
|
5952
|
-
groupIndices[0] = 0;
|
|
5953
|
-
}
|
|
5954
|
-
parentIds = [];
|
|
5955
|
-
} else {
|
|
5956
|
-
const previousItem = navigationItems[index2 - 1];
|
|
5957
|
-
if (previousItem && typeof previousItem.depth === "number") {
|
|
5958
|
-
if (item.depth === previousItem.depth + 1) {
|
|
5959
|
-
parentIds.push(previousItem.documentId.startsWith("temp-") ? newNavItemsMap.get(previousItem.documentId)?.documentId || previousItem.documentId : previousItem.documentId);
|
|
5960
|
-
groupIndices[item.depth] = 0;
|
|
5961
|
-
} else if (item.depth <= previousItem.depth) {
|
|
5962
|
-
const diff = previousItem.depth - item.depth;
|
|
5963
|
-
for (let i = 0; i < diff; i++) {
|
|
5964
|
-
parentIds.pop();
|
|
5965
|
-
groupIndices.pop();
|
|
5966
|
-
}
|
|
5967
|
-
groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
|
|
5968
|
-
} else {
|
|
5969
|
-
groupIndices[item.depth] = (groupIndices[item.depth] || 0) + 1;
|
|
5970
|
-
}
|
|
5971
|
-
}
|
|
5972
|
-
}
|
|
5973
|
-
const calculatedParent = parentIds.at(-1) || null;
|
|
5974
|
-
const calculatedOrder = groupIndices[item.depth] || 0;
|
|
5975
6403
|
try {
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
navigation: navigationId,
|
|
5994
|
-
parent: calculatedParent,
|
|
5995
|
-
order: calculatedOrder
|
|
5996
|
-
});
|
|
5997
|
-
if (newNavItem) newNavItemsMap.set(item.documentId, newNavItem);
|
|
5998
|
-
}
|
|
5999
|
-
} else {
|
|
6000
|
-
await updateNavItem(item.documentId, {
|
|
6001
|
-
order: calculatedOrder,
|
|
6002
|
-
parent: calculatedParent
|
|
6003
|
-
});
|
|
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);
|
|
6004
6421
|
}
|
|
6005
6422
|
} catch (errorMsg) {
|
|
6006
6423
|
error = true;
|
|
6007
|
-
|
|
6424
|
+
strapi2.log.error("Error updating navigation item ", errorMsg);
|
|
6008
6425
|
}
|
|
6009
6426
|
}
|
|
6010
6427
|
return !error;
|
|
@@ -6013,7 +6430,7 @@ const admin = ({ strapi: strapi2 }) => ({
|
|
|
6013
6430
|
try {
|
|
6014
6431
|
return await duplicateCheck(initialPath, targetRouteDocumentId);
|
|
6015
6432
|
} catch (e) {
|
|
6016
|
-
|
|
6433
|
+
strapi2.log.error(e);
|
|
6017
6434
|
}
|
|
6018
6435
|
}
|
|
6019
6436
|
});
|
|
@@ -6024,6 +6441,7 @@ const client = ({ strapi: strapi2 }) => ({
|
|
|
6024
6441
|
filters: {
|
|
6025
6442
|
$or: [
|
|
6026
6443
|
{ path: slug },
|
|
6444
|
+
{ canonicalPath: slug },
|
|
6027
6445
|
{ uidPath: slug }
|
|
6028
6446
|
]
|
|
6029
6447
|
}
|
|
@@ -6050,9 +6468,21 @@ const client = ({ strapi: strapi2 }) => ({
|
|
|
6050
6468
|
if (!entity) return null;
|
|
6051
6469
|
let cleanEntity = cleanRootKeys(entity);
|
|
6052
6470
|
cleanEntity = removeWaFields(cleanEntity);
|
|
6053
|
-
|
|
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
|
+
};
|
|
6054
6484
|
} catch (e) {
|
|
6055
|
-
|
|
6485
|
+
strapi2.log.error(e);
|
|
6056
6486
|
return e;
|
|
6057
6487
|
}
|
|
6058
6488
|
},
|
|
@@ -6090,7 +6520,7 @@ const client = ({ strapi: strapi2 }) => ({
|
|
|
6090
6520
|
try {
|
|
6091
6521
|
navigation2 = await method.lookup();
|
|
6092
6522
|
} catch (error) {
|
|
6093
|
-
|
|
6523
|
+
strapi2.log.error(`Navigation lookup by ${method.name} failed:`, error);
|
|
6094
6524
|
}
|
|
6095
6525
|
}
|
|
6096
6526
|
}
|
|
@@ -6100,7 +6530,7 @@ const client = ({ strapi: strapi2 }) => ({
|
|
|
6100
6530
|
const entityNavigation = extractRouteAndItems(structured.items);
|
|
6101
6531
|
return { ...structured, items: entityNavigation };
|
|
6102
6532
|
} catch (e) {
|
|
6103
|
-
|
|
6533
|
+
strapi2.log.error(e);
|
|
6104
6534
|
return e;
|
|
6105
6535
|
}
|
|
6106
6536
|
}
|