data-primals-engine 1.2.6-rc3 → 1.3.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.
- package/README.md +38 -2
- package/client/package-lock.json +247 -4354
- package/client/package.json +16 -15
- package/client/src/App.jsx +13 -20
- package/client/src/App.scss +1 -0
- package/client/src/AssistantChat.jsx +5 -4
- package/client/src/DataEditor.jsx +2 -2
- package/client/src/DataTable.jsx +47 -3
- package/client/src/ExportDialog.jsx +2 -2
- package/client/src/Field.jsx +6 -18
- package/client/src/KanbanCard.jsx +4 -2
- package/client/src/KanbanConfigModal.jsx +5 -7
- package/client/src/ModelCreatorField.jsx +9 -9
- package/client/src/PackGallery.jsx +89 -9
- package/client/src/PackGallery.scss +58 -4
- package/client/src/RTETrans.jsx +11 -0
- package/client/src/RelationValue.jsx +3 -4
- package/client/src/constants.js +1 -1
- package/client/src/core/data.js +2 -1
- package/client/src/translations.js +80 -0
- package/package.json +8 -1
- package/server.js +4 -4
- package/src/constants.js +6 -0
- package/src/defaultModels.js +23 -10
- package/src/filter.js +35 -5
- package/src/i18n.js +1 -1
- package/src/modules/{assistant.js → assistant/assistant.js} +42 -27
- package/src/modules/assistant/constants.js +16 -0
- package/src/modules/data/data.core.js +1 -3
- package/src/modules/data/data.js +4601 -4525
- package/src/modules/data/data.routes.js +29 -3
- package/src/modules/mongodb.js +3 -1
- package/src/modules/user.js +12 -1
- package/src/modules/workflow.js +198 -117
- package/src/packs.js +1015 -9
- package/src/services/index.js +11 -0
- package/src/services/stripe.js +141 -0
- package/test/data.integration.test.js +66 -3
- package/test/workflow.actions.integration.test.js +474 -0
- package/test/workflow.integration.test.js +1 -1
|
@@ -7,20 +7,38 @@
|
|
|
7
7
|
|
|
8
8
|
.gallery-header {
|
|
9
9
|
display: flex;
|
|
10
|
+
flex-wrap: wrap;
|
|
11
|
+
gap: 1rem ;
|
|
10
12
|
justify-content: space-between;
|
|
11
13
|
align-items: center;
|
|
12
14
|
padding-bottom: 1rem;
|
|
13
15
|
border-bottom: 1px solid #e0e0e0;
|
|
14
16
|
margin-bottom: 1rem;
|
|
17
|
+
|
|
15
18
|
h1 {
|
|
16
19
|
margin: 0;
|
|
20
|
+
flex: 1; // Permet au titre de prendre l'espace disponible
|
|
21
|
+
min-width: 200px; // Empêche le titre de devenir trop petit
|
|
17
22
|
}
|
|
18
|
-
|
|
23
|
+
|
|
24
|
+
.header-actions {
|
|
19
25
|
display: flex;
|
|
20
|
-
gap:
|
|
26
|
+
gap: 1rem;
|
|
21
27
|
align-items: center;
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
|
|
29
|
+
.sort-options {
|
|
30
|
+
display: flex;
|
|
31
|
+
gap: 0.5rem;
|
|
32
|
+
align-items: center;
|
|
33
|
+
flex-wrap: wrap; // Pour le responsive
|
|
34
|
+
|
|
35
|
+
.btn.active {
|
|
36
|
+
color: white;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.add-pack-button {
|
|
41
|
+
white-space: nowrap; // Empêche le texte du bouton de se casser
|
|
24
42
|
}
|
|
25
43
|
}
|
|
26
44
|
}
|
|
@@ -153,4 +171,40 @@
|
|
|
153
171
|
}
|
|
154
172
|
}
|
|
155
173
|
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// À ajouter à la fin de votre fichier CSS
|
|
177
|
+
.manual-install-dialog {
|
|
178
|
+
width: 100%;
|
|
179
|
+
|
|
180
|
+
p {
|
|
181
|
+
margin-top: 0;
|
|
182
|
+
color: #666;
|
|
183
|
+
font-size: 0.9em;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
textarea {
|
|
187
|
+
width: 100%;
|
|
188
|
+
padding: 1rem;
|
|
189
|
+
border: 1px solid #ddd;
|
|
190
|
+
border-radius: 4px;
|
|
191
|
+
font-family: monospace;
|
|
192
|
+
resize: vertical;
|
|
193
|
+
min-height: 300px;
|
|
194
|
+
background-color: #f9f9f9;
|
|
195
|
+
color: #333;
|
|
196
|
+
|
|
197
|
+
&:focus {
|
|
198
|
+
outline: none;
|
|
199
|
+
border-color: var(--primary-color);
|
|
200
|
+
box-shadow: 0 0 0 2px rgba(var(--primary-color-rgb), 0.2);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.dialog-actions {
|
|
205
|
+
display: flex;
|
|
206
|
+
justify-content: flex-end;
|
|
207
|
+
gap: 0.5rem;
|
|
208
|
+
margin-top: 1rem;
|
|
209
|
+
}
|
|
156
210
|
}
|
package/client/src/RTETrans.jsx
CHANGED
|
@@ -53,6 +53,16 @@ const RTETrans = ({ value, onChange, field }) => {
|
|
|
53
53
|
};
|
|
54
54
|
const languagesToAdd = availableLangs.filter(lang => !existingLangs.includes(lang.code));
|
|
55
55
|
|
|
56
|
+
const confirmDelete = (e, lang) => {
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
e.stopPropagation();
|
|
59
|
+
if( !confirm(t('rte.confirmLangDeletion', 'Confirm lang deletion ?')))
|
|
60
|
+
return;
|
|
61
|
+
const val = {...value};
|
|
62
|
+
delete val[lang];
|
|
63
|
+
onChange(val);
|
|
64
|
+
setActiveTab(Object.keys(val)[0] || null);
|
|
65
|
+
}
|
|
56
66
|
return (
|
|
57
67
|
<div className="rte-trans-container">
|
|
58
68
|
<div className="tabs-container flex items-center border-b border-gray-200">
|
|
@@ -64,6 +74,7 @@ const RTETrans = ({ value, onChange, field }) => {
|
|
|
64
74
|
title={availableLangs.find(f=>f.code===lang)?.name.value || ''}
|
|
65
75
|
>
|
|
66
76
|
{lang.toUpperCase()}
|
|
77
|
+
<button onClick={(e) => confirmDelete(e, lang)}>x</button>
|
|
67
78
|
</button>
|
|
68
79
|
))}
|
|
69
80
|
{languagesToAdd.length > 0 && (
|
|
@@ -187,8 +187,7 @@ const RelationValue = ({ field, data, align }) => {
|
|
|
187
187
|
if (f.type === 'code') {
|
|
188
188
|
let t;
|
|
189
189
|
try {
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
t = f.language === 'json' ? JSON.stringify(intVal[f.name], null, 2) : t = intVal[f.name].toString();
|
|
192
191
|
} catch (e) {
|
|
193
192
|
t = intVal[f.name].toString();
|
|
194
193
|
}
|
|
@@ -196,8 +195,8 @@ const RelationValue = ({ field, data, align }) => {
|
|
|
196
195
|
<dt>{columnName} {span}</dt>
|
|
197
196
|
<dd>
|
|
198
197
|
<CodeField onChange={() => {
|
|
199
|
-
}} language={
|
|
200
|
-
name={f.name} value={
|
|
198
|
+
}} language={f.language || 'json'}
|
|
199
|
+
name={f.name} value={f.language === 'json' ? JSON.stringify(intVal[f.name], null, 2) : t} />
|
|
201
200
|
</dd>
|
|
202
201
|
</>;
|
|
203
202
|
}
|
package/client/src/constants.js
CHANGED
package/client/src/core/data.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MONGO_OPERATORS} from "../constants.js";
|
|
2
|
+
import {getHost} from "../../../src/constants";
|
|
2
3
|
|
|
3
4
|
const isProd = import.meta.env.MODE === 'production';
|
|
4
5
|
export const urlData = isProd ? 'https://'+getHost()+'/' : 'http://localhost:7633/';
|
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
export const websiteTranslations = {
|
|
3
3
|
fr: {
|
|
4
4
|
translation: {
|
|
5
|
+
|
|
6
|
+
"field_endpoint_isPublic": "Accès public",
|
|
7
|
+
"field_endpoint_isPublic_hint": "Si coché, ce point d'accès sera accessible sans authentification. Le script s'exécutera avec les droits du propriétaire du point d'accès.",
|
|
8
|
+
|
|
9
|
+
"packs.manualInstall": "Importer",
|
|
10
|
+
"packs.manualInstall.title": "Installation manuelle de pack",
|
|
11
|
+
"packs.manualInstall.instructions": "Collez ici le JSON de configuration du pack que vous souhaitez installer.",
|
|
12
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Mon Pack\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
13
|
+
|
|
14
|
+
"api.data.relationFilterFailed": "La valeur {{value}} pour le champ {{field}} ne respecte pas le filtre de relation défini.",
|
|
15
|
+
|
|
5
16
|
"dataimporter.excelPreview":"Aperçu des données Excel",
|
|
6
17
|
"dataimporter.previewNote": "Note: Ceci est un aperçu des premières lignes. Les cellules vides sont affichées comme \"(vide)\".",
|
|
7
18
|
"dataimporter.nullValue": "(vide)",
|
|
@@ -532,6 +543,11 @@ export const websiteTranslations = {
|
|
|
532
543
|
},
|
|
533
544
|
en: {
|
|
534
545
|
translation: {
|
|
546
|
+
"packs.manualInstall": "Import",
|
|
547
|
+
"packs.manualInstall.title": "Manual Pack Installation",
|
|
548
|
+
"packs.manualInstall.instructions": "Paste the configuration JSON of the pack you want to install here.",
|
|
549
|
+
"packs.manualInstall.placeholder": "{\"name\": \"My Pack\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
550
|
+
|
|
535
551
|
"dataimporter.excelPreview": "Excel Data Preview",
|
|
536
552
|
"dataimporter.previewNote": "Note: This is a preview of the first few rows. Empty cells are displayed as \"(empty)\".",
|
|
537
553
|
"dataimporter.nullValue": "(empty)",
|
|
@@ -567,6 +583,8 @@ export const websiteTranslations = {
|
|
|
567
583
|
"suggested_prompt.recipes.title": "Cooking Recipes",
|
|
568
584
|
"suggested_prompt.recipes.prompt": "A collection of cooking recipes, with ingredients, instructions, and preparation time.",
|
|
569
585
|
|
|
586
|
+
"api.data.relationFilterFailed": "The value {{value}} for field {{field}} does not match the defined relationship filter.",
|
|
587
|
+
|
|
570
588
|
"api.data.duplicateValue": "The value '{{value}}' already exists for the unique field '{{field}}'.",
|
|
571
589
|
"api.model.invalidStructure": "The model is invalid. Some fields are incorrect.",
|
|
572
590
|
"api.validate.fieldArray": "Field '{{0}}' must be an array.",
|
|
@@ -1939,6 +1957,11 @@ export const websiteTranslations = {
|
|
|
1939
1957
|
},
|
|
1940
1958
|
es: {
|
|
1941
1959
|
translation: {
|
|
1960
|
+
"packs.manualInstall": "Importar",
|
|
1961
|
+
"packs.manualInstall.title": "Instalación manual del paquete",
|
|
1962
|
+
"packs.manualInstall.instructions": "Pegue aquí el JSON de configuración del paquete que desea instalar.",
|
|
1963
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Mi paquete\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
1964
|
+
|
|
1942
1965
|
"dataimporter.excelPreview": "Vista previa de datos de Excel",
|
|
1943
1966
|
"dataimporter.previewNote": "Nota: Esta es una vista previa de las primeras filas. Las celdas vacías se muestran como \"(vacío)\".",
|
|
1944
1967
|
"dataimporter.nullValue": "(vacío)",
|
|
@@ -1975,6 +1998,7 @@ export const websiteTranslations = {
|
|
|
1975
1998
|
"suggested_prompt.recipes.prompt": "Una colección de recetas de cocina, con ingredientes, instrucciones y tiempo de preparación.",
|
|
1976
1999
|
|
|
1977
2000
|
"api.data.duplicateValue": "El valor '{{value}}' ya existe para el campo único '{{field}}'.",
|
|
2001
|
+
"api.data.relationFilterFailed": "El valor {{value}} del campo {{field}} no coincide con el filtro de relación definido.",
|
|
1978
2002
|
"api.model.invalidStructure": "El modelo no es válido. Algunos campos son incorrectos.",
|
|
1979
2003
|
"api.validate.fieldArray": "El campo '{{0}}' debe ser un array.",
|
|
1980
2004
|
"api.validate.invalidMimeType": "Tipo de archivo '{{type}}' no válido. Los tipos permitidos son: {{authorized}}.",
|
|
@@ -3351,6 +3375,11 @@ export const websiteTranslations = {
|
|
|
3351
3375
|
},
|
|
3352
3376
|
pt: {
|
|
3353
3377
|
translation: {
|
|
3378
|
+
"packs.manualInstall": "Importar",
|
|
3379
|
+
"packs.manualInstall.title": "Instalação manual do pacote",
|
|
3380
|
+
"packs.manualInstall.instructions": "Cole o JSON de configuração do pacote que você deseja instalar aqui.",
|
|
3381
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Meu pacote\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
3382
|
+
|
|
3354
3383
|
"dataimporter.excelPreview": "Visualização de Dados do Excel",
|
|
3355
3384
|
"dataimporter.previewNote": "Observação: Esta é uma visualização das primeiras linhas. Células vazias são exibidas como \"(vazio)\".",
|
|
3356
3385
|
"dataimporter.nullValue": "(vazio)",
|
|
@@ -3388,6 +3417,7 @@ export const websiteTranslations = {
|
|
|
3388
3417
|
"suggested_prompt.recipes.prompt": "Uma coleção de receitas culinárias, com ingredientes, instruções e tempo de preparação.",
|
|
3389
3418
|
|
|
3390
3419
|
"api.data.duplicateValue": "O valor '{{value}}' já existe para o campo exclusivo '{{field}}'.",
|
|
3420
|
+
"api.data.relationFilterFailed": "O valor {{value}} para o campo {{field}} não corresponde ao filtro de relacionamento definido.",
|
|
3391
3421
|
"api.model.invalidStructure": "O modelo é inválido. Alguns campos estão incorretos.",
|
|
3392
3422
|
"api.validate.fieldArray": "O campo '{{0}}' deve ser um array.",
|
|
3393
3423
|
"api.validate.invalidMimeType": "Tipo de ficheiro inválido '{{type}}'. Os tipos permitidos são: {{authorized}}.",
|
|
@@ -4758,6 +4788,11 @@ export const websiteTranslations = {
|
|
|
4758
4788
|
},
|
|
4759
4789
|
de: {
|
|
4760
4790
|
translation: {
|
|
4791
|
+
"packs.manualInstall": "Importieren",
|
|
4792
|
+
"packs.manualInstall.title": "Manuelle Paketinstallation",
|
|
4793
|
+
"packs.manualInstall.instructions": "Fügen Sie hier die JSON-Konfiguration des zu installierenden Pakets ein.",
|
|
4794
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Mein Paket\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
4795
|
+
|
|
4761
4796
|
"dataimporter.excelPreview": "Excel-Datenvorschau",
|
|
4762
4797
|
"dataimporter.previewNote": "Hinweis: Dies ist eine Vorschau der ersten Zeilen. Leere Zellen werden als \"(leer)\" angezeigt.",
|
|
4763
4798
|
"dataimporter.nullValue": "(leer)",
|
|
@@ -4782,6 +4817,7 @@ export const websiteTranslations = {
|
|
|
4782
4817
|
"suggested_prompt.recipes.prompt": "Eine Sammlung von Kochrezepten mit Zutaten, Anweisungen und Vorbereitungszeit.",
|
|
4783
4818
|
|
|
4784
4819
|
"api.data.duplicateValue": "Der Wert '{{value}}' ist für das eindeutige Feld '{{field}}' bereits vorhanden.",
|
|
4820
|
+
"api.data.relationFilterFailed": "Der Wert {{value}} für das Feld {{field}} entspricht nicht dem definierten Beziehungsfilter.",
|
|
4785
4821
|
"api.model.invalidStructure": "Das Modell ist ungültig. Einige Felder sind fehlerhaft.",
|
|
4786
4822
|
"api.validate.fieldArray": "Feld '{{0}}' muss ein Array sein.",
|
|
4787
4823
|
"api.validate.invalidMimeType": "Ungültiger Dateityp '{{type}}'. Zulässige Typen sind: {{authorized}}.",
|
|
@@ -6149,6 +6185,11 @@ export const websiteTranslations = {
|
|
|
6149
6185
|
},
|
|
6150
6186
|
it: {
|
|
6151
6187
|
translation: {
|
|
6188
|
+
"packs.manualInstall": "Importa",
|
|
6189
|
+
"packs.manualInstall.title": "Installazione manuale del pacchetto",
|
|
6190
|
+
"packs.manualInstall.instructions": "Incolla qui il file JSON di configurazione del pacchetto che desideri installare.",
|
|
6191
|
+
"packs.manualInstall.placeholder": "{\"name\": \"My Pack\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
6192
|
+
|
|
6152
6193
|
"dataimporter.excelPreview": "Anteprima dati Excel",
|
|
6153
6194
|
"dataimporter.previewNote": "Nota: questa è un'anteprima delle prime righe. Le celle vuote vengono visualizzate come \"(vuoto)\".",
|
|
6154
6195
|
"dataimporter.nullValue": "(vuoto)",
|
|
@@ -6185,6 +6226,7 @@ export const websiteTranslations = {
|
|
|
6185
6226
|
"suggested_prompt.recipes.prompt": "Una raccolta di ricette di cucina, con ingredienti, istruzioni e tempi di preparazione.",
|
|
6186
6227
|
|
|
6187
6228
|
"api.data.duplicateValue": "Il valore '{{value}}' esiste già per il campo univoco '{{field}}'.",
|
|
6229
|
+
"api.data.relationFilterFailed": "Il valore {{value}} per il campo {{field}} non corrisponde al filtro di relazione definito.",
|
|
6188
6230
|
"api.model.invalidStructure": "Il modello non è valido. Alcuni campi sono errati.",
|
|
6189
6231
|
"api.validate.fieldArray": "Il campo '{{0}}' deve essere un array.",
|
|
6190
6232
|
"api.validate.invalidMimeType": "Tipo di file '{{type}}' non valido. I tipi consentiti sono: {{authorized}}.",
|
|
@@ -7553,6 +7595,11 @@ export const websiteTranslations = {
|
|
|
7553
7595
|
},
|
|
7554
7596
|
cs: {
|
|
7555
7597
|
translation: {
|
|
7598
|
+
"packs.manualInstall": "Importovat",
|
|
7599
|
+
"packs.manualInstall.title": "Ruční instalace balíčku",
|
|
7600
|
+
"packs.manualInstall.instructions": "Sem vložte konfigurační JSON balíčku, který chcete nainstalovat.",
|
|
7601
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Můj balíček\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
7602
|
+
|
|
7556
7603
|
"dataimporter.excelPreview": "Náhled dat v Excelu",
|
|
7557
7604
|
"dataimporter.previewNote": "Poznámka: Toto je náhled prvních několika řádků. Prázdné buňky se zobrazují jako \"(prázdné)\".",
|
|
7558
7605
|
"dataimporter.nullValue": "(prázdné)",
|
|
@@ -7589,6 +7636,7 @@ export const websiteTranslations = {
|
|
|
7589
7636
|
"suggested_prompt.recipes.prompt": "Sbírka receptů na vaření s ingrediencemi, návodem a přípravou čas.",
|
|
7590
7637
|
|
|
7591
7638
|
"api.data.duplicateValue": "Hodnota '{{value}}' pro jedinečné pole '{{field}}' již existuje.",
|
|
7639
|
+
"api.data.relationFilterFailed": "Hodnota {{value}} pro pole {{field}} neodpovídá definovanému filtru vztahů.",
|
|
7592
7640
|
"api.model.invalidStructure": "Model je neplatný. Některá pole jsou nesprávná.",
|
|
7593
7641
|
"api.validate.fieldArray": "Pole '{{0}}' musí být pole.",
|
|
7594
7642
|
"api.validate.invalidMimeType": "Neplatný typ souboru '{{type}}'. Povolené typy jsou: {{authorized}}.",
|
|
@@ -8952,6 +9000,11 @@ export const websiteTranslations = {
|
|
|
8952
9000
|
},
|
|
8953
9001
|
ru: {
|
|
8954
9002
|
translation: {
|
|
9003
|
+
"packs.manualInstall": "Импорт",
|
|
9004
|
+
"packs.manualInstall.title": "Ручная установка пакета",
|
|
9005
|
+
"packs.manualInstall.instructions": "Вставьте сюда JSON-файл конфигурации пакета, который вы хотите установить.",
|
|
9006
|
+
"packs.manualInstall.placeholder": "{\"name\": \"My Pack\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
9007
|
+
|
|
8955
9008
|
"dataimporter.excelPreview": "Предварительный просмотр данных Excel",
|
|
8956
9009
|
"dataimporter.previewNote": "Примечание: Это предварительный просмотр первых нескольких строк. Пустые ячейки отображаются как \"(пусто)\".",
|
|
8957
9010
|
"dataimporter.nullValue": "(пусто)",
|
|
@@ -8988,6 +9041,7 @@ export const websiteTranslations = {
|
|
|
8988
9041
|
"suggested_prompt.recipes.prompt": "Коллекция кулинарных рецептов с ингредиентами, инструкциями и описанием приготовления. время.",
|
|
8989
9042
|
|
|
8990
9043
|
"api.data.duplicateValue": "Значение '{{value}}' уже существует для уникального поля '{{field}}'.",
|
|
9044
|
+
"api.data.relationFilterFailed": "Значение {{value}} для поля {{field}} не соответствует заданному фильтру связи.",
|
|
8991
9045
|
"api.model.invalidStructure": "Модель недействительна. Некоторые поля неверны.",
|
|
8992
9046
|
"api.validate.fieldArray": "Поле '{{0}}' должно быть массивом.",
|
|
8993
9047
|
"api.validate.invalidMimeType": "Недопустимый тип файла '{{type}}'. Допустимые типы: {{authorized}}.",
|
|
@@ -10361,6 +10415,10 @@ export const websiteTranslations = {
|
|
|
10361
10415
|
},
|
|
10362
10416
|
ar: {
|
|
10363
10417
|
translation: {
|
|
10418
|
+
"packs.manualInstall": "استيراد",
|
|
10419
|
+
"packs.manualInstall.title": "تثبيت الحزمة يدويًا",
|
|
10420
|
+
"packs.manualInstall.instructions": "الصق ملف JSON الخاص بتكوين الحزمة التي تريد تثبيتها هنا",
|
|
10421
|
+
"packs.manualInstall.placeholder": "{\"name\": \"My Pack\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
10364
10422
|
"dataimporter.excelPreview": "معاينة بيانات إكسل",
|
|
10365
10423
|
"dataimporter.previewNote": "ملاحظة: هذه معاينة للصفوف القليلة الأولى. تُعرض الخلايا الفارغة كـ \"(فارغة)\".",
|
|
10366
10424
|
"dataimporter.nullValue": "(فارغة)",
|
|
@@ -10396,6 +10454,7 @@ export const websiteTranslations = {
|
|
|
10396
10454
|
"suggested_prompt.recipes.prompt": "مجموعة من وصفات الطبخ، مع المكونات، والتعليمات، ومدة التحضير.",
|
|
10397
10455
|
|
|
10398
10456
|
"api.data.duplicateValue": "القيمة '{{value}}' موجودة بالفعل للحقل الفريد '{{field}}'.",
|
|
10457
|
+
"api.data.relationFilterFailed": "القيمة {{value}} للحقل {{field}} لا تتطابق مع مرشح العلاقة المحدد.",
|
|
10399
10458
|
"api.model.invalidStructure": "النموذج غير صالح. بعض الحقول غير صحيحة.",
|
|
10400
10459
|
"api.validate.fieldArray": "يجب أن يكون الحقل '{{0}}' مصفوفة.",
|
|
10401
10460
|
"api.validate.invalidMimeType": "نوع الملف '{{type}}' غير صالح. الأنواع المسموح بها هي: {{authorized}}.",
|
|
@@ -11787,6 +11846,11 @@ export const websiteTranslations = {
|
|
|
11787
11846
|
},
|
|
11788
11847
|
sv: {
|
|
11789
11848
|
translation: {
|
|
11849
|
+
"packs.manualInstall": "Importera",
|
|
11850
|
+
"packs.manualInstall.title": "Manuell paketinstallation",
|
|
11851
|
+
"packs.manualInstall.instructions": "Klistra in konfigurations-JSON-filen för paketet du vill installera här.",
|
|
11852
|
+
"packs.manualInstall.placeholder": "{\"namn\": \"Mitt paket\", \"beskrivning\": \"...\", \"modeller\": [...], \"data\": [...]}",
|
|
11853
|
+
|
|
11790
11854
|
"dataimporter.excelPreview": "Förhandsgranskning av Excel-data",
|
|
11791
11855
|
"dataimporter.previewNote": "Obs! Detta är en förhandsgranskning av de första raderna. Tomma celler visas som \"(tomma)\"",
|
|
11792
11856
|
"dataimporter.nullValue": "(tomma)",
|
|
@@ -11823,6 +11887,7 @@ export const websiteTranslations = {
|
|
|
11823
11887
|
"suggested_prompt.recipes.prompt": "En samling matlagningsrecept, med ingredienser, instruktioner, och förberedelsetid.",
|
|
11824
11888
|
|
|
11825
11889
|
"api.data.duplicateValue": "Värdet '{{value}}' finns redan för det unika fältet '{{field}}'.",
|
|
11890
|
+
"api.data.relationFilterFailed": "Värdet {{value}} för fältet {{field}} matchar inte det definierade relationsfiltret.",
|
|
11826
11891
|
"api.model.invalidStructure": "Modellen är ogiltig. Vissa fält är felaktiga.",
|
|
11827
11892
|
"api.validate.fieldArray": "Fältet '{{0}}' måste vara en array.",
|
|
11828
11893
|
"api.validate.invalidMimeType": "Ogiltig filtyp '{{type}}'. Tillåtna typer är: {{authorized}}.",
|
|
@@ -13186,6 +13251,11 @@ export const websiteTranslations = {
|
|
|
13186
13251
|
},
|
|
13187
13252
|
el: {
|
|
13188
13253
|
translation: {
|
|
13254
|
+
"packs.manualInstall": "Εισαγωγή",
|
|
13255
|
+
"packs.manualInstall.title": "Χειροκίνητη εγκατάσταση πακέτου",
|
|
13256
|
+
"packs.manualInstall.instructions": "Επικολλήστε εδώ το JSON διαμόρφωσης του πακέτου που θέλετε να εγκαταστήσετε.",
|
|
13257
|
+
"packs.manualInstall.placeholder": "{\"name\": \"Το πακέτο μου\", \"περιγραφή\": \"...\", \"μοντέλα\": [...], \"δεδομένα\": [...]}",
|
|
13258
|
+
|
|
13189
13259
|
"dataimporter.excelPreview": "Προεπισκόπηση δεδομένων Excel",
|
|
13190
13260
|
"dataimporter.previewNote": "Σημείωση: Αυτή είναι μια προεπισκόπηση των πρώτων γραμμών. Τα κενά κελιά εμφανίζονται ως \"(κενό)\".",
|
|
13191
13261
|
"dataimporter.nullValue": "(κενό)",
|
|
@@ -13222,6 +13292,8 @@ export const websiteTranslations = {
|
|
|
13222
13292
|
"suggested_prompt.recipes.prompt": "Μια συλλογή συνταγών μαγειρικής, με υλικά, οδηγίες και χρόνο προετοιμασίας.",
|
|
13223
13293
|
|
|
13224
13294
|
"api.data.duplicateValue": "Η τιμή '{{value}}' υπάρχει ήδη για το μοναδικό πεδίο '{{field}}'.",
|
|
13295
|
+
"api.data.relationFilterFailed": "Η τιμή {{value}} για το πεδίο {{field}} δεν ταιριάζει με το καθορισμένο φίλτρο σχέσης.",
|
|
13296
|
+
|
|
13225
13297
|
"api.model.invalidStructure": "Το μοντέλο δεν είναι έγκυρο. Ορισμένα πεδία είναι λανθασμένα.",
|
|
13226
13298
|
"api.validate.fieldArray": "Το πεδίο '{{0}}' πρέπει να είναι ένας πίνακας.",
|
|
13227
13299
|
"api.validate.invalidMimeType": "Μη έγκυρος τύπος αρχείου '{{type}}'. Οι επιτρεπόμενοι τύποι είναι: {{authorized}}.",
|
|
@@ -14592,6 +14664,12 @@ export const websiteTranslations = {
|
|
|
14592
14664
|
},
|
|
14593
14665
|
fa: {
|
|
14594
14666
|
"translation": {
|
|
14667
|
+
|
|
14668
|
+
"packs.manualInstall": "وارد کردن",
|
|
14669
|
+
"packs.manualInstall.title": "نصب دستی بسته",
|
|
14670
|
+
"packs.manualInstall.instructions": "فایل JSON پیکربندی بستهای که میخواهید نصب کنید را اینجا جایگذاری کنید.",
|
|
14671
|
+
"packs.manualInstall.placeholder": "{\"name\": \"بسته من\", \"description\": \"...\", \"models\": [...], \"data\": [...]}",
|
|
14672
|
+
|
|
14595
14673
|
"dataimporter.excelPreview": "پیشنمایش دادههای اکسل",
|
|
14596
14674
|
"dataimporter.previewNote": "توجه: این پیشنمایشی از چند ردیف اول است. سلولهای خالی به صورت \"(empty)\" نمایش داده میشوند.",
|
|
14597
14675
|
"dataimporter.nullValue": "(empty)",
|
|
@@ -14629,6 +14707,8 @@ export const websiteTranslations = {
|
|
|
14629
14707
|
"suggested_prompt.recipes.prompt": "مجموعهای از دستور پخت غذا، با مواد لازم، دستورالعمل و زمان آمادهسازی.",
|
|
14630
14708
|
|
|
14631
14709
|
"api.data.duplicateValue": "مقدار '{{value}}' از قبل برای فیلد منحصر به فرد '{{field}}' وجود دارد.",
|
|
14710
|
+
"api.data.relationFilterFailed": "مقدار {{value}} برای فیلد {{field}} با فیلتر رابطه تعریف شده مطابقت ندارد.",
|
|
14711
|
+
|
|
14632
14712
|
"api.model.invalidStructure": "مدل نامعتبر است. برخی از فیلدها نادرست هستند.",
|
|
14633
14713
|
"api.validate.fieldArray": "فیلد '{{0}}' باید یک آرایه باشد.",
|
|
14634
14714
|
"api.validate.invalidMimeType": "نوع فایل '{{type}}' نامعتبر است. انواع مجاز عبارتند از: {{authorized}}.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
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,6 +33,11 @@
|
|
|
33
33
|
"brace-expansion": "2.0.2",
|
|
34
34
|
"prismjs": "1.30.0"
|
|
35
35
|
},
|
|
36
|
+
"overrides": {
|
|
37
|
+
"refractor": {
|
|
38
|
+
"prismjs": "1.30.0"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
36
41
|
"repository": {
|
|
37
42
|
"type": "git",
|
|
38
43
|
"url": "https://github.com/anonympins/data-primals-engine.git"
|
|
@@ -50,6 +55,7 @@
|
|
|
50
55
|
"react-query": ">=3.0.0"
|
|
51
56
|
},
|
|
52
57
|
"dependencies": {
|
|
58
|
+
"@langchain/anthropic": "^0.3.26",
|
|
53
59
|
"@langchain/core": "^0.3.66",
|
|
54
60
|
"@langchain/deepseek": "^0.1.0",
|
|
55
61
|
"@langchain/google-genai": "^0.2.16",
|
|
@@ -88,6 +94,7 @@
|
|
|
88
94
|
"request-ip": "^3.3.0",
|
|
89
95
|
"sanitize-html": "^2.17.0",
|
|
90
96
|
"sirv": "^3.0.1",
|
|
97
|
+
"stripe": "^18.4.0",
|
|
91
98
|
"swagger-ui-express": "^5.0.1",
|
|
92
99
|
"tar": "^7.4.3",
|
|
93
100
|
"uniqid": "^5.4.0",
|
package/server.js
CHANGED
|
@@ -7,6 +7,7 @@ import process from "node:process";
|
|
|
7
7
|
import {Config, Engine, BenchmarkTool, GameObject, Logger} from "./src/index.js";
|
|
8
8
|
import sirv from "sirv";
|
|
9
9
|
import express from "express";
|
|
10
|
+
import {port} from "./src/constants.js";
|
|
10
11
|
|
|
11
12
|
Config.Set("modules", ["mongodb", "data", "file", "bucket", "workflow","user", "assistant", "swagger"])
|
|
12
13
|
Config.Set("middlewares", []);
|
|
@@ -27,10 +28,9 @@ if (process.argv.length === 3) {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
const
|
|
31
|
-
engine.start(
|
|
31
|
+
const realPort = process.env.PORT || port;
|
|
32
|
+
engine.start(realPort, async (r) => {
|
|
32
33
|
const logger = engine.getComponent(Logger);
|
|
33
|
-
console.log("Server started on port " +
|
|
34
|
+
console.log("Server started on port " + realPort);
|
|
34
35
|
timer.stop();
|
|
35
|
-
|
|
36
36
|
});
|
package/src/constants.js
CHANGED
|
@@ -24,6 +24,8 @@ export const dbName = "engine";
|
|
|
24
24
|
*/
|
|
25
25
|
export const host = 'localhost'; // or myhost.tld
|
|
26
26
|
|
|
27
|
+
export const port = 7633;
|
|
28
|
+
|
|
27
29
|
/**
|
|
28
30
|
* Cookie secret key (if COOKIES_SECRET is set, it will override this variable)
|
|
29
31
|
* @type {string}
|
|
@@ -301,3 +303,7 @@ metaModels['erp'] = { load: [ 'accountingExercise', 'accountingLineItem', 'accou
|
|
|
301
303
|
export const allowedFields = ['locked', 'hiddenable', 'anonymized', 'condition', 'color', 'index', 'type', 'required', 'hint', 'default', 'validate', 'unique', 'name', 'placeholder', 'asMain'];
|
|
302
304
|
|
|
303
305
|
|
|
306
|
+
|
|
307
|
+
export const getHost = () => {
|
|
308
|
+
return process.env.HOST || host || 'localhost';
|
|
309
|
+
}
|
package/src/defaultModels.js
CHANGED
|
@@ -420,6 +420,7 @@ export const defaultModels = {
|
|
|
420
420
|
{ "name": "products", "type": "relation", "relation": "cartItem", "required": true, multiple: true },
|
|
421
421
|
{ "name": "customer", "type": "relation", relation: 'user' }, // Relation vers le modèle 'user'
|
|
422
422
|
{ "name": "totalAmount", "type": "number", "required": true },
|
|
423
|
+
{ "name": "paymentIntentId", "type": "string", "hint": "Stripe Payment Intent ID for this order." },
|
|
423
424
|
{ "name": "currency", "type": "relation", "relation": "currency" },
|
|
424
425
|
{ "name": "paymentMethod", "type": "string" },
|
|
425
426
|
{ "name": "shippingAddress", "type": "relation", "relation": "location" },
|
|
@@ -506,6 +507,7 @@ export const defaultModels = {
|
|
|
506
507
|
name: "return",
|
|
507
508
|
"description": "",
|
|
508
509
|
fields: [
|
|
510
|
+
{ "name": "order", "type": "relation", "relation": "order", "required": true },
|
|
509
511
|
{ "name": "user", "type": "relation", relation: "user" },
|
|
510
512
|
{ "name": "reason", "type": "string", maxlength: 2048, required: true },
|
|
511
513
|
{ "name": "channel", "type": "relation", relation: 'channel' },
|
|
@@ -897,7 +899,7 @@ export const defaultModels = {
|
|
|
897
899
|
name: 'type',
|
|
898
900
|
type: 'enum',
|
|
899
901
|
required: true,
|
|
900
|
-
items: ['UpdateData', 'CreateData', 'DeleteData', 'ExecuteScript', '
|
|
902
|
+
items: ['UpdateData', 'CreateData', 'DeleteData', 'ExecuteScript', 'HttpRequest', 'SendEmail', 'Wait', 'GenerateAIContent', 'ExecuteServiceFunction'],
|
|
901
903
|
hint: "The type of operation to perform."
|
|
902
904
|
},
|
|
903
905
|
// For UpdateData / CreateData / DeleteData
|
|
@@ -923,14 +925,11 @@ export const defaultModels = {
|
|
|
923
925
|
// For CreateData
|
|
924
926
|
{ name: 'dataToCreate', condition: {$eq: ["$type", "CreateData"]}, type: 'code', language: 'json', default: {}, hint: "Object template for the new document to create" },
|
|
925
927
|
|
|
926
|
-
// For
|
|
927
|
-
{ name: '
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
{ name: '
|
|
931
|
-
{ name: 'method', condition: {$eq: ["$type", "CallWebhook"]}, type: 'enum', items: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], default: 'POST', hint: "HTTP method." },
|
|
932
|
-
{ name: 'headers', condition: {$eq: ["$type", "CallWebhook"]}, type: 'code', language: 'json',default: {}, hint: "HTTP headers as key-value pairs." },
|
|
933
|
-
{ name: 'body', condition: {$eq: ["$type", "CallWebhook"]}, type: 'code', language: 'json',default: {}, hint: "Request body, can include variables." },
|
|
928
|
+
// For HttpRequest
|
|
929
|
+
{ name: 'url', condition: {$eq: ["$type", "HttpRequest"]}, type: 'string', hint: "The URL to call." },
|
|
930
|
+
{ name: 'method', condition: {$eq: ["$type", "HttpRequest"]}, type: 'enum', items: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], default: 'POST', hint: "HTTP method." },
|
|
931
|
+
{ name: 'headers', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "HTTP headers as key-value pairs." },
|
|
932
|
+
{ name: 'body', condition: {$eq: ["$type", "HttpRequest"]}, type: 'code', language: 'json',default: {}, hint: "Request body, can include variables." },
|
|
934
933
|
|
|
935
934
|
// For SendEmail
|
|
936
935
|
{
|
|
@@ -977,7 +976,15 @@ export const defaultModels = {
|
|
|
977
976
|
condition: { $eq: ["$type", "GenerateAIContent"] },
|
|
978
977
|
type: 'richtext', // richtext est bien pour les longs prompts
|
|
979
978
|
hint: "Le modèle de prompt. Utilise des variables comme {triggerData.field} ou {context.variable}."
|
|
980
|
-
}
|
|
979
|
+
},
|
|
980
|
+
|
|
981
|
+
// For ExecuteScript
|
|
982
|
+
{ name: 'script', condition: {$eq: ["$type", "ExecuteScript"]}, type: 'code', language: 'javascript', hint: "The script to execute." },
|
|
983
|
+
|
|
984
|
+
// For ExecuteServiceFunction
|
|
985
|
+
{ name: 'serviceName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the registered service to call (e.g., 'stripe')." },
|
|
986
|
+
{ name: 'functionName', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'string', hint: "The name of the function to execute within the service." },
|
|
987
|
+
{ name: 'args', condition: {$eq: ["$type", "ExecuteServiceFunction"]}, type: 'code', language: 'json', default: [], hint: "An array of arguments to pass to the function. Can include variables." }
|
|
981
988
|
|
|
982
989
|
]
|
|
983
990
|
},
|
|
@@ -1447,6 +1454,12 @@ export const defaultModels = {
|
|
|
1447
1454
|
default: "POST",
|
|
1448
1455
|
hint: "The HTTP method required to call this endpoint."
|
|
1449
1456
|
},
|
|
1457
|
+
{
|
|
1458
|
+
name: 'isPublic',
|
|
1459
|
+
type: 'boolean',
|
|
1460
|
+
default: false,
|
|
1461
|
+
hint: "Si coché, ce point d'accès sera accessible sans authentification."
|
|
1462
|
+
},
|
|
1450
1463
|
{
|
|
1451
1464
|
name: "code",
|
|
1452
1465
|
type: "code",
|
package/src/filter.js
CHANGED
|
@@ -175,15 +175,45 @@ export const isConditionMet = (model, cond, formData, allModels, user) => {
|
|
|
175
175
|
|
|
176
176
|
if (!condition) return true;
|
|
177
177
|
|
|
178
|
+
// Cas 0: Condition est une valeur primitive (string, number, boolean)
|
|
179
|
+
// On la considère comme toujours vraie (comportement de searchData)
|
|
180
|
+
if (typeof condition !== 'object' || condition === null) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
|
|
178
184
|
// Cas 1: Condition simple {field: value} → transformée en {field: {$eq: value}}
|
|
179
185
|
if (typeof condition === 'object' && !Array.isArray(condition)) {
|
|
180
186
|
const keys = Object.keys(condition);
|
|
187
|
+
|
|
188
|
+
// Cas spécial pour les conditions de type {field: value} (pas d'opérateur $)
|
|
181
189
|
if (keys.length === 1 && !keys[0].startsWith('$') &&
|
|
182
190
|
typeof condition[keys[0]] !== 'object') {
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
191
|
+
const fieldName = keys[0];
|
|
192
|
+
const value = condition[fieldName];
|
|
193
|
+
|
|
194
|
+
// Si la valeur est null/undefined, on vérifie simplement l'existence
|
|
195
|
+
if (value === null || value === undefined) {
|
|
196
|
+
return formData[fieldName] === value;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Sinon on fait une comparaison d'égalité simple
|
|
200
|
+
return formData[fieldName] == value;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Cas spécial pour les tableaux - vérifie si la valeur est incluse
|
|
204
|
+
if (keys.length === 1 && !keys[0].startsWith('$') &&
|
|
205
|
+
Array.isArray(condition[keys[0]])) {
|
|
206
|
+
const fieldName = keys[0];
|
|
207
|
+
const values = condition[fieldName];
|
|
208
|
+
const fieldValue = formData[fieldName];
|
|
209
|
+
|
|
210
|
+
// Si le champ est aussi un tableau, vérifie l'intersection
|
|
211
|
+
if (Array.isArray(fieldValue)) {
|
|
212
|
+
return fieldValue.some(v => values.includes(v));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Sinon vérifie si la valeur est dans le tableau
|
|
216
|
+
return values.includes(fieldValue);
|
|
187
217
|
}
|
|
188
218
|
}
|
|
189
219
|
|
|
@@ -218,4 +248,4 @@ export const isConditionMet = (model, cond, formData, allModels, user) => {
|
|
|
218
248
|
|
|
219
249
|
// Cas 4: Tous les autres cas (conditions normales avec opérateurs)
|
|
220
250
|
return evaluateSingleCondition(model, condition, formData, allModels, user);
|
|
221
|
-
};
|
|
251
|
+
};
|
package/src/i18n.js
CHANGED
|
@@ -1121,7 +1121,7 @@ export const translations = {
|
|
|
1121
1121
|
"CreateData": "Créer une donnée",
|
|
1122
1122
|
"DeleteData": "Supprimer une donnée",
|
|
1123
1123
|
"ExecuteScript": "Exécuter un script",
|
|
1124
|
-
"
|
|
1124
|
+
"HttpRequest": "Appeler un Webhook",
|
|
1125
1125
|
"SendEmail": "Envoyer un Email",
|
|
1126
1126
|
"Wait": "Attendre",
|
|
1127
1127
|
"GenerateAIContent": "Générer un contenu IA",
|