data-primals-engine 1.7.1 → 1.7.3
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 +9 -9
- package/client/package-lock.json +8430 -8121
- package/client/package.json +7 -4
- package/client/src/APIInfo.jsx +1 -1
- package/client/src/App.jsx +2 -1
- package/client/src/App.scss +1635 -1626
- package/client/src/AssistantChat.jsx +2 -3
- package/client/src/CalendarView.jsx +1 -0
- package/client/src/ContentView.jsx +3 -3
- package/client/src/Dashboard.jsx +5 -2
- package/client/src/DashboardChart.jsx +1 -0
- package/client/src/DashboardFlexViewItem.jsx +1 -0
- package/client/src/DashboardHtmlViewItem.jsx +1 -0
- package/client/src/DashboardView.jsx +2 -0
- package/client/src/DataEditor.jsx +0 -1
- package/client/src/DataImporter.jsx +489 -468
- package/client/src/DataLayout.jsx +25 -23
- package/client/src/DataTable.jsx +6 -5
- package/client/src/Dialog.jsx +92 -90
- package/client/src/Dialog.scss +122 -116
- package/client/src/DisplayFlexNodeRenderer.jsx +1 -0
- package/client/src/DocumentationPageLayout.scss +1 -1
- package/client/src/FlexBuilderControls.jsx +1 -0
- package/client/src/FlexBuilderPreview.jsx +1 -1
- package/client/src/FlexNode.jsx +1 -1
- package/client/src/HistoryDialog.jsx +3 -2
- package/client/src/KPIWidget.jsx +1 -1
- package/client/src/KanbanView.jsx +1 -0
- package/client/src/ModelCreator.jsx +4 -0
- package/client/src/ModelList.jsx +1 -0
- package/client/src/PackGallery.jsx +5 -4
- package/client/src/RTETrans.jsx +1 -1
- package/client/src/RelationField.jsx +2 -0
- package/client/src/RelationSelectorWidget.jsx +2 -0
- package/client/src/RelationValue.jsx +1 -0
- package/client/src/RestoreDialog.jsx +1 -0
- package/client/src/ViewSwitcher.jsx +1 -1
- package/client/src/WorkflowEditor.jsx +3 -0
- package/client/src/contexts/CommandContext.jsx +2 -1
- package/client/src/contexts/ModelContext.jsx +3 -3
- package/client/src/hooks/data.js +1 -0
- package/client/src/hooks/useValidation.js +1 -0
- package/client/src/translations.js +24 -24
- package/client/vite.config.js +31 -30
- package/doc/AI-assistance.md +87 -63
- package/doc/Concepts.md +122 -0
- package/doc/Custom-Endpoints.md +31 -0
- package/doc/Event-system.md +13 -14
- package/doc/Home.md +33 -0
- package/doc/Modules.md +83 -0
- package/doc/Packs-gallery.md +8 -23
- package/doc/Workflows.md +32 -0
- package/doc/automation-workflows.md +141 -102
- package/doc/dashboards-kpis-charts.md +47 -49
- package/doc/data-management.md +126 -120
- package/doc/data-models.md +68 -75
- package/doc/roles-permissions.md +144 -43
- package/doc/sharding-replication.md +158 -0
- package/doc/users.md +54 -30
- package/package.json +27 -17
- package/server.js +37 -37
- package/src/ai.jobs.js +135 -0
- package/src/constants.js +560 -545
- package/src/data.js +521 -518
- package/src/email.js +157 -154
- package/src/engine.js +167 -49
- package/src/gameObject.js +6 -0
- package/src/i18n.js +0 -1
- package/src/modules/assistant/assistant.js +782 -763
- package/src/modules/assistant/constants.js +23 -16
- package/src/modules/assistant/providers.js +77 -37
- package/src/modules/auth-google/index.js +53 -50
- package/src/modules/bucket.js +346 -335
- package/src/modules/data/data.backup.js +400 -376
- package/src/modules/data/data.cluster.js +559 -0
- package/src/modules/data/data.core.js +11 -8
- package/src/modules/data/data.js +311 -311
- package/src/modules/data/data.operations.js +3666 -3555
- package/src/modules/data/data.relations.js +1 -0
- package/src/modules/data/data.replication.js +125 -0
- package/src/modules/data/data.routes.js +2206 -1879
- package/src/modules/data/data.scheduling.js +2 -1
- package/src/modules/file.js +248 -247
- package/src/modules/mongodb.js +76 -73
- package/src/modules/user.js +18 -2
- package/src/modules/worker-script-runner.js +97 -0
- package/src/modules/workflow.js +177 -52
- package/src/packs.js +5701 -5701
- package/src/providers.js +298 -297
- package/src/sso.js +91 -25
- package/test/assistant.test.js +207 -206
- package/test/cluster.test.js +221 -0
- package/test/core.test.js +0 -2
- package/test/data.integration.test.js +1425 -1416
- package/test/import_export.integration.test.js +210 -210
- package/test/replication.test.js +163 -0
- package/test/workflow.actions.integration.test.js +487 -475
- package/test/workflow.integration.test.js +332 -329
- package/doc/core-concepts.md +0 -33
|
@@ -60,12 +60,12 @@ const NotConfiguredPlaceholder = ({ type, onConfigure }) => (
|
|
|
60
60
|
|
|
61
61
|
const WorkflowSelectorModal = ({ onClose, onSelectWorkflow }) => {
|
|
62
62
|
const { t } = useTranslation();
|
|
63
|
-
const { searchData } = useModelContext();
|
|
64
63
|
const { me } = useAuthContext();
|
|
65
64
|
const { data: activeWorkflows, isLoading } = useQuery(
|
|
66
65
|
'activeWorkflowsList',
|
|
67
66
|
() => fetch('/api/data/search?_user='+me.username, {
|
|
68
67
|
method: 'POST',
|
|
68
|
+
credentials: "include",
|
|
69
69
|
headers: { 'Content-Type': 'application/json' },
|
|
70
70
|
body: JSON.stringify({
|
|
71
71
|
model: 'workflow',
|
|
@@ -96,7 +96,7 @@ const WorkflowSelectorModal = ({ onClose, onSelectWorkflow }) => {
|
|
|
96
96
|
);
|
|
97
97
|
};
|
|
98
98
|
|
|
99
|
-
function DataLayout({refreshUI}) {
|
|
99
|
+
function DataLayout({refreshUI}, ref) {
|
|
100
100
|
const [ searchParams, setSearchParams ] = useSearchParams();
|
|
101
101
|
const [viewSettings, setViewSettings] = useLocalStorage('viewSettings', {});
|
|
102
102
|
|
|
@@ -147,6 +147,7 @@ function DataLayout({refreshUI}) {
|
|
|
147
147
|
|
|
148
148
|
const mainPartRef = useRef();
|
|
149
149
|
const modelCreatorRef = useRef();
|
|
150
|
+
const dataEditorRef = useRef(null);
|
|
150
151
|
|
|
151
152
|
const [tutorialDialogVisible, setTutorialDialogVisible] = useState(false);
|
|
152
153
|
const [importModalVisible, setImportModalVisible] = useState(false);
|
|
@@ -155,7 +156,6 @@ function DataLayout({refreshUI}) {
|
|
|
155
156
|
const [showAPIInfo, setAPIInfoVisible] = useState(false);
|
|
156
157
|
const nav = useNavigate();
|
|
157
158
|
const mod = searchParams.get('model');
|
|
158
|
-
const loc = useLocation();
|
|
159
159
|
|
|
160
160
|
|
|
161
161
|
// --- AJOUT : Récupérer le paramètre de l'URL pour l'édition de workflow ---
|
|
@@ -300,18 +300,24 @@ function DataLayout({refreshUI}) {
|
|
|
300
300
|
setFilterValues={setFilterValues}
|
|
301
301
|
model={selectedModel}
|
|
302
302
|
onAddData={(model) => {
|
|
303
|
-
mainPartRef.current.scrollIntoView({behavior: "smooth"});
|
|
304
303
|
handleAddData(model);
|
|
304
|
+
setTimeout(() => {
|
|
305
|
+
dataEditorRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
306
|
+
}, 100);
|
|
305
307
|
}}
|
|
306
308
|
onDuplicateData={(data) => {
|
|
307
|
-
mainPartRef.current.scrollIntoView({behavior: "smooth"});
|
|
308
309
|
handleAddData(selectedModel, data);
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
dataEditorRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
312
|
+
}, 100);
|
|
309
313
|
}}
|
|
310
314
|
onEdit={(item) => {
|
|
311
|
-
mainPartRef.current.scrollIntoView({behavior: "smooth"});
|
|
312
315
|
setRecordToEdit(item);
|
|
313
316
|
setFormData(item);
|
|
314
317
|
setDataEditorVisible(true);
|
|
318
|
+
setTimeout(() => {
|
|
319
|
+
dataEditorRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
320
|
+
}, 100);
|
|
315
321
|
}}
|
|
316
322
|
deleteApiCall={deleteApiCall}
|
|
317
323
|
queryClient={queryClient}
|
|
@@ -428,7 +434,8 @@ function DataLayout({refreshUI}) {
|
|
|
428
434
|
///fd.append("files", fd2);
|
|
429
435
|
return fetch(`${url}?lang=${lang}&_user=${encodeURIComponent(getUserId(me))}`, {
|
|
430
436
|
method,
|
|
431
|
-
body: fd
|
|
437
|
+
body: fd,
|
|
438
|
+
credentials: "include",
|
|
432
439
|
}).then(e => e.json());
|
|
433
440
|
} catch (error) {
|
|
434
441
|
console.error('Erreur lors de l\'enregistrement des données:', error);
|
|
@@ -508,7 +515,8 @@ function DataLayout({refreshUI}) {
|
|
|
508
515
|
return fetch(`/api/data/${ids}?lang=${lang}&_user=${encodeURIComponent(getUserId(me))}`, {
|
|
509
516
|
method: 'DELETE', headers: {
|
|
510
517
|
'Content-Type': 'application/json'
|
|
511
|
-
}
|
|
518
|
+
},
|
|
519
|
+
credentials: "include"
|
|
512
520
|
}).then(e => e.json());
|
|
513
521
|
}, [lang, me]);
|
|
514
522
|
|
|
@@ -531,7 +539,7 @@ function DataLayout({refreshUI}) {
|
|
|
531
539
|
return fetch('/api/models/import', { method: 'POST', headers: {
|
|
532
540
|
'Content-Type': 'application/json'
|
|
533
541
|
},
|
|
534
|
-
|
|
542
|
+
credentials: "include",body: JSON.stringify({ models: selectedModels.map(m => m.name) })
|
|
535
543
|
})
|
|
536
544
|
});
|
|
537
545
|
|
|
@@ -586,13 +594,6 @@ function DataLayout({refreshUI}) {
|
|
|
586
594
|
setImportModalVisible(false);
|
|
587
595
|
}
|
|
588
596
|
|
|
589
|
-
useEffect(() => {
|
|
590
|
-
if( showDataEditor && mainPartRef.current ){
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
}, [showDataEditor,mainPartRef.current]);
|
|
594
|
-
|
|
595
|
-
|
|
596
597
|
const [currentProfile, setCurrentProfile] = useLocalStorage('profile', null);
|
|
597
598
|
const {isTourOpen, setIsTourOpen, currentTourSteps, allTourSteps, setTourStepIndex, setCurrentTourSteps, currentTour,setCurrentTour, addLaunchedTour, assistantConfig, setAssistantConfig} = useUI();
|
|
598
599
|
|
|
@@ -707,7 +708,7 @@ function DataLayout({refreshUI}) {
|
|
|
707
708
|
onSelectWorkflow={(id) => {
|
|
708
709
|
nav(`?edit-workflow=${id}`);
|
|
709
710
|
setEditionMode(false)
|
|
710
|
-
mainPartRef.current
|
|
711
|
+
mainPartRef.current?.scrollIntoView();
|
|
711
712
|
setCurrentView('workflow'); // Ajout pour forcer le changement de vue
|
|
712
713
|
setWorkflowListModalOpen(false);
|
|
713
714
|
}}
|
|
@@ -740,7 +741,7 @@ function DataLayout({refreshUI}) {
|
|
|
740
741
|
setAPIInfoVisible(false);
|
|
741
742
|
setDataEditorVisible(false);
|
|
742
743
|
setEditionMode(true);
|
|
743
|
-
mainPartRef.current
|
|
744
|
+
mainPartRef.current?.scrollIntoView({behavior: 'smooth'});
|
|
744
745
|
gtag("event", "select_content", {
|
|
745
746
|
content_type: "create_model",
|
|
746
747
|
});
|
|
@@ -750,7 +751,7 @@ function DataLayout({refreshUI}) {
|
|
|
750
751
|
setAPIInfoVisible(false);
|
|
751
752
|
setEditionMode(true);
|
|
752
753
|
|
|
753
|
-
mainPartRef.current
|
|
754
|
+
mainPartRef.current?.scrollIntoView({behavior: 'smooth'});
|
|
754
755
|
gtag("event", "select_content", {
|
|
755
756
|
content_type: "edit_model",
|
|
756
757
|
content_id: model.name
|
|
@@ -760,7 +761,7 @@ function DataLayout({refreshUI}) {
|
|
|
760
761
|
setDataEditorVisible(false);
|
|
761
762
|
setEditionMode(false);
|
|
762
763
|
setAPIInfoVisible(false);
|
|
763
|
-
mainPartRef.current
|
|
764
|
+
//mainPartRef.current?.scrollIntoView({behavior: 'smooth'});
|
|
764
765
|
gtag("event", "select_content", {
|
|
765
766
|
content_type: "select_model",
|
|
766
767
|
content_id: model.name
|
|
@@ -768,12 +769,12 @@ function DataLayout({refreshUI}) {
|
|
|
768
769
|
}} onImportPack={() => {
|
|
769
770
|
setShowPackGallery(true);
|
|
770
771
|
}} onNewData={(model) => {
|
|
771
|
-
mainPartRef.current
|
|
772
|
+
mainPartRef.current?.scrollIntoView({behavior: 'smooth'});
|
|
772
773
|
handleAddData(model);
|
|
773
774
|
}}/>
|
|
774
775
|
{(editionMode) && (
|
|
775
776
|
<ModelCreator ref={modelCreatorRef} onModelGenerated={() =>{
|
|
776
|
-
modelCreatorRef
|
|
777
|
+
modelCreatorRef?.current?.scrollIntoView({behavior: 'smooth'});
|
|
777
778
|
}} initialModel={selectedModel} onModelSaved={(model) => {
|
|
778
779
|
setRefreshTime(new Date().getTime());
|
|
779
780
|
handleModelSelect(model);
|
|
@@ -785,7 +786,8 @@ function DataLayout({refreshUI}) {
|
|
|
785
786
|
)}
|
|
786
787
|
<div className="hidden-anchor" ref={mainPartRef}></div>
|
|
787
788
|
|
|
788
|
-
{showDataEditor && (<DataEditor
|
|
789
|
+
{showDataEditor && (<DataEditor
|
|
790
|
+
ref={dataEditorRef}
|
|
789
791
|
key={selectedModel?.name}
|
|
790
792
|
isLoading={isLoading}
|
|
791
793
|
model={selectedModel}
|
package/client/src/DataTable.jsx
CHANGED
|
@@ -6,7 +6,6 @@ import {useAuthContext} from "./contexts/AuthContext.jsx";
|
|
|
6
6
|
import React, {useEffect, useMemo, useRef, useState} from "react";
|
|
7
7
|
import {getUserHash, getUserId} from "../../src/data.js";
|
|
8
8
|
import cronstrue from 'cronstrue/i18n';
|
|
9
|
-
import {Event} from "../../src/events.js";
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
FaBook,
|
|
@@ -337,6 +336,7 @@ export function DataTable({
|
|
|
337
336
|
return fetch(`/api/data/export?lang=${lang}&${params.toString()}`, {
|
|
338
337
|
method: 'POST',
|
|
339
338
|
body,
|
|
339
|
+
credentials: "include",
|
|
340
340
|
headers: {"Content-Type": "application/json"}
|
|
341
341
|
})
|
|
342
342
|
.then(async resp => {
|
|
@@ -391,8 +391,9 @@ export function DataTable({
|
|
|
391
391
|
const handleConfirmRestore = async () => {
|
|
392
392
|
try {
|
|
393
393
|
// Make the API call to request the restore link
|
|
394
|
-
const response = await fetch('/api/backup/request-restore', {
|
|
394
|
+
const response = await fetch('/api/backup/request-restore?lang='+lang, {
|
|
395
395
|
method: 'POST',
|
|
396
|
+
credentials: "include",
|
|
396
397
|
// ... other options ...
|
|
397
398
|
});
|
|
398
399
|
|
|
@@ -451,7 +452,7 @@ export function DataTable({
|
|
|
451
452
|
<Button onClick={handleImport} title={t("btns.import")}><FaFileImport/><Trans
|
|
452
453
|
i18nKey="btns.import">Importer</Trans></Button>
|
|
453
454
|
<Button disabled={isLoading} onClick={handleExport} title={t("btns.export")}><FaFileExport/><Trans i18nKey="btns.export">Exporter</Trans></Button>
|
|
454
|
-
{
|
|
455
|
+
{(<Button onClick={handleBackup} title={t("btns.backup")}><FaDatabase/><Trans
|
|
455
456
|
i18nKey="btns.backup">Backup</Trans></Button>)}
|
|
456
457
|
|
|
457
458
|
</div>}
|
|
@@ -738,10 +739,10 @@ export function DataTable({
|
|
|
738
739
|
</button>)}
|
|
739
740
|
{/* AJOUT : Bouton pour ouvrir l'éditeur de workflow */}
|
|
740
741
|
{model.name === 'workflow' && (
|
|
741
|
-
<
|
|
742
|
+
<button onClick={() => nav(`?edit-workflow=${item._id}`)} className="btn-nav datatable-action-btn workflow-edit"
|
|
742
743
|
data-tooltip-id="tooltipActions" data-tooltip-content={t('workflow.editor.title', "Éditeur de Workflow")}>
|
|
743
744
|
<FaGear />
|
|
744
|
-
</
|
|
745
|
+
</button>
|
|
745
746
|
)}
|
|
746
747
|
|
|
747
748
|
<button data-tooltip-id="tooltipActions"
|
package/client/src/Dialog.jsx
CHANGED
|
@@ -1,90 +1,92 @@
|
|
|
1
|
-
import Button from "./Button.jsx";
|
|
2
|
-
import { FaWindowClose } from "react-icons/fa";
|
|
3
|
-
|
|
4
|
-
import "./Dialog.scss";
|
|
5
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
6
|
-
import {useUI} from "./contexts/UIContext.jsx";
|
|
7
|
-
|
|
8
|
-
const DialogContext = createContext({});
|
|
9
|
-
|
|
10
|
-
export const useDialogContext = () => useContext(DialogContext);
|
|
11
|
-
|
|
12
|
-
export const DialogProvider = ({ children }) => {
|
|
13
|
-
const [dialogs, setDialogs] = useState(0);
|
|
14
|
-
const { locked, setLocked } = useUI()
|
|
15
|
-
const values = {
|
|
16
|
-
addDialog: () => setDialogs((dialogs) => dialogs + 1),
|
|
17
|
-
removeDialog: () =>
|
|
18
|
-
setDialogs((dialogs) => {
|
|
19
|
-
return dialogs > 0 ? dialogs - 1 : 0;
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if( dialogs === 0){
|
|
24
|
-
setLocked(false);
|
|
25
|
-
}else{
|
|
26
|
-
setLocked(true);
|
|
27
|
-
}
|
|
28
|
-
}, [dialogs]);
|
|
29
|
-
return (
|
|
30
|
-
<DialogContext.Provider value={values}>
|
|
31
|
-
{dialogs > 0 ? (
|
|
32
|
-
<>
|
|
33
|
-
<div className="dialog-bg"></div>
|
|
34
|
-
{children}
|
|
35
|
-
</>
|
|
36
|
-
) : (
|
|
37
|
-
children
|
|
38
|
-
)}
|
|
39
|
-
</DialogContext.Provider>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
export const Dialog = ({
|
|
43
|
-
title,
|
|
44
|
-
children,
|
|
45
|
-
className,
|
|
46
|
-
onClose,
|
|
47
|
-
isClosable,
|
|
48
|
-
isModal,
|
|
49
|
-
}) => {
|
|
50
|
-
const [showModal, setModalVisible] = useState(true);
|
|
51
|
-
const { addDialog, removeDialog } = useDialogContext();
|
|
52
|
-
const handleClose = () => {
|
|
53
|
-
setModalVisible(false);
|
|
54
|
-
onClose?.();
|
|
55
|
-
removeDialog();
|
|
56
|
-
};
|
|
57
|
-
const clickEvent = (e) => {
|
|
58
|
-
|
|
59
|
-
if( !e.target.closest('.dialog') && !e.target.closest('.notification') ){
|
|
60
|
-
onClose?.();
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
addDialog();
|
|
65
|
-
document.addEventListener('mousedown', clickEvent);
|
|
66
|
-
return () => {
|
|
67
|
-
removeDialog();
|
|
68
|
-
document.removeEventListener('mousedown', clickEvent);
|
|
69
|
-
}
|
|
70
|
-
}, [addDialog, removeDialog]);
|
|
71
|
-
return showModal ? (
|
|
72
|
-
<div
|
|
73
|
-
|
|
74
|
-
aria-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
)
|
|
90
|
-
|
|
1
|
+
import Button from "./Button.jsx";
|
|
2
|
+
import { FaWindowClose } from "react-icons/fa";
|
|
3
|
+
|
|
4
|
+
import "./Dialog.scss";
|
|
5
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
6
|
+
import {useUI} from "./contexts/UIContext.jsx";
|
|
7
|
+
|
|
8
|
+
const DialogContext = createContext({});
|
|
9
|
+
|
|
10
|
+
export const useDialogContext = () => useContext(DialogContext);
|
|
11
|
+
|
|
12
|
+
export const DialogProvider = ({ children }) => {
|
|
13
|
+
const [dialogs, setDialogs] = useState(0);
|
|
14
|
+
const { locked, setLocked } = useUI()
|
|
15
|
+
const values = {
|
|
16
|
+
addDialog: () => setDialogs((dialogs) => dialogs + 1),
|
|
17
|
+
removeDialog: () =>
|
|
18
|
+
setDialogs((dialogs) => {
|
|
19
|
+
return dialogs > 0 ? dialogs - 1 : 0;
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if( dialogs === 0){
|
|
24
|
+
setLocked(false);
|
|
25
|
+
}else{
|
|
26
|
+
setLocked(true);
|
|
27
|
+
}
|
|
28
|
+
}, [dialogs]);
|
|
29
|
+
return (
|
|
30
|
+
<DialogContext.Provider value={values}>
|
|
31
|
+
{dialogs > 0 ? (
|
|
32
|
+
<>
|
|
33
|
+
<div className="dialog-bg"></div>
|
|
34
|
+
{children}
|
|
35
|
+
</>
|
|
36
|
+
) : (
|
|
37
|
+
children
|
|
38
|
+
)}
|
|
39
|
+
</DialogContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
export const Dialog = ({
|
|
43
|
+
title,
|
|
44
|
+
children,
|
|
45
|
+
className,
|
|
46
|
+
onClose,
|
|
47
|
+
isClosable,
|
|
48
|
+
isModal,
|
|
49
|
+
}) => {
|
|
50
|
+
const [showModal, setModalVisible] = useState(true);
|
|
51
|
+
const { addDialog, removeDialog } = useDialogContext();
|
|
52
|
+
const handleClose = () => {
|
|
53
|
+
setModalVisible(false);
|
|
54
|
+
onClose?.();
|
|
55
|
+
removeDialog();
|
|
56
|
+
};
|
|
57
|
+
const clickEvent = (e) => {
|
|
58
|
+
|
|
59
|
+
if( !e.target.closest('.dialog') && !e.target.closest('.notification') ){
|
|
60
|
+
onClose?.();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
addDialog();
|
|
65
|
+
document.addEventListener('mousedown', clickEvent);
|
|
66
|
+
return () => {
|
|
67
|
+
removeDialog();
|
|
68
|
+
document.removeEventListener('mousedown', clickEvent);
|
|
69
|
+
}
|
|
70
|
+
}, [addDialog, removeDialog]);
|
|
71
|
+
return showModal ? (
|
|
72
|
+
<div className="dialog-container">
|
|
73
|
+
<div
|
|
74
|
+
aria-modal={true}
|
|
75
|
+
aria-label={title}
|
|
76
|
+
className={`${className ? className : ""} dialog ${isModal ? "dialog-modal" : ""}`}
|
|
77
|
+
>
|
|
78
|
+
<div className="dialog-header">
|
|
79
|
+
{title && <h2>{title}</h2>}
|
|
80
|
+
{isClosable && (
|
|
81
|
+
<Button className={"btn btn-close"} onClick={handleClose}>
|
|
82
|
+
<FaWindowClose />
|
|
83
|
+
</Button>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
<div className="dialog-content">{children}</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<></>
|
|
91
|
+
);
|
|
92
|
+
};
|
package/client/src/Dialog.scss
CHANGED
|
@@ -1,116 +1,122 @@
|
|
|
1
|
-
|
|
2
|
-
.dialog-bg {
|
|
3
|
-
position: fixed;
|
|
4
|
-
top: 0;
|
|
5
|
-
left: 0;
|
|
6
|
-
width: 100%;
|
|
7
|
-
height: 100%;
|
|
8
|
-
z-index: 10000;
|
|
9
|
-
pointer-events: none;
|
|
10
|
-
background-color: rgba(59, 59, 59, 0.51);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
z-index: 10000;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
1
|
+
|
|
2
|
+
.dialog-bg {
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
z-index: 10000;
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
background-color: rgba(59, 59, 59, 0.51);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.dialog-container {
|
|
14
|
+
position: fixed;
|
|
15
|
+
top: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
z-index: 10000;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
pointer-events: none; /* Permet de cliquer "à travers" le conteneur */
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#content .dialog {
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
pointer-events: all;
|
|
29
|
+
background-color: #F8F8F8;
|
|
30
|
+
border: 1px solid #DDDDDD;
|
|
31
|
+
border-radius: 8px;
|
|
32
|
+
color: black;
|
|
33
|
+
width: 90%;
|
|
34
|
+
max-width: 1024px;
|
|
35
|
+
min-width: 320px;
|
|
36
|
+
box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.25);
|
|
37
|
+
text-align: left;
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.dialog .actions {
|
|
42
|
+
justify-content: flex-end;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.dark .dialog {
|
|
46
|
+
background-color: #191919;
|
|
47
|
+
color: #e3e3e3;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#content .dialog-header {
|
|
51
|
+
display: flex;
|
|
52
|
+
gap: 8px;
|
|
53
|
+
justify-content: flex-start;
|
|
54
|
+
border: none;
|
|
55
|
+
border-bottom: 1px solid #E2E2E2;
|
|
56
|
+
h2 {
|
|
57
|
+
display: flex;
|
|
58
|
+
flex: 1;
|
|
59
|
+
padding: 0;
|
|
60
|
+
align-items: center;
|
|
61
|
+
margin: 8px;
|
|
62
|
+
font-size: 100%;
|
|
63
|
+
line-height: 208%;
|
|
64
|
+
}
|
|
65
|
+
.btn {
|
|
66
|
+
display: flex;
|
|
67
|
+
justify-self: flex-end;
|
|
68
|
+
&.btn-close {
|
|
69
|
+
position: absolute;
|
|
70
|
+
right: 0px;
|
|
71
|
+
z-index: 100;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#ui .dialog-content {
|
|
77
|
+
padding: 16px;
|
|
78
|
+
cursor: auto;
|
|
79
|
+
word-wrap: break-word;
|
|
80
|
+
max-height: 85vh;
|
|
81
|
+
overflow-y: auto;
|
|
82
|
+
.field {
|
|
83
|
+
margin: 0;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
table {
|
|
87
|
+
width: 100%;
|
|
88
|
+
border: 1px solid #DDDDDD;
|
|
89
|
+
border-collapse: collapse;
|
|
90
|
+
td,th {
|
|
91
|
+
padding: 3px;
|
|
92
|
+
@media only screen and (min-width: 480px) {
|
|
93
|
+
padding: 5px;
|
|
94
|
+
}
|
|
95
|
+
&.mini {
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
min-width: auto;
|
|
98
|
+
width: 40px;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
thead tr {
|
|
102
|
+
background-color: #F1F1F1;
|
|
103
|
+
font-weight: lighter;
|
|
104
|
+
}
|
|
105
|
+
tbody tr {
|
|
106
|
+
}
|
|
107
|
+
@media only screen and (max-width: 480px){
|
|
108
|
+
font-size: 80%;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
.dark table {
|
|
112
|
+
thead tr {
|
|
113
|
+
background-color: #191919;
|
|
114
|
+
color: #e3e3e3;
|
|
115
|
+
}
|
|
116
|
+
tbody tr {
|
|
117
|
+
background-color: #191919;
|
|
118
|
+
}
|
|
119
|
+
td,th {
|
|
120
|
+
border: 1px solid #3f3f3f;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -79,6 +79,7 @@ const CtaNode = ({ node, nodeStyle, dataItem }) => {
|
|
|
79
79
|
|
|
80
80
|
if (method !== 'GET' && method !== 'HEAD' && node.requestBodyTemplate) {
|
|
81
81
|
fetchOptions.body = substituteClientVariables(node.requestBodyTemplate, dataItem);
|
|
82
|
+
fetchOptions.credentials= "include";
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
// 3. Exécuter la requête
|