data-primals-engine 1.5.1 → 1.6.0

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 (70) hide show
  1. package/README.md +924 -913
  2. package/client/README.md +136 -136
  3. package/client/index.js +0 -1
  4. package/client/public/doc/API.postman_collection.json +213 -213
  5. package/client/public/react.svg +9 -9
  6. package/client/src/AddWidgetTypeModal.jsx +47 -47
  7. package/client/src/App.css +42 -42
  8. package/client/src/App.jsx +92 -150
  9. package/client/src/App.scss +7 -1
  10. package/client/src/AssistantChat.jsx +362 -363
  11. package/client/src/Button.jsx +12 -12
  12. package/client/src/Dashboard.jsx +480 -480
  13. package/client/src/DashboardHtmlViewItem.jsx +146 -146
  14. package/client/src/DashboardView.jsx +654 -654
  15. package/client/src/DataEditor.jsx +383 -383
  16. package/client/src/DataLayout.jsx +779 -806
  17. package/client/src/DataTable.jsx +782 -822
  18. package/client/src/DataTable.scss +186 -186
  19. package/client/src/GeolocationField.jsx +93 -93
  20. package/client/src/HistoryDialog.jsx +307 -285
  21. package/client/src/HistoryDialog.scss +319 -319
  22. package/client/src/HtmlViewBuilderModal.jsx +90 -90
  23. package/client/src/HtmlViewBuilderModal.scss +17 -17
  24. package/client/src/HtmlViewCard.jsx +43 -43
  25. package/client/src/ModelCreatorField.jsx +950 -950
  26. package/client/src/ModelList.jsx +7 -2
  27. package/client/src/Notification.jsx +136 -136
  28. package/client/src/PackGallery.jsx +391 -391
  29. package/client/src/PackGallery.scss +231 -231
  30. package/client/src/Pagination.jsx +143 -143
  31. package/client/src/RelationField.jsx +354 -354
  32. package/client/src/RelationSelectorWidget.jsx +172 -172
  33. package/client/src/RelationValue.jsx +2 -1
  34. package/client/src/contexts/CommandContext.jsx +260 -0
  35. package/client/src/contexts/ModelContext.jsx +4 -1
  36. package/client/src/contexts/UIContext.jsx +72 -72
  37. package/client/src/filter.js +263 -262
  38. package/client/src/index.css +90 -90
  39. package/package.json +11 -10
  40. package/perf/artillery-hooks.js +37 -37
  41. package/perf/setup.yml +25 -25
  42. package/src/constants.js +4 -0
  43. package/src/core.js +8 -1
  44. package/src/engine.js +335 -293
  45. package/src/events.js +140 -21
  46. package/src/filter.js +274 -274
  47. package/src/index.js +3 -0
  48. package/src/modules/assistant/assistant.js +323 -192
  49. package/src/modules/assistant/constants.js +2 -1
  50. package/src/modules/auth-google/index.js +50 -50
  51. package/src/modules/auth-microsoft/index.js +81 -81
  52. package/src/modules/data/data.core.js +118 -118
  53. package/src/modules/data/data.history.js +555 -531
  54. package/src/modules/data/data.operations.js +145 -26
  55. package/src/modules/data/data.relations.js +686 -686
  56. package/src/modules/data/data.routes.js +1879 -1879
  57. package/src/modules/data/data.validation.js +2 -2
  58. package/src/modules/file.js +247 -247
  59. package/src/modules/user.js +1 -0
  60. package/src/modules/workflow.js +2 -2
  61. package/src/openai.jobs.js +3 -2
  62. package/src/packs.js +2 -2
  63. package/src/providers.js +2 -2
  64. package/src/services/stripe.js +196 -196
  65. package/src/sso.js +193 -193
  66. package/src/workers/import-export-worker.js +1 -1
  67. package/test/data.history.integration.test.js +72 -0
  68. package/test/data.integration.test.js +92 -1
  69. package/test/events.test.js +108 -10
  70. package/test/model.integration.test.js +377 -377
package/src/events.js CHANGED
@@ -10,6 +10,38 @@ const eventLayerSystems = {
10
10
  "custom": ["data"]
11
11
  };
12
12
 
13
+ /**
14
+ * Parses a priority string/number into a structured object for sorting.
15
+ * @param {string|number} [priority='identity'] - The priority value.
16
+ * - 'beforeAll': Executes before all others in the same layer.
17
+ * - 'afterAll': Executes after all others in the same layer.
18
+ * - A number (e.g., 50): A numeric weight (lower is higher priority).
19
+ * - 'identity' or undefined: Default, executes in registration order after weighted listeners.
20
+ * @returns {{type: string, weight: number}}
21
+ * @private
22
+ */
23
+ function _parsePriority(priority = 'identity') {
24
+ if (priority === 'beforeAll') {
25
+ return { type: 'special', weight: -Infinity };
26
+ }
27
+ if (priority === 'afterAll') {
28
+ return { type: 'special', weight: Infinity };
29
+ }
30
+
31
+ const numericWeight = parseInt(priority, 10);
32
+ if (!isNaN(numericWeight)) {
33
+ return {
34
+ type: 'weighted',
35
+ weight: numericWeight
36
+ };
37
+ }
38
+
39
+ // Default for 'identity' or any unrecognized format
40
+ return { type: 'identity', weight: Number.MAX_SAFE_INTEGER };
41
+ }
42
+
43
+
44
+
13
45
 
14
46
 
15
47
  export const Event = {
@@ -35,24 +67,34 @@ export const Event = {
35
67
  if (layersToProcess) {
36
68
  for (const currentLayer of layersToProcess) {
37
69
  if (events[currentSystem][name][currentLayer]) {
38
- for (const callback of events[currentSystem][name][currentLayer]) {
70
+ // Create a copy and sort listeners based on priority before execution
71
+ const sortedListeners = [...events[currentSystem][name][currentLayer]].sort((a, b) => {
72
+ const weightDifference = a.priority.weight - b.priority.weight;
73
+ if (weightDifference !== 0) {
74
+ return weightDifference;
75
+ }
76
+ // For listeners with the same weight (especially 'identity'), maintain registration order
77
+ return a.originalIndex - b.originalIndex;
78
+ });
79
+
80
+ for (const listener of sortedListeners) {
39
81
  try {
40
- const res = await callback(...args);
82
+ const res = await listener.callback(...args);
41
83
  if (typeof res === "object" && !Array.isArray(res)) {
42
84
  if (typeof ret !== "object") ret = {};
43
85
  ret = {...ret, ...res};
44
86
  } else if (Array.isArray(res)) {
45
87
  if (!ret || !Array.isArray(ret)) ret = [];
46
88
  ret = ret.concat(res);
47
- } else if (typeof res === "string") {
48
- if (typeof ret !== "string") ret = "";
49
- ret += res;
50
- } else if (typeof res === "number") {
51
- if (typeof ret !== "number") ret = 0;
52
- ret += res;
53
- } else if (typeof res === "boolean") {
54
- if (typeof ret !== "boolean") ret = true;
55
- ret = res && ret;
89
+ } else if (res !== undefined && res !== null) {
90
+ // Simplified aggregation for primitive types
91
+ if (typeof res === "string") {
92
+ ret = (ret || "") + res;
93
+ } else if (typeof res === "number") {
94
+ ret = (ret || 0) + res;
95
+ } else if (typeof res === "boolean") {
96
+ ret = res && (ret === null ? true : ret);
97
+ }
56
98
  } else {
57
99
  ret = res || ret;
58
100
  }
@@ -71,32 +113,109 @@ export const Event = {
71
113
  }
72
114
  return ret;
73
115
  },
74
- Listen: (name = "", callback, system = "priority", layer = "medium") => {
75
- const validSystems = Object.keys(eventLayerSystems); // Récupération des clés pour une vérification plus performante
116
+ Listen: function(name = "", callback, ...args) {
117
+ let system = "priority";
118
+ let layer = "medium";
119
+ let priority = 'identity';
120
+
121
+ // Détecte si la nouvelle signature (avec objet) ou l'ancienne (avec arguments multiples) est utilisée.
122
+ if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && !Array.isArray(args[0])) {
123
+ // Nouvelle signature: Listen(name, cb, { system, layer, priority })
124
+ ({ system = "priority", layer = "medium", priority = 'identity' } = args[0]);
125
+ } else if (args.length > 0) {
126
+ // Ancienne signature: Listen(name, cb, system, layer, priority)
127
+ [system = "priority", layer = "medium", priority = 'identity'] = args;
128
+ }
129
+
130
+ const validSystems = Object.keys(eventLayerSystems);
76
131
  if (!validSystems.includes(system)) {
77
- throw new Error(`System '${system}' does not exist. Valid systems are: ${validSystems.join(', ')}`); // Message d'erreur plus informatif
132
+ throw new Error(`System '${system}' does not exist. Valid systems are: ${validSystems.join(', ')}`);
78
133
  }
79
134
 
80
- const validLayers = eventLayerSystems[system]; // Récupération des couches valides pour le système
135
+ const validLayers = eventLayerSystems[system];
81
136
  if (!validLayers.includes(layer)) {
82
- throw new Error(`Layer '${layer}' does not exist in system '${system}'. Valid layers are: ${validLayers.join(', ')}`); // Message d'erreur plus informatif
137
+ throw new Error(`Layer '${layer}' does not exist in system '${system}'. Valid layers are: ${validLayers.join(', ')}`);
83
138
  }
84
139
 
85
- safeAssignObject(events, system, events[system] || {}); // Simplification de la création des objets
140
+ safeAssignObject(events, system, events[system] || {});
86
141
  safeAssignObject(events[system], name, events[system][name] || {});
87
142
  safeAssignObject(events[system][name], layer, events[system][name][layer] || []);
88
- events[system][name][layer].push(callback);
143
+
144
+ const listener = {
145
+ callback,
146
+ priority: _parsePriority(priority),
147
+ originalIndex: events[system][name][layer].length
148
+ };
149
+ events[system][name][layer].push(listener);
150
+ },
151
+ addSystem: (system) => {
152
+ if (typeof system !== 'string' || system.trim() === '') {
153
+ throw new Error('Le nom du système doit être une chaîne de caractères non vide.');
154
+ }
155
+ if (!eventLayerSystems.hasOwnProperty(system)) {
156
+ eventLayerSystems[system] = [];
157
+ } else {
158
+ console.warn(`[Event] Le système '${system}' existe déjà.`);
159
+ }
89
160
  },
90
- RemoveCallback: (name, callback, layer="medium", system='priority') => {
161
+ addLayer: (system, layer) => {
162
+ if (typeof system !== 'string' || system.trim() === '') {
163
+ throw new Error('Le nom du système doit être une chaîne de caractères non vide.');
164
+ }
165
+ if (typeof layer !== 'string' || layer.trim() === '') {
166
+ throw new Error('Le nom de la couche doit être une chaîne de caractères non vide.');
167
+ }
168
+ if (!eventLayerSystems.hasOwnProperty(system)) {
169
+ throw new Error(`Le système '${system}' n'existe pas. Veuillez l'ajouter avec addSystem('${system}').`);
170
+ }
171
+ if (!eventLayerSystems[system].includes(layer)) {
172
+ eventLayerSystems[system].push(layer);
173
+ }
174
+ },
175
+ RemoveCallback: function(name, callback, ...args) {
176
+ let system = "priority";
177
+ let layer = "medium";
178
+
179
+ if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && !Array.isArray(args[0])) {
180
+ // Nouvelle signature: Unlisten(name, cb, { system, layer })
181
+ ({ system = "priority", layer = "medium" } = args[0]);
182
+ } else if (args.length > 0) {
183
+ // Ancienne signature: Unlisten(name, cb, system, layer)
184
+ [system = "priority", layer = "medium"] = args;
185
+ }
186
+
91
187
  if (!events[system] || !events[system][name] || !events[system][name][layer]) {
92
- return; // Si l'événement, le système ou la couche n'existent pas, on ne fait rien
188
+ return;
93
189
  }
94
190
 
95
- const index = events[system][name][layer].indexOf(callback);
191
+ const index = events[system][name][layer].findIndex(listener => listener.callback === callback);
96
192
  if (index > -1) {
97
193
  events[system][name][layer].splice(index, 1);
98
194
  }
99
195
  },
196
+
197
+ /**
198
+ * Removes all listeners from a specific event layer that match a given priority.
199
+ * @param {string} name - The name of the event.
200
+ * @param {string|number} priority - The priority to remove ('beforeAll', 'afterAll', a number, or 'identity').
201
+ * @param {object} [options={}] - Options to specify the system and layer.
202
+ * @param {string} [options.system='priority'] - The system of the event.
203
+ * @param {string} [options.layer='medium'] - The layer of the event.
204
+ */
205
+ RemoveCallbacksByPriority: function(name, priority, options = {}) {
206
+ const { system = "priority", layer = "medium" } = options;
207
+
208
+ if (!events[system] || !events[system][name] || !events[system][name][layer]) {
209
+ return;
210
+ }
211
+
212
+ const parsedPriorityToRemove = _parsePriority(priority);
213
+ events[system][name][layer] = events[system][name][layer].filter(listener => {
214
+ // Keep the listener if its priority does NOT match the one to remove
215
+ return listener.priority.type !== parsedPriorityToRemove.type || listener.priority.weight !== parsedPriorityToRemove.weight;
216
+ });
217
+ },
218
+
100
219
  // Ajout d'une méthode pour supprimer tous les callbacks d'un événement (optionnel)
101
220
  RemoveAllCallbacks: (name, system = 'priority') => {
102
221
  if (events[system] && events[system][name]) {