data-primals-engine 1.1.7-rc1 → 1.1.7
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/client/src/App.jsx +55 -49
- package/client/src/App.scss +3 -1
- package/client/src/constants.js +20 -1
- package/client/src/filter.js +18 -0
- package/client/src/translations.js +34 -17
- package/package.json +1 -1
- package/src/modules/data.js +124 -0
package/client/src/App.jsx
CHANGED
|
@@ -55,12 +55,13 @@ import {useCookies, CookiesProvider} from "react-cookie";
|
|
|
55
55
|
import { translations as allTranslations} from "../../src/i18n.js";
|
|
56
56
|
import {getBrowserRandom, getRandom} from "../../src/core.js";
|
|
57
57
|
import {getUserHash} from "../../src/data.js";
|
|
58
|
-
import {seoTitle} from "./constants.js";
|
|
58
|
+
import {langs, seoTitle} from "./constants.js";
|
|
59
59
|
import {host, useAI} from "../../src/constants.js";
|
|
60
60
|
import i18next from "i18next";
|
|
61
61
|
import {websiteTranslations} from "./translations.js";
|
|
62
62
|
|
|
63
63
|
import { Tooltip } from 'react-tooltip';
|
|
64
|
+
import {availableLangs} from "data-primals-engine/constants";
|
|
64
65
|
|
|
65
66
|
let queryClient = new QueryClient();
|
|
66
67
|
|
|
@@ -84,7 +85,7 @@ function TopBar({header}) {
|
|
|
84
85
|
return <>{header}</>;
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
function Layout ({header,
|
|
88
|
+
function Layout ({header, routes, body, footer}) {
|
|
88
89
|
const [cookies, setCookie, removeCookie] = useCookies(['username']);
|
|
89
90
|
const { i18n, t } = useTranslation();
|
|
90
91
|
const lang = (i18n.resolvedLanguage || i18n.language).split(/[-_]/)?.[0];
|
|
@@ -157,8 +158,6 @@ function Layout ({header, translationMutation, routes, body, footer}) {
|
|
|
157
158
|
);
|
|
158
159
|
|
|
159
160
|
|
|
160
|
-
const [lastLang, setLastLang] = useState(null);
|
|
161
|
-
|
|
162
161
|
// AJOUT : Liste des suggestions de prompts
|
|
163
162
|
const suggestedPrompts = [
|
|
164
163
|
{
|
|
@@ -180,37 +179,11 @@ function Layout ({header, translationMutation, routes, body, footer}) {
|
|
|
180
179
|
];
|
|
181
180
|
|
|
182
181
|
const { setCurrentTourSteps, setAllTourSteps, currentTour, setCurrentTour } = useUI();
|
|
183
|
-
const [translations, setTranslations] = useState([]);
|
|
184
182
|
|
|
185
183
|
|
|
186
184
|
const isProd = import.meta.env.MODE === 'production';
|
|
187
185
|
const loc = useLocation();
|
|
188
186
|
|
|
189
|
-
const changeLanguage = (newLang) => {
|
|
190
|
-
if (typeof(newLang) === 'string' && newLang) {
|
|
191
|
-
|
|
192
|
-
i18n.changeLanguage(newLang, (err)=>{
|
|
193
|
-
|
|
194
|
-
i18next.removeResourceBundle(lang, "translation");
|
|
195
|
-
i18next.addResourceBundle(newLang, 'translation', {...websiteTranslations[newLang]['translation'], ...translations[newLang]?.['translation']});
|
|
196
|
-
|
|
197
|
-
gtag("event", "change_language "+newLang);
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
if( me ){
|
|
204
|
-
translationMutation?.mutateAsync(lang).then(d => {
|
|
205
|
-
setTranslations(d);
|
|
206
|
-
setLastLang(lang);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}, [me, lang])
|
|
210
|
-
|
|
211
|
-
useEffect(() => {
|
|
212
|
-
changeLanguage(lang);
|
|
213
|
-
}, [lang]);
|
|
214
187
|
|
|
215
188
|
const [currentProfile, setCurrentProfile] = useLocalStorage('profile', null);
|
|
216
189
|
|
|
@@ -225,24 +198,6 @@ function Layout ({header, translationMutation, routes, body, footer}) {
|
|
|
225
198
|
}
|
|
226
199
|
}
|
|
227
200
|
|
|
228
|
-
useEffect(() => {
|
|
229
|
-
if (Array.isArray(translations)) {
|
|
230
|
-
var trs= {};
|
|
231
|
-
translations.forEach(tr =>{
|
|
232
|
-
trs[tr.key] = tr.value;
|
|
233
|
-
});
|
|
234
|
-
trs= { ...allTranslations[lang]['translation'], ...trs};
|
|
235
|
-
|
|
236
|
-
if( lastLang && lang !== lastLang) {
|
|
237
|
-
i18n.removeResourceBundle(lastLang, 'translation');
|
|
238
|
-
}
|
|
239
|
-
i18n.addResourceBundle(lang, 'translation', trs);
|
|
240
|
-
}
|
|
241
|
-
}, [translations]);
|
|
242
|
-
|
|
243
|
-
useEffect(() => {
|
|
244
|
-
changeLanguage(lang);
|
|
245
|
-
}, []);
|
|
246
201
|
|
|
247
202
|
const [refreshReducer, refreshUI]= useReducer((n) => n+1, 0,() => 0);
|
|
248
203
|
|
|
@@ -389,7 +344,9 @@ function Layout ({header, translationMutation, routes, body, footer}) {
|
|
|
389
344
|
|
|
390
345
|
<div className="flex flex-row flex-no-wrap">
|
|
391
346
|
<div className="flex flex-1 flex-no-gap home-header">
|
|
392
|
-
<
|
|
347
|
+
<div className="flex flex-self-end">
|
|
348
|
+
<a href={"https://github.com/anonympins/data-primals-engine"} target={"_blank"} className="link-top"><img src={"/github.svg"} alt={"Github"} /></a>
|
|
349
|
+
</div>
|
|
393
350
|
<div className="flex prior">
|
|
394
351
|
<img
|
|
395
352
|
src="https://web.primals.net/PRIOR.png"
|
|
@@ -575,10 +532,59 @@ function UserPage({notifs,triggerSignin, onAuthenticated}) {
|
|
|
575
532
|
données</p>}</>;
|
|
576
533
|
}
|
|
577
534
|
|
|
535
|
+
const allLangs = Object.keys(langs).map(l => {
|
|
536
|
+
return {value: l, label: langs[l]};
|
|
537
|
+
})
|
|
538
|
+
|
|
578
539
|
const BaseLayout=()=>{
|
|
540
|
+
const [lastLang, setLastLang] = useState(null);
|
|
541
|
+
const { i18n, t} = useTranslation();
|
|
542
|
+
const lang = (i18n.resolvedLanguage || i18n.language).split(/[-_]/)?.[0];
|
|
543
|
+
const { me, setMe } = useAuthContext();
|
|
544
|
+
const [translations, setTranslations] = useState([]);
|
|
545
|
+
|
|
546
|
+
useEffect(() => {
|
|
547
|
+
if (Array.isArray(translations)) {
|
|
548
|
+
var trs= {};
|
|
549
|
+
translations.forEach(tr =>{
|
|
550
|
+
trs[tr.key] = tr.value;
|
|
551
|
+
});
|
|
552
|
+
trs= { ...allTranslations[lang]['translation'], ...trs};
|
|
553
|
+
|
|
554
|
+
if( lastLang && lang !== lastLang) {
|
|
555
|
+
i18n.removeResourceBundle(lastLang, 'translation');
|
|
556
|
+
}
|
|
557
|
+
i18n.addResourceBundle(lang, 'translation', trs);
|
|
558
|
+
}
|
|
559
|
+
}, [translations]);
|
|
560
|
+
|
|
561
|
+
const changeLanguage = (newLang) => {
|
|
562
|
+
if (typeof(newLang) === 'string' && newLang) {
|
|
563
|
+
|
|
564
|
+
i18n.changeLanguage(newLang, (err)=>{
|
|
565
|
+
|
|
566
|
+
i18next.removeResourceBundle(lang, "dataEngineTranslations");
|
|
567
|
+
const trs = {...websiteTranslations[newLang]?.['translation']} || {};
|
|
568
|
+
i18next.addResourceBundle(newLang, 'dataEngineTranslations', trs);
|
|
569
|
+
|
|
570
|
+
gtag("event", "change_language "+newLang);
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
useEffect(() => {
|
|
576
|
+
changeLanguage(lang);
|
|
577
|
+
}, [lang]);
|
|
578
|
+
|
|
579
579
|
return <Layout header={<header className={"flex"}>
|
|
580
580
|
<Tooltip id={"header"}/>
|
|
581
581
|
<h1 className="flex-1">{seoTitle}</h1>
|
|
582
|
+
<div className="center">
|
|
583
|
+
<SelectField label={<FaLanguage />} items={allLangs} onChange={(e) => {
|
|
584
|
+
console.log(e.value);
|
|
585
|
+
changeLanguage(e.value);
|
|
586
|
+
}} />
|
|
587
|
+
</div>
|
|
582
588
|
<div className="flex">
|
|
583
589
|
<FaQuestion data-tooltip-id="header" data-tooltip-content="Documentation" onClick={()=> {
|
|
584
590
|
window.open("https://data.primals.net/en/documentation/", "_blank");
|
package/client/src/App.scss
CHANGED
|
@@ -45,6 +45,9 @@ header {
|
|
|
45
45
|
&.flex-start {
|
|
46
46
|
align-items: start;
|
|
47
47
|
}
|
|
48
|
+
&.flex-self-end {
|
|
49
|
+
align-self: end;
|
|
50
|
+
}
|
|
48
51
|
.flex-left {
|
|
49
52
|
justify-content: flex-start;
|
|
50
53
|
}
|
|
@@ -513,7 +516,6 @@ label + .field, label + input, label + select {
|
|
|
513
516
|
|
|
514
517
|
/* website*/
|
|
515
518
|
#content {
|
|
516
|
-
margin-top: 40px;
|
|
517
519
|
padding: 0;
|
|
518
520
|
h1 {
|
|
519
521
|
margin: 24px 8px;
|
package/client/src/constants.js
CHANGED
|
@@ -66,4 +66,23 @@ export const OPERAND_TYPES = {
|
|
|
66
66
|
|
|
67
67
|
export const getHost = () => {
|
|
68
68
|
return process.env.HOST || host || 'localhost';
|
|
69
|
-
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
export const langs = {
|
|
74
|
+
fr: "Français",
|
|
75
|
+
en: "English",
|
|
76
|
+
ar: "عربي",
|
|
77
|
+
fa: "فارسی",
|
|
78
|
+
it: "Italiano",
|
|
79
|
+
es: "Español",
|
|
80
|
+
el: "Ελληνικά",
|
|
81
|
+
de: "Deutsch",
|
|
82
|
+
cs: "Čeština",
|
|
83
|
+
sv: "Svenska",
|
|
84
|
+
pt: "Português",
|
|
85
|
+
ja: "日本語",
|
|
86
|
+
zh: "简体中文",
|
|
87
|
+
ru: "Русский"
|
|
88
|
+
};
|
package/client/src/filter.js
CHANGED
|
@@ -258,4 +258,22 @@ export const pagedFilterToMongoConds = (pagedFilters, model) => {
|
|
|
258
258
|
});
|
|
259
259
|
return c;
|
|
260
260
|
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Remplace les placeholders dans un objet filtre.
|
|
265
|
+
* Gère {{userId}}.
|
|
266
|
+
*/
|
|
267
|
+
export const processFilterPlaceholders = (filter, user) => {
|
|
268
|
+
const processedFilter = JSON.parse(JSON.stringify(filter));
|
|
269
|
+
for (const key in processedFilter) {
|
|
270
|
+
if (processedFilter[key] === '{{userId}}') {
|
|
271
|
+
// Dans le système Primals, le champ utilisateur est souvent `_user`
|
|
272
|
+
// et contient le nom d'utilisateur, pas l'ID. Adaptez si besoin.
|
|
273
|
+
processedFilter[key] = user.username;
|
|
274
|
+
} else if (typeof processedFilter[key] === 'object' && processedFilter[key] !== null) {
|
|
275
|
+
processedFilter[key] = processFilterPlaceholders(processedFilter[key], user);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return processedFilter;
|
|
261
279
|
};
|
|
@@ -52,6 +52,8 @@ export const websiteTranslations = {
|
|
|
52
52
|
"modelcreator.hiddenable.hint": "Une option sera disponible pour afficher cette donnée ou la masquer (il sera masqué par défaut).",
|
|
53
53
|
|
|
54
54
|
"tourpoint.importDatapack": "Importez des packs de données pré-construits avec notre galerie de packs : Sites internets, e-commerce, CRM, et plus encore !",
|
|
55
|
+
"tourpoint.tutorials": "Laisse-vous guider en suivant nos tutoriels pas à pas !",
|
|
56
|
+
|
|
55
57
|
"add_language": "Ajouter...",
|
|
56
58
|
"select_or_add_language": "Sélectionnez ou ajoutez une langue pour commencer.",
|
|
57
59
|
"field.richtext_t": "Texte enrichi traduit",
|
|
@@ -522,7 +524,7 @@ export const websiteTranslations = {
|
|
|
522
524
|
"links.deploy_api": "Déployez votre API",
|
|
523
525
|
"links.documentation": "Documentation",
|
|
524
526
|
"links.demo": "Essayez maintenant !",
|
|
525
|
-
"filterstringfield.placeholder.regex": 'Expression régulière'
|
|
527
|
+
"filterstringfield.placeholder.regex": 'Expression régulière'
|
|
526
528
|
|
|
527
529
|
}
|
|
528
530
|
},
|
|
@@ -594,6 +596,8 @@ export const websiteTranslations = {
|
|
|
594
596
|
"api.data.serverStorageFull": "The server has reached its maximum storage capacity. Please try again later.",
|
|
595
597
|
|
|
596
598
|
"tourpoint.importDatapack": "Import pre-built data packs with our pack gallery: Websites, e-commerce, CRM, and more!",
|
|
599
|
+
"tourpoint.tutorials": "Let yourself be guided by following our step-by-step tutorials!",
|
|
600
|
+
|
|
597
601
|
"add_language": "Add...",
|
|
598
602
|
"select_or_add_language": "Select or add a language to get started.",
|
|
599
603
|
"field.richtext_t": "Translated rich text",
|
|
@@ -1925,8 +1929,8 @@ export const websiteTranslations = {
|
|
|
1925
1929
|
// channel
|
|
1926
1930
|
field_channel_name: 'Name',
|
|
1927
1931
|
field_channel_description: 'Description',
|
|
1928
|
-
field_channel_type: 'Type'
|
|
1929
|
-
}
|
|
1932
|
+
field_channel_type: 'Type'
|
|
1933
|
+
}
|
|
1930
1934
|
},
|
|
1931
1935
|
es: {
|
|
1932
1936
|
translation: {
|
|
@@ -1996,6 +2000,8 @@ export const websiteTranslations = {
|
|
|
1996
2000
|
"api.data.serverStorageFull": "El servidor ha alcanzado su capacidad máxima de almacenamiento. Inténtelo de nuevo más tarde.",
|
|
1997
2001
|
|
|
1998
2002
|
"tourpoint.importDatapack": "Importa paquetes de datos prediseñados con nuestra galería de paquetes: sitios web, comercio electrónico, CRM y más",
|
|
2003
|
+
"tourpoint.tutorials": "¡Déjate guiar por nuestros tutoriales paso a paso!",
|
|
2004
|
+
|
|
1999
2005
|
"add_language": "Añadir...",
|
|
2000
2006
|
"select_or_add_language": "Seleccione o añada un idioma para empezar.",
|
|
2001
2007
|
"field.richtext_t": "Texto enriquecido traducido",
|
|
@@ -3332,8 +3338,8 @@ export const websiteTranslations = {
|
|
|
3332
3338
|
// channel
|
|
3333
3339
|
field_channel_name: 'Nombre',
|
|
3334
3340
|
field_channel_description: 'Descripción',
|
|
3335
|
-
field_channel_type: 'Tipo'
|
|
3336
|
-
}
|
|
3341
|
+
field_channel_type: 'Tipo'
|
|
3342
|
+
}
|
|
3337
3343
|
},
|
|
3338
3344
|
pt: {
|
|
3339
3345
|
translation: {
|
|
@@ -3403,6 +3409,7 @@ export const websiteTranslations = {
|
|
|
3403
3409
|
"api.data.serverStorageFull": "O servidor atingiu a sua capacidade máxima de armazenamento. Tente novamente mais tarde.",
|
|
3404
3410
|
|
|
3405
3411
|
"tourpoint.importDatapack": "Importe pacotes de dados pré-criados com a nossa galeria de pacotes: sites, comércio eletrónico, CRM e muito mais!",
|
|
3412
|
+
"tourpoint.tutorials": "Deixe-se guiar seguindo os nossos tutoriais passo a passo!",
|
|
3406
3413
|
"add_language": "Adicionar...",
|
|
3407
3414
|
"select_or_add_language": "Selecione ou adicione um idioma para começar.",
|
|
3408
3415
|
"field.richtext_t": "Texto rico traduzido",
|
|
@@ -4736,8 +4743,8 @@ export const websiteTranslations = {
|
|
|
4736
4743
|
// channel
|
|
4737
4744
|
field_channel_name: 'Nome',
|
|
4738
4745
|
field_channel_description: 'Descrição',
|
|
4739
|
-
field_channel_type: 'Tipo'
|
|
4740
|
-
}
|
|
4746
|
+
field_channel_type: 'Tipo'
|
|
4747
|
+
}
|
|
4741
4748
|
},
|
|
4742
4749
|
de: {
|
|
4743
4750
|
translation: {
|
|
@@ -4795,6 +4802,8 @@ export const websiteTranslations = {
|
|
|
4795
4802
|
"api.data.serverStorageFull": "Der Server hat seine maximale Speicherkapazität erreicht. Bitte versuchen Sie es später erneut.",
|
|
4796
4803
|
|
|
4797
4804
|
"tourpoint.importDatapack": "Vorgefertigte Datenpakete mit unserer Packgalerie importieren: Websites, E-Commerce, CRM und mehr!",
|
|
4805
|
+
"tourpoint.tutorials": "Lassen Sie sich von unseren Schritt-für-Schritt-Tutorials leiten!",
|
|
4806
|
+
|
|
4798
4807
|
"add_language": "Hinzufügen...",
|
|
4799
4808
|
"select_or_add_language": "Wählen oder fügen Sie eine Sprache hinzu, um zu beginnen.",
|
|
4800
4809
|
"field.richtext_t": "Übersetzter Rich Text",
|
|
@@ -6122,8 +6131,8 @@ export const websiteTranslations = {
|
|
|
6122
6131
|
// channel
|
|
6123
6132
|
field_channel_name: 'Name',
|
|
6124
6133
|
field_channel_description: 'Beschreibung',
|
|
6125
|
-
field_channel_type: 'Typ'
|
|
6126
|
-
}
|
|
6134
|
+
field_channel_type: 'Typ'
|
|
6135
|
+
}
|
|
6127
6136
|
},
|
|
6128
6137
|
it: {
|
|
6129
6138
|
translation: {
|
|
@@ -6193,6 +6202,7 @@ export const websiteTranslations = {
|
|
|
6193
6202
|
"api.data.serverStorageFull": "Il server ha raggiunto la capacità massima di archiviazione. Riprova più tardi.",
|
|
6194
6203
|
|
|
6195
6204
|
"tourpoint.importDatapack": "Importa pacchetti di dati predefiniti con la nostra galleria di pacchetti: siti web, e-commerce, CRM e altro ancora!",
|
|
6205
|
+
"tourpoint.tutorials": "Lasciati guidare seguendo i nostri tutorial passo dopo passo!",
|
|
6196
6206
|
"add_language": "Aggiungi...",
|
|
6197
6207
|
"select_or_add_language": "Seleziona o aggiungi una lingua per iniziare.",
|
|
6198
6208
|
"field.richtext_t": "Rich text tradotto",
|
|
@@ -7522,8 +7532,8 @@ export const websiteTranslations = {
|
|
|
7522
7532
|
// channel
|
|
7523
7533
|
field_channel_name: 'Nome',
|
|
7524
7534
|
field_channel_description: 'Descrizione',
|
|
7525
|
-
field_channel_type: 'Tipo'
|
|
7526
|
-
}
|
|
7535
|
+
field_channel_type: 'Tipo'
|
|
7536
|
+
}
|
|
7527
7537
|
},
|
|
7528
7538
|
cs: {
|
|
7529
7539
|
translation: {
|
|
@@ -7593,6 +7603,7 @@ export const websiteTranslations = {
|
|
|
7593
7603
|
"api.data.serverStorageFull": "Server dosáhl maximální úložné kapacity. Zkuste to prosím znovu později.",
|
|
7594
7604
|
|
|
7595
7605
|
"tourpoint.importDatapack": "Importujte předpřipravené datové balíčky s naší galerií balíčků: Webové stránky, e-commerce, CRM a další!",
|
|
7606
|
+
"tourpoint.tutorials": "Nechte se vést našimi podrobnými tutoriály!",
|
|
7596
7607
|
"add_language": "Přidat...",
|
|
7597
7608
|
"select_or_add_language": "Vyberte nebo přidejte jazyk pro zahájení.",
|
|
7598
7609
|
"field.richtext_t": "Přeložený formátovaný text",
|
|
@@ -8917,8 +8928,8 @@ export const websiteTranslations = {
|
|
|
8917
8928
|
// channel
|
|
8918
8929
|
field_channel_name: 'Jméno',
|
|
8919
8930
|
field_channel_description: 'Popis',
|
|
8920
|
-
field_channel_type: 'Typ'
|
|
8921
|
-
}
|
|
8931
|
+
field_channel_type: 'Typ'
|
|
8932
|
+
}
|
|
8922
8933
|
},
|
|
8923
8934
|
ru: {
|
|
8924
8935
|
translation: {
|
|
@@ -8988,6 +8999,7 @@ export const websiteTranslations = {
|
|
|
8988
8999
|
"api.data.serverStorageFull": "Сервер достиг максимального объёма хранилища. Повторите попытку позже.",
|
|
8989
9000
|
|
|
8990
9001
|
"tourpoint.importDatapack": "Импортируйте готовые пакеты данных с помощью нашей галереи пакетов: веб-сайты, электронная коммерция, CRM и многое другое!",
|
|
9002
|
+
"tourpoint.tutorials": "Доверьтесь нашим пошаговым инструкциям!",
|
|
8991
9003
|
"add_language": "Добавить...",
|
|
8992
9004
|
"select_or_add_language": "Выберите или добавьте язык для начала работы",
|
|
8993
9005
|
"field.richtext_t": "Переведенный форматированный текст",
|
|
@@ -10322,8 +10334,8 @@ export const websiteTranslations = {
|
|
|
10322
10334
|
// channel
|
|
10323
10335
|
field_channel_name: 'Имя',
|
|
10324
10336
|
field_channel_description: 'Описание',
|
|
10325
|
-
field_channel_type: 'Тип'
|
|
10326
|
-
}
|
|
10337
|
+
field_channel_type: 'Тип'
|
|
10338
|
+
}
|
|
10327
10339
|
},
|
|
10328
10340
|
ar: {
|
|
10329
10341
|
translation: {
|
|
@@ -10395,6 +10407,8 @@ export const websiteTranslations = {
|
|
|
10395
10407
|
"api.data.storageLimitExceeded": "سيتم تجاوز حد التخزين البالغ {{limit}} ميجابايت بهذه الإضافة.",
|
|
10396
10408
|
"api.data.serverStorageFull": "وصل الخادم إلى الحد الأقصى لسعة التخزين. يُرجى المحاولة مرة أخرى لاحقًا.",
|
|
10397
10409
|
"tourpoint.importDatapack": "استورد حزم البيانات المعدة مسبقًا باستخدام معرض الحزم لدينا: مواقع الويب، والتجارة الإلكترونية، وإدارة علاقات العملاء، والمزيد!",
|
|
10410
|
+
"tourpoint.tutorials": "دع نفسك تسترشد باتباع دروسنا التعليمية خطوة بخطوة!",
|
|
10411
|
+
|
|
10398
10412
|
"add_language": "إضافة...",
|
|
10399
10413
|
"select_or_add_language": "اختر أو أضف لغة للبدء.",
|
|
10400
10414
|
"field.richtext_t": "نص منسق مترجم",
|
|
@@ -11743,7 +11757,7 @@ export const websiteTranslations = {
|
|
|
11743
11757
|
// channel
|
|
11744
11758
|
field_channel_name: 'الاسم',
|
|
11745
11759
|
field_channel_description: 'الوصف',
|
|
11746
|
-
field_channel_type: 'النوع'
|
|
11760
|
+
field_channel_type: 'النوع'
|
|
11747
11761
|
}
|
|
11748
11762
|
},
|
|
11749
11763
|
sv: {
|
|
@@ -11814,6 +11828,7 @@ export const websiteTranslations = {
|
|
|
11814
11828
|
"api.data.serverStorageFull": "Servern har nått sin maximala lagringskapacitet. Försök igen senare.",
|
|
11815
11829
|
|
|
11816
11830
|
"tourpoint.importDatapack": "Importera färdiga datapaket med vårt paketgalleri: Webbplatser, e-handel, CRM och mer!",
|
|
11831
|
+
"tourpoint.tutorials": "Låt dig vägledas av våra steg-för-steg-handledningar!",
|
|
11817
11832
|
"add_language": "Lägg till...",
|
|
11818
11833
|
"select_or_add_language": "Välj eller lägg till ett språk för att komma igång.",
|
|
11819
11834
|
"field.richtext_t": "Översatt RTF",
|
|
@@ -13138,7 +13153,7 @@ export const websiteTranslations = {
|
|
|
13138
13153
|
// channel
|
|
13139
13154
|
field_channel_name: 'Namn',
|
|
13140
13155
|
field_channel_description: 'Beskrivning',
|
|
13141
|
-
field_channel_type: 'Typ'
|
|
13156
|
+
field_channel_type: 'Typ'
|
|
13142
13157
|
}
|
|
13143
13158
|
},
|
|
13144
13159
|
el: {
|
|
@@ -13209,6 +13224,7 @@ export const websiteTranslations = {
|
|
|
13209
13224
|
"api.data.serverStorageFull": "Ο διακομιστής έχει φτάσει στη μέγιστη χωρητικότητα αποθήκευσης. Παρακαλώ προσπαθήστε ξανά αργότερα.",
|
|
13210
13225
|
|
|
13211
13226
|
"tourpoint.importDatapack": "Εισαγάγετε προκατασκευασμένα πακέτα δεδομένων με τη συλλογή πακέτων μας: Ιστότοποι, ηλεκτρονικό εμπόριο, CRM και πολλά άλλα!",
|
|
13227
|
+
"tourpoint.tutorials": "Ακολουθώντας τα βήμα προς βήμα εκπαιδευτικά μας βίντεο, αφήστε τον εαυτό σας να σας καθοδηγήσει!",
|
|
13212
13228
|
"add_language": "Προσθήκη...",
|
|
13213
13229
|
"select_or_add_language": "Επιλέξτε ή προσθέστε μια γλώσσα για να ξεκινήσετε.",
|
|
13214
13230
|
"field.richtext_t": "Μεταφρασμένο εμπλουτισμένο κείμενο",
|
|
@@ -14611,6 +14627,7 @@ export const websiteTranslations = {
|
|
|
14611
14627
|
"api.data.serverStorageFull": "سرور به حداکثر ظرفیت ذخیرهسازی خود رسیده است. لطفاً بعداً دوباره امتحان کنید.",
|
|
14612
14628
|
|
|
14613
14629
|
"tourpoint.importDatapack": "بستههای داده از پیش ساخته شده را با گالری بستههای ما وارد کنید: وبسایتها، تجارت الکترونیک، CRM و موارد دیگر!",
|
|
14630
|
+
"tourpoint.tutorials": "با دنبال کردن آموزشهای گام به گام ما، خودتان را راهنمایی کنید!",
|
|
14614
14631
|
"add_language": "اضافه کردن...",
|
|
14615
14632
|
"select_or_add_language": "برای شروع، یک زبان را انتخاب یا اضافه کنید.",
|
|
14616
14633
|
"field.richtext_t": "متن غنی ترجمه شده",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-primals-engine",
|
|
3
|
-
"version": "1.1.7
|
|
3
|
+
"version": "1.1.7",
|
|
4
4
|
"description": "data-primals-engine is the package responsible from handling large amount of data in a practical and performant way. It can handle large amount of data in a practical and performant way. It can also get workflow models working (for automation), and fully supports internationalisation.",
|
|
5
5
|
"main": "src/engine.js",
|
|
6
6
|
"type": "module",
|
package/src/modules/data.js
CHANGED
|
@@ -89,6 +89,8 @@ import {getAllPacks} from "../packs.js";
|
|
|
89
89
|
import {throttleMiddleware} from "../middlewares/throttle.js";
|
|
90
90
|
import {Config} from "../config.js";
|
|
91
91
|
import {profiles} from "../../client/src/constants.js";
|
|
92
|
+
import {processFilterPlaceholders} from "../../client/src/filter.js";
|
|
93
|
+
import {tutorialsConfig} from "../../client/src/tutorials.js";
|
|
92
94
|
|
|
93
95
|
// Obtenir le chemin du répertoire courant de manière fiable avec ES Modules
|
|
94
96
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -1507,6 +1509,128 @@ export async function onInit(defaultEngine) {
|
|
|
1507
1509
|
}
|
|
1508
1510
|
});
|
|
1509
1511
|
|
|
1512
|
+
/**
|
|
1513
|
+
* Route pour vérifier si une condition de complétion est remplie.
|
|
1514
|
+
* Utilise la fonction `searchData` existante pour interroger les données.
|
|
1515
|
+
*/
|
|
1516
|
+
engine.post('/api/tutorials/check-completion', middlewareAuthenticator, async (req, res) => {
|
|
1517
|
+
try {
|
|
1518
|
+
const { model, filter, limit } = req.fields;
|
|
1519
|
+
const user = req.me;
|
|
1520
|
+
|
|
1521
|
+
if (!model || !filter || limit === undefined) {
|
|
1522
|
+
return res.status(400).json({ error: 'Payload de condition de complétion invalide.' });
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
const processedFilter = processFilterPlaceholders(filter, user);
|
|
1526
|
+
|
|
1527
|
+
// On utilise la fonction de recherche interne de l'application
|
|
1528
|
+
const searchResult = await searchData({
|
|
1529
|
+
query: {
|
|
1530
|
+
model,
|
|
1531
|
+
filter: processedFilter,
|
|
1532
|
+
limit, // Optimisation : pas besoin de plus de résultats
|
|
1533
|
+
page: 1
|
|
1534
|
+
},
|
|
1535
|
+
user: user
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
// searchData devrait renvoyer un `count` total des documents correspondants
|
|
1539
|
+
const isCompleted = searchResult.count >= limit;
|
|
1540
|
+
|
|
1541
|
+
res.json({ isCompleted });
|
|
1542
|
+
|
|
1543
|
+
} catch (error) {
|
|
1544
|
+
console.error('[Tutoriel Check Error]', error);
|
|
1545
|
+
res.status(500).json({ error: 'Erreur lors de la vérification de la complétion.', details: error.message });
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
|
|
1551
|
+
engine.post('/api/tutorials/set-active', middlewareAuthenticator, async (req, res) => {
|
|
1552
|
+
try {
|
|
1553
|
+
const { tutorialState } = req.fields;
|
|
1554
|
+
const user = req.me;
|
|
1555
|
+
|
|
1556
|
+
if (tutorialState !== null && (typeof tutorialState !== 'object' || !tutorialState.id)) {
|
|
1557
|
+
return res.status(400).json({ error: 'Invalid tutorial state payload.' });
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// Créer une représentation de l'utilisateur mis à jour pour la réponse
|
|
1561
|
+
const updatedData = { activeTutorial: tutorialState };
|
|
1562
|
+
|
|
1563
|
+
await engine.userProvider.updateUser(user, updatedData);
|
|
1564
|
+
|
|
1565
|
+
// --- MODIFICATION ---
|
|
1566
|
+
res.json({
|
|
1567
|
+
success: true,
|
|
1568
|
+
updatedData // Renvoyer l'objet utilisateur complet
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
} catch (error) {
|
|
1572
|
+
console.error('[Tutoriel Set Active Error]', error);
|
|
1573
|
+
res.status(500).json({ error: 'Error setting active tutorial.', details: error.message });
|
|
1574
|
+
}
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
// ...
|
|
1578
|
+
|
|
1579
|
+
engine.post('/api/tutorials/:tutorialId/claim-rewards', middlewareAuthenticator, async (req, res) => {
|
|
1580
|
+
try {
|
|
1581
|
+
const { tutorialId } = req.params;
|
|
1582
|
+
const user = req.me; // L'objet utilisateur est déjà chargé
|
|
1583
|
+
const tutorial = tutorialsConfig.find(t => t.id === tutorialId);
|
|
1584
|
+
|
|
1585
|
+
if (!tutorial) return res.status(404).json({ error: 'Tutoriel non trouvé.' });
|
|
1586
|
+
if (!tutorial.rewards) return res.status(400).json({ error: 'Ce tutoriel n\'a pas de récompenses.' });
|
|
1587
|
+
if (user.completedTutorials?.includes(tutorialId)) {
|
|
1588
|
+
return res.status(400).json({ error: 'Tutoriel déjà terminé.' });
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
const { xpBonus, skill, achievement, notification } = tutorial.rewards;
|
|
1592
|
+
|
|
1593
|
+
// --- LOGIQUE CORRIGÉE ---
|
|
1594
|
+
let newData= {};
|
|
1595
|
+
newData.xp = newData.xp || 0;
|
|
1596
|
+
newData.achievements = newData.achievements || [];
|
|
1597
|
+
newData.skills = newData.skills || [];
|
|
1598
|
+
newData.completedTutorials = newData.completedTutorials || [];
|
|
1599
|
+
|
|
1600
|
+
// Appliquer les récompenses directement sur l'objet newData
|
|
1601
|
+
if (xpBonus) newData.xp += xpBonus;
|
|
1602
|
+
if (achievement && !newData.achievements.includes(achievement)) newData.achievements.push(achievement);
|
|
1603
|
+
if (skill) {
|
|
1604
|
+
const existingSkill = newData.skills.find(s => s.name === skill.name);
|
|
1605
|
+
if (existingSkill) {
|
|
1606
|
+
existingSkill.points += skill.points;
|
|
1607
|
+
} else {
|
|
1608
|
+
newData.skills.push({ name: skill.name, points: skill.points });
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
newData.completedTutorials.push(tutorialId);
|
|
1613
|
+
newData.activeTutorial = null;
|
|
1614
|
+
|
|
1615
|
+
await engine.userProvider.updateUser(user, newData);
|
|
1616
|
+
|
|
1617
|
+
const translatedNotification = {
|
|
1618
|
+
title: i18n.t(notification.title, notification.title),
|
|
1619
|
+
message: i18n.t(notification.message, notification.message)
|
|
1620
|
+
};
|
|
1621
|
+
|
|
1622
|
+
res.json({
|
|
1623
|
+
success: true,
|
|
1624
|
+
userUpdate: newData, // Renvoyer l'objet utilisateur complet et mis à jour
|
|
1625
|
+
notification: translatedNotification
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
} catch (error) {
|
|
1629
|
+
console.error('[Tutoriel Rewards Error]', error);
|
|
1630
|
+
res.status(500).json({ error: 'Erreur lors de l\'attribution des récompenses.', details: error.message });
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1510
1634
|
engine.get('/api/import/progress/:jobId', [middlewareAuthenticator], async (req, res) => {
|
|
1511
1635
|
const { jobId } = req.params;
|
|
1512
1636
|
const user = req.me;
|