data-primals-engine 1.6.1 → 1.6.2
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.
- package/README.md +73 -42
- package/client/package-lock.json +524 -5
- package/client/package.json +2 -1
- package/client/src/App.scss +14 -1
- package/client/src/Dashboard.jsx +4 -0
- package/client/src/DataLayout.jsx +85 -20
- package/client/src/DataLayout.scss +32 -6
- package/client/src/DataTable.jsx +18 -11
- package/client/src/ModelCreator.jsx +686 -683
- package/client/src/ModelImporter.jsx +1 -1
- package/client/src/ViewSwitcher.jsx +1 -1
- package/client/src/WorkflowEditor.jsx +317 -0
- package/client/src/WorkflowEditor.scss +16 -0
- package/package.json +22 -19
- package/src/client.js +4 -0
- package/src/defaultModels.js +5 -2
- package/src/i18n.js +35 -3
- package/src/modules/assistant/assistant.js +38 -56
- package/src/modules/assistant/providers.js +38 -0
- package/src/modules/data/data.history.js +2 -5
- package/src/modules/data/data.operations.js +3496 -3484
- package/src/modules/workflow.js +3 -6
- package/src/packs.js +239 -24
- package/test/assistant.test.js +207 -0
- package/test/config.test.js +41 -0
- package/test/data.history.integration.test.js +4 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, {useState, useEffect} from 'react';
|
|
2
2
|
import { useModelContext } from './contexts/ModelContext.jsx';
|
|
3
3
|
import { useAuthContext } from './contexts/AuthContext.jsx';
|
|
4
|
-
import {Trans, useTranslation} from '
|
|
4
|
+
import {Trans, useTranslation} from '../../src/i18n.js';
|
|
5
5
|
import {FaArrowDown, FaInfo} from 'react-icons/fa';
|
|
6
6
|
import { CheckboxField } from './Field.jsx';
|
|
7
7
|
import Button from './Button.jsx';
|
|
@@ -30,7 +30,7 @@ const ViewSwitcher = ({ currentView, onViewChange, configuredViews, onConfigureV
|
|
|
30
30
|
title={t(view.labelKey, view.defaultLabel)}
|
|
31
31
|
>
|
|
32
32
|
{view.icon}
|
|
33
|
-
|
|
33
|
+
{/*<span className="hidden md:inline-block ml-2">{t(view.labelKey, view.defaultLabel)}</span>*/}
|
|
34
34
|
</Button>
|
|
35
35
|
{/* AJOUT : Bouton de configuration pour la vue active */}
|
|
36
36
|
{isActive && view.id !== 'table' && (
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import React, { useState, useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import ReactFlow, {
|
|
3
|
+
MiniMap,
|
|
4
|
+
Controls,
|
|
5
|
+
Background,
|
|
6
|
+
useNodesState,
|
|
7
|
+
useEdgesState,
|
|
8
|
+
addEdge
|
|
9
|
+
} from 'reactflow';
|
|
10
|
+
import 'reactflow/dist/style.css';
|
|
11
|
+
import { useModelContext } from './contexts/ModelContext';
|
|
12
|
+
import { useAuthContext } from './contexts/AuthContext';
|
|
13
|
+
import { Trans, useTranslation } from 'react-i18next';
|
|
14
|
+
import { CodeField } from "./Field.jsx";
|
|
15
|
+
import { useQuery } from 'react-query';
|
|
16
|
+
|
|
17
|
+
import "./WorkflowEditor.scss"
|
|
18
|
+
// --- Custom Node Types (à créer) ---
|
|
19
|
+
// import TriggerNode from './nodes/TriggerNode';
|
|
20
|
+
// import StepNode from './nodes/StepNode';
|
|
21
|
+
|
|
22
|
+
const nodeTypes = {
|
|
23
|
+
// trigger: TriggerNode,
|
|
24
|
+
// step: StepNode,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const WorkflowEditor = ({ workflowId }) => {
|
|
28
|
+
const { t } = useTranslation();
|
|
29
|
+
const { me } = useAuthContext();
|
|
30
|
+
const { models } = useModelContext();
|
|
31
|
+
|
|
32
|
+
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
|
33
|
+
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
34
|
+
const [selectedNode, setSelectedNode] = useState(null);
|
|
35
|
+
const [panelWidth, setPanelWidth] = useState(300);
|
|
36
|
+
const resizeData = useRef({ isResizing: false, initialX: 0, initialWidth: 0 });
|
|
37
|
+
|
|
38
|
+
const handleMouseDown = (e) => {
|
|
39
|
+
e.preventDefault();
|
|
40
|
+
resizeData.current = {
|
|
41
|
+
isResizing: true,
|
|
42
|
+
initialX: e.clientX,
|
|
43
|
+
initialWidth: panelWidth
|
|
44
|
+
};
|
|
45
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
46
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const handleMouseMove = useCallback((e) => {
|
|
50
|
+
if (!resizeData.current.isResizing) return; // Utilise la référence qui ne change pas
|
|
51
|
+
const dx = e.clientX - resizeData.current.initialX; // Calcule le delta depuis le clic initial
|
|
52
|
+
const newWidth = resizeData.current.initialWidth - dx; // Applique le delta à la largeur initiale
|
|
53
|
+
setPanelWidth(Math.max(200, Math.min(newWidth, 800))); // Applique les limites
|
|
54
|
+
}, []); // Plus besoin de dépendances, la logique est entièrement contenue dans la ref
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
const handleMouseUp = () => {
|
|
58
|
+
resizeData.current.isResizing = false;
|
|
59
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
60
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
// Query 1: Fetch the main workflow document
|
|
65
|
+
const { data: mainWorkflowData, isLoading: isLoadingMainWorkflow, error: errorMainWorkflow } = useQuery(
|
|
66
|
+
['mainWorkflow', workflowId],
|
|
67
|
+
() => fetch('/api/data/search?_user='+me.username, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
model: 'workflow',
|
|
72
|
+
filter: { $eq: [{$toString:'$_id'}, workflowId] },
|
|
73
|
+
// No pipelines, no depth here, as per user request
|
|
74
|
+
})
|
|
75
|
+
}).then(res => res.json()),
|
|
76
|
+
{
|
|
77
|
+
enabled: !!workflowId,
|
|
78
|
+
select: (data) => data?.data?.[0]
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Query 2: Fetch all workflowStep documents related to this workflow
|
|
83
|
+
const { data: workflowStepsData, isLoading: isLoadingSteps, error: errorSteps } = useQuery(
|
|
84
|
+
['workflowSteps', workflowId],
|
|
85
|
+
() => fetch('/api/data/search?_user=' + me.username, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: { 'Content-Type': 'application/json' },
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
model: 'workflowStep',
|
|
90
|
+
filter: { workflow: workflowId },
|
|
91
|
+
// Use a shallow depth to populate direct relations like 'actions'
|
|
92
|
+
// This avoids a deep recursive lookup for the entire graph, but makes step data usable
|
|
93
|
+
depth: 1
|
|
94
|
+
})
|
|
95
|
+
}).then(res => res.json()),
|
|
96
|
+
{
|
|
97
|
+
enabled: !!workflowId, // La requête ne s'exécute que si workflowId est défini
|
|
98
|
+
select: (data) => data?.data || []
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Query 3: Fetch all workflowAction documents related to this workflow
|
|
103
|
+
const { data: workflowActionsData, isLoading: isLoadingActions, error: errorActions } = useQuery(
|
|
104
|
+
['workflowActions', workflowId],
|
|
105
|
+
() => fetch('/api/data/search?_user=' + me.username, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: { 'Content-Type': 'application/json' },
|
|
108
|
+
body: JSON.stringify({
|
|
109
|
+
model: 'workflowAction',
|
|
110
|
+
filter: { workflow: workflowId },
|
|
111
|
+
// No depth needed here as actions are usually flat
|
|
112
|
+
})
|
|
113
|
+
}).then(res => res.json()),
|
|
114
|
+
{
|
|
115
|
+
enabled: !!workflowId,
|
|
116
|
+
select: (data) => data?.data || []
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (mainWorkflowData && workflowStepsData && workflowActionsData) {
|
|
122
|
+
const initialNodes = [];
|
|
123
|
+
const initialEdges = [];
|
|
124
|
+
const processedSteps = new Set();
|
|
125
|
+
|
|
126
|
+
// Create a map for quick lookup of steps
|
|
127
|
+
const stepsMap = new Map(workflowStepsData.map(step => [step._id, step]));
|
|
128
|
+
|
|
129
|
+
// 1. Nœud du déclencheur (Trigger)
|
|
130
|
+
initialNodes.push({
|
|
131
|
+
id: `workflow-start-${mainWorkflowData._id}`,
|
|
132
|
+
type: 'input',
|
|
133
|
+
position: { x: 250, y: 5 },
|
|
134
|
+
data: {
|
|
135
|
+
label: `Début: ${typeof mainWorkflowData.name === 'object' ? mainWorkflowData.name.value : mainWorkflowData.name}`,
|
|
136
|
+
// --- CORRECTION ---
|
|
137
|
+
// On inclut toutes les données du workflow pour la cohérence
|
|
138
|
+
...mainWorkflowData
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Create a map for quick lookup of actions
|
|
143
|
+
const actionsMap = new Map(workflowActionsData.map(action => [action._id, action]));
|
|
144
|
+
|
|
145
|
+
// 2. Traitement récursif des étapes
|
|
146
|
+
const processStep = (stepId, parentNodeId, parentPosition, isSuccessBranch = true) => {
|
|
147
|
+
if (!stepId || processedSteps.has(stepId)) return;
|
|
148
|
+
|
|
149
|
+
const step = stepsMap.get(stepId);
|
|
150
|
+
if (!step) {
|
|
151
|
+
console.warn(`WorkflowEditor: Step with ID ${stepId} not found in fetched steps.`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
processedSteps.add(stepId);
|
|
156
|
+
|
|
157
|
+
const nodePosition = { x: parentPosition.x, y: parentPosition.y + 120 };
|
|
158
|
+
initialNodes.push({
|
|
159
|
+
id: step._id,
|
|
160
|
+
type: 'default',
|
|
161
|
+
className: 'workflow-step-node',
|
|
162
|
+
position: nodePosition,
|
|
163
|
+
data: {
|
|
164
|
+
label: (step?.name && typeof step.name === 'object' ? step.name.value : step.name) || `Étape ${step._id}`,
|
|
165
|
+
...step // --- CORRECTION --- On inclut l'objet step complet
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
initialEdges.push({ id: `e-${parentNodeId}-${step._id}`, source: parentNodeId, target: step._id, type: 'smoothstep' });
|
|
169
|
+
|
|
170
|
+
let lastActionId = step._id;
|
|
171
|
+
// The actions on the step are just IDs now, we need to look them up
|
|
172
|
+
const actionIds = Array.isArray(step.actions) ? step.actions : (step.actions ? [step.actions] : []);
|
|
173
|
+
const actions = actionIds.map(id => actionsMap.get(id)).filter(Boolean); // Get full action objects
|
|
174
|
+
|
|
175
|
+
if (actionIds.length !== actions.length) {
|
|
176
|
+
const missingIds = actionIds.filter(id => !actionsMap.has(id));
|
|
177
|
+
console.warn(`WorkflowEditor: Could not find the following actions: ${missingIds.join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
actions.forEach((action, index) => {
|
|
181
|
+
const actionNodePosition = { x: nodePosition.x, y: nodePosition.y + (index + 1) * 80 };
|
|
182
|
+
initialNodes.push({
|
|
183
|
+
id: action._id,
|
|
184
|
+
type: 'default',
|
|
185
|
+
className: 'workflow-action-node',
|
|
186
|
+
position: actionNodePosition,
|
|
187
|
+
data: {
|
|
188
|
+
label: action.name.value || `Action ${action._id}`,
|
|
189
|
+
...action // --- CORRECTION --- On inclut l'objet action complet
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
initialEdges.push({ id: `e-${lastActionId}-${action._id}`, source: lastActionId, target: action._id, type: 'smoothstep' });
|
|
193
|
+
lastActionId = action._id;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Créer les liens (edges)
|
|
197
|
+
if (step.onSuccessStep && typeof step.onSuccessStep === 'string') { // onSuccessStep is an ID
|
|
198
|
+
processStep(step.onSuccessStep, lastActionId, { x: nodePosition.x - 200, y: nodePosition.y + (actions.length * 80) }, true);
|
|
199
|
+
initialEdges.push({ id: `e-${lastActionId}-success-${step.onSuccessStep}`, source: lastActionId, target: step.onSuccessStep, label: t('onSuccess', 'onSuccess'), type: 'smoothstep' });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (step.onFailureStep && typeof step.onFailureStep === 'string') { // onFailureStep is an ID
|
|
203
|
+
processStep(step.onFailureStep, lastActionId, { x: nodePosition.x + 200, y: nodePosition.y + (actions.length * 80) }, false);
|
|
204
|
+
initialEdges.push({ id: `e-${lastActionId}-failure-${step.onFailureStep}`, source: lastActionId, target: step.onFailureStep, label: t('onFailure', 'onFailure'), type: 'smoothstep', animated: true, style: { stroke: '#ff4d4d' } });
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
if (mainWorkflowData.startStep) {
|
|
209
|
+
initialEdges.push({
|
|
210
|
+
id: `e-start-${mainWorkflowData.startStep}`, // startStep is an ID
|
|
211
|
+
source: `workflow-start-${mainWorkflowData._id}`,
|
|
212
|
+
target: mainWorkflowData.startStep,
|
|
213
|
+
type: 'smoothstep',
|
|
214
|
+
});
|
|
215
|
+
processStep(mainWorkflowData.startStep, `workflow-start-${mainWorkflowData._id}`, { x: 250, y: 5 });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setNodes(initialNodes);
|
|
219
|
+
setEdges(initialEdges);
|
|
220
|
+
}
|
|
221
|
+
}, [mainWorkflowData, workflowStepsData, workflowActionsData, setNodes, setEdges, t]);
|
|
222
|
+
|
|
223
|
+
const onConnect = useCallback(
|
|
224
|
+
(params) => setEdges((eds) => addEdge(params, eds)),
|
|
225
|
+
[setEdges],
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
const onNodeClick = useCallback((event, node) => { // Keep this for potential future node editing
|
|
229
|
+
setSelectedNode(node);
|
|
230
|
+
console.log('Node clicked:', node);
|
|
231
|
+
}, []);
|
|
232
|
+
|
|
233
|
+
const onPaneClick = useCallback(() => { // Keep this for potential future node editing
|
|
234
|
+
setSelectedNode(null);
|
|
235
|
+
}, []);
|
|
236
|
+
|
|
237
|
+
if (isLoadingMainWorkflow || isLoadingSteps || isLoadingActions) { // Check all loading states
|
|
238
|
+
return <div>{t('loading', 'Chargement...')}</div>;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (errorMainWorkflow || errorSteps || errorActions) { // Check all error states
|
|
242
|
+
const errorMessage = errorMainWorkflow?.message || errorSteps?.message || errorActions?.message || 'Unknown error';
|
|
243
|
+
return <div><Trans i18nKey="error.generic" values={{ message: errorMessage }}>Erreur: {{ message: errorMessage }}</Trans></div>;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<div className={"flex-1"} style={{ width: '100%', height: '80vh', display: 'flex' }}>
|
|
248
|
+
<ReactFlow
|
|
249
|
+
nodes={nodes}
|
|
250
|
+
edges={edges}
|
|
251
|
+
onNodesChange={onNodesChange}
|
|
252
|
+
onEdgesChange={onEdgesChange}
|
|
253
|
+
onConnect={onConnect}
|
|
254
|
+
onNodeClick={onNodeClick}
|
|
255
|
+
onPaneClick={onPaneClick}
|
|
256
|
+
nodeTypes={nodeTypes}
|
|
257
|
+
fitView
|
|
258
|
+
>
|
|
259
|
+
<Controls />
|
|
260
|
+
<MiniMap />
|
|
261
|
+
<Background variant="dots" gap={12} size={1} />
|
|
262
|
+
</ReactFlow>
|
|
263
|
+
|
|
264
|
+
{/* Panneau latéral pour l'édition des propriétés */}
|
|
265
|
+
{selectedNode && (
|
|
266
|
+
<div className="properties-panel" style={{ width: `${panelWidth}px`, padding: '10px', borderLeft: '1px solid #ccc' }}>
|
|
267
|
+
<div
|
|
268
|
+
className="resizer"
|
|
269
|
+
onMouseDown={handleMouseDown}
|
|
270
|
+
/>
|
|
271
|
+
<h3><Trans i18nKey="properties">Propriétés</Trans></h3>
|
|
272
|
+
<p><strong>ID:</strong> {selectedNode.id}</p>
|
|
273
|
+
|
|
274
|
+
{/* Affiche les conditions pour un workflowStep */}
|
|
275
|
+
{selectedNode.data.conditions && (
|
|
276
|
+
<div className="mt-2">
|
|
277
|
+
<strong><Trans i18nKey="conditions">Conditions:</Trans></strong>
|
|
278
|
+
<CodeField language="json" value={JSON.stringify(selectedNode.data.conditions, null, 2)} readOnly={true} />
|
|
279
|
+
</div>
|
|
280
|
+
)}
|
|
281
|
+
|
|
282
|
+
{/* Affiche le script pour une action ExecuteScript */}
|
|
283
|
+
{selectedNode.data.type && (
|
|
284
|
+
<div className="mt-2">
|
|
285
|
+
<strong><Trans i18nKey="action">Action :</Trans></strong> {selectedNode.data.type}
|
|
286
|
+
{selectedNode.data.targetModel&& (
|
|
287
|
+
<p>
|
|
288
|
+
<strong><Trans i18nKey="action">Modèle cible : </Trans></strong>{selectedNode.data.targetModel}
|
|
289
|
+
</p>
|
|
290
|
+
)}
|
|
291
|
+
{selectedNode.data.targetSelector&& (
|
|
292
|
+
<p>
|
|
293
|
+
<strong><Trans i18nKey="filter">Filtre sur :</Trans></strong>
|
|
294
|
+
<br/><CodeField language="javascript" value={JSON.stringify(selectedNode.data.targetSelector)} readOnly={true} />
|
|
295
|
+
</p>
|
|
296
|
+
)}
|
|
297
|
+
{(selectedNode.data.dataToCreate || selectedNode.data.fieldsToUpdate) && (
|
|
298
|
+
<p>
|
|
299
|
+
<strong><Trans i18nKey="filter">Code déclenché :</Trans></strong>
|
|
300
|
+
<br/><CodeField language="javascript" value={JSON.stringify(selectedNode.data.dataToCreate || selectedNode.data.fieldsToUpdate)} readOnly={true} />
|
|
301
|
+
</p>
|
|
302
|
+
)}
|
|
303
|
+
</div>
|
|
304
|
+
)}
|
|
305
|
+
{/* Affiche le script pour une action ExecuteScript */}
|
|
306
|
+
{selectedNode.data.type === 'ExecuteScript' && selectedNode.data.script && (
|
|
307
|
+
<div className="mt-2">
|
|
308
|
+
<CodeField language="javascript" value={selectedNode.data.script} readOnly={true} />
|
|
309
|
+
</div>
|
|
310
|
+
)}
|
|
311
|
+
</div>
|
|
312
|
+
)}
|
|
313
|
+
</div>
|
|
314
|
+
);
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export default WorkflowEditor;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
.workflow-step-node {
|
|
3
|
+
background-color: #e0e7ff; /* Un bleu clair pour les étapes */
|
|
4
|
+
border-color: #a5b4fc;
|
|
5
|
+
border-width: 2px;
|
|
6
|
+
font-weight: bold;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.workflow-action-node {
|
|
10
|
+
background-color: #f0f9ff; /* Un bleu très clair pour les actions */
|
|
11
|
+
border-color: #bae6fd;
|
|
12
|
+
border-width: 1px;
|
|
13
|
+
border-style: dashed;
|
|
14
|
+
width: auto;
|
|
15
|
+
min-width: 150px;
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "data-primals-engine is a package responsible from handling large amount of data using MongoDB in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation. It also has integrated AI assistant.",
|
|
5
5
|
"main": "src/engine.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
"prismjs": "1.30.0",
|
|
34
34
|
"xml2js": ">=0.5.0",
|
|
35
35
|
"tar-fs": ">=3.1.1",
|
|
36
|
-
"vite": ">=7.0.8"
|
|
36
|
+
"vite": ">=7.0.8",
|
|
37
|
+
"node-forge": ">=1.3.2",
|
|
38
|
+
"js-yaml": ">=4.1.1"
|
|
37
39
|
},
|
|
38
40
|
"overrides": {
|
|
39
41
|
"react-syntax-highlighter": {
|
|
@@ -52,17 +54,18 @@
|
|
|
52
54
|
},
|
|
53
55
|
"exports": {
|
|
54
56
|
".": "./src/index.js",
|
|
57
|
+
"./client-only": "./src/client.js",
|
|
55
58
|
"./modules/*.js": "./src/modules/*.js",
|
|
56
59
|
"./modules/*": "./src/modules/*/index.js",
|
|
57
60
|
"./client": "./client/index.js",
|
|
58
61
|
"./*": "./src/*.js"
|
|
59
62
|
},
|
|
60
63
|
"dependencies": {
|
|
61
|
-
"@langchain/core": "^0.3.
|
|
64
|
+
"@langchain/core": "^0.3.79",
|
|
62
65
|
"archiver": "^7.0.1",
|
|
63
66
|
"aws-sdk": "^2.1692.0",
|
|
64
67
|
"bcrypt": "^6.0.0",
|
|
65
|
-
"body-parser": "^2.2.
|
|
68
|
+
"body-parser": "^2.2.1",
|
|
66
69
|
"chalk": "^5.4.1",
|
|
67
70
|
"check-disk-space": "^3.4.0",
|
|
68
71
|
"compression": "^1.8.1",
|
|
@@ -77,44 +80,44 @@
|
|
|
77
80
|
"express-session": "^1.18.2",
|
|
78
81
|
"handlebars": "^4.7.8",
|
|
79
82
|
"i18next-browser-languagedetector": "^8.2.0",
|
|
80
|
-
"isolated-vm": "^5.0.
|
|
81
|
-
"juice": "^11.0.
|
|
82
|
-
"mathjs": "^
|
|
83
|
+
"isolated-vm": "^5.0.4",
|
|
84
|
+
"juice": "^11.0.3",
|
|
85
|
+
"mathjs": "^15.1.0",
|
|
83
86
|
"mongodb": "^6.18.0",
|
|
84
87
|
"node-cache": "^5.1.2",
|
|
85
88
|
"node-schedule": "^2.1.1",
|
|
86
|
-
"nodemailer": "^7.0.
|
|
87
|
-
"openai": "^
|
|
89
|
+
"nodemailer": "^7.0.10",
|
|
90
|
+
"openai": "^6.9.1",
|
|
88
91
|
"passport": "^0.7.0",
|
|
89
92
|
"passport-saml-encrypted": "^0.1.13",
|
|
90
93
|
"process": "^0.11.10",
|
|
91
94
|
"prop-types": "^15.8.1",
|
|
92
95
|
"randomcolor": "^0.6.2",
|
|
93
96
|
"react-markdown": "^10.1.0",
|
|
94
|
-
"read-excel-file": "^
|
|
97
|
+
"read-excel-file": "^6.0.1",
|
|
95
98
|
"request-ip": "^3.3.0",
|
|
96
99
|
"safe-regex": "^2.1.1",
|
|
97
100
|
"sanitize-html": "^2.17.0",
|
|
98
|
-
"sirv": "^3.0.
|
|
99
|
-
"stripe": "^
|
|
101
|
+
"sirv": "^3.0.2",
|
|
102
|
+
"stripe": "^20.0.0",
|
|
100
103
|
"swagger-ui-express": "^5.0.1",
|
|
101
|
-
"tar": "^7.
|
|
104
|
+
"tar": "^7.5.2",
|
|
102
105
|
"tinycolor2": "^1.6.0",
|
|
103
106
|
"uniqid": "^5.4.0",
|
|
104
107
|
"vitest": "^3.2.4",
|
|
105
|
-
"yaml": "^2.8.
|
|
108
|
+
"yaml": "^2.8.1"
|
|
106
109
|
},
|
|
107
110
|
"peerDependencies": {
|
|
108
111
|
"express": "^5.1.0",
|
|
109
112
|
"passport-azure-ad": "^4.3.5",
|
|
110
113
|
"passport-google-oauth20": "^2.0.0",
|
|
111
114
|
"react": "18.3.1",
|
|
112
|
-
"react-i18next": "^
|
|
113
|
-
"react-query": "
|
|
114
|
-
"@langchain/anthropic": "^0.3.
|
|
115
|
+
"react-i18next": "^16.3.4",
|
|
116
|
+
"react-query": "^3.39.3",
|
|
117
|
+
"@langchain/anthropic": "^0.3.33",
|
|
115
118
|
"@langchain/deepseek": "^0.1.0",
|
|
116
|
-
"@langchain/google-genai": "^0.2.
|
|
117
|
-
"@langchain/openai": "^0.6.
|
|
119
|
+
"@langchain/google-genai": "^0.2.18",
|
|
120
|
+
"@langchain/openai": "^0.6.16"
|
|
118
121
|
},
|
|
119
122
|
"devDependencies": {
|
|
120
123
|
"@eslint/js": "^9.32.0",
|
package/src/client.js
ADDED
package/src/defaultModels.js
CHANGED
|
@@ -918,7 +918,8 @@ export const defaultModels = {
|
|
|
918
918
|
"tags": ["system", "automation"],
|
|
919
919
|
fields: [
|
|
920
920
|
{ name: 'name', type: 'string_t', required: true, hint: "Unique name for the workflow (e.g., 'Order Validation', 'Low Stock Notification')." },
|
|
921
|
-
{ name: 'description', type: 'richtext', hint: "Detailed explanation of the workflow's purpose."
|
|
921
|
+
{ name: 'description', type: 'richtext', hint: "Detailed explanation of the workflow's purpose."
|
|
922
|
+
},
|
|
922
923
|
{ name: 'startStep', type: 'relation', relation: 'workflowStep', required: false, hint: "The first step to execute when the workflow starts." }
|
|
923
924
|
]
|
|
924
925
|
},
|
|
@@ -982,7 +983,8 @@ export const defaultModels = {
|
|
|
982
983
|
"tags": ["system", "automation"],
|
|
983
984
|
fields: [
|
|
984
985
|
{ name: 'workflow', type: 'relation', relation: 'workflow', required: true, hint: "The workflow this step belongs to." },
|
|
985
|
-
{ name: 'name', type: 'string_t', hint: "Optional descriptive name for the step (e.g., 'Check Inventory', 'Send Confirmation Email')."
|
|
986
|
+
{ name: 'name', type: 'string_t', hint: "Optional descriptive name for the step (e.g., 'Check Inventory', 'Send Confirmation Email')."
|
|
987
|
+
},
|
|
986
988
|
{ name: 'conditions', type: 'code', language: 'json', conditionBuilder: true, hint: "Optional conditions checked before executing the step's action." },
|
|
987
989
|
{ name: 'actions', type: 'relation', relation: 'workflowAction', multiple: true, required: true, hint: "The main actions performed by this step." },
|
|
988
990
|
{ name: 'onSuccessStep', type: 'relation', relation: 'workflowStep', hint: "Optional: The next step if this step's action succeeds." },
|
|
@@ -997,6 +999,7 @@ export const defaultModels = {
|
|
|
997
999
|
"tags": ["system", "automation"],
|
|
998
1000
|
fields: [
|
|
999
1001
|
{ name: 'name', type: 'string_t', required: true, hint: "Name of the action (e.g., 'Update Order Status', 'Send Email', 'Call Payment API')." },
|
|
1002
|
+
{ name: 'workflow', type: 'relation', relation: 'workflow', required: false },
|
|
1000
1003
|
{
|
|
1001
1004
|
name: 'type',
|
|
1002
1005
|
type: 'enum',
|
package/src/i18n.js
CHANGED
|
@@ -5,6 +5,10 @@ import LanguageDetector from "i18next-browser-languagedetector";
|
|
|
5
5
|
export const translations = {
|
|
6
6
|
fr: {
|
|
7
7
|
translation: {
|
|
8
|
+
|
|
9
|
+
"model_audience": "Audiences",
|
|
10
|
+
"model_deal": "Opportunités",
|
|
11
|
+
|
|
8
12
|
"relationField.select.title": "Sélectionner {{modelName}}",
|
|
9
13
|
"btns.validate": "Valider",
|
|
10
14
|
"btns.create": "Créer",
|
|
@@ -1318,6 +1322,8 @@ export const translations = {
|
|
|
1318
1322
|
},
|
|
1319
1323
|
en: {
|
|
1320
1324
|
translation: {
|
|
1325
|
+
"model_audience": "Audiences",
|
|
1326
|
+
"model_deal": "Opportunities",
|
|
1321
1327
|
"relationField.select.title": "Select {{modelName}}",
|
|
1322
1328
|
"btns.validate": "Validate",
|
|
1323
1329
|
"btns.create": "Create",
|
|
@@ -2627,6 +2633,8 @@ export const translations = {
|
|
|
2627
2633
|
},
|
|
2628
2634
|
es: {
|
|
2629
2635
|
translation: {
|
|
2636
|
+
"model_audience": "Audiencias",
|
|
2637
|
+
"model_deal": "Oportunidades",
|
|
2630
2638
|
"relationField.select.title": "Seleccionar {{modelName}}",
|
|
2631
2639
|
"btns.validate": "Validar",
|
|
2632
2640
|
"btns.create": "Crear",
|
|
@@ -3973,6 +3981,10 @@ export const translations = {
|
|
|
3973
3981
|
},
|
|
3974
3982
|
pt: {
|
|
3975
3983
|
translation: {
|
|
3984
|
+
|
|
3985
|
+
"model_audience": "Públicos",
|
|
3986
|
+
"model_campaign": "Campanhas de marketing",
|
|
3987
|
+
"model_deal": "Oportunidades",
|
|
3976
3988
|
"relationField.select.title": "Selecionar {{modelName}}",
|
|
3977
3989
|
"btns.validate": "Validar",
|
|
3978
3990
|
"btns.create": "Criar",
|
|
@@ -4125,6 +4137,8 @@ export const translations = {
|
|
|
4125
4137
|
},
|
|
4126
4138
|
de: {
|
|
4127
4139
|
translation: {
|
|
4140
|
+
"model_audience": "Zielgruppen",
|
|
4141
|
+
"model_deal": "Möglichkeiten",
|
|
4128
4142
|
"relationField.select.title": "{{modelName}} auswählen",
|
|
4129
4143
|
"btns.validate": "Validieren",
|
|
4130
4144
|
"btns.create": "Erstellen",
|
|
@@ -5424,7 +5438,6 @@ export const translations = {
|
|
|
5424
5438
|
"field_endpoint_isPublic_hint": "Se selezionato, questo endpoint sarà accessibile senza autenticazione. Lo script verrà eseguito con i permessi del proprietario dell'endpoint.",
|
|
5425
5439
|
"field_endpoint_code": "Codice da eseguire",
|
|
5426
5440
|
"field_endpoint_code_hint": "Lo script da eseguire. Deve restituire un valore o un oggetto che sarà la risposta JSON.",
|
|
5427
|
-
"model_env": "Variabili d'Ambiente (env)",
|
|
5428
5441
|
"datatable.advancedFilter.title": "Filtro avanzato (MongoDB)",
|
|
5429
5442
|
"datatable.advancedFilter.desc": "Crea i tuoi filtri avanzati da zero, utilizzando gli operatori di aggregazione di MongoDB disponibili qui.",
|
|
5430
5443
|
"editData": "Modifica in {{0}}",
|
|
@@ -5696,6 +5709,10 @@ export const translations = {
|
|
|
5696
5709
|
"model_channel": "Canali di notifica",
|
|
5697
5710
|
"model_message": "Messaggi",
|
|
5698
5711
|
"model_kpi": "Indicatori KPI",
|
|
5712
|
+
"model_env": "Variabili d'Ambiente (env)",
|
|
5713
|
+
"model_audience": "Pubblici",
|
|
5714
|
+
"model_deal": "Opportunità",
|
|
5715
|
+
|
|
5699
5716
|
"field_permission_name": "Nome",
|
|
5700
5717
|
"field_permission_description": "Descrizione",
|
|
5701
5718
|
|
|
@@ -6628,6 +6645,9 @@ export const translations = {
|
|
|
6628
6645
|
},
|
|
6629
6646
|
cs: {
|
|
6630
6647
|
translation: {
|
|
6648
|
+
"model_audience": "Publika",
|
|
6649
|
+
"model_campaign": "Marketingové kampaně",
|
|
6650
|
+
"model_deal": "Příležitosti",
|
|
6631
6651
|
"relationField.select.title": "Vybrat {{modelName}}",
|
|
6632
6652
|
"btns.validate": "Ověřit",
|
|
6633
6653
|
"btns.create": "Vytvořit",
|
|
@@ -7553,6 +7573,8 @@ export const translations = {
|
|
|
7553
7573
|
},
|
|
7554
7574
|
ru: {
|
|
7555
7575
|
translation: {
|
|
7576
|
+
"model_audience": "Аудитории",
|
|
7577
|
+
"model_deal": "Возможности",
|
|
7556
7578
|
"relationField.select.title": "Выбрать {{modelName}}",
|
|
7557
7579
|
"btns.validate": "Проверить",
|
|
7558
7580
|
"btns.create": "Создать",
|
|
@@ -8832,6 +8854,8 @@ export const translations = {
|
|
|
8832
8854
|
},
|
|
8833
8855
|
ar: {
|
|
8834
8856
|
translation: {
|
|
8857
|
+
"model_audience": "الجماهير",
|
|
8858
|
+
"model_deal": "الفرص",
|
|
8835
8859
|
"relationField.select.title": "اختر {{modelName}}",
|
|
8836
8860
|
"btns.validate": "تحقق",
|
|
8837
8861
|
"btns.create": "إنشاء",
|
|
@@ -8901,7 +8925,7 @@ export const translations = {
|
|
|
8901
8925
|
"field_endpoint_code": "الكود المنفذ",
|
|
8902
8926
|
"field_endpoint_code_hint": "السكريبت الذي سيتم تنفيذه. يجب أن يعيد قيمة أو كائنًا سيكون استجابة JSON.",
|
|
8903
8927
|
"model_env": "متغيرات البيئة (env)",
|
|
8904
|
-
|
|
8928
|
+
|
|
8905
8929
|
"datatable.advancedFilter.title": "مرشح متقدم (MongoDB)",
|
|
8906
8930
|
"datatable.advancedFilter.desc": "أنشئ مرشحاتك المتقدمة من الصفر، باستخدام عوامل تجميع MongoDB المتوفرة هنا",
|
|
8907
8931
|
"editData": "تعديل في {{0}}",
|
|
@@ -10156,6 +10180,8 @@ export const translations = {
|
|
|
10156
10180
|
},
|
|
10157
10181
|
sv: {
|
|
10158
10182
|
translation: {
|
|
10183
|
+
"model_audience": "Målgrupper",
|
|
10184
|
+
"model_deal": "Möjligheter",
|
|
10159
10185
|
"relationField.select.title": "Välj {{modelName}}",
|
|
10160
10186
|
"btns.validate": "Validera",
|
|
10161
10187
|
"btns.create": "Skapa",
|
|
@@ -11316,7 +11342,7 @@ export const translations = {
|
|
|
11316
11342
|
"no": "Nej",
|
|
11317
11343
|
"true": "Sant",
|
|
11318
11344
|
"false": "Falskt",
|
|
11319
|
-
|
|
11345
|
+
|
|
11320
11346
|
|
|
11321
11347
|
"assistant.type": "Skriv ditt meddelande...",
|
|
11322
11348
|
"assistant.welcome": "Hej! Hur kan jag hjälpa dig med din data?",
|
|
@@ -11383,6 +11409,10 @@ export const translations = {
|
|
|
11383
11409
|
},
|
|
11384
11410
|
el: {
|
|
11385
11411
|
translation: {
|
|
11412
|
+
"model_audience": "Κοινά",
|
|
11413
|
+
"model_deal": "Ευκαιρίες",
|
|
11414
|
+
"model_endpoint": "Τελικά σημεία",
|
|
11415
|
+
"model_env": "Μεταβλητές Περιβάλλοντος",
|
|
11386
11416
|
"relationField.select.title": "Επιλογή {{modelName}}",
|
|
11387
11417
|
"btns.validate": "Επικύρωση",
|
|
11388
11418
|
"btns.create": "Δημιουργία",
|
|
@@ -12586,6 +12616,8 @@ export const translations = {
|
|
|
12586
12616
|
},
|
|
12587
12617
|
fa: {
|
|
12588
12618
|
translation: {
|
|
12619
|
+
"model_audience": "مخاطبان",
|
|
12620
|
+
"model_deal": "فرصتها",
|
|
12589
12621
|
"relationField.select.title": "{{modelName}} را انتخاب کنید",
|
|
12590
12622
|
"btns.validate": "اعتبارسنجی",
|
|
12591
12623
|
"btns.create": "ایجاد",
|