ldap-rest 0.0.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 (296) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +48 -0
  3. package/bin/cleanup-external-users.mjs +219 -0
  4. package/bin/index.mjs +54 -0
  5. package/bin/sync-james.mjs +190 -0
  6. package/dist/abstract/ldapFlat.js +1 -0
  7. package/dist/abstract/plugin.js +1 -0
  8. package/dist/abstract/twakePlugin.js +1 -0
  9. package/dist/bin/index.js +1 -0
  10. package/dist/config/args.js +1 -0
  11. package/dist/lib/auth/base.js +1 -0
  12. package/dist/lib/authz/base.js +1 -0
  13. package/dist/lib/expressFormatedResponses.js +1 -0
  14. package/dist/lib/ldapActions.js +1 -0
  15. package/dist/lib/parseConfig.js +1 -0
  16. package/dist/lib/utils.js +1 -0
  17. package/dist/logger/winston.js +1 -0
  18. package/dist/plugins/auth/authzLinid1.js +1 -0
  19. package/dist/plugins/auth/authzPerBranch.js +1 -0
  20. package/dist/plugins/auth/crowdsec.js +1 -0
  21. package/dist/plugins/auth/llng.js +1 -0
  22. package/dist/plugins/auth/openidconnect.js +1 -0
  23. package/dist/plugins/auth/rateLimit.js +1 -0
  24. package/dist/plugins/auth/token.js +1 -0
  25. package/dist/plugins/configApi.js +1 -0
  26. package/dist/plugins/demo/helloworld.js +1 -0
  27. package/dist/plugins/ldap/bulkImport.js +1 -0
  28. package/dist/plugins/ldap/departmentSync.js +1 -0
  29. package/dist/plugins/ldap/externalUsersInGroups.js +1 -0
  30. package/dist/plugins/ldap/flatGeneric.js +1 -0
  31. package/dist/plugins/ldap/groups.js +1 -0
  32. package/dist/plugins/ldap/onChange.js +1 -0
  33. package/dist/plugins/ldap/organization.js +1 -0
  34. package/dist/plugins/ldap/trash.js +1 -0
  35. package/dist/plugins/priority.json.js +1 -0
  36. package/dist/plugins/static.js +1 -0
  37. package/dist/plugins/twake/calendarResources.js +1 -0
  38. package/dist/plugins/twake/james.js +1 -0
  39. package/dist/plugins/weblogs.js +1 -0
  40. package/dist/src/abstract/ldapFlat.d.ts +94 -0
  41. package/dist/src/abstract/plugin.d.ts +43 -0
  42. package/dist/src/abstract/twakePlugin.d.ts +90 -0
  43. package/dist/src/bin/index.d.ts +43 -0
  44. package/dist/src/browser/ldap-group-editor/LdapGroupEditor.d.ts +31 -0
  45. package/dist/src/browser/ldap-group-editor/api/GroupApiClient.d.ts +23 -0
  46. package/dist/src/browser/ldap-group-editor/components/CreateGroupModal.d.ts +19 -0
  47. package/dist/src/browser/ldap-group-editor/components/GroupPropertyEditor.d.ts +30 -0
  48. package/dist/src/browser/ldap-group-editor/components/GroupTree.d.ts +17 -0
  49. package/dist/src/browser/ldap-group-editor/components/MoveGroupModal.d.ts +20 -0
  50. package/dist/src/browser/ldap-group-editor/index.d.ts +6 -0
  51. package/dist/src/browser/ldap-group-editor/types.d.ts +58 -0
  52. package/dist/src/browser/ldap-resource-editor/api/ResourceApiClient.d.ts +53 -0
  53. package/dist/src/browser/ldap-resource-editor/cache/CacheManager.d.ts +65 -0
  54. package/dist/src/browser/ldap-resource-editor/index.d.ts +6 -0
  55. package/dist/src/browser/ldap-resource-editor/types.d.ts +78 -0
  56. package/dist/src/browser/ldap-tree-viewer/LdapTreeViewer.d.ts +26 -0
  57. package/dist/src/browser/ldap-tree-viewer/api/LdapApiClient.d.ts +30 -0
  58. package/dist/src/browser/ldap-tree-viewer/components/TreeNode.d.ts +17 -0
  59. package/dist/src/browser/ldap-tree-viewer/components/TreeRoot.d.ts +14 -0
  60. package/dist/src/browser/ldap-tree-viewer/index.d.ts +7 -0
  61. package/dist/src/browser/ldap-tree-viewer/store/Store.d.ts +18 -0
  62. package/dist/src/browser/ldap-tree-viewer/store/actions.d.ts +28 -0
  63. package/dist/src/browser/ldap-tree-viewer/store/reducers.d.ts +7 -0
  64. package/dist/src/browser/ldap-tree-viewer/types.d.ts +34 -0
  65. package/dist/src/browser/ldap-unit-editor/LdapUnitEditor.d.ts +27 -0
  66. package/dist/src/browser/ldap-unit-editor/api/UnitApiClient.d.ts +24 -0
  67. package/dist/src/browser/ldap-unit-editor/components/MoveUnitModal.d.ts +28 -0
  68. package/dist/src/browser/ldap-unit-editor/components/UnitPropertyEditor.d.ts +28 -0
  69. package/dist/src/browser/ldap-unit-editor/components/UnitTree.d.ts +18 -0
  70. package/dist/src/browser/ldap-unit-editor/index.d.ts +6 -0
  71. package/dist/src/browser/ldap-unit-editor/types.d.ts +55 -0
  72. package/dist/src/browser/ldap-user-editor/LdapUserEditor.d.ts +32 -0
  73. package/dist/src/browser/ldap-user-editor/api/UserApiClient.d.ts +55 -0
  74. package/dist/src/browser/ldap-user-editor/cache/CacheManager.d.ts +65 -0
  75. package/dist/src/browser/ldap-user-editor/components/MoveUserModal.d.ts +28 -0
  76. package/dist/src/browser/ldap-user-editor/components/PointerField.d.ts +22 -0
  77. package/dist/src/browser/ldap-user-editor/components/UserEditor.d.ts +46 -0
  78. package/dist/src/browser/ldap-user-editor/components/UserList.d.ts +24 -0
  79. package/dist/src/browser/ldap-user-editor/components/UserTree.d.ts +24 -0
  80. package/dist/src/browser/ldap-user-editor/index.d.ts +7 -0
  81. package/dist/src/browser/ldap-user-editor/types.d.ts +67 -0
  82. package/dist/src/browser/shared/components/Modal.d.ts +38 -0
  83. package/dist/src/browser/shared/components/StatusMessage.d.ts +48 -0
  84. package/dist/src/browser/shared/index.d.ts +10 -0
  85. package/dist/src/browser/shared/types/index.d.ts +65 -0
  86. package/dist/src/browser/shared/utils/dom.d.ts +33 -0
  87. package/dist/src/browser/shared/utils/form.d.ts +28 -0
  88. package/dist/src/browser/shared/utils/schema.d.ts +29 -0
  89. package/dist/src/config/args.d.ts +128 -0
  90. package/dist/src/config/schema.d.ts +18 -0
  91. package/dist/src/hooks.d.ts +76 -0
  92. package/dist/src/lib/auth/base.d.ts +9 -0
  93. package/dist/src/lib/authz/base.d.ts +63 -0
  94. package/dist/src/lib/expressFormatedResponses.d.ts +26 -0
  95. package/dist/src/lib/ldapActions.d.ts +91 -0
  96. package/dist/src/lib/parseConfig.d.ts +23 -0
  97. package/dist/src/lib/utils.d.ts +73 -0
  98. package/dist/src/logger/winston.d.ts +3 -0
  99. package/dist/src/plugins/auth/authzLinid1.d.ts +46 -0
  100. package/dist/src/plugins/auth/authzPerBranch.d.ts +59 -0
  101. package/dist/src/plugins/auth/crowdsec.d.ts +29 -0
  102. package/dist/src/plugins/auth/llng.d.ts +8 -0
  103. package/dist/src/plugins/auth/openidconnect.d.ts +11 -0
  104. package/dist/src/plugins/auth/rateLimit.d.ts +24 -0
  105. package/dist/src/plugins/auth/token.d.ts +17 -0
  106. package/dist/src/plugins/configApi.d.ts +24 -0
  107. package/dist/src/plugins/demo/helloworld.d.ts +12 -0
  108. package/dist/src/plugins/ldap/bulkImport.d.ts +48 -0
  109. package/dist/src/plugins/ldap/departmentSync.d.ts +35 -0
  110. package/dist/src/plugins/ldap/externalUsersInGroups.d.ts +21 -0
  111. package/dist/src/plugins/ldap/flatGeneric.d.ts +31 -0
  112. package/dist/src/plugins/ldap/groups.d.ts +95 -0
  113. package/dist/src/plugins/ldap/onChange.d.ts +32 -0
  114. package/dist/src/plugins/ldap/organization.d.ts +65 -0
  115. package/dist/src/plugins/ldap/trash.d.ts +52 -0
  116. package/dist/src/plugins/static.d.ts +7 -0
  117. package/dist/src/plugins/twake/calendarResources.d.ts +31 -0
  118. package/dist/src/plugins/twake/james.d.ts +83 -0
  119. package/dist/src/plugins/weblogs.d.ts +8 -0
  120. package/docs/DEVELOPER_GUIDE.md +298 -0
  121. package/docs/OPENAPI.md +440 -0
  122. package/docs/PLUGIN_DEPENDENCIES.md +612 -0
  123. package/docs/README.md +466 -0
  124. package/docs/api/REFERENCE.md +983 -0
  125. package/docs/api/REST_API.md +1237 -0
  126. package/docs/authentication.md +469 -0
  127. package/docs/authzLinid1.md +521 -0
  128. package/docs/authzPerBranch.md +596 -0
  129. package/docs/browser/LIBRARIES.md +1196 -0
  130. package/docs/examples/EXAMPLES.md +1659 -0
  131. package/docs/examples/twake-mailbox-type-nomenclature.ldif +37 -0
  132. package/docs/examples/twake-mailbox-type-schema-amendment.ldif +30 -0
  133. package/docs/jamesTeamMailboxes.md +343 -0
  134. package/docs/ldapBulkImport.md +722 -0
  135. package/docs/ldapExternalUsersInGroups.md +325 -0
  136. package/docs/ldapFlatGeneric.md +444 -0
  137. package/docs/ldapGroups.md +589 -0
  138. package/docs/ldapOrganizations.md +659 -0
  139. package/docs/ldapTrash.md +260 -0
  140. package/docs/linagora.png +0 -0
  141. package/docs/onChange.md +318 -0
  142. package/docs/plugins/DEVELOPMENT.md +1219 -0
  143. package/docs/presenterm-fr.md +721 -0
  144. package/docs/presenterm.md +721 -0
  145. package/docs/schemas/SCHEMAS.md +1212 -0
  146. package/docs/static.md +410 -0
  147. package/docs/twakeCalendarResources.md +148 -0
  148. package/docs/twakeJames.md +661 -0
  149. package/docs/weblogs.md +399 -0
  150. package/examples/web/ldap-group-editor.html +113 -0
  151. package/examples/web/ldap-tree-viewer.html +368 -0
  152. package/examples/web/ldap-unit-editor.html +108 -0
  153. package/examples/web/ldap-user-editor.html +412 -0
  154. package/package.json +458 -0
  155. package/static/browser/common-demo.css +450 -0
  156. package/static/browser/ldap-group-editor/LdapGroupEditor.js +207 -0
  157. package/static/browser/ldap-group-editor/LdapGroupEditor.js.map +1 -0
  158. package/static/browser/ldap-group-editor/api/GroupApiClient.js +112 -0
  159. package/static/browser/ldap-group-editor/api/GroupApiClient.js.map +1 -0
  160. package/static/browser/ldap-group-editor/components/CreateGroupModal.js +212 -0
  161. package/static/browser/ldap-group-editor/components/CreateGroupModal.js.map +1 -0
  162. package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js +497 -0
  163. package/static/browser/ldap-group-editor/components/GroupPropertyEditor.js.map +1 -0
  164. package/static/browser/ldap-group-editor/components/GroupTree.js +153 -0
  165. package/static/browser/ldap-group-editor/components/GroupTree.js.map +1 -0
  166. package/static/browser/ldap-group-editor/components/MoveGroupModal.js +235 -0
  167. package/static/browser/ldap-group-editor/components/MoveGroupModal.js.map +1 -0
  168. package/static/browser/ldap-group-editor/index.js +2 -0
  169. package/static/browser/ldap-group-editor/index.js.map +1 -0
  170. package/static/browser/ldap-group-editor/types.js +2 -0
  171. package/static/browser/ldap-group-editor/types.js.map +1 -0
  172. package/static/browser/ldap-group-editor.esm.js +1399 -0
  173. package/static/browser/ldap-group-editor.esm.js.map +1 -0
  174. package/static/browser/ldap-group-editor.js +1407 -0
  175. package/static/browser/ldap-group-editor.js.map +1 -0
  176. package/static/browser/ldap-group-editor.min.js +2 -0
  177. package/static/browser/ldap-group-editor.min.js.map +1 -0
  178. package/static/browser/ldap-resource-editor/api/ResourceApiClient.js +226 -0
  179. package/static/browser/ldap-resource-editor/api/ResourceApiClient.js.map +1 -0
  180. package/static/browser/ldap-resource-editor/cache/CacheManager.js +123 -0
  181. package/static/browser/ldap-resource-editor/cache/CacheManager.js.map +1 -0
  182. package/static/browser/ldap-resource-editor/index.js +2 -0
  183. package/static/browser/ldap-resource-editor/index.js.map +1 -0
  184. package/static/browser/ldap-resource-editor/types.js +2 -0
  185. package/static/browser/ldap-resource-editor/types.js.map +1 -0
  186. package/static/browser/ldap-tree-viewer/LdapTreeViewer.js +187 -0
  187. package/static/browser/ldap-tree-viewer/LdapTreeViewer.js.map +1 -0
  188. package/static/browser/ldap-tree-viewer/api/LdapApiClient.js +50 -0
  189. package/static/browser/ldap-tree-viewer/api/LdapApiClient.js.map +1 -0
  190. package/static/browser/ldap-tree-viewer/components/TreeNode.js +140 -0
  191. package/static/browser/ldap-tree-viewer/components/TreeNode.js.map +1 -0
  192. package/static/browser/ldap-tree-viewer/components/TreeRoot.js +98 -0
  193. package/static/browser/ldap-tree-viewer/components/TreeRoot.js.map +1 -0
  194. package/static/browser/ldap-tree-viewer/index.js +2 -0
  195. package/static/browser/ldap-tree-viewer/index.js.map +1 -0
  196. package/static/browser/ldap-tree-viewer/store/Store.js +29 -0
  197. package/static/browser/ldap-tree-viewer/store/Store.js.map +1 -0
  198. package/static/browser/ldap-tree-viewer/store/actions.js +53 -0
  199. package/static/browser/ldap-tree-viewer/store/actions.js.map +1 -0
  200. package/static/browser/ldap-tree-viewer/store/reducers.js +79 -0
  201. package/static/browser/ldap-tree-viewer/store/reducers.js.map +1 -0
  202. package/static/browser/ldap-tree-viewer/types.js +2 -0
  203. package/static/browser/ldap-tree-viewer/types.js.map +1 -0
  204. package/static/browser/ldap-tree-viewer.css +2 -0
  205. package/static/browser/ldap-tree-viewer.css.map +1 -0
  206. package/static/browser/ldap-tree-viewer.esm.js +606 -0
  207. package/static/browser/ldap-tree-viewer.esm.js.map +1 -0
  208. package/static/browser/ldap-tree-viewer.js +614 -0
  209. package/static/browser/ldap-tree-viewer.js.map +1 -0
  210. package/static/browser/ldap-tree-viewer.min.js +2 -0
  211. package/static/browser/ldap-tree-viewer.min.js.map +1 -0
  212. package/static/browser/ldap-unit-editor/LdapUnitEditor.js +119 -0
  213. package/static/browser/ldap-unit-editor/LdapUnitEditor.js.map +1 -0
  214. package/static/browser/ldap-unit-editor/api/UnitApiClient.js +95 -0
  215. package/static/browser/ldap-unit-editor/api/UnitApiClient.js.map +1 -0
  216. package/static/browser/ldap-unit-editor/components/MoveUnitModal.js +295 -0
  217. package/static/browser/ldap-unit-editor/components/MoveUnitModal.js.map +1 -0
  218. package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js +321 -0
  219. package/static/browser/ldap-unit-editor/components/UnitPropertyEditor.js.map +1 -0
  220. package/static/browser/ldap-unit-editor/components/UnitTree.js +197 -0
  221. package/static/browser/ldap-unit-editor/components/UnitTree.js.map +1 -0
  222. package/static/browser/ldap-unit-editor/index.js +2 -0
  223. package/static/browser/ldap-unit-editor/index.js.map +1 -0
  224. package/static/browser/ldap-unit-editor/types.js +2 -0
  225. package/static/browser/ldap-unit-editor/types.js.map +1 -0
  226. package/static/browser/ldap-unit-editor.esm.js +1013 -0
  227. package/static/browser/ldap-unit-editor.esm.js.map +1 -0
  228. package/static/browser/ldap-unit-editor.js +1021 -0
  229. package/static/browser/ldap-unit-editor.js.map +1 -0
  230. package/static/browser/ldap-unit-editor.min.js +2 -0
  231. package/static/browser/ldap-unit-editor.min.js.map +1 -0
  232. package/static/browser/ldap-user-editor/LdapUserEditor.js +184 -0
  233. package/static/browser/ldap-user-editor/LdapUserEditor.js.map +1 -0
  234. package/static/browser/ldap-user-editor/api/UserApiClient.js +209 -0
  235. package/static/browser/ldap-user-editor/api/UserApiClient.js.map +1 -0
  236. package/static/browser/ldap-user-editor/cache/CacheManager.js +123 -0
  237. package/static/browser/ldap-user-editor/cache/CacheManager.js.map +1 -0
  238. package/static/browser/ldap-user-editor/components/MoveUserModal.js +302 -0
  239. package/static/browser/ldap-user-editor/components/MoveUserModal.js.map +1 -0
  240. package/static/browser/ldap-user-editor/components/PointerField.js +152 -0
  241. package/static/browser/ldap-user-editor/components/PointerField.js.map +1 -0
  242. package/static/browser/ldap-user-editor/components/UserEditor.js +608 -0
  243. package/static/browser/ldap-user-editor/components/UserEditor.js.map +1 -0
  244. package/static/browser/ldap-user-editor/components/UserList.js +181 -0
  245. package/static/browser/ldap-user-editor/components/UserList.js.map +1 -0
  246. package/static/browser/ldap-user-editor/components/UserTree.js +164 -0
  247. package/static/browser/ldap-user-editor/components/UserTree.js.map +1 -0
  248. package/static/browser/ldap-user-editor/index.js +2 -0
  249. package/static/browser/ldap-user-editor/index.js.map +1 -0
  250. package/static/browser/ldap-user-editor/types.js +2 -0
  251. package/static/browser/ldap-user-editor/types.js.map +1 -0
  252. package/static/browser/ldap-user-editor.css +2 -0
  253. package/static/browser/ldap-user-editor.css.map +1 -0
  254. package/static/browser/ldap-user-editor.esm.js +1897 -0
  255. package/static/browser/ldap-user-editor.esm.js.map +1 -0
  256. package/static/browser/ldap-user-editor.js +1905 -0
  257. package/static/browser/ldap-user-editor.js.map +1 -0
  258. package/static/browser/ldap-user-editor.min.js +2 -0
  259. package/static/browser/ldap-user-editor.min.js.map +1 -0
  260. package/static/browser/shared/components/Modal.js +121 -0
  261. package/static/browser/shared/components/Modal.js.map +1 -0
  262. package/static/browser/shared/components/StatusMessage.js +119 -0
  263. package/static/browser/shared/components/StatusMessage.js.map +1 -0
  264. package/static/browser/shared/index.js +7 -0
  265. package/static/browser/shared/index.js.map +1 -0
  266. package/static/browser/shared/types/index.js +37 -0
  267. package/static/browser/shared/types/index.js.map +1 -0
  268. package/static/browser/shared/utils/dom.js +78 -0
  269. package/static/browser/shared/utils/dom.js.map +1 -0
  270. package/static/browser/shared/utils/form.js +234 -0
  271. package/static/browser/shared/utils/form.js.map +1 -0
  272. package/static/browser/shared/utils/schema.js +121 -0
  273. package/static/browser/shared/utils/schema.js.map +1 -0
  274. package/static/browser/shared.esm.js +694 -0
  275. package/static/browser/shared.esm.js.map +1 -0
  276. package/static/browser/shared.js +723 -0
  277. package/static/browser/shared.js.map +1 -0
  278. package/static/browser/shared.min.js +2 -0
  279. package/static/browser/shared.min.js.map +1 -0
  280. package/static/schemas/ad/computers.json +92 -0
  281. package/static/schemas/ad/groups.json +55 -0
  282. package/static/schemas/ad/organizations.json +66 -0
  283. package/static/schemas/ad/users.json +116 -0
  284. package/static/schemas/standard/devices.json +72 -0
  285. package/static/schemas/standard/groups.json +54 -0
  286. package/static/schemas/standard/organizations.json +49 -0
  287. package/static/schemas/standard/users.json +86 -0
  288. package/static/schemas/twake/groups.json +75 -0
  289. package/static/schemas/twake/nomenclature/twakeAccountStatus.json +31 -0
  290. package/static/schemas/twake/nomenclature/twakeDeliveryMode.json +31 -0
  291. package/static/schemas/twake/nomenclature/twakeListType.json +31 -0
  292. package/static/schemas/twake/nomenclature/twakeMailboxType.json +31 -0
  293. package/static/schemas/twake/nomenclature/twakeTitle.json +31 -0
  294. package/static/schemas/twake/organizations.json +52 -0
  295. package/static/schemas/twake/positions.json +32 -0
  296. package/static/schemas/twake/users.json +112 -0
@@ -0,0 +1,723 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MiniDmShared = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * DOM utility functions
9
+ * @module browser/shared/utils/dom
10
+ */
11
+ /**
12
+ * Escape HTML special characters to prevent XSS attacks
13
+ * Reference: https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html
14
+ */
15
+ function escapeHtml(text) {
16
+ if (text == null)
17
+ return '';
18
+ const map = {
19
+ '&': '&',
20
+ '<': '&lt;',
21
+ '>': '&gt;',
22
+ '"': '&quot;',
23
+ "'": '&#x27;',
24
+ '/': '&#x2F;',
25
+ };
26
+ return String(text).replace(/[&<>"'/]/g, m => map[m]);
27
+ }
28
+ /**
29
+ * Convert camelCase or snake_case to Title Case
30
+ */
31
+ function toTitleCase(text) {
32
+ const label = text.replace(/([A-Z])/g, ' $1').replace(/_/g, ' ');
33
+ return label.charAt(0).toUpperCase() + label.slice(1);
34
+ }
35
+ /**
36
+ * Create an HTML element with attributes and children
37
+ */
38
+ function createElement(tag, attributes = {}, children = []) {
39
+ const element = document.createElement(tag);
40
+ for (const [key, value] of Object.entries(attributes)) {
41
+ if (key === 'className') {
42
+ element.className = value;
43
+ }
44
+ else {
45
+ element.setAttribute(key, value);
46
+ }
47
+ }
48
+ for (const child of children) {
49
+ if (typeof child === 'string') {
50
+ element.appendChild(document.createTextNode(child));
51
+ }
52
+ else {
53
+ element.appendChild(child);
54
+ }
55
+ }
56
+ return element;
57
+ }
58
+ /**
59
+ * Set innerHTML safely (assumes content has been properly escaped)
60
+ */
61
+ function setInnerHTML(element, html) {
62
+ element.innerHTML = html;
63
+ }
64
+ /**
65
+ * Get element by ID with type safety
66
+ */
67
+ function getElementByIdSafe(id) {
68
+ return document.getElementById(id);
69
+ }
70
+ /**
71
+ * Query selector with type safety
72
+ */
73
+ function querySelectorSafe(selector, parent = document) {
74
+ return parent.querySelector(selector);
75
+ }
76
+ /**
77
+ * Query selector all with type safety
78
+ */
79
+ function querySelectorAllSafe(selector, parent = document) {
80
+ return parent.querySelectorAll(selector);
81
+ }
82
+
83
+ /**
84
+ * Form utility functions
85
+ * @module browser/shared/utils/form
86
+ */
87
+ /**
88
+ * Get user-friendly field label from field name
89
+ */
90
+ function getFieldLabel(fieldName, attribute, customLabels) {
91
+ // Check custom labels first
92
+ if (customLabels && customLabels[fieldName]) {
93
+ return customLabels[fieldName];
94
+ }
95
+ // Common label mappings
96
+ const labelMap = {
97
+ ou: 'Unit Name',
98
+ l: 'Location',
99
+ telephoneNumber: 'Phone Number',
100
+ facsimileTelephoneNumber: 'Fax Number',
101
+ postalAddress: 'Postal Address',
102
+ twakeDepartmentPath: 'Department Path',
103
+ twakeLocalAdminLink: 'Local Administrators',
104
+ twakeMailboxType: 'Mailbox Type',
105
+ };
106
+ if (labelMap[fieldName]) {
107
+ return labelMap[fieldName];
108
+ }
109
+ // Convert to title case
110
+ return toTitleCase(fieldName);
111
+ }
112
+ /**
113
+ * Generate HTML for a form field based on schema attribute
114
+ */
115
+ async function generateFormField(fieldName, attribute, options) {
116
+ const label = getFieldLabel(fieldName, attribute, options?.customLabels);
117
+ const required = attribute.required ? 'required' : '';
118
+ const labelClass = attribute.required ? 'required' : '';
119
+ let fieldHtml = '';
120
+ if (attribute.type === 'pointer') {
121
+ // Pointer field - load options and display select
122
+ const branch = attribute.branch?.[0];
123
+ if (branch && options?.pointerOptionsLoader) {
124
+ const pointerOptions = await options.pointerOptionsLoader(branch);
125
+ fieldHtml = `
126
+ <div class="form-group">
127
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
128
+ <select id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" class="form-select" ${required}>
129
+ <option value="">Select...</option>
130
+ ${pointerOptions
131
+ .map(opt => `
132
+ <option value="${escapeHtml(opt.dn)}">${escapeHtml(opt.label)}</option>
133
+ `)
134
+ .join('')}
135
+ </select>
136
+ ${fieldName === 'twakeMailboxType' ? '<div class="help-text">Select "mailingList" or "teamMailbox" to enable mail functionality</div>' : ''}
137
+ </div>
138
+ `;
139
+ }
140
+ else {
141
+ // Fallback if no branch defined
142
+ fieldHtml = `
143
+ <div class="form-group">
144
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
145
+ <input type="text" id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" ${required} />
146
+ <div class="help-text">Enter DN (Distinguished Name)</div>
147
+ </div>
148
+ `;
149
+ }
150
+ }
151
+ else if (attribute.type === 'array' &&
152
+ attribute.items?.type === 'pointer') {
153
+ // Array of pointers - will be handled dynamically
154
+ const branch = attribute.items.branch?.[0];
155
+ if (branch) {
156
+ fieldHtml = `
157
+ <div class="form-group">
158
+ <label class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
159
+ <div class="array-field pointer-array-field" data-field="${escapeHtml(fieldName)}" data-branch="${escapeHtml(branch)}">
160
+ <button type="button" class="btn btn-secondary add-pointer-item" data-field="${escapeHtml(fieldName)}">
161
+ <span class="material-icons">add</span>
162
+ Add ${escapeHtml(label)}
163
+ </button>
164
+ </div>
165
+ <input type="hidden" name="${escapeHtml(fieldName)}" id="${escapeHtml(fieldName)}-hidden" value="" />
166
+ </div>
167
+ `;
168
+ }
169
+ else {
170
+ // Fallback
171
+ fieldHtml = `
172
+ <div class="form-group">
173
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
174
+ <textarea id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" ${required}></textarea>
175
+ <div class="help-text">Enter one DN per line</div>
176
+ </div>
177
+ `;
178
+ }
179
+ }
180
+ else if (attribute.type === 'array' && attribute.items?.type === 'string') {
181
+ // Array field - use textarea
182
+ fieldHtml = `
183
+ <div class="form-group">
184
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
185
+ <textarea id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" ${required}></textarea>
186
+ <div class="help-text">Enter one value per line</div>
187
+ </div>
188
+ `;
189
+ }
190
+ else if (attribute.type === 'number' || attribute.type === 'integer') {
191
+ // Number field
192
+ fieldHtml = `
193
+ <div class="form-group">
194
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
195
+ <input type="number" id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" ${required} />
196
+ </div>
197
+ `;
198
+ }
199
+ else if (attribute.type === 'string') {
200
+ // String field - use input with appropriate type
201
+ const type = fieldName.toLowerCase().includes('password') ||
202
+ fieldName.toLowerCase().includes('pwd')
203
+ ? 'password'
204
+ : fieldName.toLowerCase().includes('mail')
205
+ ? 'email'
206
+ : fieldName.toLowerCase().includes('phone') ||
207
+ fieldName.toLowerCase().includes('telephone')
208
+ ? 'tel'
209
+ : 'text';
210
+ fieldHtml = `
211
+ <div class="form-group">
212
+ <label for="${escapeHtml(fieldName)}" class="${escapeHtml(labelClass)}">${escapeHtml(label)}</label>
213
+ <input type="${escapeHtml(type)}" id="${escapeHtml(fieldName)}" name="${escapeHtml(fieldName)}" ${required} />
214
+ </div>
215
+ `;
216
+ }
217
+ return fieldHtml;
218
+ }
219
+ /**
220
+ * Process form data and convert types based on schema
221
+ */
222
+ function processFormData(formData, schema) {
223
+ const data = {};
224
+ // Collect form data
225
+ for (const [key, value] of formData) {
226
+ if (data[key]) {
227
+ // Multiple values for the same key - convert to array
228
+ if (!Array.isArray(data[key])) {
229
+ data[key] = [data[key]];
230
+ }
231
+ data[key].push(value);
232
+ }
233
+ else {
234
+ data[key] = value;
235
+ }
236
+ }
237
+ // Process special field types based on schema
238
+ for (const [fieldName, attribute] of Object.entries(schema)) {
239
+ if (!data[fieldName])
240
+ continue;
241
+ if (attribute.type === 'array' && typeof data[fieldName] === 'string') {
242
+ // Split by newlines and filter empty lines
243
+ data[fieldName] = data[fieldName]
244
+ .split('\n')
245
+ .map(line => line.trim())
246
+ .filter(line => line.length > 0);
247
+ }
248
+ else if ((attribute.type === 'number' || attribute.type === 'integer') &&
249
+ typeof data[fieldName] === 'string') {
250
+ // Convert to number
251
+ data[fieldName] =
252
+ attribute.type === 'integer'
253
+ ? parseInt(data[fieldName], 10)
254
+ : parseFloat(data[fieldName]);
255
+ }
256
+ }
257
+ // Clean up: remove empty strings, null values, and empty arrays
258
+ const cleanedData = {};
259
+ for (const [key, value] of Object.entries(data)) {
260
+ if (value === '' || value === null || value === undefined) {
261
+ continue;
262
+ }
263
+ if (Array.isArray(value) && value.length === 0) {
264
+ continue;
265
+ }
266
+ cleanedData[key] = value;
267
+ }
268
+ return cleanedData;
269
+ }
270
+ /**
271
+ * Collect values from pointer array fields
272
+ */
273
+ function collectPointerArrayValues(container) {
274
+ const values = {};
275
+ const pointerArrayFields = container.querySelectorAll('.pointer-array-field');
276
+ pointerArrayFields.forEach(field => {
277
+ const fieldName = field.getAttribute('data-field');
278
+ if (!fieldName)
279
+ return;
280
+ const selects = field.querySelectorAll('.pointer-array-select');
281
+ const fieldValues = Array.from(selects)
282
+ .map(select => select.value)
283
+ .filter(val => val); // Remove empty values
284
+ if (fieldValues.length > 0) {
285
+ values[fieldName] = fieldValues;
286
+ }
287
+ });
288
+ return values;
289
+ }
290
+ /**
291
+ * Group schema fields by category
292
+ */
293
+ function groupSchemaFields(schema, categorizer) {
294
+ const groups = new Map();
295
+ for (const [fieldName, attribute] of Object.entries(schema)) {
296
+ if (attribute.fixed)
297
+ continue;
298
+ if (fieldName === 'objectClass')
299
+ continue;
300
+ const category = categorizer
301
+ ? categorizer(fieldName, attribute)
302
+ : attribute.group || 'default';
303
+ if (category === null)
304
+ continue; // Skip this field
305
+ if (!groups.has(category)) {
306
+ groups.set(category, []);
307
+ }
308
+ groups.get(category).push([fieldName, attribute]);
309
+ }
310
+ return groups;
311
+ }
312
+
313
+ /**
314
+ * Schema utility functions
315
+ * @module browser/shared/utils/schema
316
+ */
317
+ /**
318
+ * Cache for pointer options to avoid repeated API calls
319
+ */
320
+ const pointerOptionsCache = new Map();
321
+ /**
322
+ * Load pointer options from API
323
+ */
324
+ async function loadPointerOptions(branch, apiLoader, useCache = true) {
325
+ if (useCache && pointerOptionsCache.has(branch)) {
326
+ return pointerOptionsCache.get(branch);
327
+ }
328
+ try {
329
+ const options = await apiLoader(branch);
330
+ if (useCache) {
331
+ pointerOptionsCache.set(branch, options);
332
+ }
333
+ return options;
334
+ }
335
+ catch (error) {
336
+ console.error('Failed to load pointer options for branch:', branch, error);
337
+ return [];
338
+ }
339
+ }
340
+ /**
341
+ * Clear pointer options cache
342
+ */
343
+ function clearPointerOptionsCache() {
344
+ pointerOptionsCache.clear();
345
+ }
346
+ /**
347
+ * Replace placeholders in schema branches
348
+ */
349
+ function replacePlaceholders(value, replacements) {
350
+ const replace = (str) => {
351
+ let result = str;
352
+ for (const [key, val] of Object.entries(replacements)) {
353
+ result = result.replace(new RegExp(key, 'g'), val);
354
+ }
355
+ return result;
356
+ };
357
+ if (Array.isArray(value)) {
358
+ return value.map(replace);
359
+ }
360
+ return replace(value);
361
+ }
362
+ /**
363
+ * Replace placeholders in schema attributes
364
+ */
365
+ function replaceSchemaPlaceholders(schema, replacements) {
366
+ const processValue = (value) => {
367
+ if (typeof value === 'string') {
368
+ return replacePlaceholders(value, replacements);
369
+ }
370
+ if (Array.isArray(value)) {
371
+ return value.map(processValue);
372
+ }
373
+ if (value && typeof value === 'object') {
374
+ return processObject(value);
375
+ }
376
+ return value;
377
+ };
378
+ const processObject = (obj) => {
379
+ const result = {};
380
+ for (const [key, value] of Object.entries(obj)) {
381
+ result[key] = processValue(value);
382
+ }
383
+ return result;
384
+ };
385
+ return processObject(schema);
386
+ }
387
+ /**
388
+ * Fetch organization path from API
389
+ */
390
+ async function getOrganizationPath(orgDn, apiBaseUrl) {
391
+ try {
392
+ const response = await fetch(`${apiBaseUrl}/api/v1/ldap/organizations/${encodeURIComponent(orgDn)}`);
393
+ if (!response.ok) {
394
+ console.error('Failed to fetch organization:', response.status);
395
+ return orgDn;
396
+ }
397
+ const org = await response.json();
398
+ // Use twakeDepartmentPath if available (Twake schema)
399
+ if (org.twakeDepartmentPath) {
400
+ const pathValue = Array.isArray(org.twakeDepartmentPath)
401
+ ? org.twakeDepartmentPath[0]
402
+ : org.twakeDepartmentPath;
403
+ return pathValue;
404
+ }
405
+ // Fallback to ou name for non-Twake schemas
406
+ if (org.ou) {
407
+ const ouValue = Array.isArray(org.ou) ? org.ou[0] : org.ou;
408
+ return ouValue;
409
+ }
410
+ // Last resort: use DN
411
+ return orgDn;
412
+ }
413
+ catch (error) {
414
+ console.error('Failed to get organization info:', error);
415
+ return orgDn;
416
+ }
417
+ }
418
+ /**
419
+ * Load schema from URL or object
420
+ */
421
+ async function loadSchema(schemaSource) {
422
+ if (typeof schemaSource === 'string') {
423
+ const response = await fetch(schemaSource);
424
+ if (!response.ok) {
425
+ throw new Error(`Failed to load schema from ${schemaSource}`);
426
+ }
427
+ return (await response.json());
428
+ }
429
+ return schemaSource;
430
+ }
431
+
432
+ /**
433
+ * Reusable Modal component
434
+ * @module browser/shared/components/Modal
435
+ */
436
+ class Modal {
437
+ constructor(options) {
438
+ this.overlay = null;
439
+ this.options = options;
440
+ this.overlay = getElementByIdSafe(options.id);
441
+ if (!this.overlay) {
442
+ throw new Error(`Modal overlay with id "${options.id}" not found`);
443
+ }
444
+ this.attachEventListeners();
445
+ }
446
+ attachEventListeners() {
447
+ if (!this.overlay)
448
+ return;
449
+ // Close button
450
+ const closeBtn = this.overlay.querySelector('.close-button');
451
+ if (closeBtn) {
452
+ closeBtn.addEventListener('click', () => this.close());
453
+ }
454
+ // Cancel button
455
+ const cancelBtn = this.overlay.querySelector('[data-modal-cancel]');
456
+ if (cancelBtn) {
457
+ cancelBtn.addEventListener('click', () => this.close());
458
+ }
459
+ // Click outside to close
460
+ this.overlay.addEventListener('click', e => {
461
+ if (e.target === this.overlay) {
462
+ this.close();
463
+ }
464
+ });
465
+ // Escape key to close
466
+ document.addEventListener('keydown', e => {
467
+ if (e.key === 'Escape' && this.isOpen()) {
468
+ this.close();
469
+ }
470
+ });
471
+ }
472
+ open() {
473
+ if (this.overlay) {
474
+ this.overlay.classList.add('active');
475
+ document.body.style.overflow = 'hidden'; // Prevent background scroll
476
+ }
477
+ }
478
+ close() {
479
+ if (this.overlay) {
480
+ this.overlay.classList.remove('active');
481
+ document.body.style.overflow = ''; // Restore scroll
482
+ if (this.options.onClose) {
483
+ this.options.onClose();
484
+ }
485
+ }
486
+ }
487
+ isOpen() {
488
+ return this.overlay?.classList.contains('active') || false;
489
+ }
490
+ getFormElement() {
491
+ return this.overlay?.querySelector('form') || null;
492
+ }
493
+ resetForm() {
494
+ const form = this.getFormElement();
495
+ if (form) {
496
+ form.reset();
497
+ }
498
+ }
499
+ setContent(html) {
500
+ const contentEl = this.overlay?.querySelector('[data-modal-content]');
501
+ if (contentEl) {
502
+ contentEl.innerHTML = html;
503
+ }
504
+ }
505
+ setTitle(title) {
506
+ const titleEl = this.overlay?.querySelector('.modal-header h2');
507
+ if (titleEl) {
508
+ titleEl.textContent = title;
509
+ }
510
+ }
511
+ /**
512
+ * Create modal HTML structure
513
+ */
514
+ static createModalHTML(options) {
515
+ const formId = options.formId || `${options.id}-form`;
516
+ const submitLabel = options.submitLabel || 'Submit';
517
+ return `
518
+ <div class="modal-overlay" id="${escapeHtml(options.id)}">
519
+ <div class="modal">
520
+ <div class="modal-header">
521
+ <h2>${escapeHtml(options.title)}</h2>
522
+ <button class="close-button" type="button">
523
+ <span class="material-icons">close</span>
524
+ </button>
525
+ </div>
526
+ <form id="${escapeHtml(formId)}">
527
+ <div data-modal-content></div>
528
+ <div class="modal-footer">
529
+ <button type="button" class="secondary" data-modal-cancel>
530
+ Cancel
531
+ </button>
532
+ <button type="submit" class="primary">${escapeHtml(submitLabel)}</button>
533
+ </div>
534
+ </form>
535
+ </div>
536
+ </div>
537
+ `;
538
+ }
539
+ /**
540
+ * Create and inject modal into DOM
541
+ */
542
+ static create(options) {
543
+ const html = Modal.createModalHTML(options);
544
+ document.body.insertAdjacentHTML('beforeend', html);
545
+ return new Modal(options);
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Status message component for displaying notifications
551
+ * @module browser/shared/components/StatusMessage
552
+ */
553
+ class StatusMessage {
554
+ constructor(options) {
555
+ this.container = null;
556
+ this.timeoutId = null;
557
+ this.options = {
558
+ duration: 5000,
559
+ dismissible: true,
560
+ ...options,
561
+ };
562
+ this.container = getElementByIdSafe(options.containerId);
563
+ if (!this.container) {
564
+ throw new Error(`Status container with id "${options.containerId}" not found`);
565
+ }
566
+ }
567
+ /**
568
+ * Show a status message
569
+ */
570
+ show(message, type = 'info') {
571
+ if (!this.container)
572
+ return;
573
+ // Clear any existing timeout
574
+ if (this.timeoutId !== null) {
575
+ window.clearTimeout(this.timeoutId);
576
+ this.timeoutId = null;
577
+ }
578
+ const iconMap = {
579
+ error: 'error_outline',
580
+ success: 'check_circle',
581
+ info: 'info',
582
+ warning: 'warning',
583
+ };
584
+ const icon = iconMap[type] || 'info';
585
+ let html = `
586
+ <div class="status-message ${escapeHtml(type)}">
587
+ <span class="material-icons">${icon}</span>
588
+ <span class="status-message-text">${escapeHtml(message)}</span>
589
+ `;
590
+ if (this.options.dismissible) {
591
+ html += `
592
+ <button class="status-message-close" type="button" aria-label="Close">
593
+ <span class="material-icons">close</span>
594
+ </button>
595
+ `;
596
+ }
597
+ html += '</div>';
598
+ this.container.innerHTML = html;
599
+ // Attach close button handler
600
+ if (this.options.dismissible) {
601
+ const closeBtn = this.container.querySelector('.status-message-close');
602
+ if (closeBtn) {
603
+ closeBtn.addEventListener('click', () => this.hide());
604
+ }
605
+ }
606
+ // Auto-hide after duration
607
+ if (this.options.duration && this.options.duration > 0) {
608
+ this.timeoutId = window.setTimeout(() => {
609
+ this.hide();
610
+ }, this.options.duration);
611
+ }
612
+ }
613
+ /**
614
+ * Show error message
615
+ */
616
+ error(message) {
617
+ this.show(message, 'error');
618
+ }
619
+ /**
620
+ * Show success message
621
+ */
622
+ success(message) {
623
+ this.show(message, 'success');
624
+ }
625
+ /**
626
+ * Show info message
627
+ */
628
+ info(message) {
629
+ this.show(message, 'info');
630
+ }
631
+ /**
632
+ * Show warning message
633
+ */
634
+ warning(message) {
635
+ this.show(message, 'warning');
636
+ }
637
+ /**
638
+ * Hide the status message
639
+ */
640
+ hide() {
641
+ if (this.container) {
642
+ this.container.innerHTML = '';
643
+ }
644
+ if (this.timeoutId !== null) {
645
+ window.clearTimeout(this.timeoutId);
646
+ this.timeoutId = null;
647
+ }
648
+ }
649
+ /**
650
+ * Get the container element
651
+ */
652
+ getContainer() {
653
+ return this.container;
654
+ }
655
+ }
656
+ /**
657
+ * Simple functional API for showing status messages
658
+ */
659
+ function showStatus(containerId, message, type = 'info', duration = 5000) {
660
+ const statusMessage = new StatusMessage({ containerId, duration });
661
+ statusMessage.show(message, type);
662
+ }
663
+
664
+ /**
665
+ * Shared TypeScript types for browser components
666
+ * @module browser/shared/types
667
+ */
668
+ const THEMES = {
669
+ purple: {
670
+ name: 'Purple',
671
+ primaryColor: '#6200ee',
672
+ primaryColorDark: '#3700b3',
673
+ gradientStart: '#667eea',
674
+ gradientEnd: '#764ba2',
675
+ },
676
+ blue: {
677
+ name: 'Blue',
678
+ primaryColor: '#185a9d',
679
+ primaryColorDark: '#0d3a6b',
680
+ gradientStart: '#43cea2',
681
+ gradientEnd: '#185a9d',
682
+ },
683
+ pink: {
684
+ name: 'Pink',
685
+ primaryColor: '#f5576c',
686
+ primaryColorDark: '#d43d50',
687
+ gradientStart: '#f093fb',
688
+ gradientEnd: '#f5576c',
689
+ },
690
+ green: {
691
+ name: 'Green',
692
+ primaryColor: '#00c853',
693
+ primaryColorDark: '#009624',
694
+ gradientStart: '#56ab2f',
695
+ gradientEnd: '#a8e063',
696
+ },
697
+ };
698
+
699
+ exports.Modal = Modal;
700
+ exports.StatusMessage = StatusMessage;
701
+ exports.THEMES = THEMES;
702
+ exports.clearPointerOptionsCache = clearPointerOptionsCache;
703
+ exports.collectPointerArrayValues = collectPointerArrayValues;
704
+ exports.createElement = createElement;
705
+ exports.escapeHtml = escapeHtml;
706
+ exports.generateFormField = generateFormField;
707
+ exports.getElementByIdSafe = getElementByIdSafe;
708
+ exports.getFieldLabel = getFieldLabel;
709
+ exports.getOrganizationPath = getOrganizationPath;
710
+ exports.groupSchemaFields = groupSchemaFields;
711
+ exports.loadPointerOptions = loadPointerOptions;
712
+ exports.loadSchema = loadSchema;
713
+ exports.processFormData = processFormData;
714
+ exports.querySelectorAllSafe = querySelectorAllSafe;
715
+ exports.querySelectorSafe = querySelectorSafe;
716
+ exports.replacePlaceholders = replacePlaceholders;
717
+ exports.replaceSchemaPlaceholders = replaceSchemaPlaceholders;
718
+ exports.setInnerHTML = setInnerHTML;
719
+ exports.showStatus = showStatus;
720
+ exports.toTitleCase = toTitleCase;
721
+
722
+ }));
723
+ //# sourceMappingURL=shared.js.map