data-primals-engine 1.4.3 → 1.5.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 (77) hide show
  1. package/README.md +913 -867
  2. package/client/package-lock.json +49 -0
  3. package/client/package.json +1 -0
  4. package/client/src/AddWidgetTypeModal.jsx +47 -43
  5. package/client/src/App.jsx +3 -7
  6. package/client/src/App.scss +25 -3
  7. package/client/src/AssistantChat.jsx +363 -323
  8. package/client/src/AssistantChat.scss +30 -12
  9. package/client/src/Dashboard.jsx +480 -396
  10. package/client/src/Dashboard.scss +1 -1
  11. package/client/src/DashboardHtmlViewItem.jsx +147 -0
  12. package/client/src/DashboardView.jsx +104 -19
  13. package/client/src/DataEditor.jsx +12 -5
  14. package/client/src/DataLayout.jsx +805 -762
  15. package/client/src/DataLayout.scss +14 -0
  16. package/client/src/DataTable.jsx +63 -77
  17. package/client/src/Dialog.scss +1 -1
  18. package/client/src/Field.jsx +591 -322
  19. package/client/src/FlexDataRenderer.jsx +2 -0
  20. package/client/src/FlexTreeUtils.js +1 -1
  21. package/client/src/FlexViewCard.jsx +44 -0
  22. package/client/src/HistoryDialog.jsx +47 -14
  23. package/client/src/HtmlViewBuilderModal.jsx +91 -0
  24. package/client/src/HtmlViewBuilderModal.scss +18 -0
  25. package/client/src/HtmlViewCard.jsx +44 -0
  26. package/client/src/HtmlViewCard.scss +35 -0
  27. package/client/src/KPIDialog.jsx +11 -1
  28. package/client/src/KanbanCard.jsx +1 -2
  29. package/client/src/ModelCreator.jsx +6 -6
  30. package/client/src/ModelCreatorField.jsx +74 -31
  31. package/client/src/ModelList.jsx +93 -54
  32. package/client/src/Notification.jsx +136 -136
  33. package/client/src/Notification.scss +0 -18
  34. package/client/src/Pagination.jsx +5 -3
  35. package/client/src/RelationField.jsx +354 -258
  36. package/client/src/RelationSelectorWidget.jsx +173 -0
  37. package/client/src/constants.js +1 -1
  38. package/client/src/contexts/ModelContext.jsx +10 -1
  39. package/client/src/contexts/UIContext.jsx +72 -63
  40. package/client/src/filter.js +262 -212
  41. package/client/src/hooks/useTutorials.jsx +62 -65
  42. package/client/src/hooks/useValidation.js +75 -0
  43. package/client/src/translations.js +26 -24
  44. package/package.json +3 -1
  45. package/perf/README.md +147 -0
  46. package/perf/artillery-hooks.js +37 -0
  47. package/perf/perf-shot-hardwork.yml +84 -0
  48. package/perf/perf-shot-search.yml +45 -0
  49. package/perf/setup.yml +26 -0
  50. package/server.js +1 -1
  51. package/src/constants.js +3 -28
  52. package/src/core.js +15 -1
  53. package/src/data.js +1 -1
  54. package/src/defaultModels.js +63 -7
  55. package/src/email.js +5 -2
  56. package/src/engine.js +5 -3
  57. package/src/filter.js +5 -3
  58. package/src/i18n.js +710 -10
  59. package/src/modules/assistant/assistant.js +151 -19
  60. package/src/modules/bucket.js +14 -16
  61. package/src/modules/data/data.backup.js +11 -8
  62. package/src/modules/data/data.core.js +118 -92
  63. package/src/modules/data/data.history.js +531 -492
  64. package/src/modules/data/data.js +9 -56
  65. package/src/modules/data/data.operations.js +3282 -2999
  66. package/src/modules/data/data.relations.js +686 -686
  67. package/src/modules/data/data.routes.js +118 -24
  68. package/src/modules/data/data.scheduling.js +2 -1
  69. package/src/modules/data/data.validation.js +85 -3
  70. package/src/modules/file.js +247 -236
  71. package/src/modules/user.js +4 -1
  72. package/src/modules/workflow.js +9 -10
  73. package/src/openai.jobs.js +2 -0
  74. package/src/packs.js +5482 -5461
  75. package/src/providers.js +22 -7
  76. package/test/data.integration.test.js +136 -2
  77. package/test/import_export.integration.test.js +1 -1
@@ -4,6 +4,7 @@ export const defaultModels = {
4
4
  "name": "permission",
5
5
  "icon": "FaKey",
6
6
  "description": "",
7
+ "tags": ["system", "security"],
7
8
  "fields": [
8
9
  {
9
10
  "name": "name",
@@ -20,6 +21,7 @@ export const defaultModels = {
20
21
  name: 'role',
21
22
  "icon": "FaUserTag",
22
23
  "description": "",
24
+ "tags": ["system", "security"],
23
25
  fields: [
24
26
  { name: 'name', type: 'string_t', required: true, unique: true, color: '#363636' },
25
27
  { name: 'permissions', type: 'relation', multiple: true, relation: 'permission' }
@@ -30,6 +32,7 @@ export const defaultModels = {
30
32
  "description": "",
31
33
  "icon": "FaUser",
32
34
  locked: true,
35
+ "tags": ["system", "users"],
33
36
  fields: [
34
37
  { name: 'username', type: 'string', required: true, unique: true, color: '#3C7D08' },
35
38
  { name: 'password', type: 'password' },
@@ -53,6 +56,7 @@ export const defaultModels = {
53
56
  "icon": "FaUserCheck",
54
57
  "name": "userPermission",
55
58
  "description": "Gère les exceptions aux permissions des rôles pour un utilisateur (ajouts ou retraits, permanents ou temporaires).",
59
+ "tags": ["system", "security"],
56
60
  "fields": [
57
61
  {
58
62
  "name": "user",
@@ -87,6 +91,7 @@ export const defaultModels = {
87
91
  name: 'token',
88
92
  "icon": "FaKey",
89
93
  "description": "",
94
+ "tags": ["system", "security"],
90
95
  fields: [
91
96
  { name: 'name', type: 'string' },
92
97
  { name: 'value', type: 'password' },
@@ -98,6 +103,7 @@ export const defaultModels = {
98
103
  "icon": "FaLanguage",
99
104
  locked: true,
100
105
  "description": "",
106
+ "tags": ["system", "i18n"],
101
107
  fields: [
102
108
  { name: 'lang', type: 'relation', 'relation': 'lang', required: true, color: '#4CACCD' },
103
109
  { name: 'key', type: 'string', maxlength: 200, required: true },
@@ -109,6 +115,7 @@ export const defaultModels = {
109
115
  "icon": "FaGlobe",
110
116
  locked: true,
111
117
  "description": "",
118
+ "tags": ["system", "i18n"],
112
119
  fields: [
113
120
  { name: 'name', unique: true, type: 'string_t', maxlength: 200, color: '#4CACCD' },
114
121
  { name: 'code', type: 'string', maxlength: 5 }
@@ -119,6 +126,7 @@ export const defaultModels = {
119
126
  "icon": "FaMoneyBill",
120
127
  "description": "",
121
128
  locked: true,
129
+ "tags": ["system", "finance"],
122
130
  fields: [
123
131
  { name: 'symbol', type: 'string', required: true, color: '#E0E0E0', maxlength: 20, asMain: true },
124
132
  { name: 'code', type: 'string', required: true, unique: true, maxlength: 3, asMain: true },
@@ -131,6 +139,7 @@ export const defaultModels = {
131
139
  name: 'channel',
132
140
  "icon": "FaComments",
133
141
  "description": "",
142
+ "tags": ["system", "messaging"],
134
143
  fields: [
135
144
  { name: 'name', type: 'string_t', required: true, unique: true }, // Nom du canal (ex: "email", "SMS")
136
145
  { name: 'description', type: 'string_t' },
@@ -142,6 +151,7 @@ export const defaultModels = {
142
151
  "icon": "FaEnvelope",
143
152
  "description": "",
144
153
  locked: true,
154
+ "tags": ["system", "messaging"],
145
155
  fields: [
146
156
  { name: 'sender', type: 'relation', relation: 'user' }, // Utilisateur émetteur (si applicable, sinon système)
147
157
  { name: 'recipient', type: 'relation', relation: 'user' }, // Utilisateur destinataire
@@ -160,6 +170,7 @@ export const defaultModels = {
160
170
  name: "alert",
161
171
  "icon": "FaBell",
162
172
  description: "Définit les règles pour les alertes et les insights automatiques.",
173
+ "tags": ["system", "automation", "monitoring"],
163
174
  fields: [
164
175
  { name: "name", type: "string", required: true, asMain: true },
165
176
  { name: "targetModel", type: "model", required: true },
@@ -206,6 +217,7 @@ export const defaultModels = {
206
217
  name: "env",
207
218
  "icon": "FaCog",
208
219
  description: "Définit les variables d'environnement qui seront accessibles dans vos scripts et webhooks.",
220
+ "tags": ["system", "configuration"],
209
221
  fields: [
210
222
  { name: "name", type: "string", required: true, unique: true, asMain: true },
211
223
  { name: "value", type: "string", anonymized: true, hiddenable: true }
@@ -216,6 +228,7 @@ export const defaultModels = {
216
228
  "icon": "FaFileAlt",
217
229
  locked: true,
218
230
  "description": "",
231
+ "tags": ["cms", "website"],
219
232
  fields: [
220
233
  { name: 'title', type: 'string_t', required: true, color: '#659DE6' },
221
234
  { name: 'path', type: 'string', required: true, unique: true, color: '#DEDEDE' },
@@ -232,6 +245,7 @@ export const defaultModels = {
232
245
  name: 'content',
233
246
  "icon": "FaFileAlt",
234
247
  "description": "",
248
+ "tags": ["cms", "website"],
235
249
  fields: [
236
250
  { name: 'lang', type: 'relation', relation: 'lang' },
237
251
  { name: 'title', type: 'string_t', required: true },
@@ -263,6 +277,7 @@ export const defaultModels = {
263
277
  name: 'resource',
264
278
  "icon": "FaBoxOpen",
265
279
  "description": "",
280
+ "tags": ["cms", "assets"],
266
281
  fields: [
267
282
  { name: "source", type: "url"},
268
283
  { name: "file", type: "file"}
@@ -272,6 +287,7 @@ export const defaultModels = {
272
287
  name: 'taxonomy',
273
288
  "icon": "FaTags",
274
289
  "description": "",
290
+ "tags": ["cms", "organization"],
275
291
  fields: [
276
292
  { name: 'name', type: 'string_t', required: true, color: '#71A314' },
277
293
  { name: 'parent', type: 'relation', relation: 'taxonomy', color: '#233607' }, // Relation vers la taxonomie parente
@@ -286,6 +302,7 @@ export const defaultModels = {
286
302
  name: 'contact',
287
303
  "icon": "FaAddressBook",
288
304
  "description": "",
305
+ "tags": ["crm", "contacts"],
289
306
  fields: [
290
307
  { name: 'legalName', type: 'string', asMain: true, color: '#D9D9D9' },
291
308
  { name: 'firstName', type: 'string', asMain: true},
@@ -301,6 +318,7 @@ export const defaultModels = {
301
318
  "icon": "FaMapMarkerAlt",
302
319
  locked: true,
303
320
  "description": "",
321
+ "tags": ["crm", "geolocation"],
304
322
  "fields": [
305
323
  {
306
324
  "name": "address_1",
@@ -359,6 +377,7 @@ export const defaultModels = {
359
377
  name: 'brand',
360
378
  "icon": "FaTrademark",
361
379
  "description": "",
380
+ "tags": ["ecommerce", "products"],
362
381
  fields: [
363
382
  { name: 'name', type: 'string', required: true },
364
383
  { name: 'logo', type: 'file' },
@@ -370,6 +389,7 @@ export const defaultModels = {
370
389
  name: 'product',
371
390
  "icon": "FaShoppingBag",
372
391
  "description": "",
392
+ "tags": ["ecommerce", "products"],
373
393
  fields: [
374
394
  { name: 'name', type: 'string_t', required: true },
375
395
  { name: 'image', type: 'array', itemsType: 'file', mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] },
@@ -388,6 +408,7 @@ export const defaultModels = {
388
408
  name: 'productVariant',
389
409
  "icon": "FaBox",
390
410
  "description": "",
411
+ "tags": ["ecommerce", "products"],
391
412
  fields: [
392
413
  { name: 'product', type: 'relation', relation: 'product', required: true },
393
414
  { name: 'size', type: 'string' },
@@ -404,6 +425,7 @@ export const defaultModels = {
404
425
  name: 'cart',
405
426
  "icon": "FaShoppingCart",
406
427
  "description": "",
428
+ "tags": ["ecommerce", "sales"],
407
429
  fields: [
408
430
  { name: 'user', type: 'relation', relation: 'user', required: true },
409
431
  { name: 'items', type: 'relation', relation: 'cartItem', multiple: true },
@@ -416,6 +438,7 @@ export const defaultModels = {
416
438
  name: 'cartItem',
417
439
  "icon": "FaShoppingBasket",
418
440
  "description": "",
441
+ "tags": ["ecommerce", "sales"],
419
442
  fields: [
420
443
  { name: 'product', type: 'relation', relation: 'product', required: true },
421
444
  { name: 'quantity', type: 'number', required: true, min: 1, step: 1 },
@@ -427,6 +450,7 @@ export const defaultModels = {
427
450
  "icon": "FaTicketAlt",
428
451
  locked: true,
429
452
  "description": "",
453
+ "tags": ["ecommerce", "sales"],
430
454
  fields: [
431
455
  { "name": "code", "type": "string", "required": true, "unique": true },
432
456
  { "name": "productSelection", "type": "relation", "relation": "product", "required": false, multiple: true },
@@ -445,6 +469,7 @@ export const defaultModels = {
445
469
  "icon": "FaClipboardList",
446
470
  locked: true,
447
471
  "description": "",
472
+ "tags": ["ecommerce", "sales"],
448
473
  fields: [
449
474
  { "name": "orderId", "type": "string", "required": true, "unique": true },
450
475
  { "name": "orderDate", "type": "datetime" },
@@ -466,6 +491,7 @@ export const defaultModels = {
466
491
  name: 'invoice',
467
492
  "icon": "FaFileInvoice",
468
493
  "description": "",
494
+ "tags": ["ecommerce", "finance"],
469
495
  fields: [
470
496
  { name: 'order', type: 'relation', relation: 'order', required: true },
471
497
  { name: 'invoiceId', type: 'string', required: true, unique: true },
@@ -479,6 +505,7 @@ export const defaultModels = {
479
505
  "icon": "FaCalendarCheck",
480
506
  "description": "",
481
507
  locked: true,
508
+ "tags": ["ecommerce", "billing"],
482
509
  fields: [
483
510
  { name: 'user', type: 'relation', relation: 'user', required: true },
484
511
  { name: 'product', type: 'relation', relation: 'product', required: true },
@@ -499,6 +526,7 @@ export const defaultModels = {
499
526
  name: 'stock',
500
527
  "icon": "FaWarehouse",
501
528
  "description": "",
529
+ "tags": ["ecommerce", "inventory"],
502
530
  fields: [
503
531
  { name: 'product', type: 'relation', relation: 'product', required: true },
504
532
  { name: 'variant', type: 'relation', relation: 'productVariant' }, // Optionnel
@@ -511,6 +539,7 @@ export const defaultModels = {
511
539
  name: 'stockAlert',
512
540
  "icon": "FaExclamationTriangle",
513
541
  "description": "",
542
+ "tags": ["ecommerce", "inventory", "monitoring"],
514
543
  fields: [
515
544
  { name: 'user', type: 'relation', relation: 'user', required: true },
516
545
  { name: 'stock', type: 'relation', relation: 'stock', required: true },
@@ -522,6 +551,7 @@ export const defaultModels = {
522
551
  name: 'shipment',
523
552
  "icon": "FaTruck",
524
553
  "description": "",
554
+ "tags": ["ecommerce", "logistics"],
525
555
  fields: [
526
556
  { name: 'order', type: 'relation', relation: 'order', required: true },
527
557
  { name: 'trackingNumber', type: 'string' },
@@ -535,6 +565,7 @@ export const defaultModels = {
535
565
  name: 'warehouse',
536
566
  "description": "",
537
567
  "icon": "FaWarehouse",
568
+ "tags": ["ecommerce", "inventory"],
538
569
  fields: [
539
570
  { name: 'name', type: 'string_t', required: true },
540
571
  { name: 'location', type: 'relation', relation: 'location' },
@@ -545,6 +576,7 @@ export const defaultModels = {
545
576
  name: "return",
546
577
  "description": "",
547
578
  "icon": "FaUndo",
579
+ "tags": ["ecommerce", "sales"],
548
580
  fields: [
549
581
  { "name": "order", "type": "relation", "relation": "order", "required": true },
550
582
  { "name": "user", "type": "relation", relation: "user" },
@@ -560,6 +592,7 @@ export const defaultModels = {
560
592
  name: 'returnItem',
561
593
  "icon": "FaBoxOpen",
562
594
  "description": "",
595
+ "tags": ["ecommerce", "sales"],
563
596
  fields: [
564
597
  { name: 'return', type: 'relation', relation: 'return', required: true },
565
598
  { name: 'product', type: 'relation', relation: 'product', required: true },
@@ -573,6 +606,7 @@ export const defaultModels = {
573
606
  "icon": "FaTicketAlt",
574
607
  "description": "",
575
608
  locked: true,
609
+ "tags": ["support", "communication"],
576
610
  fields: [
577
611
  { name: 'user', type: 'relation', relation: 'user', required: true },
578
612
  { name: 'order', type: 'relation', relation: 'order' },
@@ -590,6 +624,7 @@ export const defaultModels = {
590
624
  name: "review",
591
625
  "icon": "FaStar",
592
626
  "description": "",
627
+ "tags": ["ecommerce", "feedback"],
593
628
  fields: [
594
629
  { "name": "user", "type": "relation", relation: "user" },
595
630
  { "name": "product", "type": "relation", relation: 'product' },
@@ -603,6 +638,7 @@ export const defaultModels = {
603
638
  name: "device",
604
639
  "icon": "FaMobile",
605
640
  "description": "",
641
+ "tags": ["system", "iot"],
606
642
  fields: [
607
643
  { "name": "location", "type": "relation", relation: 'location' },
608
644
  { "name": "lastLocationUpdate", "type": "datetime" }
@@ -613,6 +649,7 @@ export const defaultModels = {
613
649
  name: 'accountingExercise',
614
650
  "icon": "FaBook",
615
651
  description: "Représente un exercice comptable pour une entreprise donnée.",
652
+ "tags": ["finance", "accounting"],
616
653
  fields: [
617
654
  { name: 'name', type: 'string_t', 'required': true, unique: true, hint: "Intitulé de l'exercice comptable" },
618
655
  { name: 'companyContact', type: 'relation', relation: 'contact', 'required': true, hint: "Désignation de l'entreprise" },
@@ -628,6 +665,7 @@ export const defaultModels = {
628
665
  "icon": "FaListAlt",
629
666
  description: "Définit une ligne/catégorie dans un document comptable.",
630
667
  locked: true, // Probablement géré par l'application, pas par l'utilisateur final
668
+ "tags": ["finance", "accounting"],
631
669
  fields: [
632
670
  { name: 'accountingExercise', type: 'relation', required: true, unique: true, relation: "accountingExercise" },
633
671
  { name: 'code', type: 'string', required: true, unique: true, hint: "Code unique de la ligne (ex: AA, FB, HA)" },
@@ -657,6 +695,7 @@ export const defaultModels = {
657
695
  "name": "accountingEntry",
658
696
  "icon": "FaPenAlt",
659
697
  "description": "",
698
+ "tags": ["finance", "accounting"],
660
699
  "fields": [
661
700
  {
662
701
  "name": "exercise",
@@ -727,6 +766,7 @@ export const defaultModels = {
727
766
  "name": "employee",
728
767
  "icon": "FaUserTie",
729
768
  "description": "",
769
+ "tags": ["hr", "users"],
730
770
  "fields": [
731
771
  {
732
772
  "name": "employeeId",
@@ -868,6 +908,7 @@ export const defaultModels = {
868
908
  name: 'workflow',
869
909
  "icon": "FaProjectDiagram",
870
910
  description: "Defines an automated process.",
911
+ "tags": ["system", "automation"],
871
912
  fields: [
872
913
  { name: 'name', type: 'string_t', required: true, hint: "Unique name for the workflow (e.g., 'Order Validation', 'Low Stock Notification')." },
873
914
  { name: 'description', type: 'richtext', hint: "Detailed explanation of the workflow's purpose." },
@@ -878,6 +919,7 @@ export const defaultModels = {
878
919
  name: 'workflowTrigger',
879
920
  "icon": "FaPlay",
880
921
  description: "Represents an event that can initiate a workflow.",
922
+ "tags": ["system", "automation"],
881
923
  fields: [
882
924
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
883
925
  { name: 'name', type: 'string_t', required: true, unique: true, hint: "Descriptive name for the trigger (e.g., 'New Order Created', 'Stock < 5', 'Monday 9 AM Report')." },
@@ -898,9 +940,9 @@ export const defaultModels = {
898
940
  {$eq: ["$type", "manual"]},
899
941
  {
900
942
  $or: [
901
- { path: "onEvent", op: "$eq", value: "DataAdded" },
902
- { path: "onEvent", op: "$eq", value: "DataEdited" },
903
- { path: "onEvent", op: "$eq", value: "DataDeleted" }
943
+ { $eq: ["$onEvent", "DataAdded"] },
944
+ { $eq: ["$onEvent", "DataEdited"] },
945
+ { $eq: ["$onEvent", "DataDeleted"] }
904
946
  ]
905
947
  }
906
948
  ]
@@ -911,9 +953,9 @@ export const defaultModels = {
911
953
  {$eq: ["$type", "manual"]},
912
954
  {
913
955
  $or: [
914
- { path: "onEvent", op: "$eq", value: "DataAdded" },
915
- { path: "onEvent", op: "$eq", value: "DataEdited" },
916
- { path: "onEvent", op: "$eq", value: "DataDeleted" }
956
+ { $eq: ["$onEvent", "DataAdded"] },
957
+ { $eq: ["$onEvent", "DataEdited"] },
958
+ { $eq: ["$onEvent", "DataDeleted"] }
917
959
  ]
918
960
  }
919
961
  ]
@@ -930,6 +972,7 @@ export const defaultModels = {
930
972
  name: 'workflowStep',
931
973
  "icon": "FaStepForward",
932
974
  description: "A single step within a workflow process.",
975
+ "tags": ["system", "automation"],
933
976
  fields: [
934
977
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
935
978
  { name: 'name', type: 'string_t', hint: "Optional descriptive name for the step (e.g., 'Check Inventory', 'Send Confirmation Email')." },
@@ -944,6 +987,7 @@ export const defaultModels = {
944
987
  name: 'workflowAction',
945
988
  "icon": "FaCogs",
946
989
  description: "Defines a specific operation to be performed by a workflow step.",
990
+ "tags": ["system", "automation"],
947
991
  fields: [
948
992
  { name: 'name', type: 'string_t', required: true, hint: "Name of the action (e.g., 'Update Order Status', 'Send Email', 'Call Payment API')." },
949
993
  {
@@ -1044,6 +1088,7 @@ export const defaultModels = {
1044
1088
  name: 'workflowRun',
1045
1089
  "icon": "FaRunning",
1046
1090
  description: "Tracks a specific execution instance of a workflow.",
1091
+ "tags": ["system", "automation", "logs"],
1047
1092
  fields: [
1048
1093
  { name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow definition that was executed." },
1049
1094
  { name: 'contextData', type: 'code', language: 'json',default: {}, hint: "Snapshot of the data or event that triggered this run." },
@@ -1068,6 +1113,7 @@ export const defaultModels = {
1068
1113
  "icon": "FaTachometerAlt",
1069
1114
  description: "Configuration d'un tableau de bord personnalisé par l'utilisateur.", // Description du modèle
1070
1115
  locked: false, // Indique si le modèle peut être modifié par l'utilisateur (false = modifiable)
1116
+ "tags": ["reporting", "analytics"],
1071
1117
  fields: [
1072
1118
  {
1073
1119
  name: 'name', // Nom du tableau de bord
@@ -1109,6 +1155,7 @@ export const defaultModels = {
1109
1155
  "icon": "FaExchangeAlt",
1110
1156
  description: "Journal des requêtes reçues par l'API.",
1111
1157
  locked: true, // Géré par le système, non modifiable directement par l'utilisateur via l'UI standard
1158
+ "tags": ["system", "logs", "monitoring"],
1112
1159
  fields: [
1113
1160
  {
1114
1161
  name: 'timestamp',
@@ -1194,6 +1241,7 @@ export const defaultModels = {
1194
1241
  name: 'kpi',
1195
1242
  "icon": "FaChartLine",
1196
1243
  description: "Configuration d'un Indicateur Clé de Performance (KPI)",
1244
+ "tags": ["reporting", "analytics"],
1197
1245
  fields: [
1198
1246
  { name: 'name', type: 'string_t', required: true, hint: "Nom affiché du KPI (ex: Chiffre d'affaires total)" },
1199
1247
  { name: 'description', type: 'string_t', hint: "Informations complémentaires sur le KPI" },
@@ -1207,13 +1255,17 @@ export const defaultModels = {
1207
1255
  },
1208
1256
  {
1209
1257
  name: 'aggregationField',
1210
- type: 'string',
1258
+ type: 'modelField',
1259
+ targetModel: '$targetModel',
1260
+ condition: { $ne: ["$aggregationType", "count"] },
1211
1261
  hint: "Nom du champ numérique sur lequel appliquer l'agrégation (ex: totalAmount). Non requis pour 'count'."
1212
1262
  },
1213
1263
  {
1214
1264
  name: 'matchFormula',
1215
1265
  type: 'code', // Utiliser l'éditeur de code pour le JSON
1216
1266
  language: 'json',
1267
+ conditionBuilder: true,
1268
+ targetModel: '$targetModel',
1217
1269
  default: {}, // Valeur par défaut: aucun filtre
1218
1270
  hint: "Filtre JSON (MongoDB $match) à appliquer avant l'agrégation (ex: { \"status\": \"delivered\" })"
1219
1271
  },
@@ -1259,6 +1311,7 @@ export const defaultModels = {
1259
1311
  "icon": "FaImages",
1260
1312
  description: "Représente une galerie d'images avec un titre et une description.",
1261
1313
  locked: false, // Les utilisateurs peuvent créer/gérer leurs galeries
1314
+ "tags": ["cms", "assets"],
1262
1315
  fields: [
1263
1316
  {
1264
1317
  name: 'name',
@@ -1300,6 +1353,7 @@ export const defaultModels = {
1300
1353
  name: 'budget',
1301
1354
  "icon": "FaMoneyCheck",
1302
1355
  description: "Un budget permet de lister vos transactions personnelles.",
1356
+ "tags": ["personal", "finance"],
1303
1357
  fields: [
1304
1358
  {
1305
1359
  name: 'name',
@@ -1372,6 +1426,7 @@ export const defaultModels = {
1372
1426
  "name": "event",
1373
1427
  "icon": "FaCalendar",
1374
1428
  "description": "A model for managing events, conferences, meetups, and gatherings.",
1429
+ "tags": ["cms", "events"],
1375
1430
  "fields": [
1376
1431
  {
1377
1432
  "name": "title",
@@ -1485,6 +1540,7 @@ export const defaultModels = {
1485
1540
  name: "endpoint",
1486
1541
  "icon": "FaCode",
1487
1542
  description: "Defines custom API endpoints that execute a server-side script.",
1543
+ "tags": ["system", "api", "automation"],
1488
1544
  fields: [
1489
1545
  {
1490
1546
  name: "isActive",
package/src/email.js CHANGED
@@ -3,6 +3,7 @@ import nodemailer from "nodemailer";
3
3
  import juice from "juice";
4
4
  import {Event} from "./events.js";
5
5
  import {emailDefaultConfig} from "./constants.js";
6
+ import {Config} from "./config.js";
6
7
 
7
8
  // Le transporteur par défaut, utilisé si aucune config spécifique n'est fournie.
8
9
  const defaultTransporter = nodemailer.createTransport({
@@ -45,12 +46,14 @@ const createTransporter = (smtpConfig) => {
45
46
  * @param {string|null} tpl - Le template HTML à utiliser.
46
47
  */
47
48
  export const sendEmail = async (email = "", data, smtpConfig = null, lang, tpl = null) => {
48
- const contactEmail = smtpConfig ? (smtpConfig.from || emailDefaultConfig.from) :"Our company <noreply@ourdomain.tld>";
49
+
50
+ const cfg = Config.Get('emailDefaultConfig', emailDefaultConfig);
51
+ const contactEmail = smtpConfig ? (smtpConfig.from || cfg.from) :"Our company <noreply@ourdomain.tld>";
49
52
  const emails = Array.isArray(email) ? email : [email];
50
53
  if (emails.length === 0) return false;
51
54
 
52
55
  // Choisir le transporteur à utiliser
53
- const transporter = smtpConfig ? createTransporter(smtpConfig||emailDefaultConfig) : defaultTransporter;
56
+ const transporter = smtpConfig ? createTransporter(smtpConfig||cfg) : defaultTransporter;
54
57
 
55
58
  Event.Listen("OnEmailTemplate", (data, lang) => data.content, "event", "system");
56
59
 
package/src/engine.js CHANGED
@@ -7,7 +7,7 @@ import process from "process";
7
7
  import {
8
8
  cookiesSecret,
9
9
  databasePoolSize,
10
- dbName,
10
+ dbName as dbNameBase,
11
11
  tlsAllowInvalidCertificates, tlsAllowInvalidHostnames
12
12
  } from "./constants.js";
13
13
  import http from "http";
@@ -32,7 +32,7 @@ import {createModel, deleteModels, getModels, installAllPacks} from "./modules/d
32
32
  const __filename = fileURLToPath(import.meta.url);
33
33
  const __dirname = path.dirname(__filename);
34
34
 
35
-
35
+ let dbName = Config.Get('dbName', dbNameBase);
36
36
  let caFile, certFile, keyFile;
37
37
  try {
38
38
  if (process.env.CA_CERT)
@@ -127,7 +127,9 @@ export const Engine = {
127
127
  uploadDir: process.cwd()+'/uploads/tmp',
128
128
  multiples: true // req.files to be arrays of files
129
129
  }));
130
- app.use(cookieParser(process.env.COOKIES_SECRET || cookiesSecret));
130
+
131
+ const cs = Config.Get('cookieSecret', process.env.COOKIES_SECRET || cookiesSecret)
132
+ app.use(cookieParser(cs));
131
133
  app.use(requestIp.mw())
132
134
 
133
135
  engine.use = (...args) => {
package/src/filter.js CHANGED
@@ -36,12 +36,14 @@ const evaluateSingleCondition = (currentModelDef, condition, formData, allModels
36
36
 
37
37
  // Gestion des opérateurs d'agrégation (commencent par $)
38
38
  const operator = Object.keys(condition)[0];
39
- if (operator === '$eq' && Array.isArray(condition[operator])) {
40
- // Cas spécial pour {$eq: ['$field', value]}
39
+ if ((operator === '$eq' || operator === '$ne') && Array.isArray(condition[operator])) {
40
+ // Cas spécial pour {$op: ['$field', value]}
41
41
  const [fieldPath, expectedValue] = condition[operator];
42
42
  if (typeof fieldPath === 'string' && fieldPath.startsWith('$')) {
43
43
  const fieldName = fieldPath.substring(1); // Enlève le $ devant
44
- return formData[fieldName] == expectedValue;
44
+ const actualValue = formData[fieldName];
45
+ if (operator === '$eq') return actualValue == expectedValue;
46
+ if (operator === '$ne') return actualValue != expectedValue;
45
47
  }
46
48
  }
47
49