adminizer 4.6.0 → 4.7.0-build.221

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 (335) hide show
  1. package/Readme.md +12 -0
  2. package/assets/RelationDialogStack-CnHFOYyR.css +1 -0
  3. package/assets/RelationDialogStack-DI2bZxQX.js +20 -0
  4. package/assets/add-4213XScp.js +1 -0
  5. package/assets/add-group--F1XxfJ1.js +1 -0
  6. package/assets/add-group-form-DKRXC2n-.js +1 -0
  7. package/assets/add-user-b9HfMq7z.js +1 -0
  8. package/assets/add-user-form-UXAToWQd.js +1 -0
  9. package/assets/app-Clx8f5hd.css +1 -0
  10. package/assets/app-layout-C02ja4OI.js +1 -0
  11. package/assets/app-shell-D8wtkECO.js +1 -0
  12. package/assets/app-sidebar-BR5_zwxj.js +1 -0
  13. package/assets/app-sidebar-header-BZbIBQjq.js +1 -0
  14. package/assets/app.js +59 -7990
  15. package/assets/breadcrumbs-CODaqVkB.js +1 -0
  16. package/assets/catalog-6ZZjWdFs.js +6 -0
  17. package/assets/dashboard-CftAdKiH.js +3 -0
  18. package/assets/date-picker-DSOkNiNo.js +1 -0
  19. package/assets/del-modal-Cd4M7af8.js +1 -0
  20. package/assets/dynamic-controls-BsrJhPDY.js +1 -0
  21. package/assets/geo-json-CzR5JBXL.js +1 -0
  22. package/assets/handsontable-BI98OF5R.js +336 -0
  23. package/assets/history-DLHSU7Ak.js +1 -0
  24. package/assets/home-NcQ7nnU0.js +2 -0
  25. package/assets/icon-C2JNaLxH.js +1 -0
  26. package/assets/init-user-D2HSyXup.js +1 -0
  27. package/assets/input-error-CH2caTtO.js +1 -0
  28. package/assets/jsoneditor-DVNQmA6G.js +3869 -0
  29. package/assets/list-CFU0-TgN.js +4 -0
  30. package/assets/login-DFSLEO17.js +1 -0
  31. package/assets/manifest.json +246 -273
  32. package/assets/material-icon-Bx9pGQiQ.js +1 -0
  33. package/assets/media-manager-WcKe1EvD.js +6 -0
  34. package/assets/module-CT7PC6pc.js +1 -0
  35. package/assets/monaco-Bl4zdWCn.js +11 -0
  36. package/assets/nav-footer-BiSQkPt4.js +1 -0
  37. package/assets/nav-main-rTH0PfDw.js +1 -0
  38. package/assets/nav-user-Bj6cWs0a.js +1 -0
  39. package/assets/notification-Bi-PX87D.js +20 -0
  40. package/assets/pagination-render-AKJvTIRA.js +1 -0
  41. package/assets/register-BTP4uxsK.js +1 -0
  42. package/assets/ru-eW0WKkga.js +1 -0
  43. package/assets/theme-switcher-Dm8EOGzx.js +1 -0
  44. package/assets/toast-editor-DOg_gvSp.js +668 -0
  45. package/assets/user-filters-list-YUfR4XMI.js +1 -0
  46. package/assets/user-info-BgSbT02v.js +1 -0
  47. package/assets/user-menu-content-TQTXHIv6.js +1 -0
  48. package/assets/{vanilla-picker-l5rcX3cq.js → vanilla-picker-B3LgXoKV.js} +1 -7
  49. package/assets/welcome-vLwTu1R6.js +1 -0
  50. package/controllers/add.d.ts +1 -1
  51. package/controllers/add.js +20 -26
  52. package/controllers/addGroup.d.ts +1 -1
  53. package/controllers/addGroup.js +7 -15
  54. package/controllers/addUser.d.ts +1 -1
  55. package/controllers/addUser.js +10 -16
  56. package/controllers/catalog/Catalog.d.ts +1 -1
  57. package/controllers/catalog/Catalog.js +1 -10
  58. package/controllers/catalog/FrontendCatalogAdapter.d.ts +3 -3
  59. package/controllers/catalog/FrontendCatalogAdapter.js +0 -6
  60. package/controllers/catalog/FrontentCatalogAdapter.d.ts +3 -3
  61. package/controllers/catalog/FrontentCatalogAdapter.js +0 -4
  62. package/controllers/ckeditorUpload.js +2 -18
  63. package/controllers/dashboard.d.ts +1 -1
  64. package/controllers/dashboard.js +2 -5
  65. package/controllers/edit.js +24 -37
  66. package/controllers/editGroup.d.ts +1 -1
  67. package/controllers/editGroup.js +10 -21
  68. package/controllers/editUser.d.ts +1 -1
  69. package/controllers/editUser.js +11 -23
  70. package/controllers/exportData.d.ts +6 -0
  71. package/controllers/exportData.js +315 -0
  72. package/controllers/feed.d.ts +6 -0
  73. package/controllers/feed.js +73 -0
  74. package/controllers/feedback/feedbackController.d.ts +1 -1
  75. package/controllers/feedback/feedbackController.js +5 -7
  76. package/controllers/filter-fields/columns.d.ts +11 -0
  77. package/controllers/filter-fields/columns.js +106 -0
  78. package/controllers/filter-fields/filterFields.d.ts +10 -0
  79. package/controllers/filter-fields/filterFields.js +141 -0
  80. package/controllers/filter-fields/getAllUserFilters.d.ts +6 -0
  81. package/controllers/filter-fields/getAllUserFilters.js +115 -0
  82. package/controllers/filter-fields/groups.d.ts +5 -0
  83. package/controllers/filter-fields/groups.js +26 -0
  84. package/controllers/filter-fields/savedFilters.d.ts +25 -0
  85. package/controllers/filter-fields/savedFilters.js +317 -0
  86. package/controllers/getAllWidgets.d.ts +1 -1
  87. package/controllers/getAllWidgets.js +1 -9
  88. package/controllers/history-actions/HistoryController.js +6 -31
  89. package/controllers/initUser.js +6 -5
  90. package/controllers/inlineUpdate.d.ts +7 -0
  91. package/controllers/inlineUpdate.js +148 -0
  92. package/controllers/list.d.ts +1 -1
  93. package/controllers/list.js +383 -70
  94. package/controllers/listUserFilters.d.ts +5 -0
  95. package/controllers/listUserFilters.js +26 -0
  96. package/controllers/login.js +2 -2
  97. package/controllers/media-manager/mediaManagerApi.js +0 -9
  98. package/controllers/navigation/edit.js +3 -9
  99. package/controllers/notifications/NotificationController.d.ts +1 -1
  100. package/controllers/notifications/NotificationController.js +12 -36
  101. package/controllers/register.js +10 -9
  102. package/controllers/remove.js +10 -19
  103. package/controllers/timezones.d.ts +1 -1
  104. package/controllers/timezones.js +0 -6
  105. package/controllers/userApiKey.d.ts +7 -0
  106. package/controllers/userApiKey.js +36 -0
  107. package/controllers/view.js +14 -26
  108. package/controllers/welcome.d.ts +1 -1
  109. package/controllers/welcome.js +0 -4
  110. package/controllers/widgets/Action.d.ts +1 -1
  111. package/controllers/widgets/Action.js +1 -9
  112. package/controllers/widgets/Custom.d.ts +1 -1
  113. package/controllers/widgets/Custom.js +1 -9
  114. package/controllers/widgets/Info.d.ts +1 -1
  115. package/controllers/widgets/Info.js +1 -9
  116. package/controllers/widgets/filterInfo.d.ts +1 -0
  117. package/controllers/widgets/filterInfo.js +44 -0
  118. package/controllers/widgets/switch.d.ts +1 -1
  119. package/controllers/widgets/switch.js +1 -9
  120. package/controllers/widgetsDB.d.ts +1 -1
  121. package/controllers/widgetsDB.js +2 -8
  122. package/helpers/accessRightsHelper.d.ts +1 -1
  123. package/helpers/accessRightsHelper.js +5 -4
  124. package/helpers/apiKeyHelper.d.ts +5 -0
  125. package/helpers/apiKeyHelper.js +8 -0
  126. package/helpers/configHelper.js +12 -15
  127. package/helpers/controllerHelper.d.ts +14 -21
  128. package/helpers/controllerHelper.js +50 -83
  129. package/helpers/fieldsHelper.js +3 -3
  130. package/helpers/filterDatetimeHelper.d.ts +5 -0
  131. package/helpers/filterDatetimeHelper.js +84 -0
  132. package/helpers/inertiaActionsHelper.d.ts +2 -2
  133. package/helpers/inertiaActionsHelper.js +5 -4
  134. package/helpers/inertiaAddHelper.d.ts +3 -414
  135. package/helpers/inertiaAddHelper.js +39 -15
  136. package/helpers/inertiaGroupHelper.d.ts +2 -2
  137. package/helpers/inertiaGroupHelper.js +3 -3
  138. package/helpers/inertiaListHelper.d.ts +7 -3
  139. package/helpers/inertiaListHelper.js +26 -12
  140. package/helpers/inertiaMenuHelper.d.ts +1 -0
  141. package/helpers/inertiaMenuHelper.js +15 -3
  142. package/helpers/inertiaUserHelper.d.ts +3 -2
  143. package/helpers/inertiaUserHelper.js +7 -3
  144. package/helpers/menuHelper.d.ts +5 -2
  145. package/helpers/menuHelper.js +64 -12
  146. package/helpers/viteHelper.js +1 -2
  147. package/index.d.ts +6 -2
  148. package/index.js +6 -2
  149. package/interfaces/adminpanelConfig.d.ts +126 -39
  150. package/interfaces/internalModelAccess.d.ts +37 -0
  151. package/interfaces/internalModelAccess.js +1 -0
  152. package/interfaces/listQueryBuilder.d.ts +22 -0
  153. package/interfaces/listQueryBuilder.js +1 -0
  154. package/interfaces/queryCriteria.d.ts +54 -0
  155. package/interfaces/queryCriteria.js +1 -0
  156. package/interfaces/types.d.ts +1 -13
  157. package/lib/Adminizer.d.ts +4 -2
  158. package/lib/Adminizer.js +29 -10
  159. package/lib/DataAccessor.d.ts +8 -5
  160. package/lib/DataAccessor.js +89 -42
  161. package/lib/I18n.d.ts +5 -1
  162. package/lib/I18n.js +45 -19
  163. package/lib/MiddlewareManager.d.ts +8 -0
  164. package/lib/MiddlewareManager.js +53 -0
  165. package/lib/ai-assistant/OpenAiModelService.d.ts +3 -3
  166. package/lib/ai-assistant/OpenAiModelService.js +23 -24
  167. package/lib/catalog/Navigation.d.ts +1 -0
  168. package/lib/catalog/Navigation.js +12 -11
  169. package/lib/controls/jsoneditor/JsonEditor.d.ts +1 -2
  170. package/lib/controls/markdown/ToastUiEditor.d.ts +1 -2
  171. package/lib/feedback/FeedbackHandler.js +2 -2
  172. package/lib/filters/ConditionValidator.d.ts +107 -0
  173. package/lib/filters/ConditionValidator.js +483 -0
  174. package/lib/filters/CustomFilterHandler.d.ts +122 -0
  175. package/lib/filters/CustomFilterHandler.js +131 -0
  176. package/lib/filters/FilterCustomFieldHandler.d.ts +2 -0
  177. package/lib/filters/FilterCustomFieldHandler.js +2 -0
  178. package/lib/filters/FilterService.d.ts +82 -0
  179. package/lib/filters/FilterService.js +323 -0
  180. package/lib/filters/index.d.ts +6 -0
  181. package/lib/filters/index.js +4 -0
  182. package/lib/history-actions/AbstractHistoryAdapter.d.ts +5 -4
  183. package/lib/history-actions/AbstractHistoryAdapter.js +45 -30
  184. package/lib/history-actions/DefaultHistoryAdapter.d.ts +2 -0
  185. package/lib/history-actions/DefaultHistoryAdapter.js +12 -6
  186. package/lib/history-actions/HistoryHandler.js +1 -1
  187. package/lib/list-query-builder/ListQueryBuilder.d.ts +117 -0
  188. package/lib/list-query-builder/ListQueryBuilder.js +707 -0
  189. package/lib/media-manager/AbstractMediaManager.d.ts +9 -8
  190. package/lib/media-manager/DefaultMediaManager.d.ts +2 -0
  191. package/lib/media-manager/DefaultMediaManager.js +27 -15
  192. package/lib/media-manager/Items.d.ts +4 -1
  193. package/lib/media-manager/Items.js +62 -59
  194. package/lib/media-manager/MediaManagerHandler.js +1 -1
  195. package/lib/media-manager/helpers/MediaManagerHelper.d.ts +5 -1
  196. package/lib/media-manager/helpers/MediaManagerHelper.js +38 -4
  197. package/lib/model/AbstractModel.d.ts +33 -25
  198. package/lib/model/AbstractModel.js +54 -2
  199. package/lib/model/InternalModelAccessFactory.d.ts +18 -0
  200. package/lib/model/InternalModelAccessFactory.js +82 -0
  201. package/lib/model/ModelHandler.d.ts +6 -0
  202. package/lib/model/ModelHandler.js +14 -0
  203. package/lib/model/adapter/sequelize.d.ts +32 -10
  204. package/lib/model/adapter/sequelize.js +409 -62
  205. package/lib/model/adapter/typeorm.d.ts +62 -0
  206. package/lib/model/adapter/typeorm.js +777 -0
  207. package/lib/model/internalModelAccessToken.d.ts +1 -0
  208. package/lib/model/internalModelAccessToken.js +1 -0
  209. package/lib/model/internalModelRepository.d.ts +3 -0
  210. package/lib/model/internalModelRepository.js +4 -0
  211. package/lib/notifications/AbstractNotificationService.d.ts +3 -0
  212. package/lib/notifications/AbstractNotificationService.js +42 -36
  213. package/lib/notifications/GeneralNotificationService.js +37 -40
  214. package/lib/notifications/SystemNotificationService.js +33 -36
  215. package/lib/requestProcessor.js +0 -3
  216. package/lib/ui-i18n/getUiTranslations.d.ts +1 -0
  217. package/lib/ui-i18n/getUiTranslations.js +3 -0
  218. package/lib/ui-i18n/uiTranslationKeys.d.ts +6 -0
  219. package/lib/ui-i18n/uiTranslationKeys.js +268 -0
  220. package/lib/widgets/widgetHandler.d.ts +7 -2
  221. package/lib/widgets/widgetHandler.js +98 -18
  222. package/models/FilterAP.d.ts +116 -0
  223. package/models/FilterAP.js +68 -0
  224. package/models/FilterColumnAP.d.ts +32 -0
  225. package/models/FilterColumnAP.js +21 -0
  226. package/models/GroupAP.d.ts +1 -1
  227. package/models/HistoryActionsAP.d.ts +3 -3
  228. package/models/MediaManagerMetaAP.d.ts +1 -1
  229. package/models/NavigationAP.d.ts +1 -1
  230. package/models/UserAP.d.ts +6 -1
  231. package/models/UserAP.js +4 -0
  232. package/package.json +39 -32
  233. package/policies/authPolicies.d.ts +12 -0
  234. package/policies/authPolicies.js +104 -0
  235. package/policies/permissionResolvers.d.ts +12 -0
  236. package/policies/permissionResolvers.js +52 -0
  237. package/services/FeedService.d.ts +70 -0
  238. package/services/FeedService.js +334 -0
  239. package/system/Router.d.ts +1 -0
  240. package/system/Router.js +136 -59
  241. package/system/bindAccessRights.js +11 -30
  242. package/system/bindAuthorization.js +18 -18
  243. package/system/bindCors.js +16 -1
  244. package/system/bindCustomFilterHandlers.d.ts +2 -0
  245. package/system/bindCustomFilterHandlers.js +4 -0
  246. package/system/bindInertia.js +18 -61
  247. package/system/bindReqFunctions.js +10 -2
  248. package/system/bindTranslations.js +7 -3
  249. package/system/buildInternalModelAccess.d.ts +4 -0
  250. package/system/buildInternalModelAccess.js +59 -0
  251. package/system/defaults.js +18 -14
  252. package/system/routePolicies.d.ts +2 -0
  253. package/system/routePolicies.js +29 -0
  254. package/translations/en.json +151 -39
  255. package/translations/ru.json +211 -64
  256. package/ui/components/handsontable.js +13 -27
  257. package/ui/components/ui/dialog-stack.js +1 -3
  258. package/ui/components/ui/popover.js +1 -1
  259. package/ui/components/ui/sidebar.js +1 -1
  260. package/assets/RelationDialogStack-D9UVEF9s.js +0 -407
  261. package/assets/RelationDialogStack-DV8OITPR.css +0 -4
  262. package/assets/add-BlvzWQKF.js +0 -1
  263. package/assets/add-group-1Uoq9NWe.js +0 -1
  264. package/assets/add-group-form-B01gwDGu.js +0 -1
  265. package/assets/add-user-BQCAsaRy.js +0 -1
  266. package/assets/add-user-form-Cgwc9JkI.js +0 -1
  267. package/assets/app-DaOMy1nl.css +0 -72
  268. package/assets/app-layout-CAm60qoE.js +0 -1
  269. package/assets/app-shell-QWCtn9ye.js +0 -1
  270. package/assets/app-sidebar-CfaYbnSy.js +0 -1
  271. package/assets/app-sidebar-header-BsPFDhZ8.js +0 -1
  272. package/assets/breadcrumbs-CZZirDj8.js +0 -1
  273. package/assets/catalog-k5myk7fk.js +0 -6
  274. package/assets/dashboard-BkL9ybBw.js +0 -3
  275. package/assets/date-picker-B5AZ_7Q9.js +0 -1
  276. package/assets/del-modal-BoyXZloG.js +0 -1
  277. package/assets/dynamic-controls-k61T9W2P.js +0 -1
  278. package/assets/form-1WGY0YgG.js +0 -1
  279. package/assets/form-DJapG3qF.js +0 -1
  280. package/assets/geo-json-DsMUHo0l.js +0 -4
  281. package/assets/handsontable-PxYdjN8c.js +0 -298
  282. package/assets/history-CluyR-yJ.js +0 -1
  283. package/assets/home-Dug9zBzM.js +0 -2
  284. package/assets/icon-DfDLMG5f.js +0 -1
  285. package/assets/init-user-CF80MEnT.js +0 -1
  286. package/assets/input-error-DuuqFgZa.js +0 -1
  287. package/assets/jsoneditor-De1FvcYu.js +0 -3882
  288. package/assets/list-CuexshNt.js +0 -1
  289. package/assets/list-table-BsEWjTKY.js +0 -22
  290. package/assets/login-eDemYzN-.js +0 -1
  291. package/assets/material-icon-DMT8KdmE.js +0 -1
  292. package/assets/media-manager-DfYa_mT_.js +0 -14
  293. package/assets/module-Cd4Tm6uq.js +0 -1
  294. package/assets/monaco-BhBYtg3d.js +0 -11
  295. package/assets/nav-footer-D3olYxtz.js +0 -1
  296. package/assets/nav-main-BctqyzeV.js +0 -1
  297. package/assets/nav-user-Bn1Lt-BZ.js +0 -1
  298. package/assets/notification-D64qvni-.js +0 -27
  299. package/assets/pagination-render-DxD78ahJ.js +0 -1
  300. package/assets/register-349PwYbe.js +0 -1
  301. package/assets/theme-switcher-DfExsHW2.js +0 -1
  302. package/assets/toast-editor-ESK5iWPx.js +0 -845
  303. package/assets/user-info-DtBK5Kh8.js +0 -1
  304. package/assets/user-menu-content-0XYOCMaA.js +0 -1
  305. package/assets/welcome-PDp-gUei.js +0 -1
  306. package/controllers/form.d.ts +0 -1
  307. package/controllers/form.js +0 -86
  308. package/helpers/formHelper.d.ts +0 -6
  309. package/helpers/formHelper.js +0 -38
  310. package/helpers/inertiaFromHelper.d.ts +0 -11
  311. package/helpers/inertiaFromHelper.js +0 -98
  312. package/helpers/runtimeMode.d.ts +0 -1
  313. package/helpers/runtimeMode.js +0 -3
  314. package/lib/PolicyManager.d.ts +0 -8
  315. package/lib/PolicyManager.js +0 -53
  316. package/lib/datatable/NodeTable.d.ts +0 -49
  317. package/lib/datatable/NodeTable.js +0 -207
  318. package/lib/model/adapter/waterline.d.ts +0 -32
  319. package/lib/model/adapter/waterline.js +0 -180
  320. package/migrations/index.d.ts +0 -3
  321. package/migrations/index.js +0 -4
  322. package/migrations/knex/20250106000001_adminizer_init.d.ts +0 -8
  323. package/migrations/knex/20250106000001_adminizer_init.js +0 -164
  324. package/migrations/umzug/0001.d.ts +0 -7
  325. package/migrations/umzug/0001.js +0 -121
  326. package/migrations/umzugExports.d.ts +0 -2
  327. package/migrations/umzugExports.js +0 -9
  328. package/system/bindForms.d.ts +0 -2
  329. package/system/bindForms.js +0 -20
  330. /package/{policies → middlewares}/addMessages.d.ts +0 -0
  331. /package/{policies → middlewares}/addMessages.js +0 -0
  332. /package/{policies → middlewares}/checkAuth.d.ts +0 -0
  333. /package/{policies → middlewares}/checkAuth.js +0 -0
  334. /package/{policies → middlewares}/setLocale.d.ts +0 -0
  335. /package/{policies → middlewares}/setLocale.js +0 -0
package/lib/I18n.js CHANGED
@@ -6,7 +6,10 @@ export class I18n {
6
6
  devMode;
7
7
  static locales = {};
8
8
  defaultLocale;
9
+ defaultDirectory;
9
10
  directory;
11
+ customDirectory;
12
+ missingDirectory;
10
13
  extension;
11
14
  cookieName;
12
15
  sessionVarName;
@@ -16,15 +19,27 @@ export class I18n {
16
19
  static localeCache = {};
17
20
  static resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];
18
21
  constructor(options = {}) {
19
- this.devMode = process.env.NODE_ENV !== "production";
22
+ this.devMode = process.env.ADMINIZER_ENV === "dev";
20
23
  this.defaultLocale = options.defaultLocale || "en";
21
- this.directory = options.directory || path.join(import.meta.filename, '../../translations');
24
+ const runtimeDefaultTranslationsPath = path.resolve(import.meta.dirname, "../translations");
25
+ const sourceTranslationsPath = path.resolve(import.meta.dirname, "../../src/translations");
26
+ this.defaultDirectory = this.devMode
27
+ ? (fs.existsSync(sourceTranslationsPath) ? sourceTranslationsPath : runtimeDefaultTranslationsPath)
28
+ : runtimeDefaultTranslationsPath;
29
+ this.customDirectory = options.directory ? path.resolve(options.directory) : undefined;
30
+ this.missingDirectory = options.missingDirectory ? path.resolve(options.missingDirectory) : undefined;
31
+ this.directory = this.customDirectory || this.defaultDirectory;
22
32
  this.extension = options.extension || ".json";
23
33
  this.cookieName = options.cookieName || "lang";
24
34
  this.sessionVarName = options.sessionVarName || "locale";
25
35
  this.indent = options.indent || "\t";
26
36
  if (options.locales) {
27
- options.locales.forEach((locale) => this.readFile(locale));
37
+ options.locales.forEach((locale) => {
38
+ this.readFile(locale, this.defaultDirectory);
39
+ if (this.customDirectory && this.customDirectory !== this.defaultDirectory) {
40
+ this.readFile(locale, this.customDirectory);
41
+ }
42
+ });
28
43
  }
29
44
  this.setLocale(this.defaultLocale);
30
45
  }
@@ -75,16 +90,17 @@ export class I18n {
75
90
  const localeDictionary = I18n.locales[locale] || {};
76
91
  const translation = localeDictionary[singular];
77
92
  if (!translation && this.devMode) {
78
- I18n.locales[locale] = I18n.locales[locale] || {};
79
- I18n.locales[locale][singular] = plural ? { one: singular, other: plural } : singular;
80
- this.writeFile(locale);
93
+ this.writeMissingTranslation(locale, singular, plural);
81
94
  }
82
95
  return translation || (plural ? { one: singular, other: plural } : singular);
83
96
  }
84
- readFile(locale) {
85
- const file = this.locateFile(locale);
97
+ readFile(locale, directory = this.directory) {
98
+ const file = this.locateFile(locale, directory);
86
99
  if (!this.devMode && I18n.localeCache[file]) {
87
- I18n.locales[locale] = I18n.localeCache[file];
100
+ I18n.locales[locale] = {
101
+ ...(I18n.locales[locale] || {}),
102
+ ...I18n.localeCache[file]
103
+ };
88
104
  return;
89
105
  }
90
106
  try {
@@ -95,34 +111,44 @@ export class I18n {
95
111
  ...parsed
96
112
  };
97
113
  if (!this.devMode) {
98
- I18n.localeCache[file] = I18n.locales[locale];
114
+ I18n.localeCache[file] = parsed;
99
115
  }
100
116
  }
101
117
  catch (error) {
102
118
  if (this.devMode) {
103
119
  Adminizer.log.warn(`Failed to read locale file ${file}:`, error);
104
120
  }
105
- I18n.locales[locale] = {};
121
+ I18n.locales[locale] = I18n.locales[locale] || {};
106
122
  }
107
123
  }
108
- writeFile(locale) {
109
- if (!this.devMode)
124
+ locateFile(locale, directory = this.directory) {
125
+ return path.normalize(`${directory}/${locale}${this.extension}`);
126
+ }
127
+ writeMissingTranslation(locale, singular, plural) {
128
+ if (!this.missingDirectory)
110
129
  return;
111
- const file = this.locateFile(locale);
130
+ const file = this.locateFile(locale, this.missingDirectory);
112
131
  const tmpFile = `${file}.tmp`;
113
132
  const dir = path.dirname(file);
133
+ const value = plural ? { one: singular, other: plural } : singular;
114
134
  try {
115
135
  fs.mkdirSync(dir, { recursive: true });
116
- fs.writeFileSync(tmpFile, JSON.stringify(I18n.locales[locale], null, this.indent), "utf8");
136
+ let missingTranslations = {};
137
+ if (fs.existsSync(file)) {
138
+ const data = fs.readFileSync(file, "utf8");
139
+ missingTranslations = JSON.parse(data);
140
+ }
141
+ if (Object.prototype.hasOwnProperty.call(missingTranslations, singular)) {
142
+ return;
143
+ }
144
+ missingTranslations[singular] = value;
145
+ fs.writeFileSync(tmpFile, JSON.stringify(missingTranslations, null, this.indent), "utf8");
117
146
  fs.renameSync(tmpFile, file);
118
147
  }
119
148
  catch (error) {
120
- Adminizer.log.error(`Failed to write locale file ${file}:`, error);
149
+ Adminizer.log.error(`Failed to write missing translation file ${file}:`, error);
121
150
  }
122
151
  }
123
- locateFile(locale) {
124
- return path.normalize(`${this.directory}/${locale}${this.extension}`);
125
- }
126
152
  static appendLocale(locale, data) {
127
153
  I18n.locales[locale] = { ...I18n.locales[locale], ...data };
128
154
  }
@@ -0,0 +1,8 @@
1
+ import { Adminizer } from "./Adminizer";
2
+ declare class MiddlewareManager {
3
+ private readonly _adminizer;
4
+ constructor(adminizer: Adminizer);
5
+ loadMiddlewares(): Promise<void>;
6
+ bindMiddlewares(middleware: MiddlewareType[], action: MiddlewareType): MiddlewareType[];
7
+ }
8
+ export default MiddlewareManager;
@@ -0,0 +1,53 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { Adminizer } from "./Adminizer.js";
4
+ import { pathToFileURL } from "url";
5
+ class MiddlewareManager {
6
+ _adminizer;
7
+ constructor(adminizer) {
8
+ this._adminizer = adminizer;
9
+ }
10
+ async loadMiddlewares() {
11
+ try {
12
+ const middlewaresDirPath = path.join(import.meta.dirname, "../middlewares");
13
+ const middlewaresDir = fs.readdirSync(middlewaresDirPath);
14
+ for (const middlewareFile of middlewaresDir) {
15
+ if (path.extname(middlewareFile).toLowerCase() === ".js") {
16
+ const middlewarePath = path.join(middlewaresDirPath, middlewareFile);
17
+ const middleware = (await import(pathToFileURL(middlewarePath).href)).default;
18
+ if (typeof middleware === "function" &&
19
+ Array.isArray(this._adminizer.config.middlewares)) {
20
+ this._adminizer.config.middlewares.push(middleware);
21
+ }
22
+ else {
23
+ Adminizer.log.error(`Adminizer > Middleware ${middlewareFile} is not a function`);
24
+ }
25
+ }
26
+ }
27
+ Adminizer.log.info("Adminizer middlewares loaded");
28
+ }
29
+ catch (e) {
30
+ Adminizer.log.error("Adminizer > Could not load middlewares", e);
31
+ }
32
+ }
33
+ bindMiddlewares(middleware, action) {
34
+ const result = [];
35
+ const bindMiddleware = (middleware) => {
36
+ if (typeof middleware === "function") {
37
+ result.push(middleware);
38
+ }
39
+ else {
40
+ Adminizer.log.error("AdminPanel: Middleware format unknown: " + middleware);
41
+ }
42
+ };
43
+ if (Array.isArray(middleware)) {
44
+ middleware.forEach(bindMiddleware);
45
+ }
46
+ else {
47
+ bindMiddleware(middleware);
48
+ }
49
+ result.push(action);
50
+ return result;
51
+ }
52
+ }
53
+ export default MiddlewareManager;
@@ -3,9 +3,9 @@ import { AiAssistantMessage } from '../../interfaces/types';
3
3
  import { UserAP } from '../../models/UserAP';
4
4
  import { Adminizer } from '../Adminizer';
5
5
  import { ActionType } from '../../interfaces/adminpanelConfig';
6
- import { Entity } from '../../interfaces/types';
6
+ import { ModelResource } from '../../interfaces/types';
7
7
  import { DataAccessor } from '../DataAccessor';
8
- type DataAccessorFactory = (entity: Entity, user: UserAP, action: ActionType) => DataAccessor;
8
+ type DataAccessorFactory = (modelResource: ModelResource, user: UserAP, action: ActionType) => DataAccessor;
9
9
  export declare class OpenAiModelService extends AbstractAiModelService {
10
10
  private readonly createAccessor;
11
11
  constructor(adminizer: Adminizer, accessorFactory?: DataAccessorFactory);
@@ -13,7 +13,7 @@ export declare class OpenAiModelService extends AbstractAiModelService {
13
13
  private handleCreate;
14
14
  private parseInstruction;
15
15
  private usageMessage;
16
- private resolveEntity;
16
+ private resolveModelResource;
17
17
  private normalizeModelConfig;
18
18
  private userHasPermission;
19
19
  private getPermissionToken;
@@ -16,7 +16,7 @@ export class OpenAiModelService extends AbstractAiModelService {
16
16
  name: 'OpenAI fixture agent',
17
17
  description: 'Executes structured commands with DataAccessor using the current user permissions.',
18
18
  });
19
- this.createAccessor = accessorFactory ?? ((entity, user, action) => new DataAccessor(adminizer, user, entity, action));
19
+ this.createAccessor = accessorFactory ?? ((modelResource, user, action) => new DataAccessor(adminizer, user, modelResource, action));
20
20
  }
21
21
  async generateReply(prompt, _history, user) {
22
22
  const instruction = this.parseInstruction(prompt);
@@ -31,28 +31,28 @@ export class OpenAiModelService extends AbstractAiModelService {
31
31
  }
32
32
  }
33
33
  async handleCreate(instruction, user) {
34
- const entity = this.resolveEntity(instruction.entity);
35
- if (!entity || !entity.model) {
36
- return `Model "${instruction.entity}" is not available in this project.`;
34
+ const modelResource = this.resolveModelResource(instruction.modelResource);
35
+ if (!modelResource || !modelResource.model) {
36
+ return `Model "${instruction.modelResource}" is not available in this project.`;
37
37
  }
38
- if (!this.userHasPermission(entity, user, 'add')) {
39
- return `User "${user.login}" does not have permission to create ${entity.name} records.`;
38
+ if (!this.userHasPermission(modelResource, user, 'add')) {
39
+ return `User "${user.login}" does not have permission to create ${modelResource.name} records.`;
40
40
  }
41
41
  if (!instruction.payload || typeof instruction.payload !== 'object') {
42
42
  return 'The "create" action requires a "data" object with field values.';
43
43
  }
44
44
  try {
45
- const accessor = this.createAccessor(entity, user, 'add');
46
- const created = await entity.model.create(instruction.payload, accessor);
45
+ const accessor = this.createAccessor(modelResource, user, 'add');
46
+ const created = await modelResource.model.create(instruction.payload, accessor);
47
47
  const preview = JSON.stringify(created, null, 2);
48
- const recordId = this.extractPrimaryKey(created, entity);
48
+ const recordId = this.extractPrimaryKey(created, modelResource);
49
49
  const idMessage = recordId !== undefined ? ` (id: ${recordId})` : '';
50
- return `Record created in ${entity.name}${idMessage}:\n${preview}`;
50
+ return `Record created in ${modelResource.name}${idMessage}:\n${preview}`;
51
51
  }
52
52
  catch (error) {
53
53
  const message = error instanceof Error ? error.message : String(error);
54
54
  Adminizer.log.error('OpenAI agent failed to create record', error);
55
- return `Failed to create ${entity.name} record: ${message}`;
55
+ return `Failed to create ${modelResource.name} record: ${message}`;
56
56
  }
57
57
  }
58
58
  parseInstruction(prompt) {
@@ -69,15 +69,15 @@ export class OpenAiModelService extends AbstractAiModelService {
69
69
  if (!['create', 'list', 'update', 'delete'].includes(action)) {
70
70
  return null;
71
71
  }
72
- const entity = this.extractString(parsed, ['entity', 'model']);
73
- if (!entity) {
72
+ const modelResource = this.extractString(parsed, ['modelResource', 'model']);
73
+ if (!modelResource) {
74
74
  return null;
75
75
  }
76
76
  const payload = this.extractObject(parsed, ['data', 'payload', 'record']);
77
77
  const criteria = this.extractObject(parsed, ['criteria', 'where', 'filter']);
78
78
  return {
79
79
  action: action,
80
- entity,
80
+ modelResource,
81
81
  payload,
82
82
  criteria,
83
83
  };
@@ -93,14 +93,14 @@ export class OpenAiModelService extends AbstractAiModelService {
93
93
  '```json',
94
94
  '{',
95
95
  ' "action": "create",',
96
- ' "entity": "Example",',
96
+ ' "modelResource": "Example",',
97
97
  ' "data": { "title": "Hello from the agent" }',
98
98
  '}',
99
99
  '```',
100
100
  'The agent uses DataAccessor, so any field-level restrictions from your account are respected.',
101
101
  ].join('\n');
102
102
  }
103
- resolveEntity(modelName) {
103
+ resolveModelResource(modelName) {
104
104
  const models = this.adminizer.config.models;
105
105
  if (!models) {
106
106
  return null;
@@ -127,7 +127,6 @@ export class OpenAiModelService extends AbstractAiModelService {
127
127
  return {
128
128
  name: configName,
129
129
  uri: `${this.adminizer.config.routePrefix}/model/${configName}`,
130
- type: 'model',
131
130
  config: normalizedConfig,
132
131
  model,
133
132
  };
@@ -148,20 +147,20 @@ export class OpenAiModelService extends AbstractAiModelService {
148
147
  }
149
148
  return { ...baseConfig, ...config };
150
149
  }
151
- userHasPermission(entity, user, action) {
152
- const token = this.getPermissionToken(entity, action);
150
+ userHasPermission(modelResource, user, action) {
151
+ const token = this.getPermissionToken(modelResource, action);
153
152
  return this.adminizer.accessRightsHelper.hasPermission(token, user);
154
153
  }
155
- getPermissionToken(entity, action) {
154
+ getPermissionToken(modelResource, action) {
156
155
  const verb = ACTION_TOKENS[action];
157
- const modelName = entity.model?.modelname ?? entity.config?.model ?? entity.name;
158
- return `${verb}-${modelName}-${entity.type}`.toLowerCase();
156
+ const modelName = modelResource.model?.modelname ?? modelResource.config?.model ?? modelResource.name;
157
+ return `${verb}-${modelName}-model`.toLowerCase();
159
158
  }
160
- extractPrimaryKey(record, entity) {
159
+ extractPrimaryKey(record, modelResource) {
161
160
  if (!record) {
162
161
  return undefined;
163
162
  }
164
- const primaryKey = entity.model?.primaryKey ?? 'id';
163
+ const primaryKey = modelResource.model?.primaryKey ?? 'id';
165
164
  return record[primaryKey];
166
165
  }
167
166
  extractString(source, keys) {
@@ -14,6 +14,7 @@ export declare class StorageService {
14
14
  protected readonly adminizer: Adminizer;
15
15
  readonly ready: Promise<void>;
16
16
  constructor(adminizer: Adminizer, id: string, model: string);
17
+ private navigationModel;
17
18
  initModel(): Promise<void>;
18
19
  getId(): string;
19
20
  buildTree(): Promise<any>;
@@ -13,17 +13,18 @@ export class StorageService {
13
13
  this.model = model.toLowerCase();
14
14
  this.ready = this.initModel();
15
15
  }
16
+ navigationModel() {
17
+ return this.adminizer.modelHandler.internal("navigation").get(this.model);
18
+ }
16
19
  async initModel() {
17
- // Direct call by model adapter
18
- const navigation = await this.adminizer.modelHandler.model.get(this.model)["_findOne"]({ label: this.id });
20
+ const navigation = await this.navigationModel().findOne({ where: { label: this.id } });
19
21
  if (navigation) {
20
22
  Adminizer.log.info(`Found existing navigation: ${this.id}`);
21
23
  await this.populateFromTree(navigation.tree);
22
24
  }
23
25
  else {
24
26
  const newNavigation = { label: this.id, tree: [] };
25
- // Direct call by model adapter
26
- await this.adminizer.modelHandler.model.get(this.model)["_create"](newNavigation);
27
+ await this.navigationModel().create(newNavigation);
27
28
  Adminizer.log.info(`Created a new navigation: ${this.id}`);
28
29
  }
29
30
  }
@@ -99,8 +100,7 @@ export class StorageService {
99
100
  async saveToDB() {
100
101
  let tree = await this.buildTree();
101
102
  try {
102
- // Direct call by model adapter
103
- await this.adminizer.modelHandler.model.get(this.model)["_update"]({ label: this.id }, { tree: tree });
103
+ await this.navigationModel().update({ where: { label: this.id } }, { tree: tree });
104
104
  }
105
105
  catch (e) {
106
106
  console.log(e);
@@ -208,12 +208,14 @@ class NavigationItem extends AbstractItem {
208
208
  this.adminizer = adminizer;
209
209
  this.storageServices = storageServices;
210
210
  }
211
+ contentModel() {
212
+ return this.adminizer.modelHandler.internal("navigation").get(this.model);
213
+ }
211
214
  async create(data, catalogId) {
212
215
  let storage = this.storageServices.get(catalogId);
213
216
  let storageData = null;
214
217
  if (data._method === 'select') {
215
- // Direct call by model adapter
216
- let record = await this.adminizer.modelHandler.model.get(this.model)["_findOne"]({ id: data.record });
218
+ let record = await this.contentModel().findOne({ where: { id: data.record } });
217
219
  storageData = await this.dataPreparation({
218
220
  record: record,
219
221
  parentId: data.parentId,
@@ -275,13 +277,12 @@ class NavigationItem extends AbstractItem {
275
277
  return await storage.findElementById(itemId);
276
278
  }
277
279
  /**
278
- * @deprecated reason: migration for intertia
280
+ * @deprecated reason: transition to Inertia
279
281
  * // TODO: need passing custom React module
280
282
  */
281
283
  async getAddTemplate(req) {
282
284
  let type = 'model.link';
283
- // Direct call by model adapter
284
- let itemsDB = await this.adminizer.modelHandler.model.get(this.model)["_find"]({});
285
+ let itemsDB = await this.contentModel().find({});
285
286
  let items = itemsDB.map((item) => {
286
287
  return {
287
288
  id: item.id,
@@ -1,8 +1,7 @@
1
1
  import { AbstractControls, ControlType, Path, Config } from "../AbstractControls";
2
- import { EditorOptions } from "@toast-ui/editor/types/editor";
3
2
  import { Adminizer } from "../../Adminizer";
4
3
  export declare class JsonEditor extends AbstractControls {
5
- readonly config: Partial<EditorOptions>;
4
+ readonly config: Record<string, string | string[] | object | number | boolean>;
6
5
  readonly name: string;
7
6
  readonly path: Path;
8
7
  readonly type: ControlType;
@@ -1,8 +1,7 @@
1
1
  import { AbstractControls, ControlType, Path, Config } from "../AbstractControls";
2
- import { EditorOptions } from "@toast-ui/editor/types/editor";
3
2
  import { Adminizer } from "../../Adminizer";
4
3
  export declare class ToastUiEditor extends AbstractControls {
5
- readonly config: Partial<EditorOptions>;
4
+ readonly config: Record<string, string | string[] | object | number | boolean>;
6
5
  readonly name: string;
7
6
  readonly path: Path;
8
7
  readonly type: ControlType;
@@ -8,8 +8,8 @@ export class FeedbackHandler {
8
8
  }
9
9
  register(handler) {
10
10
  this.handler = handler;
11
- const policies = this.adminizer.config.policies ?? [];
12
- bindFeedbackController(this.adminizer, policies);
11
+ const middlewares = this.adminizer.config.middlewares ?? [];
12
+ bindFeedbackController(this.adminizer, middlewares);
13
13
  Adminizer.log.info('FeedbackHandler registered');
14
14
  }
15
15
  isRegistered() {
@@ -0,0 +1,107 @@
1
+ import { FilterCondition, FilterOperator } from '../../models/FilterAP';
2
+ /**
3
+ * Security event types for logging suspicious filter attempts
4
+ */
5
+ export type SecurityEventType = 'MAX_DEPTH_EXCEEDED' | 'TOO_MANY_CONDITIONS' | 'TOO_MANY_TOTAL_CONDITIONS' | 'DANGEROUS_SQL' | 'TOO_MANY_IN_VALUES' | 'STRING_TOO_LONG';
6
+ /**
7
+ * Security event details for logging
8
+ */
9
+ export interface SecurityEvent {
10
+ type: SecurityEventType;
11
+ conditionId: string;
12
+ details: string;
13
+ timestamp: Date;
14
+ value?: any;
15
+ }
16
+ /**
17
+ * Logger interface for security events
18
+ */
19
+ export interface SecurityLogger {
20
+ warn: (...args: any[]) => void;
21
+ }
22
+ /**
23
+ * Validation result
24
+ */
25
+ export interface ValidationResult {
26
+ valid: boolean;
27
+ errors: ValidationError[];
28
+ securityEvents?: SecurityEvent[];
29
+ }
30
+ /**
31
+ * Validation error
32
+ */
33
+ export interface ValidationError {
34
+ conditionId: string;
35
+ field?: string;
36
+ message: string;
37
+ code: string;
38
+ }
39
+ /**
40
+ * Field configuration for validation
41
+ */
42
+ export interface FieldConfig {
43
+ type: string;
44
+ required?: boolean;
45
+ maxLength?: number;
46
+ min?: number;
47
+ max?: number;
48
+ }
49
+ /**
50
+ * ConditionValidator - validates filter conditions
51
+ *
52
+ * Validates:
53
+ * - Field existence
54
+ * - Operator validity for field type
55
+ * - Value type and format
56
+ * - Security limits (depth, array size, etc.)
57
+ *
58
+ * Security logging:
59
+ * Set ConditionValidator.logger to enable logging of suspicious attempts
60
+ */
61
+ export declare class ConditionValidator {
62
+ private fieldsConfig;
63
+ private allowedFields?;
64
+ /**
65
+ * Static logger for security events
66
+ * Set this to enable logging of suspicious filter attempts
67
+ */
68
+ static logger: SecurityLogger | null;
69
+ /**
70
+ * Collected security events during validation
71
+ */
72
+ private securityEvents;
73
+ constructor(fieldsConfig: Record<string, FieldConfig>, allowedFields?: string[]);
74
+ /**
75
+ * Validate array of conditions
76
+ */
77
+ validate(conditions: FilterCondition[]): ValidationResult;
78
+ /**
79
+ * Log a security event (suspicious filter attempt)
80
+ */
81
+ private logSecurityEvent;
82
+ /**
83
+ * Validate single condition recursively
84
+ */
85
+ private validateCondition;
86
+ /**
87
+ * Check if operator is valid for field type
88
+ */
89
+ private isOperatorValidForType;
90
+ /**
91
+ * Validate value for operator and field type
92
+ */
93
+ private validateValue;
94
+ /**
95
+ * Validate raw SQL for obvious injection attempts
96
+ */
97
+ private validateRawSQL;
98
+ /**
99
+ * Get list of allowed operators for a field
100
+ */
101
+ getOperatorsForField(fieldName: string): FilterOperator[];
102
+ /**
103
+ * Get list of allowed operators for a field type
104
+ */
105
+ getOperatorsForType(fieldType: string): FilterOperator[];
106
+ }
107
+ export default ConditionValidator;