adminizer 5.0.0-build.8 → 5.1.0-build.24

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 (232) hide show
  1. package/assets/abnfDiagram-VCTEODGH-DFY3Pztx.js +1 -0
  2. package/assets/add-31tS-g4V.js +1 -0
  3. package/assets/add-group-Cf3zT7WE.js +1 -0
  4. package/assets/add-user-C62wOna-.js +1 -0
  5. package/assets/ai-assistant/agent.es.js +28464 -0
  6. package/assets/app-DPmI-MvN.css +1 -0
  7. package/assets/app-vdHbjOQX.js +138 -0
  8. package/assets/arc-DP4o1zz3.js +1 -0
  9. package/assets/architectureDiagram-5GKGNRK7-BjXW5Zu0.js +36 -0
  10. package/assets/asmcrypto-DZeQH0LC.js +1 -0
  11. package/assets/blockDiagram-I7D4REHJ-BUPnDwN0.js +129 -0
  12. package/assets/c4Diagram-7LVT6UL2-Cmb_dAhd.js +38 -0
  13. package/assets/{catalog-BEvJZYJP.js → catalog-C-y5rMaG.js} +3 -3
  14. package/assets/channel-CkJRUsq_.js +1 -0
  15. package/assets/chunk-2Q5K7J3B-CmS-dWwQ.js +1 -0
  16. package/assets/chunk-5VM5RSS4-Cqs2Ow64.js +15 -0
  17. package/assets/chunk-F27PBJKO-BoMCpJA1.js +1 -0
  18. package/assets/chunk-IMKFNOWR-DlDcPk1x.js +231 -0
  19. package/assets/chunk-JWPE2WC7-DzL_SU8s.js +1 -0
  20. package/assets/chunk-POPQ4Y6H-Cwq2-Vb8.js +1 -0
  21. package/assets/chunk-SVP7TREG-BfRHY5FU.js +88 -0
  22. package/assets/chunk-TICWLB2K-CRP7rHkW.js +206 -0
  23. package/assets/chunk-XXDRQBXY-Bg2jg-98.js +1 -0
  24. package/assets/classDiagram-ZZMXUADV-D4EF3HGj.js +1 -0
  25. package/assets/classDiagram-v2-VYDZK3BY-D4EF3HGj.js +1 -0
  26. package/assets/controls/ckeditor.es.js +9382 -9320
  27. package/assets/controls/handsontable.es.js +11971 -11938
  28. package/assets/controls/jsoneditor.es.js +10442 -10233
  29. package/assets/controls/toast-ui.es.js +1308 -1279
  30. package/assets/cose-bilkent-JH36ORCC-CCJ0SGyO.js +1 -0
  31. package/assets/cynefin-OW5HDTMX-B2Jx5fw3.js +166 -0
  32. package/assets/cynefinDiagram-5FMLGOSQ-DuK0Lb62.js +62 -0
  33. package/assets/cytoscape.esm-DzSz-X2X.js +321 -0
  34. package/assets/dagre-GXQ25YYZ-DnOYexET.js +4 -0
  35. package/assets/dashboard-X8k4X6Sw.js +3 -0
  36. package/assets/debounce-B3mXI_sx.js +1 -0
  37. package/assets/defaultLocale-DX6XiGOO.js +1 -0
  38. package/assets/diagram-S7CK7UJ4-DDgPBHsK.js +30 -0
  39. package/assets/diagram-UQ7AKVKN-qlL0GZs8.js +41 -0
  40. package/assets/diagram-VSXAHHWV-CQbiU1_c.js +3 -0
  41. package/assets/diagram-VX7I27RA-DFDI9_au.js +24 -0
  42. package/assets/diagram-Z3DM3KII-B5C9dtmJ.js +24 -0
  43. package/assets/docs-BiZOD7PP.js +1 -0
  44. package/assets/ebnfDiagram-PWID7BFC-CLMUsXEI.js +1 -0
  45. package/assets/erDiagram-RLTQ6QDP-ax9Xol5-.js +99 -0
  46. package/assets/flowDiagram-HODETNUW-CvaH7l3S.js +168 -0
  47. package/assets/ganttDiagram-EL5Y4UJY-Cga5U19j.js +292 -0
  48. package/assets/gitGraphDiagram-WWUBYQGX-B6o1T3-d.js +106 -0
  49. package/assets/history-CVBJUNSQ.js +1 -0
  50. package/assets/infoDiagram-27XIBGKW-BpWxgBCE.js +2 -0
  51. package/assets/init-Gi6I4Gst.js +1 -0
  52. package/assets/init-user-xSvnFTF0.js +1 -0
  53. package/assets/isObject-DL-BuaBl.js +1 -0
  54. package/assets/ishikawaDiagram-5VMMS53U-zE83db4H.js +70 -0
  55. package/assets/journeyDiagram-3NMN7TZE-DZNVFqrX.js +139 -0
  56. package/assets/kanban-definition-UXKFOSKX-CqxNgk27.js +89 -0
  57. package/assets/katex-HP8lGamR.js +257 -0
  58. package/assets/layout-CN3kt_jt.js +1 -0
  59. package/assets/linear-nvkaQ6BA.js +1 -0
  60. package/assets/{list-DhK0McVn.js → list-CrIU2eZz.js} +2 -2
  61. package/assets/login-CX9xVjCn.js +1 -0
  62. package/assets/manifest.json +834 -58
  63. package/assets/media-manager-BfYftLIH.js +6 -0
  64. package/assets/mermaid.core-C0V1NaVJ.js +310 -0
  65. package/assets/mindmap-definition-YA3MSWOX-Bh7_d9f1.js +96 -0
  66. package/assets/module-DPEvnad3.js +1 -0
  67. package/assets/notification-Dqpt5AIZ.js +20 -0
  68. package/assets/ordinal-Cboi1Yqb.js +1 -0
  69. package/assets/pegDiagram-XKGWAZYB-DMnjm6Z1.js +1 -0
  70. package/assets/pieDiagram-E7YTZNPT-D-RWCgYb.js +39 -0
  71. package/assets/quadrantDiagram-AXDQQJYC-BNBGP7RM.js +7 -0
  72. package/assets/railroadDiagram-O6MQD6OU-BIjVPT01.js +1 -0
  73. package/assets/register-CF4KQ97e.js +1 -0
  74. package/assets/requirementDiagram-BXWQKSXE-VPrtGdjM.js +84 -0
  75. package/assets/ru-CFJ4fysR.js +1 -0
  76. package/assets/sankeyDiagram-P5KCCOFB-ct9mLF3U.js +40 -0
  77. package/assets/sequenceDiagram-WJ2MYXX4-TC06Mbmw.js +162 -0
  78. package/assets/sizeCapture-INFHLROL-BMMwriCf.js +1 -0
  79. package/assets/stateDiagram-D77RDMKH-DtwYRPCX.js +1 -0
  80. package/assets/stateDiagram-v2-MP3YSRHH-C1yB0O5U.js +1 -0
  81. package/assets/swimlanes-42K2YHIH-DE3hRbbr.js +1 -0
  82. package/assets/swimlanesDiagram-VR7AAH4N-Ce4l1sQD.js +8 -0
  83. package/assets/timeline-definition-24CTP7MA-N7s_hfjj.js +120 -0
  84. package/assets/toNumber-DZb-r9sy.js +1 -0
  85. package/assets/use-appearance-DYTIKpT2.js +1 -0
  86. package/assets/user-filters-list-fR0YNJ3l.js +1 -0
  87. package/assets/vennDiagram-4TSXK5OY-Dj5bFQkR.js +34 -0
  88. package/assets/wardleyDiagram-VM6X3IG4-83ax25Z6.js +78 -0
  89. package/assets/welcome-v11MTsRK.js +1 -0
  90. package/assets/with-app-layout-CH6RIib1.js +31 -0
  91. package/assets/xychartDiagram-S5SC5T6Z-CW9Br5Xp.js +7 -0
  92. package/controllers/access-rights/permissionOptions.d.ts +2 -0
  93. package/controllers/access-rights/permissionOptions.js +23 -0
  94. package/controllers/add.js +2 -2
  95. package/controllers/addGroup.js +15 -6
  96. package/controllers/ai/AiAgentController.d.ts +66 -0
  97. package/controllers/ai/AiAgentController.js +435 -0
  98. package/controllers/ai/AiAssistantController.d.ts +0 -4
  99. package/controllers/ai/AiAssistantController.js +4 -78
  100. package/controllers/catalog/FrontendCatalogAdapter.js +7 -8
  101. package/controllers/docs/index.d.ts +22 -0
  102. package/controllers/docs/index.js +126 -0
  103. package/controllers/edit.js +2 -2
  104. package/controllers/editGroup.js +15 -6
  105. package/controllers/filter-fields/savedFilters.js +1 -1
  106. package/controllers/history-actions/HistoryController.js +7 -7
  107. package/controllers/inlineUpdate.js +10 -3
  108. package/controllers/list.js +1 -1
  109. package/controllers/login.js +1 -1
  110. package/controllers/notifications/NotificationController.js +14 -8
  111. package/controllers/view.js +3 -3
  112. package/controllers/widgets/filterInfo.js +1 -1
  113. package/helpers/accessRightsHelper.d.ts +30 -3
  114. package/helpers/accessRightsHelper.js +140 -12
  115. package/helpers/assetVersionHelper.d.ts +14 -0
  116. package/helpers/assetVersionHelper.js +42 -0
  117. package/helpers/configHelper.js +19 -18
  118. package/helpers/controllerHelper.d.ts +1 -0
  119. package/helpers/controllerHelper.js +25 -15
  120. package/helpers/fieldsHelper.d.ts +2 -1
  121. package/helpers/fieldsHelper.js +11 -5
  122. package/helpers/inertiaActionsHelper.d.ts +1 -1
  123. package/helpers/inertiaActionsHelper.js +4 -5
  124. package/helpers/inertiaAddHelper.d.ts +1 -1
  125. package/helpers/inertiaAddHelper.js +7 -6
  126. package/helpers/inertiaGroupHelper.js +10 -2
  127. package/helpers/inertiaListHelper.d.ts +1 -1
  128. package/helpers/inertiaListHelper.js +7 -8
  129. package/helpers/inertiaMenuHelper.d.ts +7 -2
  130. package/helpers/inertiaMenuHelper.js +12 -27
  131. package/helpers/menuHelper.d.ts +11 -1
  132. package/helpers/menuHelper.js +12 -0
  133. package/helpers/modelResourceHelper.d.ts +9 -0
  134. package/helpers/modelResourceHelper.js +43 -0
  135. package/helpers/navigationAccessHelper.d.ts +13 -0
  136. package/helpers/navigationAccessHelper.js +45 -0
  137. package/index.d.ts +11 -0
  138. package/index.js +11 -0
  139. package/interfaces/adminpanelConfig.d.ts +160 -2
  140. package/interfaces/queryCriteria.d.ts +13 -0
  141. package/interfaces/types.d.ts +169 -0
  142. package/lib/Adminizer.d.ts +8 -0
  143. package/lib/Adminizer.js +29 -2
  144. package/lib/DataAccessor.d.ts +100 -3
  145. package/lib/DataAccessor.js +454 -245
  146. package/lib/access-graph/AccessGraphResolver.d.ts +136 -0
  147. package/lib/access-graph/AccessGraphResolver.js +605 -0
  148. package/lib/access-graph/RecordAccessCache.d.ts +23 -0
  149. package/lib/access-graph/RecordAccessCache.js +30 -0
  150. package/lib/access-graph/RecordAccessResolver.d.ts +83 -0
  151. package/lib/access-graph/RecordAccessResolver.js +295 -0
  152. package/lib/access-graph/shared.d.ts +60 -0
  153. package/lib/access-graph/shared.js +121 -0
  154. package/lib/admin-links/AdminLinkHandler.d.ts +72 -0
  155. package/lib/admin-links/AdminLinkHandler.js +183 -0
  156. package/lib/ai-assistant/AbstractAiConversationHistoryService.d.ts +39 -0
  157. package/lib/ai-assistant/AbstractAiConversationHistoryService.js +98 -0
  158. package/lib/ai-assistant/AbstractAiModelService.d.ts +139 -2
  159. package/lib/ai-assistant/AbstractAiModelService.js +154 -1
  160. package/lib/ai-assistant/AiAgentRunManager.d.ts +35 -0
  161. package/lib/ai-assistant/AiAgentRunManager.js +109 -0
  162. package/lib/ai-assistant/AiAssistantAgentSkillHandler.d.ts +61 -0
  163. package/lib/ai-assistant/AiAssistantAgentSkillHandler.js +90 -0
  164. package/lib/ai-assistant/AiAssistantHandler.d.ts +1 -0
  165. package/lib/ai-assistant/AiAssistantHandler.js +4 -0
  166. package/lib/ai-assistant/AiAssistantUiMethodHandler.d.ts +60 -0
  167. package/lib/ai-assistant/AiAssistantUiMethodHandler.js +144 -0
  168. package/lib/ai-assistant/builtinAgentSkills.d.ts +9 -0
  169. package/lib/ai-assistant/builtinAgentSkills.js +259 -0
  170. package/lib/ai-assistant/jsonSafe.d.ts +13 -0
  171. package/lib/ai-assistant/jsonSafe.js +81 -0
  172. package/lib/app-manager/AdminizerApp.d.ts +31 -2
  173. package/lib/app-manager/AppManager.js +43 -42
  174. package/lib/app-manager/ConfigLayerHandler.js +4 -0
  175. package/lib/docs/AbstractDocumentation.d.ts +100 -0
  176. package/lib/docs/AbstractDocumentation.js +108 -0
  177. package/lib/docs/DocumentationHandler.d.ts +100 -0
  178. package/lib/docs/DocumentationHandler.js +198 -0
  179. package/lib/docs/FileDocumentation.d.ts +47 -0
  180. package/lib/docs/FileDocumentation.js +189 -0
  181. package/lib/docs/docsAgentSkills.d.ts +10 -0
  182. package/lib/docs/docsAgentSkills.js +93 -0
  183. package/lib/filters/FilterService.js +4 -3
  184. package/lib/history-actions/AbstractHistoryAdapter.d.ts +26 -1
  185. package/lib/history-actions/AbstractHistoryAdapter.js +155 -25
  186. package/lib/media-manager/helpers/MediaManagerHelper.js +9 -7
  187. package/lib/model/AbstractModel.d.ts +48 -0
  188. package/lib/model/AbstractModel.js +14 -4
  189. package/lib/model/ModelHandler.d.ts +50 -2
  190. package/lib/model/ModelHandler.js +117 -8
  191. package/lib/model/adapter/sequelize.d.ts +43 -3
  192. package/lib/model/adapter/sequelize.js +317 -138
  193. package/lib/model/adapter/typeorm.d.ts +16 -0
  194. package/lib/model/adapter/typeorm.js +136 -9
  195. package/lib/notifications/GeneralNotificationService.js +6 -5
  196. package/lib/notifications/SystemNotificationService.js +1 -1
  197. package/lib/ui-i18n/uiTranslationKeys.d.ts +2 -1
  198. package/lib/ui-i18n/uiTranslationKeys.js +42 -1
  199. package/lib/widgets/widgetHandler.js +10 -6
  200. package/models/Group.d.ts +2 -1
  201. package/package.json +35 -23
  202. package/policies/authPolicies.js +6 -6
  203. package/policies/permissionResolvers.d.ts +1 -0
  204. package/policies/permissionResolvers.js +3 -0
  205. package/system/Router.js +21 -3
  206. package/system/bindAccessRights.js +13 -3
  207. package/system/bindDocs.d.ts +13 -0
  208. package/system/bindDocs.js +77 -0
  209. package/system/bindInertia.js +30 -7
  210. package/system/buildInternalModelAccess.d.ts +8 -0
  211. package/system/buildInternalModelAccess.js +36 -4
  212. package/system/defaults.js +7 -1
  213. package/system/validateSystemModels.js +29 -9
  214. package/assets/add-DED_wpga.js +0 -1
  215. package/assets/add-group-CL80RdYb.js +0 -1
  216. package/assets/add-user-BRmwvQB8.js +0 -1
  217. package/assets/app-DNXiApCk.css +0 -1
  218. package/assets/app-layout-86yxiZOy.js +0 -1
  219. package/assets/app.js +0 -138
  220. package/assets/dashboard-ZP6K2s_8.js +0 -3
  221. package/assets/debounce-BMmXVQ06.js +0 -1
  222. package/assets/history-M61Bcv02.js +0 -1
  223. package/assets/init-user-8aUohVDq.js +0 -1
  224. package/assets/login-CO4laf6m.js +0 -1
  225. package/assets/media-manager-BDbpSSjH.js +0 -6
  226. package/assets/module-DfBneaUl.js +0 -1
  227. package/assets/notification-CVnQf3ef.js +0 -20
  228. package/assets/register-DBYIMXGQ.js +0 -1
  229. package/assets/ru-rYKdQbWF.js +0 -1
  230. package/assets/use-appearance-_EbbjHTh.js +0 -1
  231. package/assets/user-filters-list-DXhGLFTn.js +0 -1
  232. package/assets/welcome-CLxvXkcg.js +0 -1
@@ -28,6 +28,22 @@ export declare class TypeOrmModel<T extends ObjectLiteral> extends AbstractModel
28
28
  private normalizeCriteria;
29
29
  private addRequestedRelations;
30
30
  private addAllRelationJoins;
31
+ /**
32
+ * `criteria.populateOn` support: many-to-one with its FK declared as a real column
33
+ * property — the hydrated entity then carries the value the filtered association
34
+ * collapses to. (An undeclared FK leaves `joinColumns[0].propertyName` equal to the
35
+ * relation's own property name.)
36
+ */
37
+ canPushdownPopulateAccess(association: string): boolean;
38
+ /**
39
+ * Renders a `populateOn` entry into the JOIN's ON clause. Only the shapes the
40
+ * record-access layer marks pushdown-safe (primitive equality, `{in: [...]}`) are
41
+ * supported; anything else fails closed to a never-matching condition — the
42
+ * association then collapses to its foreign key rather than leaking.
43
+ */
44
+ private buildJoinCondition;
45
+ /** A record filtered out of a `populateOn` JOIN comes back as its bare foreign key. */
46
+ private collapsePopulateOn;
31
47
  private isNativeWhere;
32
48
  private applyFindOptions;
33
49
  private applyWhere;
@@ -1,7 +1,11 @@
1
1
  import { Brackets, EntitySchema, NotBrackets, } from "typeorm";
2
2
  import { v4 as uuid } from "uuid";
3
3
  import { AbstractAdapter, AbstractModel } from "../AbstractModel.js";
4
+ import { Adminizer } from "../../Adminizer.js";
4
5
  const ROOT_ALIAS = "record";
6
+ /** Always-false / always-true predicates: an empty IN-list must not depend on driver quirks. */
7
+ const MATCH_NOTHING = "1 = 0";
8
+ const MATCH_EVERYTHING = "1 = 1";
5
9
  function normalizeModelName(modelName) {
6
10
  return modelName.toLowerCase();
7
11
  }
@@ -295,7 +299,7 @@ export class TypeOrmModel extends AbstractModel {
295
299
  normalizeCriteria(criteria = {}) {
296
300
  const criteriaSortValue = "sort" in criteria ? criteria.sort : undefined;
297
301
  const isOrderingSort = typeof criteriaSortValue === "string";
298
- const { where: nestedWhere, skip, limit, sort, select, populate, ...rest } = criteria;
302
+ const { where: nestedWhere, skip, limit, sort, select, populate, populateOn: _populateOn, ...rest } = criteria;
299
303
  if (!isOrderingSort && criteriaSortValue !== undefined) {
300
304
  rest.sort = criteriaSortValue;
301
305
  }
@@ -308,7 +312,7 @@ export class TypeOrmModel extends AbstractModel {
308
312
  select: this.buildAttributes(select),
309
313
  };
310
314
  }
311
- addRequestedRelations(qb, populate) {
315
+ addRequestedRelations(qb, populate, populateOn) {
312
316
  const aliases = new Map();
313
317
  const relations = populate ? Object.keys(populate) : this.relationNames;
314
318
  for (const relationName of relations) {
@@ -316,7 +320,15 @@ export class TypeOrmModel extends AbstractModel {
316
320
  continue;
317
321
  }
318
322
  const alias = `${ROOT_ALIAS}_${relationName}`;
319
- qb.leftJoinAndSelect(`${ROOT_ALIAS}.${relationName}`, alias);
323
+ const joinCondition = populateOn?.[relationName]
324
+ ? this.buildJoinCondition(populateOn[relationName], alias)
325
+ : undefined;
326
+ if (joinCondition) {
327
+ qb.leftJoinAndSelect(`${ROOT_ALIAS}.${relationName}`, alias, joinCondition.sql, joinCondition.params);
328
+ }
329
+ else {
330
+ qb.leftJoinAndSelect(`${ROOT_ALIAS}.${relationName}`, alias);
331
+ }
320
332
  aliases.set(relationName, alias);
321
333
  }
322
334
  if (populate) {
@@ -353,17 +365,93 @@ export class TypeOrmModel extends AbstractModel {
353
365
  }
354
366
  return aliases;
355
367
  }
368
+ /**
369
+ * `criteria.populateOn` support: many-to-one with its FK declared as a real column
370
+ * property — the hydrated entity then carries the value the filtered association
371
+ * collapses to. (An undeclared FK leaves `joinColumns[0].propertyName` equal to the
372
+ * relation's own property name.)
373
+ */
374
+ canPushdownPopulateAccess(association) {
375
+ const relation = this.getRelation(association);
376
+ const joinColumn = relation?.joinColumns[0];
377
+ return Boolean(relation?.isManyToOne
378
+ && joinColumn?.propertyName
379
+ && joinColumn.propertyName !== relation.propertyName
380
+ && this.metadata.columns.some((column) => column.propertyName === joinColumn.propertyName));
381
+ }
382
+ /**
383
+ * Renders a `populateOn` entry into the JOIN's ON clause. Only the shapes the
384
+ * record-access layer marks pushdown-safe (primitive equality, `{in: [...]}`) are
385
+ * supported; anything else fails closed to a never-matching condition — the
386
+ * association then collapses to its foreign key rather than leaking.
387
+ */
388
+ buildJoinCondition(on, alias) {
389
+ const expressions = [];
390
+ const params = {};
391
+ for (const [field, value] of Object.entries(on)) {
392
+ if (value === null) {
393
+ expressions.push(`${alias}.${field} IS NULL`);
394
+ continue;
395
+ }
396
+ if (["string", "number", "boolean"].includes(typeof value)) {
397
+ const param = this.nextParamName();
398
+ expressions.push(`${alias}.${field} = :${param}`);
399
+ params[param] = value;
400
+ continue;
401
+ }
402
+ const inList = value && typeof value === "object" && Object.keys(value).length === 1
403
+ ? value.in
404
+ : undefined;
405
+ if (Array.isArray(inList)) {
406
+ if (!inList.length) {
407
+ expressions.push(MATCH_NOTHING);
408
+ continue;
409
+ }
410
+ const param = this.nextParamName();
411
+ expressions.push(`${alias}.${field} IN (:...${param})`);
412
+ params[param] = inList;
413
+ continue;
414
+ }
415
+ expressions.push(MATCH_NOTHING);
416
+ }
417
+ return { sql: expressions.join(" AND ") || MATCH_NOTHING, params };
418
+ }
419
+ /** A record filtered out of a `populateOn` JOIN comes back as its bare foreign key. */
420
+ collapsePopulateOn(entities, populateOn) {
421
+ if (!populateOn) {
422
+ return;
423
+ }
424
+ for (const association of Object.keys(populateOn)) {
425
+ const fkProperty = this.getRelation(association)?.joinColumns[0]?.propertyName;
426
+ if (!fkProperty || fkProperty === association) {
427
+ continue;
428
+ }
429
+ for (const entity of entities) {
430
+ if (entity[association] == null && entity[fkProperty] != null) {
431
+ entity[association] = entity[fkProperty];
432
+ }
433
+ }
434
+ }
435
+ }
356
436
  isNativeWhere(where) {
357
437
  return where instanceof Brackets || where instanceof NotBrackets;
358
438
  }
359
439
  applyFindOptions(qb, criteria) {
360
440
  const options = this.normalizeCriteria(criteria);
361
- const aliases = this.addRequestedRelations(qb, criteria.populate);
441
+ const aliases = this.addRequestedRelations(qb, criteria.populate, criteria.populateOn);
362
442
  if (this.isNativeWhere(options.where) || Object.keys(options.where).length > 0) {
363
443
  this.applyWhere(qb, options.where, ROOT_ALIAS, aliases);
364
444
  }
365
445
  if (options.select) {
366
- qb.select(options.select.map((field) => `${ROOT_ALIAS}.${field}`));
446
+ // The populateOn collapse reads the FK properties — keep them selected.
447
+ const selected = [...options.select];
448
+ for (const association of Object.keys(criteria.populateOn ?? {})) {
449
+ const fkProperty = this.getRelation(association)?.joinColumns[0]?.propertyName;
450
+ if (fkProperty && fkProperty !== association && !selected.includes(fkProperty)) {
451
+ selected.push(fkProperty);
452
+ }
453
+ }
454
+ qb.select(selected.map((field) => `${ROOT_ALIAS}.${field}`));
367
455
  }
368
456
  for (const [field, direction] of options.order) {
369
457
  const orderColumn = this.getOrderColumn(ROOT_ALIAS, field);
@@ -389,7 +477,16 @@ export class TypeOrmModel extends AbstractModel {
389
477
  }
390
478
  }
391
479
  buildWhereBrackets(where, alias, relationAliases) {
392
- const entries = Object.entries(where).filter(([, value]) => value !== undefined);
480
+ const entries = Object.entries(where).filter(([key, value]) => {
481
+ if (value === undefined) {
482
+ // Historical behaviour: an undefined value drops the condition. Record-access
483
+ // filters never emit one, so this only fires for hand-built criteria — but a
484
+ // dropped condition widens the query, so it must not stay silent.
485
+ Adminizer.log.warn(`TypeORM adapter: criteria field "${key}" has an undefined value and was dropped`);
486
+ return false;
487
+ }
488
+ return true;
489
+ });
393
490
  if (!entries.length) {
394
491
  return undefined;
395
492
  }
@@ -467,6 +564,9 @@ export class TypeOrmModel extends AbstractModel {
467
564
  return { sql: `${column} IS NULL` };
468
565
  }
469
566
  if (Array.isArray(value)) {
567
+ if (!value.length) {
568
+ return { sql: MATCH_NOTHING };
569
+ }
470
570
  const param = this.nextParamName();
471
571
  return { sql: `${column} IN (:...${param})`, params: { [param]: value } };
472
572
  }
@@ -474,8 +574,15 @@ export class TypeOrmModel extends AbstractModel {
474
574
  const expressions = [];
475
575
  const params = {};
476
576
  for (const [operator, raw] of Object.entries(value)) {
477
- if (raw === undefined)
577
+ if (raw === undefined || raw === null) {
578
+ // Access scoping emits `in` lists, so an absent operand must fail
579
+ // closed (match nothing) rather than silently widen the query.
580
+ // Other operators keep the historical skip: filter builders rely on it.
581
+ if (operator === "in" || operator === "$in") {
582
+ expressions.push(MATCH_NOTHING);
583
+ }
478
584
  continue;
585
+ }
479
586
  const built = this.buildOperatorCondition(column, operator, raw);
480
587
  if (!built)
481
588
  continue;
@@ -528,10 +635,18 @@ export class TypeOrmModel extends AbstractModel {
528
635
  return { sql: `CAST(${column} AS TEXT) LIKE :${param}`, params: { [param]: `%${value}` } };
529
636
  case "in":
530
637
  case "$in":
638
+ // An empty list matches nothing on every driver; the spread placeholder
639
+ // would depend on TypeORM's empty-array handling.
640
+ if (Array.isArray(value) && !value.length) {
641
+ return { sql: MATCH_NOTHING };
642
+ }
531
643
  return { sql: `${column} IN (:...${param})`, params };
532
644
  case "notIn":
533
645
  case "nin":
534
646
  case "$notIn":
647
+ if (Array.isArray(value) && !value.length) {
648
+ return { sql: MATCH_EVERYTHING };
649
+ }
535
650
  return { sql: `${column} NOT IN (:...${param})`, params };
536
651
  case "between":
537
652
  case "$between": {
@@ -551,7 +666,13 @@ export class TypeOrmModel extends AbstractModel {
551
666
  const serialized = JSON.stringify(value).replace(/[%_]/g, "\\$&");
552
667
  return { sql: `CAST(${column} AS TEXT) LIKE :${param}`, params: { [param]: `%${serialized}%` } };
553
668
  }
669
+ case "intersects":
670
+ // Emitted only by the (unsupported) collection form of
671
+ // `userAccessRelation` — fail loudly instead of silently dropping the
672
+ // condition, which would widen the query (sequelize adapter parity).
673
+ throw new Error(`TypeORM adapter does not support the "intersects" operator (column "${column}")`);
554
674
  default:
675
+ Adminizer.log.warn(`TypeORM adapter: unsupported criteria operator "${operator}" was dropped for column "${column}"`);
555
676
  return undefined;
556
677
  }
557
678
  }
@@ -660,12 +781,18 @@ export class TypeOrmModel extends AbstractModel {
660
781
  async _findOne(criteria = {}) {
661
782
  const qb = this.createQueryBuilder();
662
783
  this.applyFindOptions(qb, criteria);
663
- return await qb.getOne();
784
+ const record = await qb.getOne();
785
+ if (record) {
786
+ this.collapsePopulateOn([record], criteria.populateOn);
787
+ }
788
+ return record;
664
789
  }
665
790
  async _find(criteria = {}) {
666
791
  const qb = this.createQueryBuilder();
667
792
  this.applyFindOptions(qb, criteria);
668
- return await qb.getMany();
793
+ const records = await qb.getMany();
794
+ this.collapsePopulateOn(records, criteria.populateOn);
795
+ return records;
669
796
  }
670
797
  async _updateOne(criteria, data) {
671
798
  const record = await this._findOne(criteria);
@@ -6,23 +6,24 @@ export class GeneralNotificationService extends AbstractNotificationService {
6
6
  icon = 'info';
7
7
  iconColor = '#5987de';
8
8
  async dispatchNotification(notification) {
9
+ const { userId, ...notificationData } = notification;
9
10
  const fullNotification = {
10
- ...notification,
11
+ ...notificationData,
11
12
  notificationClass: this.notificationClass
12
13
  };
13
14
  let notificationDB;
14
15
  try {
15
16
  notificationDB = await this.notificationModel().create(fullNotification);
16
- if (notification.userId) {
17
+ if (userId) {
17
18
  // For specific user
18
- await this.createUserNotification(notificationDB.id, notification.userId);
19
+ await this.createUserNotification(notificationDB.id, userId);
19
20
  }
20
21
  else {
21
22
  // For all users
22
23
  const users = await this.userModel().find({});
23
24
  for (const user of users) {
24
25
  try {
25
- if (this.adminizer.accessRightsHelper.hasPermission(`notification-${this.notificationClass}`, user)) {
26
+ if (await this.adminizer.accessRightsHelper.hasPermission(`notification-${this.notificationClass}`, user)) {
26
27
  await this.createUserNotification(notificationDB.id, user.id);
27
28
  }
28
29
  else {
@@ -45,7 +46,7 @@ export class GeneralNotificationService extends AbstractNotificationService {
45
46
  },
46
47
  },
47
48
  notificationClass: this.notificationClass,
48
- userId: notification.userId ?? null
49
+ userId: userId ?? null
49
50
  };
50
51
  this.broadcast(event);
51
52
  Adminizer.log.info(`[General] Notification dispatched: ${fullNotification.title}`);
@@ -19,7 +19,7 @@ export class SystemNotificationService extends AbstractNotificationService {
19
19
  const users = await this.userModel().find({});
20
20
  for (const user of users) {
21
21
  try {
22
- if (this.adminizer.accessRightsHelper.hasPermission(`notification-${this.notificationClass}`, user)) {
22
+ if (await this.adminizer.accessRightsHelper.hasPermission(`notification-${this.notificationClass}`, user)) {
23
23
  await this.createUserNotification(notificationDB.id, user.id);
24
24
  }
25
25
  }
@@ -1,6 +1,7 @@
1
- export declare const COMMON_UI_TRANSLATION_KEYS: readonly ["Delete", "Diff", "Preview", "Add", "Search", "Yes", "No", "On", "Off", "Hide", "Show", "No notifications found", "No notifications", "No widgets found", "Changes not found", "Old", "New", "Added", "Removed", "Updated", "changed type", "Error: Invalid field data", "Error: Fields data is invalid", "No fields to display", "Error: Some fields are missing required properties (name, type, label)", "Edit", "create", "Clean", "Are you sure?", "Select Item type", "Select Ids", "Open in a new window", "Visible", "Performing an action...", "Action completed", "Action failed", "Save", "First", "Last", "Previous", "Next", "Send feedback", "Feedback", "Title", "Description", "Attach files", "Send", "Sending...", "Feedback sent successfully", "Title is required", "File size exceeds the 5 MB limit", "Remove file", "Max 5 MB per file", "View All", "Make read", "Make all read", "Message", "Date", "Watch", "Current", "There is no history"];
1
+ export declare const COMMON_UI_TRANSLATION_KEYS: readonly ["Delete", "Diff", "Preview", "Add", "Search", "Yes", "No", "On", "Off", "Hide", "Show", "No notifications found", "No notifications", "No widgets found", "Changes not found", "Old", "New", "Added", "Removed", "Updated", "changed type", "Error: Invalid field data", "Error: Fields data is invalid", "No fields to display", "Error: Some fields are missing required properties (name, type, label)", "Edit", "create", "Clean", "Are you sure?", "Select Item type", "Select Ids", "Open in a new window", "Visible", "Performing an action...", "Action completed", "Action failed", "Save", "First", "Last", "Previous", "Next", "Send feedback", "Feedback", "Title", "Description", "Attach files", "Send", "Sending...", "Feedback sent successfully", "Title is required", "File size exceeds the 5 MB limit", "Remove file", "Max 5 MB per file", "View All", "Make read", "Make all read", "Message", "Date", "Watch", "Current", "There is no history", "Documentation", "Page documentation", "Knowledge base", "Schema", "Back to contents", "Open in knowledge base", "Send to assistant", "Failed to load documentation", "Loading...", "Nothing found", "Field", "Type", "Required", "Language"];
2
2
  export declare const FILTER_UI_TRANSLATION_KEYS: readonly ["Filters", "Saved filters", "Active filter", "Add filter", "Reset filter", "Reset", "Equal", "Not equal", "Contains", "Not contains", "Starts with", "Ends with", "Is empty", "Is not empty", "Greater than", "Greater or equal", "Less than", "Less or equal", "Between", "After", "After or equal", "Before", "Before or equal", "In list", "Not in list", "Is null", "Is not null", "Yes", "No", "From", "To", "From...", "To...", "Date...", "Today", "Month", "Month range", "Year", "Year range", "Value...", "Select...", "selected", "Search...", "No results", "Error", "Model not found", "Error applying filter", "Enter filter name", "Temporary filter", "Error: model not found", "Error loading columns", "Network error", "Columns settings", "Available columns", "Visible columns", "Add all", "Hide all", "No available columns", "Move columns here", "Save changes", "Apply", "Save", "Back", "Cancel", "conditions", "modified", "Private filter", "For groups", "Public filter", "Only for you", "For selected groups", "For all users", "Visible only to you", "Visible only to your group", "API access (feed)", "Hide", "Show", "Regenerate", "copied to clipboard", "Failed to copy", "Loading filters...", "No saved filters", "Save current filter for quick access", "Someone else's private filter (owner:", "unknown)", "Owner", "Apply filter", "Delete filter", "No permission to delete filter", "Edit filter", "New filter", "Filter conditions", "Add condition", "Select field", "No conditions. Add a condition above.", "Name", "Description", "Icon", "Color", "Filter parameters", "Change filter conditions and parameters", "Configure filter conditions", "Specify name and parameters for saving", "Someone else's private filter", "You cannot change someone else's filter visibility", "Private", "Public", "Visibility", "Export", "Exporting...", "Export is only available with an active filter", "Export to", "completed", "Export error", "Data in JSON format", "Text format CSV", "Excel file", "Conditions", "Access for groups", "Selected groups", "Groups list", "Columns", "Saving...", "Error saving filter", "Column configuration", "Select and arrange columns to display in the table", "Loading columns...", "Use buttons", "to move and", "to change order", "Add", "Edit", "Save filter", "and", "Custom filtering", "Select a saved filter or create a new one", "Select a filter or create a new one", "Filter visibility", "Unknown", "JSON URL", "XML URL", "API key is not created", "The key is not created. Create it or contact an administrator.", "OK"];
3
3
  export declare const HISTORY_UI_TRANSLATION_KEYS: readonly ["Models", "All", "Users", "Date", "Pick a date", "Search", "Reset", "Model", "Name", "Event", "User", "Diff", "The end of the list has been reached", "There are no records to display"];
4
4
  export declare const HISTORY_TABLE_UI_TRANSLATION_KEYS: readonly ["Event", "Date", "User", "Watch", "Current", "There is no history", "Diff"];
5
5
  export declare const NOTIFICATION_UI_TRANSLATION_KEYS: readonly ["Make read", "View All", "Search", "Make all read", "Title", "Message", "Date", "Diff", "No notifications", "No notifications found", "The end of the list has been reached"];
6
6
  export declare const USER_FILTERS_UI_TRANSLATION_KEYS: readonly ["Loading...", "Search filters...", "All models", "No filters found", "Loading more...", "Filter Name", "Model", "Visibility", "API access (feed)", "Owner", "Private", "Public", "Groups", "Yes", "No", "You", "Unknown", "Reset", "found", "User Filters"];
7
+ export declare const DOCS_UI_TRANSLATION_KEYS: readonly ["Documentation", "Knowledge base", "Contents", "Search documentation", "Search", "Keywords", "Clear", "Nothing found", "There is no documentation yet", "Select a document to read", "Loading...", "Language", "Send to assistant", "Schema", "Related models", "Failed to load documentation", "Field", "Type", "Required", "No fields to display", "Previous", "Next", "Found", "In this document", "Document not found"];
@@ -59,7 +59,21 @@ export const COMMON_UI_TRANSLATION_KEYS = [
59
59
  "Date",
60
60
  "Watch",
61
61
  "Current",
62
- "There is no history"
62
+ "There is no history",
63
+ "Documentation",
64
+ "Page documentation",
65
+ "Knowledge base",
66
+ "Schema",
67
+ "Back to contents",
68
+ "Open in knowledge base",
69
+ "Send to assistant",
70
+ "Failed to load documentation",
71
+ "Loading...",
72
+ "Nothing found",
73
+ "Field",
74
+ "Type",
75
+ "Required",
76
+ "Language"
63
77
  ];
64
78
  export const FILTER_UI_TRANSLATION_KEYS = [
65
79
  "Filters",
@@ -267,3 +281,30 @@ export const USER_FILTERS_UI_TRANSLATION_KEYS = [
267
281
  "found",
268
282
  "User Filters"
269
283
  ];
284
+ export const DOCS_UI_TRANSLATION_KEYS = [
285
+ "Documentation",
286
+ "Knowledge base",
287
+ "Contents",
288
+ "Search documentation",
289
+ "Search",
290
+ "Keywords",
291
+ "Clear",
292
+ "Nothing found",
293
+ "There is no documentation yet",
294
+ "Select a document to read",
295
+ "Loading...",
296
+ "Language",
297
+ "Send to assistant",
298
+ "Schema",
299
+ "Related models",
300
+ "Failed to load documentation",
301
+ "Field",
302
+ "Type",
303
+ "Required",
304
+ "No fields to display",
305
+ "Previous",
306
+ "Next",
307
+ "Found",
308
+ "In this document",
309
+ "Document not found"
310
+ ];
@@ -116,7 +116,11 @@ export class WidgetHandler {
116
116
  const filterService = new FilterService(this.adminizer);
117
117
  const result = [];
118
118
  for (const modelName of modelNames) {
119
- if (!this.adminizer.accessRightsHelper.hasPermission(`read-${modelName}-model`, user)) {
119
+ const readToken = `read-${modelName}-model`;
120
+ if (!this.adminizer.accessRightsHelper.hasToken(readToken)) {
121
+ continue;
122
+ }
123
+ if (!await this.adminizer.accessRightsHelper.hasPermission(readToken, user)) {
120
124
  continue;
121
125
  }
122
126
  let filters = [];
@@ -163,7 +167,7 @@ export class WidgetHandler {
163
167
  let id_key = 0;
164
168
  for (const widget of this.widgets) {
165
169
  if (widget.widgetType === 'switcher') {
166
- if (this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
170
+ if (await this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
167
171
  widgets.push({
168
172
  id: `${widget.id}__${id_key}`,
169
173
  type: widget.widgetType,
@@ -178,7 +182,7 @@ export class WidgetHandler {
178
182
  }
179
183
  }
180
184
  else if (widget.widgetType === 'info') {
181
- if (this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
185
+ if (await this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
182
186
  widgets.push({
183
187
  id: `${widget.id}__${id_key}`,
184
188
  type: widget.widgetType,
@@ -195,7 +199,7 @@ export class WidgetHandler {
195
199
  }
196
200
  }
197
201
  else if (widget.widgetType === 'action') {
198
- if (this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
202
+ if (await this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
199
203
  widgets.push({
200
204
  id: `${widget.id}__${id_key}`,
201
205
  type: widget.widgetType,
@@ -210,7 +214,7 @@ export class WidgetHandler {
210
214
  }
211
215
  }
212
216
  else if (widget.widgetType === 'link') {
213
- if (this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
217
+ if (await this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
214
218
  let links_id_key = 0;
215
219
  for (const link of widget.links) {
216
220
  widgets.push({
@@ -229,7 +233,7 @@ export class WidgetHandler {
229
233
  }
230
234
  }
231
235
  else if (widget.widgetType === 'custom') {
232
- if (this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
236
+ if (await this.adminizer.accessRightsHelper.hasPermission(this.resolveAccessRightsToken(widget), dashboardUser)) {
233
237
  widgets.push({
234
238
  id: `${widget.id}_${id_key}`,
235
239
  type: widget.widgetType,
package/models/Group.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { User } from "./User.js";
2
+ import type { PermissionGrant } from "../interfaces/types.js";
2
3
  export interface Group {
3
4
  id?: number;
4
5
  name: string;
5
6
  description?: string;
6
- tokens?: string[];
7
+ tokens?: PermissionGrant[];
7
8
  users?: User[];
8
9
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "adminizer",
3
3
  "type": "module",
4
- "version": "5.0.0-build.8",
4
+ "version": "5.1.0-build.24",
5
5
  "main": "index.js",
6
6
  "exports": {
7
7
  ".": "./index.js",
@@ -21,7 +21,7 @@
21
21
  "dev:typeorm:no-seed": "cross-env ADMINIZER_ENV=dev NO_SEED_DATA=true ORM=typeorm tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
22
22
  "dev:no-seed-clean": "cross-env ADMINIZER_ENV=dev NO_SEED_DATA=true CLEAN_TMP=true ORM=sequelize tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
23
23
  "dev:cors": "cross-env ADMINIZER_ENV=dev NO_SEED_DATA=true ORM=sequelize FRONTEND_URL=http://localhost:8080 tsx watch --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
24
- "build:assets": "vite build && vite build --config vite.config.controls.ts && vite build --config fixture/widgets/vite.config.widget.ts",
24
+ "build:assets": "vite build && vite build --config vite.config.controls.ts && vite build --config vite.config.ai-assistant.ts && vite build --config fixture/widgets/vite.config.widget.ts",
25
25
  "build:controls": "vite build --config vite.config.controls.ts",
26
26
  "compile:backend": "tsc -p src/tsconfig.json && node ./scripts/appendJsExtension.js",
27
27
  "compile:ui": "tsc -p tsconfig.ui.json",
@@ -31,7 +31,10 @@
31
31
  "build": "npm run copy:backend && npm run compile:backend && npm run compile:ui && npm run build:assets",
32
32
  "build:catalog-modules": "cross-env CATALOG_COMPONENT=catalogAction vite build --config fixture/virtual-catalog/vite.config.module.ts && cross-env CATALOG_COMPONENT=Group vite build --config fixture/virtual-catalog/vite.config.module.ts",
33
33
  "start:typeorm:seed": "cross-env ORM=typeorm tsx --tsconfig ./fixture/tsconfig.json ./fixture/index.ts",
34
- "build:apps": "vite build --config fixture/apps/notification-sender/vite.config.module.ts && vite build --config fixture/apps/module-manager/vite.config.module.ts && vite build --config fixture/apps/navigation/vite.config.module.ts && vite build --config fixture/apps/quill-editor/vite.config.module.ts && vite build --config fixture/apps/widgets/vite.config.module.ts && vite build --config fixture/apps/handsontable-test/vite.config.module.ts && npm run build:catalog-modules"
34
+ "build:apps": "vite build --config fixture/apps/notification-sender/vite.config.module.ts && vite build --config fixture/apps/module-manager/vite.config.module.ts && vite build --config fixture/apps/navigation/vite.config.module.ts && vite build --config fixture/apps/quill-editor/vite.config.module.ts && vite build --config fixture/apps/widgets/vite.config.module.ts && vite build --config fixture/apps/handsontable-test/vite.config.module.ts && vite build --config fixture/apps/record-scope-test/vite.config.module.ts && npm run build:catalog-modules",
35
+ "build:ai-assistant": "vite build --config vite.config.ai-assistant.ts",
36
+ "lint": "eslint src",
37
+ "lint:async": "eslint src -c eslint.config.async.mjs"
35
38
  },
36
39
  "keywords": [],
37
40
  "author": "Siziy Ivan <xziy88@gmail.com>",
@@ -59,41 +62,34 @@
59
62
  "jsonwebtoken": "^9.0.3",
60
63
  "multer": "^2.1.1",
61
64
  "password-hash": "^1.2.2",
65
+ "serve-static": "^2.2.1",
62
66
  "sharp": "^0.33.5",
63
67
  "sprintf-js": "^1.1.3",
68
+ "sqlite3": "^5.1.7",
69
+ "typeorm": "^0.3.20",
64
70
  "uuid": "^14.0.0",
65
71
  "winston": "^3.17.0",
66
72
  "xlsx": "^0.18.5",
67
- "zod": "^4.1.11",
68
- "sqlite3": "^5.1.7",
69
- "typeorm": "^0.3.20"
73
+ "zod": "^4.1.11"
70
74
  },
71
75
  "devDependencies": {
72
- "reflect-metadata": "^0.2.2",
73
- "react-dnd": "^16.0.1",
74
- "react-cropper": "^2.3.3",
75
- "material-icons": "^1.13.14",
76
- "next-themes": "^0.4.6",
77
- "dotenv": "^17.4.2",
78
- "date-fns": "^3.6.0",
79
- "cmdk": "^1.1.1",
80
- "@handsontable/react-wrapper": "^17.0.1",
81
- "@minoru/react-dnd-treeview": "^3.5.2",
82
- "@radix-ui/react-context-menu": "^2.2.15",
83
- "@radix-ui/react-tabs": "^1.1.12",
84
- "typescript": "^6.0.3",
76
+ "@assistant-ui/react": "^0.15.15",
77
+ "@assistant-ui/react-markdown": "^0.14.6",
85
78
  "@babel/plugin-proposal-decorators": "^7.27.1",
86
79
  "@ckeditor/ckeditor5-react": "^9.5.0",
87
80
  "@dnd-kit/core": "^6.3.1",
88
81
  "@dnd-kit/sortable": "^10.0.0",
89
82
  "@eslint/compat": "^1.2.9",
90
83
  "@faker-js/faker": "^9.7.0",
84
+ "@handsontable/react-wrapper": "^17.0.1",
91
85
  "@inertiajs/react": "^3.0.3",
86
+ "@minoru/react-dnd-treeview": "^3.5.2",
92
87
  "@monaco-editor/react": "^4.7.0",
93
88
  "@openai/agents": "^0.3.2",
94
89
  "@radix-ui/react-avatar": "^1.1.3",
95
90
  "@radix-ui/react-checkbox": "^1.1.4",
96
91
  "@radix-ui/react-collapsible": "^1.1.3",
92
+ "@radix-ui/react-context-menu": "^2.2.15",
97
93
  "@radix-ui/react-dialog": "^1.1.7",
98
94
  "@radix-ui/react-dropdown-menu": "^2.1.6",
99
95
  "@radix-ui/react-label": "^2.1.2",
@@ -105,6 +101,7 @@
105
101
  "@radix-ui/react-slider": "^1.2.3",
106
102
  "@radix-ui/react-slot": "^1.2.0",
107
103
  "@radix-ui/react-switch": "^1.2.4",
104
+ "@radix-ui/react-tabs": "^1.1.12",
108
105
  "@radix-ui/react-tooltip": "^1.1.8",
109
106
  "@tailwindcss/vite": "^4.0.15",
110
107
  "@tanstack/react-table": "^8.21.2",
@@ -127,12 +124,17 @@
127
124
  "@types/react-grid-layout": "^1.3.5",
128
125
  "@types/sprintf-js": "^1.1.4",
129
126
  "@types/uuid": "^10.0.0",
130
- "@typescript-eslint/eslint-plugin": "^8.32.1",
127
+ "@typescript-eslint/eslint-plugin": "^8.67.0",
128
+ "@typescript-eslint/parser": "^8.67.0",
131
129
  "@vitejs/plugin-react": "^5.2.0",
130
+ "asmcrypto.js": "^0.22.0",
132
131
  "ckeditor5": "^45.0.0",
133
132
  "class-variance-authority": "^0.7.1",
134
133
  "clsx": "^2.1.1",
134
+ "cmdk": "^1.1.1",
135
135
  "cross-env": "^7.0.3",
136
+ "date-fns": "^3.6.0",
137
+ "dotenv": "^17.4.2",
136
138
  "eslint": "^9.26.0",
137
139
  "handsontable": "^17.0.1",
138
140
  "isomorphic-webcrypto": "^2.3.8",
@@ -141,14 +143,22 @@
141
143
  "leaflet-draw": "^1.0.4",
142
144
  "lodash-es": "^4.17.21",
143
145
  "lucide-react": "^0.485.0",
144
- "react": "^19.0.0",
146
+ "material-icons": "^1.13.14",
147
+ "mermaid": "^11.17.0",
148
+ "next-themes": "^0.4.6",
149
+ "radix-ui": "^1.6.7",
150
+ "react": "19.2.8",
151
+ "react-cropper": "^2.3.3",
145
152
  "react-day-picker": "^8.10.1",
146
- "react-dom": "^19.0.0",
153
+ "react-dnd": "^16.0.1",
154
+ "react-dom": "19.2.8",
147
155
  "react-grid-layout": "^1.5.1",
148
156
  "react-intersection-observer": "^9.16.0",
149
157
  "react-leaflet": "^5.0.0",
150
158
  "react-quill-new": "^3.4.6",
151
159
  "react-simple-wysiwyg": "^3.2.2",
160
+ "reflect-metadata": "^0.2.2",
161
+ "remark-gfm": "^4.0.1",
152
162
  "sequelize": "^6.37.7",
153
163
  "sequelize-typescript": "^2.1.6",
154
164
  "shelljs": "^0.9.2",
@@ -157,10 +167,12 @@
157
167
  "tailwindcss": "^4.0.15",
158
168
  "tsx": "^4.21.0",
159
169
  "tw-animate-css": "^1.2.5",
170
+ "typescript": "^6.0.3",
160
171
  "vanilla-jsoneditor": "^3.1.1",
161
172
  "vite": "^7.3.2",
162
173
  "vite-plugin-externals": "^0.6.2",
163
- "vitest": "^3.0.7"
174
+ "vitest": "^3.0.7",
175
+ "zustand": "^5.0.14"
164
176
  },
165
177
  "overrides": {
166
178
  "@toast-ui/react-editor": {