data-primals-engine 1.7.2 → 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.
Files changed (78) hide show
  1. package/README.md +160 -160
  2. package/client/package-lock.json +8430 -8430
  3. package/client/src/APIInfo.jsx +1 -1
  4. package/client/src/App.jsx +2 -1
  5. package/client/src/App.scss +1635 -1626
  6. package/client/src/AssistantChat.jsx +1 -0
  7. package/client/src/CalendarView.jsx +1 -0
  8. package/client/src/ContentView.jsx +3 -3
  9. package/client/src/Dashboard.jsx +5 -2
  10. package/client/src/DashboardChart.jsx +1 -0
  11. package/client/src/DashboardFlexViewItem.jsx +1 -0
  12. package/client/src/DashboardHtmlViewItem.jsx +1 -0
  13. package/client/src/DashboardView.jsx +2 -0
  14. package/client/src/DataEditor.jsx +0 -1
  15. package/client/src/DataImporter.jsx +489 -468
  16. package/client/src/DataLayout.jsx +6 -3
  17. package/client/src/DataTable.jsx +4 -3
  18. package/client/src/Dialog.jsx +92 -90
  19. package/client/src/Dialog.scss +122 -116
  20. package/client/src/DisplayFlexNodeRenderer.jsx +1 -0
  21. package/client/src/FlexBuilderControls.jsx +1 -0
  22. package/client/src/FlexBuilderPreview.jsx +1 -1
  23. package/client/src/FlexNode.jsx +1 -1
  24. package/client/src/HistoryDialog.jsx +3 -2
  25. package/client/src/KPIWidget.jsx +1 -1
  26. package/client/src/KanbanView.jsx +1 -0
  27. package/client/src/ModelCreator.jsx +4 -0
  28. package/client/src/ModelList.jsx +1 -0
  29. package/client/src/PackGallery.jsx +5 -4
  30. package/client/src/RTETrans.jsx +1 -1
  31. package/client/src/RelationField.jsx +2 -0
  32. package/client/src/RelationSelectorWidget.jsx +2 -0
  33. package/client/src/RelationValue.jsx +1 -0
  34. package/client/src/RestoreDialog.jsx +1 -0
  35. package/client/src/WorkflowEditor.jsx +3 -0
  36. package/client/src/contexts/CommandContext.jsx +2 -1
  37. package/client/src/contexts/ModelContext.jsx +3 -3
  38. package/client/src/hooks/data.js +1 -0
  39. package/client/src/hooks/useValidation.js +1 -0
  40. package/client/src/translations.js +24 -24
  41. package/doc/AI-assistance.md +87 -63
  42. package/doc/Concepts.md +122 -0
  43. package/doc/Custom-Endpoints.md +31 -0
  44. package/doc/Event-system.md +13 -14
  45. package/doc/Home.md +33 -0
  46. package/doc/Modules.md +83 -0
  47. package/doc/Packs-gallery.md +8 -23
  48. package/doc/Workflows.md +32 -0
  49. package/doc/automation-workflows.md +141 -102
  50. package/doc/dashboards-kpis-charts.md +47 -49
  51. package/doc/data-management.md +126 -120
  52. package/doc/data-models.md +68 -75
  53. package/doc/roles-permissions.md +144 -43
  54. package/doc/sharding-replication.md +158 -0
  55. package/doc/users.md +54 -30
  56. package/package.json +1 -1
  57. package/server.js +37 -37
  58. package/src/constants.js +7 -8
  59. package/src/data.js +521 -520
  60. package/src/email.js +157 -154
  61. package/src/engine.js +117 -7
  62. package/src/gameObject.js +6 -0
  63. package/src/i18n.js +0 -1
  64. package/src/modules/auth-google/index.js +53 -50
  65. package/src/modules/bucket.js +346 -339
  66. package/src/modules/data/data.backup.js +400 -376
  67. package/src/modules/data/data.cluster.js +410 -42
  68. package/src/modules/data/data.operations.js +3666 -3635
  69. package/src/modules/data/data.replication.js +106 -64
  70. package/src/modules/data/data.routes.js +87 -64
  71. package/src/modules/data/data.scheduling.js +2 -1
  72. package/src/modules/file.js +248 -247
  73. package/src/modules/user.js +11 -1
  74. package/src/sso.js +91 -25
  75. package/test/cluster.test.js +221 -0
  76. package/test/core.test.js +0 -2
  77. package/test/replication.test.js +163 -0
  78. package/doc/core-concepts.md +0 -33
@@ -65,6 +65,7 @@ const WorkflowSelectorModal = ({ onClose, onSelectWorkflow }) => {
65
65
  'activeWorkflowsList',
66
66
  () => fetch('/api/data/search?_user='+me.username, {
67
67
  method: 'POST',
68
+ credentials: "include",
68
69
  headers: { 'Content-Type': 'application/json' },
69
70
  body: JSON.stringify({
70
71
  model: 'workflow',
@@ -433,7 +434,8 @@ function DataLayout({refreshUI}, ref) {
433
434
  ///fd.append("files", fd2);
434
435
  return fetch(`${url}?lang=${lang}&_user=${encodeURIComponent(getUserId(me))}`, {
435
436
  method,
436
- body: fd
437
+ body: fd,
438
+ credentials: "include",
437
439
  }).then(e => e.json());
438
440
  } catch (error) {
439
441
  console.error('Erreur lors de l\'enregistrement des données:', error);
@@ -513,7 +515,8 @@ function DataLayout({refreshUI}, ref) {
513
515
  return fetch(`/api/data/${ids}?lang=${lang}&_user=${encodeURIComponent(getUserId(me))}`, {
514
516
  method: 'DELETE', headers: {
515
517
  'Content-Type': 'application/json'
516
- }
518
+ },
519
+ credentials: "include"
517
520
  }).then(e => e.json());
518
521
  }, [lang, me]);
519
522
 
@@ -536,7 +539,7 @@ function DataLayout({refreshUI}, ref) {
536
539
  return fetch('/api/models/import', { method: 'POST', headers: {
537
540
  'Content-Type': 'application/json'
538
541
  },
539
- body: JSON.stringify({ models: selectedModels.map(m => m.name) })
542
+ credentials: "include",body: JSON.stringify({ models: selectedModels.map(m => m.name) })
540
543
  })
541
544
  });
542
545
 
@@ -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
- {!/^demo[0-9]{1,2}$/.test(me.username) && (<Button onClick={handleBackup} title={t("btns.backup")}><FaDatabase/><Trans
455
+ {(<Button onClick={handleBackup} title={t("btns.backup")}><FaDatabase/><Trans
455
456
  i18nKey="btns.backup">Backup</Trans></Button>)}
456
457
 
457
458
  </div>}
@@ -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
- aria-modal={true}
74
- aria-label={title}
75
- className={`${className ? className : ""} dialog ${isModal ? "dialog-modal" : ""}`}
76
- >
77
- <div className="dialog-header">
78
- {title && <h2>{title}</h2>}
79
- {isClosable && (
80
- <Button className={"btn btn-close"} onClick={handleClose}>
81
- <FaWindowClose />
82
- </Button>
83
- )}
84
- </div>
85
- <div className="dialog-content">{children}</div>
86
- </div>
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
+ };
@@ -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
- #content .dialog {
14
- box-sizing: border-box;
15
- filter: opacity(1);
16
- pointer-events: all;
17
- position: fixed;
18
- overflow: visible;
19
- z-index: 10000;
20
- top: 50%;
21
- left: 50%;
22
- transform: translate(-50%, -50%);
23
- background-color: #F8F8F8;
24
- border: 1px solid #DDDDDD;
25
- border-radius: 8px;
26
- color: black;
27
- width: 90%;
28
- max-width: 1024px;
29
- min-width: 320px;
30
- box-shadow: 0px 2px 6px rgba(0, 0, 0, 0.25);
31
- text-align: left;
32
-
33
- }
34
-
35
- .dialog .actions {
36
- justify-content: flex-end;
37
- }
38
-
39
- .dark .dialog {
40
- background-color: #191919;
41
- color: #e3e3e3;
42
- }
43
-
44
- #content .dialog-header {
45
- display: flex;
46
- gap: 8px;
47
- justify-content: flex-start;
48
- border: none;
49
- border-bottom: 1px solid #E2E2E2;
50
- h2 {
51
- display: flex;
52
- flex: 1;
53
- padding: 0;
54
- align-items: center;
55
- margin: 8px;
56
- font-size: 100%;
57
- line-height: 208%;
58
- }
59
- .btn {
60
- display: flex;
61
- justify-self: flex-end;
62
- &.btn-close {
63
- position: absolute;
64
- right: 0px;
65
- z-index: 100;
66
- }
67
- }
68
- }
69
-
70
- #ui .dialog-content {
71
- padding: 16px;
72
- cursor: auto;
73
- word-wrap: break-word;
74
- max-height: 85vh;
75
- overflow-y: auto;
76
- .field {
77
- margin: 0;
78
- }
79
- }
80
- table {
81
- width: 100%;
82
- border: 1px solid #DDDDDD;
83
- border-collapse: collapse;
84
- td,th {
85
- padding: 3px;
86
- @media only screen and (min-width: 480px) {
87
- padding: 5px;
88
- }
89
- &.mini {
90
- cursor: pointer;
91
- min-width: auto;
92
- width: 40px;
93
- }
94
- }
95
- thead tr {
96
- background-color: #F1F1F1;
97
- font-weight: lighter;
98
- }
99
- tbody tr {
100
- }
101
- @media only screen and (max-width: 480px){
102
- font-size: 80%;
103
- }
104
- }
105
- .dark table {
106
- thead tr {
107
- background-color: #191919;
108
- color: #e3e3e3;
109
- }
110
- tbody tr {
111
- background-color: #191919;
112
- }
113
- td,th {
114
- border: 1px solid #3f3f3f;
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
@@ -30,6 +30,7 @@ const FlexBuilderControls = ({
30
30
  ['endpoints', 'GET'], // Clé de requête
31
31
  () => fetch('/api/data/search', {
32
32
  method: 'POST',
33
+ credentials: "include",
33
34
  headers: { 'Content-Type': 'application/json' },
34
35
  body: JSON.stringify({
35
36
  model: 'endpoint',
@@ -28,7 +28,7 @@ const FlexBuilderPreview = ({
28
28
  setIsModalOpen(true);
29
29
 
30
30
  try {
31
- const response = await fetch(`/api/actions/${node.endpointPath}`, { method: 'GET' });
31
+ const response = await fetch(`/api/actions/${node.endpointPath}`, {credentials: "include", method: 'GET' });
32
32
  const data = await response.json();
33
33
  setModalContent({ path: node.endpointPath, status: response.status, data });
34
34
  } catch (error) {
@@ -92,7 +92,7 @@ export const FlexNodeRenderer = React.forwardRef((props, ref) => {
92
92
  setResult(null);
93
93
 
94
94
  try {
95
- const response = await fetch(`/api/actions/${endpointPath}`, { method: 'GET' });
95
+ const response = await fetch(`/api/actions/${endpointPath}`, { credentials: "include",method: 'GET' });
96
96
  const data = await response.json();
97
97
  setResult({ status: response.status, data });
98
98
  } catch (error) {
@@ -153,7 +153,7 @@ export const HistoryDialog = ({ modelName, recordId, onClose }) => {
153
153
  const params = new URLSearchParams({ page, limit: elementsPerPage, lang: i18n.language });
154
154
  if (startDate) params.append('startDate', startDate);
155
155
  if (endDate) params.append('endDate', endDate);
156
- const query = await fetch(`/api/data/history/${modelName}/${recordId}?${params.toString()}`);
156
+ const query = await fetch(`/api/data/history/${modelName}/${recordId}?${params.toString()}`, {credentials: "include"});
157
157
  const response = await query.json();
158
158
  if (response.success) {
159
159
  setHistory(response.data);
@@ -185,7 +185,7 @@ export const HistoryDialog = ({ modelName, recordId, onClose }) => {
185
185
  setPreviewLoading(true);
186
186
  setPreviewData(null);
187
187
  try {
188
- const res = await fetch(`/api/data/history/${modelName}/${recordId}/${version}`);
188
+ const res = await fetch(`/api/data/history/${modelName}/${recordId}/${version}`, {credentials: "include"});
189
189
  const response = await res.json();
190
190
  if (response.success) {
191
191
  setPreviewData(response.data);
@@ -209,6 +209,7 @@ export const HistoryDialog = ({ modelName, recordId, onClose }) => {
209
209
  try {
210
210
  const res = await fetch(`/api/data/history/${modelName}/${recordId}/revert/${version}`, {
211
211
  method: 'POST',
212
+ credentials: "include",
212
213
  headers: { 'Content-Type': 'application/json' }
213
214
  });
214
215
  const response = await res.json();
@@ -9,7 +9,7 @@ import { Tooltip } from 'react-tooltip';
9
9
  // Fonction pour récupérer la valeur calculée d'un KPI (MODIFIÉE)
10
10
  const fetchKpiValue = async (kpiId) => {
11
11
  if (!kpiId) return null;
12
- const response = await fetch(`/api/kpis/calculate/${kpiId}`);
12
+ const response = await fetch(`/api/kpis/calculate/${kpiId}`, { credentials: "include",});
13
13
  if (!response.ok) {
14
14
  const errorData = await response.json().catch(() => ({}));
15
15
  throw new Error(errorData.error || `Network response was not ok (${response.status})`);
@@ -62,6 +62,7 @@ const KanbanView = ({ settings, model }) => {
62
62
  ['kanbanData', model.name], // Clé de requête unique pour ce modèle
63
63
  () => fetch(`/api/data/search?_user=${me.username}&depth=2`, { // La fonction qui appelle l'API
64
64
  method: 'POST',
65
+ credentials: "include",
65
66
  headers: { 'Content-Type': 'application/json' },
66
67
  // On demande toutes les données pour le modèle spécifié (limit: 0 pour "tout")
67
68
  body: JSON.stringify({ model: model.name, page: 1 })
@@ -94,6 +94,7 @@ const ModelCreator = forwardRef(({ initialPrompt = '', onModelGenerated, autoGen
94
94
  const url = `/api/model/${initialModel._id}/renameField?_user=${encodeURIComponent(getUserId(me))}`;
95
95
  return fetch(url, {
96
96
  method: 'PATCH',
97
+ credentials: "include",
97
98
  headers: { 'Content-Type': 'application/json' },
98
99
  body: JSON.stringify({ oldFieldName: oldName, newFieldName: newName }),
99
100
  }).then((res) => res.json());
@@ -120,6 +121,7 @@ const ModelCreator = forwardRef(({ initialPrompt = '', onModelGenerated, autoGen
120
121
  const method = initialModel?._id ? 'PUT' : 'POST';
121
122
  return fetch(url+'?_user='+me.username, {
122
123
  method: method,
124
+ credentials: "include",
123
125
  headers: { 'Content-Type': 'application/json' },
124
126
  body: JSON.stringify(modelData),
125
127
  }).then((res) => res.json());
@@ -173,6 +175,7 @@ const ModelCreator = forwardRef(({ initialPrompt = '', onModelGenerated, autoGen
173
175
  (modelName) =>
174
176
  fetch(`/api/model?name=${modelName}&_user=${encodeURIComponent(getUserId(me))}`, {
175
177
  method: 'DELETE',
178
+ credentials:"include",
176
179
  }).then((res) => res.json()),
177
180
  {
178
181
  onSuccess: () => {
@@ -386,6 +389,7 @@ const ModelCreator = forwardRef(({ initialPrompt = '', onModelGenerated, autoGen
386
389
 
387
390
  const response = await fetch(`/api/model/generate?lang=${lang}`, {
388
391
  method: 'POST',
392
+ credentials:"include",
389
393
  headers: { 'Content-Type': 'application/json' },
390
394
  body: JSON.stringify(bodyPayload),
391
395
  });
@@ -95,6 +95,7 @@ export function ModelList({ editionMode, onModelSelect, onCreateModel, onImportM
95
95
  const demoInitMutation = useMutation((profile) => {
96
96
  return fetch('/api/demo/initialize', {
97
97
  method: 'POST',
98
+ credentials:"include",
98
99
  headers: { "Content-Type": "application/json"},
99
100
  body: JSON.stringify({profile: profile, packs: profiles[profile].packs}),
100
101
  });
@@ -16,7 +16,7 @@ import {TextField, CheckboxField} from "./Field.jsx";
16
16
  // --- API Fetching Functions ---
17
17
  const fetchPacks = async (sortBy, lang, filterByUser = false, user) => {
18
18
  const url = `/api/packs?lang=${lang}&sortBy=${sortBy.field}&order=${sortBy.order}${filterByUser ? '&user='+user.username : ''}`;
19
- const response = await fetch(url);
19
+ const response = await fetch(url, {credentials:"include"});
20
20
  if (!response.ok) {
21
21
  throw new Error('Network response was not ok');
22
22
  }
@@ -25,7 +25,7 @@ const fetchPacks = async (sortBy, lang, filterByUser = false, user) => {
25
25
 
26
26
  const fetchPackDetails = async (packId, lang) => {
27
27
  if (!packId) return null;
28
- const response = await fetch(`/api/packs/${packId}?lang=${lang}`);
28
+ const response = await fetch(`/api/packs/${packId}?lang=${lang}`, {credentials:"include"});
29
29
  if (!response.ok) {
30
30
  throw new Error('Failed to fetch pack details');
31
31
  }
@@ -182,7 +182,7 @@ const PackDetail = ({ packId, onBack }) => {
182
182
 
183
183
  const installPackMutationFn = async ({packId, lang}) => {
184
184
  const response = await fetch(`/api/packs/${packId}/install?lang=${lang}`, {
185
- method: 'POST',
185
+ method: 'POST',credentials: "include",
186
186
  headers: {
187
187
  'Content-Type': 'application/json',
188
188
  },
@@ -196,7 +196,7 @@ const installPackMutationFn = async ({packId, lang}) => {
196
196
 
197
197
  const updatePackMutationFn = async ({ packId, updateData }) => {
198
198
  const response = await fetch(`/api/packs/${packId}`, {
199
- method: 'PATCH',
199
+ method: 'PATCH',credentials: "include",
200
200
  headers: {
201
201
  'Content-Type': 'application/json',
202
202
  },
@@ -241,6 +241,7 @@ const PackGallery = () => {
241
241
 
242
242
  const response = await fetch('/api/packs/install', {
243
243
  method: 'POST',
244
+ credentials: "include",
244
245
  headers: {
245
246
  'Content-Type': 'application/json',
246
247
  },