@mattisvensson/strapi-plugin-webatlas 0.9.6 → 0.10.1

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 (132) hide show
  1. package/README.md +24 -36
  2. package/dist/{_chunks/SettingTitle-77mvMRg_.mjs → admin/SettingTitle-DbsxB1V9.mjs} +2 -2
  3. package/dist/{_chunks/SettingTitle-DLj_Wwqy.js → admin/SettingTitle-uw1S5OmC.js} +2 -2
  4. package/dist/{_chunks/de-C-uxto84.mjs → admin/de-B5pRvs13.mjs} +13 -7
  5. package/dist/{_chunks/de-CGXL_3o_.js → admin/de-CqU1FU8C.js} +13 -7
  6. package/dist/{_chunks/en-B1CHnIH7.mjs → admin/en-BE-zzIv8.mjs} +13 -7
  7. package/dist/{_chunks/en-DWEd5BXK.js → admin/en-C7I90FwV.js} +13 -7
  8. package/dist/{_chunks/index-5OG4i6qO.mjs → admin/index-B07KlG03.mjs} +40 -84
  9. package/dist/{_chunks/index-BRKi-K-v.mjs → admin/index-BKWY9Ta-.mjs} +61 -24
  10. package/dist/admin/index-BXt-QjKo.js +9368 -0
  11. package/dist/{_chunks/index-VXuAEnpX.js → admin/index-BYlmJycd.js} +3 -3
  12. package/dist/{_chunks/index-Dt-AXdaw.js → admin/index-CGsC8P9P.js} +40 -84
  13. package/dist/{_chunks/index-DwaKIwAz.mjs → admin/index-CIr8o1RP.mjs} +403 -356
  14. package/dist/{_chunks/index-3pYLMhui.mjs → admin/index-CUaBX_v-.mjs} +3 -3
  15. package/dist/{_chunks/index-COfk3YSm.js → admin/index-DC5WwNdi.js} +402 -355
  16. package/dist/{_chunks/index-DTsHvlTa.js → admin/index-DkqiqVx2.js} +61 -24
  17. package/dist/admin/index-tPrfjOIn.mjs +9368 -0
  18. package/dist/admin/index.js +3 -2
  19. package/dist/admin/index.mjs +1 -1
  20. package/dist/server/index.js +5266 -4524
  21. package/dist/server/index.mjs +5264 -4523
  22. package/dist/server/src/index.d.ts +33 -13
  23. package/package.json +19 -7
  24. package/dist/_chunks/index-BOtvXSPU.js +0 -8310
  25. package/dist/_chunks/index-BWzalvVi.mjs +0 -8310
  26. package/dist/admin/src/components/CMEditViewAside/Path.d.ts +0 -5
  27. package/dist/admin/src/components/CMEditViewAside/index.d.ts +0 -3
  28. package/dist/admin/src/components/Initializer.d.ts +0 -5
  29. package/dist/admin/src/components/PathInfo.d.ts +0 -7
  30. package/dist/admin/src/components/PluginIcon.d.ts +0 -3
  31. package/dist/admin/src/components/Tooltip.d.ts +0 -3
  32. package/dist/admin/src/components/UI/Center.d.ts +0 -5
  33. package/dist/admin/src/components/UI/EmptyBox.d.ts +0 -5
  34. package/dist/admin/src/components/UI/FullLoader.d.ts +0 -3
  35. package/dist/admin/src/components/UI/index.d.ts +0 -4
  36. package/dist/admin/src/components/modals/Delete.d.ts +0 -14
  37. package/dist/admin/src/components/modals/NavCreate.d.ts +0 -1
  38. package/dist/admin/src/components/modals/NavEdit.d.ts +0 -7
  39. package/dist/admin/src/components/modals/NavModal.d.ts +0 -17
  40. package/dist/admin/src/components/modals/NavOverview.d.ts +0 -8
  41. package/dist/admin/src/components/modals/externalItem/index.d.ts +0 -15
  42. package/dist/admin/src/components/modals/index.d.ts +0 -12
  43. package/dist/admin/src/components/modals/internalItem/internalItemCreate.d.ts +0 -3
  44. package/dist/admin/src/components/modals/internalItem/internalItemEdit.d.ts +0 -3
  45. package/dist/admin/src/components/modals/useModalSharedLogic.d.ts +0 -2
  46. package/dist/admin/src/components/modals/withModalSharedLogic.d.ts +0 -3
  47. package/dist/admin/src/components/modals/wrapperItem/index.d.ts +0 -15
  48. package/dist/admin/src/contexts/index.d.ts +0 -13
  49. package/dist/admin/src/hooks/index.d.ts +0 -6
  50. package/dist/admin/src/hooks/useAllContentTypes.d.ts +0 -7
  51. package/dist/admin/src/hooks/useAllEntities.d.ts +0 -7
  52. package/dist/admin/src/hooks/useApi.d.ts +0 -17
  53. package/dist/admin/src/hooks/useNavigations.d.ts +0 -7
  54. package/dist/admin/src/hooks/usePluginConfig.d.ts +0 -9
  55. package/dist/admin/src/pages/Navigation/Page.d.ts +0 -2
  56. package/dist/admin/src/pages/Navigation/PageWrapper.d.ts +0 -7
  57. package/dist/admin/src/pages/Navigation/RouteItem.d.ts +0 -17
  58. package/dist/admin/src/pages/Navigation/SortableRouteItem.d.ts +0 -2
  59. package/dist/admin/src/pages/Navigation/index.d.ts +0 -2
  60. package/dist/admin/src/pages/Paths/PageWrapper.d.ts +0 -4
  61. package/dist/admin/src/pages/Paths/PathTable.d.ts +0 -8
  62. package/dist/admin/src/pages/Paths/SearchInput.d.ts +0 -6
  63. package/dist/admin/src/pages/Paths/TableHeader.d.ts +0 -5
  64. package/dist/admin/src/pages/Paths/TableRow.d.ts +0 -4
  65. package/dist/admin/src/pages/Paths/compareBy.d.ts +0 -3
  66. package/dist/admin/src/pages/Paths/index.d.ts +0 -2
  67. package/dist/admin/src/pages/Settings/ContentBox.d.ts +0 -5
  68. package/dist/admin/src/pages/Settings/General/ContentTypeAccordion.d.ts +0 -7
  69. package/dist/admin/src/pages/Settings/General/index.d.ts +0 -2
  70. package/dist/admin/src/pages/Settings/Navigation/index.d.ts +0 -2
  71. package/dist/admin/src/pages/Settings/PageWrapper.d.ts +0 -8
  72. package/dist/admin/src/pages/Settings/SettingTitle.d.ts +0 -4
  73. package/dist/admin/src/pages/Settings/index.d.ts +0 -4
  74. package/dist/admin/src/permissions.d.ts +0 -23
  75. package/dist/admin/src/types/index.d.ts +0 -1
  76. package/dist/admin/src/types/modal.d.ts +0 -0
  77. package/dist/admin/src/types/route.d.ts +0 -2
  78. package/dist/admin/src/utils/countChildren.d.ts +0 -2
  79. package/dist/admin/src/utils/createTempNavItemObject.d.ts +0 -24
  80. package/dist/admin/src/utils/debounce.d.ts +0 -1
  81. package/dist/admin/src/utils/dnd.d.ts +0 -13
  82. package/dist/admin/src/utils/duplicateCheck.d.ts +0 -9
  83. package/dist/admin/src/utils/getTranslation.d.ts +0 -2
  84. package/dist/admin/src/utils/index.d.ts +0 -7
  85. package/dist/admin/src/utils/typeChecks.d.ts +0 -3
  86. package/dist/server/src/bootstrap.d.ts +0 -5
  87. package/dist/server/src/config/index.d.ts +0 -10
  88. package/dist/server/src/content-types/index.d.ts +0 -184
  89. package/dist/server/src/content-types/navigation/index.d.ts +0 -50
  90. package/dist/server/src/content-types/navigation/schema.d.ts +0 -48
  91. package/dist/server/src/content-types/navitem/index.d.ts +0 -51
  92. package/dist/server/src/content-types/navitem/schema.d.ts +0 -49
  93. package/dist/server/src/content-types/route/index.d.ts +0 -83
  94. package/dist/server/src/content-types/route/schema.d.ts +0 -81
  95. package/dist/server/src/controllers/admin.d.ts +0 -14
  96. package/dist/server/src/controllers/client.d.ts +0 -8
  97. package/dist/server/src/controllers/index.d.ts +0 -22
  98. package/dist/server/src/destroy.d.ts +0 -5
  99. package/dist/server/src/middlewares/index.d.ts +0 -2
  100. package/dist/server/src/policies/has-permissions.d.ts +0 -2
  101. package/dist/server/src/policies/index.d.ts +0 -4
  102. package/dist/server/src/register.d.ts +0 -5
  103. package/dist/server/src/routes/admin.d.ts +0 -17
  104. package/dist/server/src/routes/client.d.ts +0 -12
  105. package/dist/server/src/routes/index.d.ts +0 -30
  106. package/dist/server/src/services/admin.d.ts +0 -17
  107. package/dist/server/src/services/client.d.ts +0 -8
  108. package/dist/server/src/services/index.d.ts +0 -24
  109. package/dist/server/src/utils/buildStructuredNavigation.d.ts +0 -11
  110. package/dist/server/src/utils/cleanRootKeys.d.ts +0 -1
  111. package/dist/server/src/utils/duplicateCheck.d.ts +0 -1
  112. package/dist/server/src/utils/extractRouteAndItems.d.ts +0 -2
  113. package/dist/server/src/utils/index.d.ts +0 -11
  114. package/dist/server/src/utils/navItemHandler.d.ts +0 -5
  115. package/dist/server/src/utils/pluginHelpers.d.ts +0 -3
  116. package/dist/server/src/utils/populateDeep.d.ts +0 -4
  117. package/dist/server/src/utils/reduceDepthOfOrphanedItems.d.ts +0 -2
  118. package/dist/server/src/utils/removeWaFields.d.ts +0 -1
  119. package/dist/server/src/utils/routeHandler.d.ts +0 -3
  120. package/dist/types/api.d.ts +0 -7
  121. package/dist/types/index.d.ts +0 -5
  122. package/dist/types/modal.d.ts +0 -36
  123. package/dist/types/navigation.d.ts +0 -65
  124. package/dist/types/route.d.ts +0 -32
  125. package/dist/types/strapi.d.ts +0 -53
  126. package/dist/utils/getPath.d.ts +0 -1
  127. package/dist/utils/index.d.ts +0 -5
  128. package/dist/utils/pluginConstants.d.ts +0 -3
  129. package/dist/utils/pluginId.d.ts +0 -4
  130. package/dist/utils/transformToUrl.d.ts +0 -1
  131. /package/dist/{_chunks → admin}/FullLoader-Cmsf8xS6.js +0 -0
  132. /package/dist/{_chunks → admin}/FullLoader-CrPED_dY.mjs +0 -0
@@ -4,8 +4,8 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const icons = require("@strapi/icons");
5
5
  const admin = require("@strapi/strapi/admin");
6
6
  const designSystem = require("@strapi/design-system");
7
- const ReactDOM = require("react-dom");
8
7
  const reactIntl = require("react-intl");
8
+ const ReactDOM = require("react-dom");
9
9
  function _interopNamespace(e) {
10
10
  if (e && e.__esModule) return e;
11
11
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
@@ -52,6 +52,7 @@ function transformToUrl(input) {
52
52
  input = input.replace(/\/+/g, "/");
53
53
  input = input.startsWith("/") ? input.slice(1) : input;
54
54
  input = input.endsWith("/") ? input.slice(0, -1) : input;
55
+ input = input.replace(/\//g, "-");
55
56
  for (const char in specialCharMap) {
56
57
  const regex = new RegExp(char, "g");
57
58
  input = input.replace(regex, specialCharMap[char]);
@@ -62,122 +63,11 @@ function transformToUrl(input) {
62
63
  input = input.replace(/-+/g, "-");
63
64
  return input;
64
65
  }
65
- const version = "0.9.5";
66
- const keywords = [];
67
- const type = "commonjs";
68
- const exports$1 = {
69
- "./package.json": "./package.json",
70
- "./strapi-admin": {
71
- types: "./dist/admin/src/index.d.ts",
72
- source: "./admin/src/index.tsx",
73
- "import": "./dist/admin/index.mjs",
74
- require: "./dist/admin/index.js",
75
- "default": "./dist/admin/index.js"
76
- },
77
- "./strapi-server": {
78
- types: "./dist/server/src/index.d.ts",
79
- source: "./server/src/index.ts",
80
- "import": "./dist/server/index.mjs",
81
- require: "./dist/server/index.js",
82
- "default": "./dist/server/index.js"
83
- }
84
- };
85
- const files = [
86
- "dist"
87
- ];
88
- const scripts = {
89
- build: "strapi-plugin build && yalc push --publish",
90
- watch: "strapi-plugin watch",
91
- "watch:link": "strapi-plugin watch:link",
92
- verify: "strapi-plugin verify",
93
- "test:ts:front": "tsc -p admin/tsconfig.json",
94
- "test:ts:back": "tsc -p server/tsconfig.json",
95
- "test:jest": "ENV_PATH=./playground/.env jest --verbose --runInBand --forceExit",
96
- "test:cypress": "cypress run",
97
- "test:cypress:open": "cypress open",
98
- preversion: "yarn build",
99
- postversion: "git push && git push --tags"
100
- };
101
- const dependencies = {
102
- "@dnd-kit/core": "^6.3.1",
103
- "@dnd-kit/sortable": "^10.0.0",
104
- "@dnd-kit/utilities": "^3.2.2",
105
- "@strapi/design-system": "^2.0.0-rc.14",
106
- "@strapi/icons": "^2.0.0-rc.14",
107
- "react-intl": "^7.1.0"
108
- };
109
- const devDependencies = {
110
- "@strapi/sdk-plugin": "^5.0.0",
111
- "@strapi/strapi": "^5.0.0",
112
- "@strapi/typescript-utils": "^5.0.0",
113
- "@types/react": "^19.0.0",
114
- "@types/react-dom": "^19.0.0",
115
- cypress: "^13.9.0",
116
- "cypress-terminal-report": "^6.0.2",
117
- jest: "^29.7.0",
118
- prettier: "^3.4.2",
119
- react: "^19.0.0",
120
- "react-router-dom": "^6.0.0",
121
- supertest: "^7.0.0",
122
- typescript: "^5.7.2"
123
- };
124
- const peerDependencies = {
125
- "@strapi/strapi": "^5.0.0",
126
- react: "^17.0.0 || ^18.0.0",
127
- "react-dom": "^17.0.0 || ^18.0.0",
128
- "react-router-dom": "^6.0.0",
129
- "styled-components": "^6.0.0"
130
- };
131
- const description = "A strapi plugin to manage URL routes and navigations.";
132
- const strapi = {
133
- name: "webatlas",
134
- displayName: "Webatlas",
135
- description: "A strapi plugin to manage URL routes and navigations.",
136
- kind: "plugin"
137
- };
138
- const name = "@mattisvensson/strapi-plugin-webatlas";
139
- const license = "MIT";
140
- const repository = {
141
- type: "git",
142
- url: "git+ssh://git@github.com:mattisvensson/strapi-plugin-webatlas.git"
143
- };
144
- const bugs = {
145
- url: "https://github.com/mattisvensson/strapi-plugin-webatlas/issues"
146
- };
147
- const homepage = "https://github.com/mattisvensson/strapi-plugin-webatlas#readme";
148
- const author = {
149
- name: "Matti Svensson",
150
- email: "mattisvensson@web.de",
151
- url: "https://mattisvensson.dev"
152
- };
153
- const maintainers = [
154
- {
155
- name: "Matti Svensson",
156
- email: "mattisvensson@web.de",
157
- url: "https://mattisvensson.dev"
158
- }
159
- ];
160
- const packageManager = "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e";
66
+ const version = "0.10.0";
67
+ const strapi$1 = { "name": "webatlas", "displayName": "Webatlas" };
161
68
  const pluginPkg = {
162
69
  version,
163
- keywords,
164
- type,
165
- exports: exports$1,
166
- files,
167
- scripts,
168
- dependencies,
169
- devDependencies,
170
- peerDependencies,
171
- description,
172
- strapi,
173
- name,
174
- license,
175
- repository,
176
- bugs,
177
- homepage,
178
- author,
179
- maintainers,
180
- packageManager
70
+ strapi: strapi$1
181
71
  };
182
72
  const PLUGIN_ID = pluginPkg.strapi.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plugin-/i, "") || "webatlas";
183
73
  const PLUGIN_NAME = pluginPkg.strapi.displayName;
@@ -198,7 +88,7 @@ function useApi() {
198
88
  const { data } = await get("/content-manager/content-types");
199
89
  return data.data;
200
90
  } catch (error) {
201
- console.warn("Cannot fetch all content types:", error);
91
+ strapi.log.error("Cannot fetch all content types:", error);
202
92
  return [];
203
93
  }
204
94
  };
@@ -213,7 +103,7 @@ function useApi() {
213
103
  const configuredUIDs = new Set(configuredTypes.map((ct) => ct.uid));
214
104
  return allContentTypes.filter((ct) => configuredUIDs.has(ct.uid));
215
105
  } catch (err) {
216
- console.error("Error fetching configured content types:", err);
106
+ strapi.log.error("Error fetching configured content types:", err);
217
107
  return [];
218
108
  }
219
109
  };
@@ -237,7 +127,7 @@ function useApi() {
237
127
  contentType
238
128
  };
239
129
  } catch (err) {
240
- console.warn(`Cannot access entities for ${contentType.uid}:`, err);
130
+ strapi.log.error(`Cannot access entities for ${contentType.uid}:`, err);
241
131
  return null;
242
132
  }
243
133
  })
@@ -245,7 +135,7 @@ function useApi() {
245
135
  entities = entityResults.map((result) => result.status === "fulfilled" ? result.value : null).filter(Boolean);
246
136
  return entities;
247
137
  } catch (err) {
248
- console.error("Error fetching entities:", err);
138
+ strapi.log.error("Error fetching entities:", err);
249
139
  throw err;
250
140
  }
251
141
  };
@@ -253,16 +143,16 @@ function useApi() {
253
143
  const { data } = await get(`/${PLUGIN_ID}/route/related?documentId=${relatedDocumentId}`);
254
144
  return data;
255
145
  };
256
- const getRoutes = async () => {
146
+ const getRoute = async (documentId) => {
147
+ const { data } = await get(`/${PLUGIN_ID}/route/${documentId}`);
148
+ return data;
149
+ };
150
+ const getAllRoutes = async () => {
257
151
  const { data } = await get(`/${PLUGIN_ID}/route`);
258
152
  return data;
259
153
  };
260
- const updateRoute = async (body, documentId) => {
261
- const { data } = await put(`/${PLUGIN_ID}/route?documentId=${documentId}`, {
262
- data: {
263
- ...body
264
- }
265
- });
154
+ const getProhibitedRouteIds = async (documentId) => {
155
+ const { data } = await get(`/${PLUGIN_ID}/route/prohibitedIds/${documentId ? `${documentId}` : ""}`);
266
156
  return data;
267
157
  };
268
158
  const getNavigation = async ({ documentId, variant } = {}) => {
@@ -300,8 +190,9 @@ function useApi() {
300
190
  fetchConfiguredContentTypes,
301
191
  fetchAllEntities,
302
192
  getRelatedRoute,
303
- getRoutes,
304
- updateRoute,
193
+ getRoute,
194
+ getAllRoutes,
195
+ getProhibitedRouteIds,
305
196
  getNavigation,
306
197
  createNavigation,
307
198
  deleteNavigation,
@@ -345,10 +236,10 @@ function usePluginConfig() {
345
236
  throw new Error(`Couldn't fetch plugin config`);
346
237
  }
347
238
  const allowedContentTypes = contentTypesArray.filter(
348
- (type2) => type2.pluginOptions?.webatlas?.enabled === true
239
+ (type) => type.pluginOptions?.webatlas?.enabled === true
349
240
  );
350
- const contentTypeUids = new Set(allowedContentTypes.map((type2) => type2.uid));
351
- const activeContentTypes = config2.selectedContentTypes.filter((type2) => contentTypeUids.has(type2.uid));
241
+ const contentTypeUids = new Set(allowedContentTypes.map((type) => type.uid));
242
+ const activeContentTypes = config2.selectedContentTypes.filter((type) => contentTypeUids.has(type.uid));
352
243
  const displayConfig = {
353
244
  ...config2,
354
245
  selectedContentTypes: activeContentTypes
@@ -371,6 +262,113 @@ function usePluginConfig() {
371
262
  }
372
263
  return { config, loading, fetchError, setConfig };
373
264
  }
265
+ function debounce(func, wait) {
266
+ let timeout;
267
+ return function executedFunction(...args) {
268
+ const later = () => {
269
+ clearTimeout(timeout);
270
+ func(...args);
271
+ };
272
+ clearTimeout(timeout);
273
+ timeout = setTimeout(later, wait);
274
+ };
275
+ }
276
+ async function duplicateCheck({
277
+ fetchFunction,
278
+ path,
279
+ routeDocumentId,
280
+ withoutTransform = false
281
+ }) {
282
+ if (!path) throw new Error("URL is required");
283
+ try {
284
+ const pathToCheck = withoutTransform ? path : transformToUrl(path);
285
+ const { data } = await fetchFunction(`/${PLUGIN_ID}/checkUniquePath?path=${pathToCheck}${routeDocumentId ? `&targetRouteDocumentId=${routeDocumentId}` : ""}`);
286
+ if (!data.uniquePath) {
287
+ throw new Error("Network response was not ok");
288
+ }
289
+ return data.uniquePath;
290
+ } catch (err) {
291
+ throw new Error("Failed to check URL uniqueness: " + err.message);
292
+ }
293
+ }
294
+ const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
295
+ function PathInfo({ validationState, replacement }) {
296
+ const [color, setColor] = React.useState("neutral800");
297
+ const [text, setText] = React.useState(null);
298
+ const { formatMessage } = reactIntl.useIntl();
299
+ React.useEffect(() => {
300
+ if (validationState === "initial") return;
301
+ if (validationState === "checking") {
302
+ setColor("neutral800");
303
+ setText(formatMessage({
304
+ id: getTranslation("components.pathInfo.checking"),
305
+ defaultMessage: "Checking if path is available..."
306
+ }));
307
+ } else if (validationState === "done") {
308
+ setColor(replacement ? "danger500" : "success500");
309
+ setText(replacement ? `${formatMessage({
310
+ id: getTranslation("components.pathInfo.notAvailable"),
311
+ defaultMessage: "Path is not available. Replaced with"
312
+ })} "${replacement}".` : formatMessage({
313
+ id: getTranslation("components.pathInfo.available"),
314
+ defaultMessage: "Path is available."
315
+ }));
316
+ }
317
+ }, [validationState, replacement, formatMessage]);
318
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: color, children: text }) });
319
+ }
320
+ function OverrideCheckbox({ isOverride, setIsOverride, disabledCondition }) {
321
+ const { formatMessage } = reactIntl.useIntl();
322
+ return /* @__PURE__ */ jsxRuntime.jsx(
323
+ designSystem.Flex,
324
+ {
325
+ gap: 2,
326
+ paddingTop: 2,
327
+ children: /* @__PURE__ */ jsxRuntime.jsx(
328
+ designSystem.Checkbox,
329
+ {
330
+ id: "path-override-checkbox",
331
+ checked: isOverride,
332
+ onCheckedChange: () => setIsOverride(!isOverride),
333
+ disabled: disabledCondition,
334
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
335
+ id: getTranslation("components.CMEditViewAside.path.overrideCheckbox"),
336
+ defaultMessage: "Override automatic path generation"
337
+ }) })
338
+ }
339
+ )
340
+ }
341
+ );
342
+ }
343
+ function NewPathInfo() {
344
+ const { formatMessage } = reactIntl.useIntl();
345
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
346
+ id: getTranslation("components.CMEditViewAside.path.newPathInfo"),
347
+ defaultMessage: "A new path will be created upon saving this entry."
348
+ }) });
349
+ }
350
+ function UidPathDisplay({ path }) {
351
+ const { formatMessage } = reactIntl.useIntl();
352
+ return /* @__PURE__ */ jsxRuntime.jsxs(
353
+ designSystem.Field.Root,
354
+ {
355
+ hint: formatMessage({
356
+ id: getTranslation("components.CMEditViewAside.path.uidPath.hint"),
357
+ defaultMessage: "Permanent UID path, cannot be changed"
358
+ }),
359
+ children: [
360
+ /* @__PURE__ */ jsxRuntime.jsx(
361
+ designSystem.Field.Input,
362
+ {
363
+ value: path,
364
+ disabled: true
365
+ }
366
+ ),
367
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
368
+ ]
369
+ }
370
+ );
371
+ }
374
372
  function _extends() {
375
373
  return _extends = Object.assign ? Object.assign.bind() : function(n) {
376
374
  for (var e = 1; e < arguments.length; e++) {
@@ -800,14 +798,14 @@ function $5cb92bef7577960e$var$dispatchUpdate() {
800
798
  const event = new CustomEvent($5cb92bef7577960e$var$CONTEXT_UPDATE);
801
799
  document.dispatchEvent(event);
802
800
  }
803
- function $5cb92bef7577960e$var$handleAndDispatchCustomEvent(name2, handler, detail, { discrete }) {
801
+ function $5cb92bef7577960e$var$handleAndDispatchCustomEvent(name, handler, detail, { discrete }) {
804
802
  const target = detail.originalEvent.target;
805
- const event = new CustomEvent(name2, {
803
+ const event = new CustomEvent(name, {
806
804
  bubbles: false,
807
805
  cancelable: true,
808
806
  detail
809
807
  });
810
- if (handler) target.addEventListener(name2, handler, {
808
+ if (handler) target.addEventListener(name, handler, {
811
809
  once: true
812
810
  });
813
811
  if (discrete) $8927f6f2acc4f386$export$6d1a0317bde7de7f(target, event);
@@ -1035,7 +1033,7 @@ const computePosition$1 = async (reference, floating, config) => {
1035
1033
  let resetCount = 0;
1036
1034
  for (let i = 0; i < validMiddleware.length; i++) {
1037
1035
  const {
1038
- name: name2,
1036
+ name,
1039
1037
  fn
1040
1038
  } = validMiddleware[i];
1041
1039
  const {
@@ -1061,8 +1059,8 @@ const computePosition$1 = async (reference, floating, config) => {
1061
1059
  y = nextY != null ? nextY : y;
1062
1060
  middlewareData = {
1063
1061
  ...middlewareData,
1064
- [name2]: {
1065
- ...middlewareData[name2],
1062
+ [name]: {
1063
+ ...middlewareData[name],
1066
1064
  ...data
1067
1065
  }
1068
1066
  };
@@ -3162,7 +3160,7 @@ const $ea1ef594cf570d83$export$439d29a4e110a164 = /* @__PURE__ */ React.forwardR
3162
3160
  }));
3163
3161
  });
3164
3162
  const $ea1ef594cf570d83$export$be92b6f5f03c0fe9 = $ea1ef594cf570d83$export$439d29a4e110a164;
3165
- const [$a093c7e1ec25a057$var$createTooltipContext, $a093c7e1ec25a057$export$1c540a2224f0d865] = $c512c27ab02ef895$export$50c7b4e9d9f19c1("Tooltip", [
3163
+ const [$a093c7e1ec25a057$var$createTooltipContext] = $c512c27ab02ef895$export$50c7b4e9d9f19c1("Tooltip", [
3166
3164
  $cf1ac5d9fe0e8206$export$722aac194ae923
3167
3165
  ]);
3168
3166
  const $a093c7e1ec25a057$var$usePopperScope = $cf1ac5d9fe0e8206$export$722aac194ae923();
@@ -3653,7 +3651,7 @@ const $a093c7e1ec25a057$export$be92b6f5f03c0fe9 = $a093c7e1ec25a057$export$28c66
3653
3651
  const $a093c7e1ec25a057$export$41fb9f06171c75f4 = $a093c7e1ec25a057$export$8c610744efcf8a1d;
3654
3652
  const $a093c7e1ec25a057$export$602eac185826482c = $a093c7e1ec25a057$export$7b36b8f925ab7497;
3655
3653
  const $a093c7e1ec25a057$export$7c6e2c02157bb7d2 = $a093c7e1ec25a057$export$e9003e2be37ec060;
3656
- function Tooltip({ description: description2 }) {
3654
+ function Tooltip({ description }) {
3657
3655
  return /* @__PURE__ */ jsxRuntime.jsx($a093c7e1ec25a057$export$2881499e37b75b9a, { children: /* @__PURE__ */ jsxRuntime.jsxs($a093c7e1ec25a057$export$be92b6f5f03c0fe9, { children: [
3658
3656
  /* @__PURE__ */ jsxRuntime.jsx($a093c7e1ec25a057$export$41fb9f06171c75f4, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Information, { "aria-hidden": "true" }) }),
3659
3657
  /* @__PURE__ */ jsxRuntime.jsx($a093c7e1ec25a057$export$602eac185826482c, { children: /* @__PURE__ */ jsxRuntime.jsx($a093c7e1ec25a057$export$7c6e2c02157bb7d2, { sideOffset: 5, style: { zIndex: 9999 }, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -3665,75 +3663,137 @@ function Tooltip({ description: description2 }) {
3665
3663
  hasRadius: true,
3666
3664
  shadow: "filterShadow",
3667
3665
  maxWidth: "300px",
3668
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral0", children: description2 })
3666
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral0", children: description })
3669
3667
  }
3670
3668
  ) }) })
3671
3669
  ] }) });
3672
3670
  }
3673
- function debounce(func, wait) {
3674
- let timeout;
3675
- return function executedFunction(...args) {
3676
- const later = () => {
3677
- clearTimeout(timeout);
3678
- func(...args);
3679
- };
3680
- clearTimeout(timeout);
3681
- timeout = setTimeout(later, wait);
3682
- };
3683
- }
3684
- async function duplicateCheck(get, url, routeDocumentId) {
3685
- if (!url) throw new Error("URL is required");
3686
- try {
3687
- const { data } = await get(`/${PLUGIN_ID}/checkUniquePath?path=${transformToUrl(url)}${routeDocumentId ? `&targetRouteDocumentId=${routeDocumentId}` : ""}`);
3688
- if (!data.uniquePath) {
3689
- throw new Error("Network response was not ok");
3671
+ function PathInput({ path, dispatchPath, isOverride, config }) {
3672
+ const { formatMessage } = reactIntl.useIntl();
3673
+ const displayedPath = isOverride && path.overridePath !== void 0 ? path.overridePath : path.value ?? "";
3674
+ const inputBorder = path.replacement === null ? "" : path.replacement ? "1px solid #ee5e52" : "1px solid #5cb176";
3675
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3676
+ designSystem.Field.Root,
3677
+ {
3678
+ hint: config.default ? formatMessage({
3679
+ id: getTranslation("components.CMEditViewAside.path.input.start"),
3680
+ defaultMessage: "Edit the"
3681
+ }) + ' "' + config.default + '" ' + formatMessage({
3682
+ id: getTranslation("components.CMEditViewAside.path.input.end"),
3683
+ defaultMessage: "field to generate a path"
3684
+ }) : formatMessage({
3685
+ id: getTranslation("components.CMEditViewAside.path.input.noSourceField"),
3686
+ defaultMessage: "Use the override option to set a custom path"
3687
+ }),
3688
+ children: [
3689
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Label, { children: [
3690
+ formatMessage({
3691
+ id: getTranslation("components.CMEditViewAside.path.input.label"),
3692
+ defaultMessage: "Path"
3693
+ }),
3694
+ /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { description: formatMessage({
3695
+ id: getTranslation("components.CMEditViewAside.path.input.tooltip"),
3696
+ defaultMessage: "The following characters are valid: A-Z, a-z, 0-9, /, -, _, $, ., +, !, *, ', (, )"
3697
+ }) })
3698
+ ] }),
3699
+ /* @__PURE__ */ jsxRuntime.jsx(
3700
+ designSystem.Field.Input,
3701
+ {
3702
+ id: "path-input",
3703
+ value: displayedPath,
3704
+ onChange: (e) => dispatchPath({ type: "SET_OVERRIDEPATH", payload: e.target.value }),
3705
+ disabled: !isOverride,
3706
+ onBlur: (e) => {
3707
+ if (e.target.value === path.prevValue) return;
3708
+ dispatchPath({ type: "DEFAULT", payload: e.target.value });
3709
+ },
3710
+ style: { outline: inputBorder }
3711
+ }
3712
+ ),
3713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
3714
+ ]
3690
3715
  }
3691
- return data.uniquePath;
3692
- } catch (err) {
3693
- console.error("Error in duplicateCheck:", err);
3694
- throw new Error("Failed to check URL uniqueness");
3695
- }
3716
+ );
3696
3717
  }
3697
- const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
3698
- function PathInfo({ validationState, replacement, setUrlStatus }) {
3699
- const [color, setColor] = React.useState(null);
3700
- const [text, setText] = React.useState(null);
3718
+ function RouteStructure({ routes, selectedParent, setSelectedParent, canonicalPath, prohibitedRouteIds }) {
3701
3719
  const { formatMessage } = reactIntl.useIntl();
3702
- React.useEffect(() => {
3703
- if (validationState === "initial") return;
3704
- if (validationState === "checking") {
3705
- setColor("neutral800");
3706
- setText(formatMessage({
3707
- id: getTranslation("components.pathInfo.checking"),
3708
- defaultMessage: "Checking if path is available..."
3709
- }));
3710
- } else if (validationState === "done") {
3711
- setColor(replacement ? "danger500" : "success500");
3712
- setText(replacement ? `${formatMessage({
3713
- id: getTranslation("components.pathInfo.notAvailable"),
3714
- defaultMessage: "Path is not available. Replaced with"
3715
- })} "${replacement}".` : formatMessage({
3716
- id: getTranslation("components.pathInfo.available"),
3717
- defaultMessage: "Path is available."
3718
- }));
3719
- if (setUrlStatus) setUrlStatus(replacement ? "invalid" : "valid");
3720
- }
3721
- }, [validationState, replacement, formatMessage, setUrlStatus]);
3722
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: color, children: text }) });
3720
+ const sortedRoutes = React.useMemo(() => {
3721
+ return [...routes].sort((a, b) => a.title.localeCompare(b.title));
3722
+ }, [routes]);
3723
+ const handleSelectParent = (value) => {
3724
+ const parentRoute = routes.find((route) => route.documentId === value) || null;
3725
+ setSelectedParent(parentRoute);
3726
+ };
3727
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { paddingBottom: 2, children: [
3728
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { children: [
3729
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({
3730
+ id: getTranslation("components.CMEditViewAside.path.input.parentSelect.label"),
3731
+ defaultMessage: "Place under"
3732
+ }) }),
3733
+ /* @__PURE__ */ jsxRuntime.jsxs(
3734
+ designSystem.SingleSelect,
3735
+ {
3736
+ value: selectedParent?.documentId || "",
3737
+ onValueChange: handleSelectParent,
3738
+ children: [
3739
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: "", children: formatMessage({
3740
+ id: getTranslation("components.CMEditViewAside.path.input.parentSelect.rootPath"),
3741
+ defaultMessage: "None (root path)"
3742
+ }) }),
3743
+ sortedRoutes.filter((route) => !prohibitedRouteIds?.includes(route.documentId) || route.documentId === selectedParent?.documentId).map(
3744
+ (route) => /* @__PURE__ */ jsxRuntime.jsx(
3745
+ designSystem.SingleSelectOption,
3746
+ {
3747
+ value: route.documentId,
3748
+ children: route.title
3749
+ },
3750
+ route.documentId
3751
+ )
3752
+ )
3753
+ ]
3754
+ }
3755
+ )
3756
+ ] }),
3757
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { marginTop: 4, children: [
3758
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Label, { children: [
3759
+ formatMessage({
3760
+ id: getTranslation("components.CMEditViewAside.canonicalPath.input.label"),
3761
+ defaultMessage: "Canonical Path"
3762
+ }),
3763
+ /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { description: formatMessage({
3764
+ id: getTranslation("components.CMEditViewAside.canonicalPath.input.tooltip"),
3765
+ defaultMessage: "The path determined by your content's natural hierarchy, independent of where it appears in navigation menus."
3766
+ }) })
3767
+ ] }),
3768
+ /* @__PURE__ */ jsxRuntime.jsx(
3769
+ designSystem.Field.Input,
3770
+ {
3771
+ id: "canonicalPath-input",
3772
+ value: canonicalPath,
3773
+ disabled: true
3774
+ }
3775
+ ),
3776
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
3777
+ ] })
3778
+ ] });
3779
+ }
3780
+ function getCanonicalPath(selectedParent, sourceFieldValue) {
3781
+ const parentPath = selectedParent ? selectedParent.canonicalPath + "/" : "";
3782
+ return `${parentPath}${transformToUrl(sourceFieldValue)}`;
3723
3783
  }
3724
3784
  function reducer(state, action) {
3725
3785
  switch (action.type) {
3726
3786
  case "DEFAULT":
3727
3787
  return {
3728
3788
  ...state,
3729
- value: transformToUrl(action.payload),
3789
+ value: action.payload,
3730
3790
  prevValue: state.value,
3731
3791
  needsUrlCheck: true
3732
3792
  };
3733
3793
  case "NO_URL_CHECK":
3734
3794
  return {
3735
3795
  ...state,
3736
- value: transformToUrl(action.payload),
3796
+ value: action.payload,
3737
3797
  prevValue: state.value,
3738
3798
  needsUrlCheck: false
3739
3799
  };
@@ -3746,16 +3806,22 @@ function reducer(state, action) {
3746
3806
  };
3747
3807
  case "RESET_URL_CHECK_FLAG":
3748
3808
  return { ...state, needsUrlCheck: false };
3809
+ case "SET_REPLACEMENT":
3810
+ return { ...state, replacement: action.payload };
3749
3811
  case "SET_UIDPATH":
3750
- return { ...state, uIdPath: action.payload };
3812
+ return { ...state, uidPath: action.payload };
3813
+ case "SET_CANONICALPATH":
3814
+ return { ...state, canonicalPath: action.payload };
3815
+ case "SET_OVERRIDEPATH":
3816
+ return { ...state, overridePath: action.payload };
3751
3817
  default:
3752
3818
  throw new Error();
3753
3819
  }
3754
3820
  }
3755
- const Path = ({ config }) => {
3821
+ const Panel = ({ config }) => {
3756
3822
  const { form, model } = admin.unstable_useContentManagerContext();
3757
3823
  const { initialValues, values, onChange } = form;
3758
- const { getRelatedRoute } = useApi();
3824
+ const { getRelatedRoute, getAllRoutes, getProhibitedRouteIds } = useApi();
3759
3825
  const { formatMessage } = reactIntl.useIntl();
3760
3826
  const { get } = admin.useFetchClient();
3761
3827
  const { allowedActions: {
@@ -3775,26 +3841,39 @@ const Path = ({ config }) => {
3775
3841
  conditions: []
3776
3842
  }
3777
3843
  ]);
3778
- const [routeId, setRouteId] = React.useState();
3844
+ const [route, setRoute] = React.useState(null);
3845
+ const [routes, setRoutes] = React.useState([]);
3846
+ const [prohibitedRouteIds, setProhibitedRouteIds] = React.useState([]);
3847
+ const [selectedParent, setSelectedParent] = React.useState(null);
3779
3848
  const [isOverride, setIsOverride] = React.useState(false);
3780
3849
  const [validationState, setValidationState] = React.useState("initial");
3781
- const [replacement, setReplacement] = React.useState("");
3782
3850
  const [initialLoadComplete, setInitialLoadComplete] = React.useState(false);
3783
- const [urlIsValid, setUrlIsValid] = React.useState(null);
3784
3851
  const [path, dispatchPath] = React.useReducer(reducer, {
3785
3852
  needsUrlCheck: false,
3786
3853
  value: "",
3787
3854
  prevValue: "",
3788
- uIdPath: ""
3855
+ replacement: null,
3856
+ uidPath: "",
3857
+ canonicalPath: "",
3858
+ overridePath: ""
3789
3859
  });
3790
3860
  const hasUserChangedField = React.useRef(false);
3791
3861
  const initialPath = React.useRef("");
3792
- const prevValueRef = React.useRef(null);
3793
- const debouncedCheckUrl = React.useCallback(debounce(checkUrl, 250), []);
3862
+ const prevSourceValueRef = React.useRef(null);
3863
+ const sourceFieldValue = React.useMemo(() => {
3864
+ const key = config?.default;
3865
+ if (!key) return "";
3866
+ const currentValue = values[key];
3867
+ if (!currentValue) return "";
3868
+ return currentValue;
3869
+ }, [values, config]);
3870
+ const debouncedCheckPath = React.useCallback(debounce(checkPath, 250), []);
3871
+ const debouncedCheckCanonicalPath = React.useCallback(debounce(checkCanonicalPath, 250), []);
3794
3872
  React.useEffect(() => {
3795
- onChange("webatlas_path", path.value);
3873
+ if (isOverride) onChange("webatlas_path", path.overridePath);
3796
3874
  onChange("webatlas_override", isOverride);
3797
- }, [path.value, isOverride]);
3875
+ onChange("webatlas_parent", selectedParent?.documentId || null);
3876
+ }, [path.value, path.overridePath, isOverride, selectedParent]);
3798
3877
  const debouncedValueEffect = React.useMemo(() => debounce((currentValues) => {
3799
3878
  const key = config?.default;
3800
3879
  if (!key) return;
@@ -3803,38 +3882,37 @@ const Path = ({ config }) => {
3803
3882
  dispatchPath({ type: "NO_URL_CHECK", payload: "" });
3804
3883
  return;
3805
3884
  }
3806
- if (initialLoadComplete && (hasUserChangedField.current || !routeId) && prevValueRef.current !== currentValue && !isOverride) {
3807
- const path2 = config.pattern ? `${config.pattern}/${currentValue}` : `${currentValue}`;
3885
+ if (initialLoadComplete && (hasUserChangedField.current || !route) && prevSourceValueRef.current !== currentValue && !isOverride) {
3886
+ const path2 = getCanonicalPath(selectedParent, currentValue);
3808
3887
  if (currentValue === initialValues[key]) {
3809
3888
  dispatchPath({ type: "NO_URL_CHECK", payload: path2 });
3810
3889
  } else {
3811
3890
  dispatchPath({ type: "DEFAULT", payload: path2 });
3812
3891
  }
3813
- prevValueRef.current = currentValue;
3892
+ prevSourceValueRef.current = currentValue;
3814
3893
  }
3815
- }, 500), [config?.default, config?.pattern, initialValues, isOverride, initialLoadComplete, routeId]);
3894
+ }, 500), [config?.default, initialValues, isOverride, initialLoadComplete, route, selectedParent]);
3816
3895
  React.useEffect(() => {
3817
3896
  const key = config?.default;
3818
3897
  if (!key) return;
3819
3898
  const currentValue = values[key];
3820
3899
  const initialValue = initialValues[key];
3821
- if (currentValue && !isOverride) {
3822
- const path2 = config.pattern ? `${config.pattern}/${currentValue}` : `${currentValue}`;
3823
- onChange("webatlas_path", transformToUrl(path2));
3900
+ if (currentValue !== initialValue && currentValue && !isOverride) {
3901
+ onChange("webatlas_path", transformToUrl(currentValue));
3824
3902
  }
3825
3903
  if (!initialLoadComplete) return;
3826
3904
  if (currentValue !== initialValue) {
3827
3905
  hasUserChangedField.current = true;
3828
3906
  }
3829
3907
  debouncedValueEffect(values);
3830
- }, [values, debouncedValueEffect, initialLoadComplete]);
3908
+ }, [values, debouncedValueEffect, initialLoadComplete, selectedParent]);
3831
3909
  React.useEffect(() => {
3832
3910
  if (path.needsUrlCheck && path.value) {
3833
- if (path.uIdPath === path.value || initialPath.current === path.value) return;
3834
- debouncedCheckUrl(path.value);
3911
+ if (path.uidPath === path.value || initialPath.current === path.value) return;
3912
+ debouncedCheckPath(path.value, route?.documentId || null);
3835
3913
  dispatchPath({ type: "RESET_URL_CHECK_FLAG" });
3836
3914
  }
3837
- }, [path.needsUrlCheck]);
3915
+ }, [path.needsUrlCheck, path.value, path.uidPath, route]);
3838
3916
  React.useEffect(() => {
3839
3917
  async function getTypes() {
3840
3918
  if (!initialValues.documentId) {
@@ -3842,42 +3920,84 @@ const Path = ({ config }) => {
3842
3920
  return;
3843
3921
  }
3844
3922
  try {
3845
- const route = await getRelatedRoute(initialValues.documentId);
3846
- if (!route) return;
3847
- initialPath.current = initialValues.webatlas_path || route.uidPath;
3848
- setRouteId(route.id);
3849
- setIsOverride(route.isOverride || false);
3850
- dispatchPath({ type: "NO_TRANSFORM_AND_CHECK", payload: route.path || "" });
3851
- dispatchPath({ type: "SET_UIDPATH", payload: route.uidPath || "" });
3923
+ const route2 = await getRelatedRoute(initialValues.documentId);
3924
+ if (!route2) return;
3925
+ initialPath.current = initialValues.webatlas_path || route2.uidPath;
3926
+ setRoute(route2);
3927
+ setIsOverride(route2.isOverride || false);
3928
+ if (route2.isOverride) {
3929
+ dispatchPath({ type: "SET_OVERRIDEPATH", payload: route2.path || "" });
3930
+ } else {
3931
+ dispatchPath({ type: "NO_TRANSFORM_AND_CHECK", payload: route2.path || "" });
3932
+ }
3933
+ dispatchPath({ type: "SET_UIDPATH", payload: route2.uidPath || "" });
3852
3934
  const key = config?.default;
3853
3935
  if (key) {
3854
- prevValueRef.current = values[key];
3936
+ prevSourceValueRef.current = values[key];
3855
3937
  }
3856
3938
  } catch (err) {
3857
- setRouteId(null);
3858
- console.log(err);
3939
+ setRoute(null);
3940
+ strapi.log.error(err);
3859
3941
  }
3860
3942
  setInitialLoadComplete(true);
3861
3943
  }
3862
3944
  getTypes();
3863
3945
  }, [config]);
3946
+ React.useEffect(() => {
3947
+ if (initialValues.webatlas_parent && routes.length > 0 && !selectedParent) {
3948
+ const parentRoute = routes.find((route2) => route2.documentId === initialValues.webatlas_parent);
3949
+ if (parentRoute) {
3950
+ setSelectedParent(parentRoute);
3951
+ const canonicalPath = getCanonicalPath(parentRoute, sourceFieldValue);
3952
+ dispatchPath({ type: "DEFAULT", payload: canonicalPath });
3953
+ }
3954
+ }
3955
+ }, [initialValues, routes]);
3864
3956
  React.useEffect(() => {
3865
3957
  if (initialValues.webatlas_path) dispatchPath({ type: "NO_URL_CHECK", payload: initialValues.webatlas_path });
3866
3958
  if (initialValues.webatlas_override) setIsOverride(initialValues.webatlas_override);
3959
+ async function fetchAllRoutes() {
3960
+ const allRoutes = await getAllRoutes();
3961
+ setRoutes(allRoutes);
3962
+ }
3963
+ fetchAllRoutes();
3867
3964
  }, []);
3868
- async function checkUrl(url) {
3869
- if (!url) return;
3965
+ React.useEffect(() => {
3966
+ async function fetchProhibitedRouteIds() {
3967
+ const prohibitedIds = await getProhibitedRouteIds(route?.documentId);
3968
+ setProhibitedRouteIds(prohibitedIds);
3969
+ }
3970
+ fetchProhibitedRouteIds();
3971
+ }, [route]);
3972
+ React.useEffect(() => {
3973
+ if (!sourceFieldValue) return;
3974
+ const canonicalPath = getCanonicalPath(selectedParent, sourceFieldValue);
3975
+ !isOverride && dispatchPath({ type: "DEFAULT", payload: canonicalPath });
3976
+ dispatchPath({ type: "SET_CANONICALPATH", payload: canonicalPath });
3977
+ debouncedCheckCanonicalPath(canonicalPath, route?.documentId || null);
3978
+ dispatchPath({ type: "RESET_URL_CHECK_FLAG" });
3979
+ }, [selectedParent, sourceFieldValue, route, isOverride]);
3980
+ async function checkCanonicalPath(path2, documentId) {
3981
+ if (!path2) return;
3982
+ try {
3983
+ const result = await duplicateCheck({ fetchFunction: get, path: path2, routeDocumentId: documentId, withoutTransform: true });
3984
+ dispatchPath({ type: "SET_CANONICALPATH", payload: result });
3985
+ } catch (err) {
3986
+ strapi.log.error(err);
3987
+ }
3988
+ }
3989
+ async function checkPath(path2, route2) {
3990
+ if (!path2) return;
3870
3991
  setValidationState("checking");
3871
- setReplacement("");
3992
+ dispatchPath({ type: "SET_REPLACEMENT", payload: "" });
3872
3993
  try {
3873
- const data = await duplicateCheck(get, url);
3874
- if (!data || data === url) return;
3994
+ const data = await duplicateCheck({ fetchFunction: get, path: path2, routeDocumentId: route2, withoutTransform: true });
3995
+ if (!data || data === path2) return;
3875
3996
  dispatchPath({ type: "NO_URL_CHECK", payload: data });
3876
- setReplacement(data);
3997
+ dispatchPath({ type: "SET_REPLACEMENT", payload: data });
3877
3998
  } catch (err) {
3878
- console.log(err);
3999
+ strapi.log.error(err);
3879
4000
  } finally {
3880
- setUrlIsValid(null);
3881
4001
  setValidationState("done");
3882
4002
  }
3883
4003
  }
@@ -3888,7 +4008,7 @@ const Path = ({ config }) => {
3888
4008
  return /* @__PURE__ */ jsxRuntime.jsx(
3889
4009
  designSystem.Box,
3890
4010
  {
3891
- as: "aside",
4011
+ tag: "aside",
3892
4012
  "aria-labelledby": "URL Route",
3893
4013
  width: "100%",
3894
4014
  children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3896,101 +4016,52 @@ const Path = ({ config }) => {
3896
4016
  {
3897
4017
  direction: "column",
3898
4018
  alignItems: "stretch",
3899
- gap: 4,
4019
+ gap: 1,
3900
4020
  children: [
4021
+ !route && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4022
+ /* @__PURE__ */ jsxRuntime.jsx(NewPathInfo, {}),
4023
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { marginTop: 2, marginBottom: 2 })
4024
+ ] }),
4025
+ /* @__PURE__ */ jsxRuntime.jsx(
4026
+ RouteStructure,
4027
+ {
4028
+ canonicalPath: path.canonicalPath,
4029
+ routes,
4030
+ selectedParent,
4031
+ setSelectedParent,
4032
+ prohibitedRouteIds
4033
+ }
4034
+ ),
4035
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { marginTop: 2, marginBottom: 2 }),
3901
4036
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
3902
- !routeId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3903
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", marginBottom: 2, children: formatMessage({
3904
- id: getTranslation("components.CMEditViewAside.path.newPathInfo"),
3905
- defaultMessage: "A new path will be created upon saving this entry."
3906
- }) }),
3907
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingBottom: 2, paddingTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}) })
3908
- ] }),
3909
- /* @__PURE__ */ jsxRuntime.jsxs(
3910
- designSystem.Field.Root,
4037
+ /* @__PURE__ */ jsxRuntime.jsx(
4038
+ PathInput,
3911
4039
  {
3912
- hint: config.default ? formatMessage({
3913
- id: getTranslation("components.CMEditViewAside.path.input.start"),
3914
- defaultMessage: "Edit the"
3915
- }) + ' "' + config.default + '" ' + formatMessage({
3916
- id: getTranslation("components.CMEditViewAside.path.input.end"),
3917
- defaultMessage: "field to generate a path"
3918
- }) : formatMessage({
3919
- id: getTranslation("components.CMEditViewAside.path.input.noSourceField"),
3920
- defaultMessage: "Use the override option to set a custom path"
3921
- }),
3922
- children: [
3923
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Label, { children: [
3924
- formatMessage({
3925
- id: getTranslation("components.CMEditViewAside.path.input.label"),
3926
- defaultMessage: "Path"
3927
- }),
3928
- /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { description: formatMessage({
3929
- id: getTranslation("components.CMEditViewAside.path.input.tooltip"),
3930
- defaultMessage: "The following characters are valid: A-Z, a-z, 0-9, /, -, _, $, ., +, !, *, ', (, )"
3931
- }) })
3932
- ] }),
3933
- /* @__PURE__ */ jsxRuntime.jsx(
3934
- designSystem.Field.Input,
3935
- {
3936
- id: "path-input",
3937
- value: path.value,
3938
- onChange: (e) => dispatchPath({ type: "NO_TRANSFORM_AND_CHECK", payload: e.target.value }),
3939
- disabled: !isOverride,
3940
- onBlur: (e) => {
3941
- if (e.target.value === path.prevValue) return;
3942
- dispatchPath({ type: "DEFAULT", payload: e.target.value });
3943
- },
3944
- style: { outline: urlIsValid !== null ? urlIsValid === "valid" ? "1px solid #5cb176" : "1px solid #ee5e52" : void 0 }
3945
- }
3946
- ),
3947
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
3948
- ]
4040
+ path,
4041
+ dispatchPath,
4042
+ isOverride,
4043
+ config
3949
4044
  }
3950
4045
  ),
3951
- /* @__PURE__ */ jsxRuntime.jsx(PathInfo, { validationState, replacement, setUrlStatus: setUrlIsValid }),
3952
- /* @__PURE__ */ jsxRuntime.jsx(
3953
- designSystem.Flex,
4046
+ validationState !== "initial" && /* @__PURE__ */ jsxRuntime.jsx(
4047
+ PathInfo,
3954
4048
  {
3955
- gap: 2,
3956
- paddingTop: 2,
3957
- children: /* @__PURE__ */ jsxRuntime.jsx(
3958
- designSystem.Checkbox,
3959
- {
3960
- id: "path-override-checkbox",
3961
- checked: isOverride,
3962
- onCheckedChange: () => setIsOverride((prev) => !prev),
3963
- disabled: !routeId && !canCreate || routeId && !canUpdate,
3964
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
3965
- id: getTranslation("components.CMEditViewAside.path.overrideCheckbox"),
3966
- defaultMessage: "Override automatic path generation"
3967
- }) })
3968
- }
3969
- )
4049
+ validationState,
4050
+ replacement: path.replacement
3970
4051
  }
3971
4052
  )
3972
4053
  ] }),
3973
- path.uIdPath && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3974
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, {}) }),
3975
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { children: /* @__PURE__ */ jsxRuntime.jsxs(
3976
- designSystem.Field.Root,
3977
- {
3978
- hint: formatMessage({
3979
- id: getTranslation("components.CMEditViewAside.path.uidPath.hint"),
3980
- defaultMessage: "Permanent UID path, cannot be changed"
3981
- }),
3982
- children: [
3983
- /* @__PURE__ */ jsxRuntime.jsx(
3984
- designSystem.Field.Input,
3985
- {
3986
- value: path.uIdPath,
3987
- disabled: true
3988
- }
3989
- ),
3990
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
3991
- ]
3992
- }
3993
- ) })
4054
+ /* @__PURE__ */ jsxRuntime.jsx(
4055
+ OverrideCheckbox,
4056
+ {
4057
+ isOverride,
4058
+ setIsOverride,
4059
+ disabledCondition: !canCreate && !canUpdate
4060
+ }
4061
+ ),
4062
+ path.uidPath && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Divider, { marginTop: 2, marginBottom: 2 }),
4064
+ /* @__PURE__ */ jsxRuntime.jsx(UidPathDisplay, { path: path.uidPath })
3994
4065
  ] })
3995
4066
  ]
3996
4067
  }
@@ -4005,14 +4076,7 @@ const pluginPermissions = {
4005
4076
  "settings.general": [{ action: `plugin::${PLUGIN_ID}.settings.general`, subject: null }],
4006
4077
  "settings.navigation": [{ action: `plugin::${PLUGIN_ID}.settings.navigation`, subject: null }]
4007
4078
  };
4008
- const CMEditViewAside = ({
4009
- // activeTab,
4010
- // collectionType,
4011
- // document,
4012
- documentId,
4013
- // meta,
4014
- model
4015
- }) => {
4079
+ const CMEditViewAside = ({ documentId, model }) => {
4016
4080
  const { contentTypes } = useAllContentTypes();
4017
4081
  const { config } = usePluginConfig();
4018
4082
  const { formatMessage } = reactIntl.useIntl();
@@ -4057,10 +4121,10 @@ const CMEditViewAside = ({
4057
4121
  if (!config) return;
4058
4122
  setIsActiveContentType(false);
4059
4123
  setContentTypeConfig(null);
4060
- config?.selectedContentTypes?.forEach((type2) => {
4061
- if (type2.uid === model) {
4124
+ config?.selectedContentTypes?.forEach((type) => {
4125
+ if (type.uid === model) {
4062
4126
  setIsActiveContentType(true);
4063
- setContentTypeConfig(type2);
4127
+ setContentTypeConfig(type);
4064
4128
  }
4065
4129
  });
4066
4130
  setIsLoading(false);
@@ -4072,7 +4136,7 @@ const CMEditViewAside = ({
4072
4136
  });
4073
4137
  if (!canAside || !isAllowedContentType || !isActiveContentType || !contentTypeConfig) return null;
4074
4138
  if (!config) {
4075
- console.error("CMEditViewAside: Plugin is not configured.");
4139
+ strapi.log.error("CMEditViewAside: Plugin is not configured.");
4076
4140
  return null;
4077
4141
  }
4078
4142
  if (isLoading) return {
@@ -4084,37 +4148,31 @@ const CMEditViewAside = ({
4084
4148
  };
4085
4149
  return {
4086
4150
  title: panelTitle,
4087
- content: /* @__PURE__ */ jsxRuntime.jsx(Path, { config: contentTypeConfig })
4151
+ content: /* @__PURE__ */ jsxRuntime.jsx(Panel, { config: contentTypeConfig })
4088
4152
  };
4089
4153
  };
4090
4154
  const index = {
4091
4155
  register(app) {
4092
4156
  app.addMenuLink({
4093
- to: `/plugins/${PLUGIN_ID}/paths`,
4157
+ to: `plugins/${PLUGIN_ID}/paths`,
4094
4158
  icon: PathIcon,
4095
4159
  intlLabel: {
4096
4160
  id: `${PLUGIN_ID}.link.paths`,
4097
4161
  defaultMessage: "Paths"
4098
4162
  },
4099
- Component: async () => {
4100
- const component = await Promise.resolve().then(() => require("./index-DTsHvlTa.js"));
4101
- return { default: component.default };
4102
- },
4163
+ Component: () => Promise.resolve().then(() => require("./index-DkqiqVx2.js")),
4103
4164
  permissions: [
4104
4165
  pluginPermissions["page.routes"][0]
4105
4166
  ]
4106
4167
  });
4107
4168
  app.addMenuLink({
4108
- to: `/plugins/${PLUGIN_ID}/navigation`,
4169
+ to: `plugins/${PLUGIN_ID}/navigation`,
4109
4170
  icon: NavigationIcon,
4110
4171
  intlLabel: {
4111
4172
  id: `${PLUGIN_ID}.link.navigation`,
4112
4173
  defaultMessage: "Navigation"
4113
4174
  },
4114
- Component: async () => {
4115
- const component = await Promise.resolve().then(() => require("./index-BOtvXSPU.js"));
4116
- return { default: component.default };
4117
- },
4175
+ Component: () => Promise.resolve().then(() => require("./index-BXt-QjKo.js")),
4118
4176
  permissions: [
4119
4177
  pluginPermissions["page.navigation"][0]
4120
4178
  ]
@@ -4133,13 +4191,8 @@ const index = {
4133
4191
  defaultMessage: "General"
4134
4192
  },
4135
4193
  id: `${PLUGIN_ID}-general`,
4136
- to: `/settings/${PLUGIN_ID}/general`,
4137
- Component: async () => {
4138
- return await Promise.resolve().then(() => require(
4139
- /* webpackChunkName: "webatlas-settings-general-page" */
4140
- "./index-Dt-AXdaw.js"
4141
- ));
4142
- },
4194
+ to: `${PLUGIN_ID}/general`,
4195
+ Component: () => Promise.resolve().then(() => require("./index-CGsC8P9P.js")),
4143
4196
  permissions: [
4144
4197
  pluginPermissions["settings.general"][0]
4145
4198
  ]
@@ -4153,13 +4206,8 @@ const index = {
4153
4206
  defaultMessage: "Navigation"
4154
4207
  },
4155
4208
  id: `${PLUGIN_ID}-navigation`,
4156
- to: `/settings/${PLUGIN_ID}/navigation`,
4157
- Component: async () => {
4158
- return await Promise.resolve().then(() => require(
4159
- /* webpackChunkName: "webatlas-settings-navigation-page" */
4160
- "./index-VXuAEnpX.js"
4161
- ));
4162
- },
4209
+ to: `${PLUGIN_ID}/navigation`,
4210
+ Component: () => Promise.resolve().then(() => require("./index-BYlmJycd.js")),
4163
4211
  permissions: [
4164
4212
  pluginPermissions["settings.navigation"][0]
4165
4213
  ]
@@ -4179,7 +4227,7 @@ const index = {
4179
4227
  return Promise.all(
4180
4228
  locales.map(async (locale) => {
4181
4229
  try {
4182
- const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-CGXL_3o_.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-DWEd5BXK.js")) }), `./translations/${locale}.json`, 3);
4230
+ const { default: data } = await __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => Promise.resolve().then(() => require("./de-CqU1FU8C.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-C7I90FwV.js")) }), `./translations/${locale}.json`, 3);
4183
4231
  return { data, locale };
4184
4232
  } catch {
4185
4233
  return { data: {}, locale };
@@ -4198,7 +4246,6 @@ exports.duplicateCheck = duplicateCheck;
4198
4246
  exports.getTranslation = getTranslation;
4199
4247
  exports.index = index;
4200
4248
  exports.pluginPermissions = pluginPermissions;
4201
- exports.transformToUrl = transformToUrl;
4202
4249
  exports.useAllContentTypes = useAllContentTypes;
4203
4250
  exports.useApi = useApi;
4204
4251
  exports.usePluginConfig = usePluginConfig;