data-primals-engine 1.5.2 → 1.6.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 (70) hide show
  1. package/README.md +938 -915
  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 +6 -0
  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 -808
  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 -307
  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/ModelCreator.jsx +683 -686
  26. package/client/src/ModelCreator.scss +1 -1
  27. package/client/src/ModelCreatorField.jsx +950 -950
  28. package/client/src/ModelImporter.jsx +3 -0
  29. package/client/src/ModelList.jsx +280 -280
  30. package/client/src/Notification.jsx +136 -136
  31. package/client/src/PackGallery.jsx +391 -391
  32. package/client/src/PackGallery.scss +231 -231
  33. package/client/src/Pagination.jsx +143 -143
  34. package/client/src/RelationField.jsx +354 -354
  35. package/client/src/RelationSelectorWidget.jsx +172 -172
  36. package/client/src/RelationValue.jsx +2 -1
  37. package/client/src/contexts/CommandContext.jsx +260 -0
  38. package/client/src/contexts/ModelContext.jsx +4 -1
  39. package/client/src/contexts/UIContext.jsx +72 -72
  40. package/client/src/filter.js +263 -263
  41. package/client/src/index.css +90 -90
  42. package/package.json +6 -5
  43. package/perf/artillery-hooks.js +37 -37
  44. package/perf/setup.yml +25 -25
  45. package/src/constants.js +4 -0
  46. package/src/defaultModels.js +7 -0
  47. package/src/engine.js +335 -335
  48. package/src/events.js +232 -137
  49. package/src/filter.js +274 -274
  50. package/src/index.js +1 -0
  51. package/src/modules/assistant/assistant.js +225 -83
  52. package/src/modules/auth-google/index.js +50 -50
  53. package/src/modules/auth-microsoft/index.js +81 -81
  54. package/src/modules/data/data.core.js +118 -118
  55. package/src/modules/data/data.history.js +555 -555
  56. package/src/modules/data/data.operations.js +112 -9
  57. package/src/modules/data/data.relations.js +686 -686
  58. package/src/modules/data/data.routes.js +1879 -1879
  59. package/src/modules/data/data.validation.js +2 -2
  60. package/src/modules/file.js +247 -247
  61. package/src/modules/user.js +14 -9
  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/test/data.history.integration.test.js +264 -264
  67. package/test/data.integration.test.js +1281 -1206
  68. package/test/events.test.js +108 -10
  69. package/test/model.integration.test.js +377 -377
  70. package/test/user.test.js +106 -1
package/src/events.js CHANGED
@@ -1,137 +1,232 @@
1
- import {safeAssignObject} from "./core.js";
2
-
3
- const events = {};
4
-
5
- const eventLayerSystems = {
6
- "priority": ["high", "medium", "low"],
7
- "log": ["info", "debug", "warn", "error", "critical"],
8
- "system": ["calls", "users"],
9
- "event": ["system","user"],
10
- "custom": ["data"]
11
- };
12
-
13
-
14
-
15
- export const Event = {
16
- Trigger: async (name, system = "priority", layer = "medium", ...args) => { // Ajout des arguments system et layer
17
- if (!name || typeof name !== 'string') {
18
- throw new Error('Event name must be a non-empty string');
19
- }
20
-
21
- if (!events[system] || !events[system][name] || (layer && !events[system][name][layer])) {
22
- //console.warn(`No trigger found for ${name} in system ${system} layer ${layer}`);
23
- return null;
24
- }
25
-
26
- const systemsToProcess = system ? [system] : Object.keys(events); // Si system est spécifié, on cible ce système uniquement, sinon tous les systèmes
27
- console.log(`[Event] Triggering ${system}.${layer}.${name}`, {
28
- callbacks: events[system]?.[name]?.[layer]?.length || 0
29
- });
30
- let ret = null;
31
- for (const currentSystem of systemsToProcess) {
32
- if (events[currentSystem] && events[currentSystem][name]) {
33
- const layersToProcess = layer ? [layer] : eventLayerSystems[currentSystem] || Object.keys(events[currentSystem][name]); // Si layer est spécifié, on cible cette couche, sinon toutes les couches ou celles définies dans eventLayerSystems
34
-
35
- if (layersToProcess) {
36
- for (const currentLayer of layersToProcess) {
37
- if (events[currentSystem][name][currentLayer]) {
38
- for (const callback of events[currentSystem][name][currentLayer]) {
39
- try {
40
- const res = await callback(...args);
41
- if (typeof res === "object" && !Array.isArray(res)) {
42
- if (typeof ret !== "object") ret = {};
43
- ret = {...ret, ...res};
44
- } else if (Array.isArray(res)) {
45
- if (!ret || !Array.isArray(ret)) ret = [];
46
- 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;
56
- } else {
57
- ret = res || ret;
58
- }
59
- } catch (error) {
60
- const errorMsg = `Error in callback for event ${name} in system ${currentSystem} layer ${currentLayer}: ${error.message}`;
61
- const newError = new Error(errorMsg);
62
- newError.originalError = error; // Conserve l'erreur originale
63
- newError.eventDetails = { name, system: currentSystem, layer: currentLayer };
64
- throw newError;
65
- }
66
- }
67
- }
68
- }
69
- }
70
- }
71
- }
72
- return ret;
73
- },
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
76
- if (!validSystems.includes(system)) {
77
- throw new Error(`System '${system}' does not exist. Valid systems are: ${validSystems.join(', ')}`); // Message d'erreur plus informatif
78
- }
79
-
80
- const validLayers = eventLayerSystems[system]; // Récupération des couches valides pour le système
81
- 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
83
- }
84
-
85
- safeAssignObject(events, system, events[system] || {}); // Simplification de la création des objets
86
- safeAssignObject(events[system], name, events[system][name] || {});
87
- safeAssignObject(events[system][name], layer, events[system][name][layer] || []);
88
- events[system][name][layer].push(callback);
89
- },
90
- addSystem: (system) => {
91
- if (typeof system !== 'string' || system.trim() === '') {
92
- throw new Error('Le nom du système doit être une chaîne de caractères non vide.');
93
- }
94
- if (!eventLayerSystems.hasOwnProperty(system)) {
95
- eventLayerSystems[system] = [];
96
- } else {
97
- console.warn(`[Event] Le système '${system}' existe déjà.`);
98
- }
99
- },
100
- addLayer: (system, layer) => {
101
- if (typeof system !== 'string' || system.trim() === '') {
102
- throw new Error('Le nom du système doit être une chaîne de caractères non vide.');
103
- }
104
- if (typeof layer !== 'string' || layer.trim() === '') {
105
- throw new Error('Le nom de la couche doit être une chaîne de caractères non vide.');
106
- }
107
- if (!eventLayerSystems.hasOwnProperty(system)) {
108
- throw new Error(`Le système '${system}' n'existe pas. Veuillez l'ajouter avec addSystem('${system}').`);
109
- }
110
- if (!eventLayerSystems[system].includes(layer)) {
111
- eventLayerSystems[system].push(layer);
112
- }
113
- },
114
- RemoveCallback: (name, callback, layer="medium", system='priority') => {
115
- if (!events[system] || !events[system][name] || !events[system][name][layer]) {
116
- return; // Si l'événement, le système ou la couche n'existent pas, on ne fait rien
117
- }
118
-
119
- const index = events[system][name][layer].indexOf(callback);
120
- if (index > -1) {
121
- events[system][name][layer].splice(index, 1);
122
- }
123
- },
124
- // Ajout d'une méthode pour supprimer tous les callbacks d'un événement (optionnel)
125
- RemoveAllCallbacks: (name, system = 'priority') => {
126
- if (events[system] && events[system][name]) {
127
- delete events[system][name]; // Supprime l'objet contenant les couches et les callbacks
128
- }
129
- },
130
-
131
- // Ajout d'une méthode pour supprimer tous les callbacks d'un système (optionnel)
132
- RemoveSystemCallbacks: (system) => {
133
- if (events[system]) {
134
- delete events[system];
135
- }
136
- }
137
- }
1
+ import {safeAssignObject} from "./core.js";
2
+
3
+ const events = {};
4
+
5
+ const eventLayerSystems = {
6
+ "priority": ["high", "medium", "low"],
7
+ "log": ["info", "debug", "warn", "error", "critical"],
8
+ "system": ["calls", "users"],
9
+ "event": ["system","user"],
10
+ "custom": ["data"]
11
+ };
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
+
45
+
46
+
47
+ export const Event = {
48
+ Trigger: async (name, system = "priority", layer = "medium", ...args) => { // Ajout des arguments system et layer
49
+ if (!name || typeof name !== 'string') {
50
+ throw new Error('Event name must be a non-empty string');
51
+ }
52
+
53
+ if (!events[system] || !events[system][name] || (layer && !events[system][name][layer])) {
54
+ //console.warn(`No trigger found for ${name} in system ${system} layer ${layer}`);
55
+ return null;
56
+ }
57
+
58
+ const systemsToProcess = system ? [system] : Object.keys(events); // Si system est spécifié, on cible ce système uniquement, sinon tous les systèmes
59
+ console.log(`[Event] Triggering ${system}.${layer}.${name}`, {
60
+ callbacks: events[system]?.[name]?.[layer]?.length || 0
61
+ });
62
+ let ret = null;
63
+ for (const currentSystem of systemsToProcess) {
64
+ if (events[currentSystem] && events[currentSystem][name]) {
65
+ const layersToProcess = layer ? [layer] : eventLayerSystems[currentSystem] || Object.keys(events[currentSystem][name]); // Si layer est spécifié, on cible cette couche, sinon toutes les couches ou celles définies dans eventLayerSystems
66
+
67
+ if (layersToProcess) {
68
+ for (const currentLayer of layersToProcess) {
69
+ if (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) {
81
+ try {
82
+ const res = await listener.callback(...args);
83
+ if (typeof res === "object" && !Array.isArray(res)) {
84
+ if (typeof ret !== "object") ret = {};
85
+ ret = {...ret, ...res};
86
+ } else if (Array.isArray(res)) {
87
+ if (!ret || !Array.isArray(ret)) ret = [];
88
+ ret = ret.concat(res);
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
+ }
98
+ } else {
99
+ ret = res || ret;
100
+ }
101
+ } catch (error) {
102
+ const errorMsg = `Error in callback for event ${name} in system ${currentSystem} layer ${currentLayer}: ${error.message}`;
103
+ const newError = new Error(errorMsg);
104
+ newError.originalError = error; // Conserve l'erreur originale
105
+ newError.eventDetails = { name, system: currentSystem, layer: currentLayer };
106
+ throw newError;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+ return ret;
115
+ },
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);
131
+ if (!validSystems.includes(system)) {
132
+ throw new Error(`System '${system}' does not exist. Valid systems are: ${validSystems.join(', ')}`);
133
+ }
134
+
135
+ const validLayers = eventLayerSystems[system];
136
+ if (!validLayers.includes(layer)) {
137
+ throw new Error(`Layer '${layer}' does not exist in system '${system}'. Valid layers are: ${validLayers.join(', ')}`);
138
+ }
139
+
140
+ safeAssignObject(events, system, events[system] || {});
141
+ safeAssignObject(events[system], name, events[system][name] || {});
142
+ safeAssignObject(events[system][name], layer, events[system][name][layer] || []);
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
+ }
160
+ },
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
+
187
+ if (!events[system] || !events[system][name] || !events[system][name][layer]) {
188
+ return;
189
+ }
190
+
191
+ const index = events[system][name][layer].findIndex(listener => listener.callback === callback);
192
+ if (index > -1) {
193
+ events[system][name][layer].splice(index, 1);
194
+ }
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
+
219
+ // Ajout d'une méthode pour supprimer tous les callbacks d'un événement (optionnel)
220
+ RemoveAllCallbacks: (name, system = 'priority') => {
221
+ if (events[system] && events[system][name]) {
222
+ delete events[system][name]; // Supprime l'objet contenant les couches et les callbacks
223
+ }
224
+ },
225
+
226
+ // Ajout d'une méthode pour supprimer tous les callbacks d'un système (optionnel)
227
+ RemoveSystemCallbacks: (system) => {
228
+ if (events[system]) {
229
+ delete events[system];
230
+ }
231
+ }
232
+ }