data-primals-engine 1.5.0 → 1.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +37 -0
  2. package/client/src/AddWidgetTypeModal.jsx +47 -43
  3. package/client/src/App.jsx +2 -6
  4. package/client/src/App.scss +13 -1
  5. package/client/src/AssistantChat.jsx +363 -323
  6. package/client/src/AssistantChat.scss +27 -10
  7. package/client/src/Dashboard.jsx +480 -396
  8. package/client/src/Dashboard.scss +1 -1
  9. package/client/src/DashboardHtmlViewItem.jsx +147 -0
  10. package/client/src/DashboardView.jsx +654 -569
  11. package/client/src/DataEditor.jsx +10 -3
  12. package/client/src/DataLayout.jsx +807 -755
  13. package/client/src/DataLayout.scss +14 -0
  14. package/client/src/DataTable.jsx +39 -75
  15. package/client/src/Dialog.scss +1 -1
  16. package/client/src/Field.jsx +2057 -1825
  17. package/client/src/FlexViewCard.jsx +44 -0
  18. package/client/src/HistoryDialog.jsx +69 -14
  19. package/client/src/HtmlViewBuilderModal.jsx +91 -0
  20. package/client/src/HtmlViewBuilderModal.scss +18 -0
  21. package/client/src/HtmlViewCard.jsx +44 -0
  22. package/client/src/HtmlViewCard.scss +35 -0
  23. package/client/src/KanbanCard.jsx +1 -2
  24. package/client/src/ModelCreator.jsx +5 -4
  25. package/client/src/ModelCreatorField.jsx +51 -4
  26. package/client/src/ModelList.jsx +280 -236
  27. package/client/src/Notification.jsx +136 -136
  28. package/client/src/Notification.scss +0 -18
  29. package/client/src/Pagination.jsx +5 -3
  30. package/client/src/RelationField.jsx +354 -258
  31. package/client/src/RelationSelectorWidget.jsx +173 -0
  32. package/client/src/contexts/ModelContext.jsx +10 -1
  33. package/client/src/contexts/UIContext.jsx +72 -63
  34. package/client/src/filter.js +263 -212
  35. package/client/src/hooks/useValidation.js +75 -0
  36. package/client/src/translations.js +24 -24
  37. package/package.json +7 -6
  38. package/src/constants.js +1 -1
  39. package/src/core.js +8 -1
  40. package/src/defaultModels.js +1596 -1544
  41. package/src/engine.js +85 -43
  42. package/src/events.js +137 -113
  43. package/src/i18n.js +710 -10
  44. package/src/index.js +3 -0
  45. package/src/modules/assistant/assistant.js +253 -134
  46. package/src/modules/assistant/constants.js +2 -1
  47. package/src/modules/bucket.js +2 -1
  48. package/src/modules/data/data.core.js +118 -92
  49. package/src/modules/data/data.history.js +555 -492
  50. package/src/modules/data/data.js +3 -53
  51. package/src/modules/data/data.operations.js +3381 -3231
  52. package/src/modules/data/data.relations.js +686 -686
  53. package/src/modules/data/data.routes.js +1879 -1821
  54. package/src/modules/data/data.validation.js +81 -2
  55. package/src/modules/file.js +247 -238
  56. package/src/modules/user.js +1 -0
  57. package/src/modules/workflow.js +2 -2
  58. package/src/openai.jobs.js +3 -2
  59. package/src/packs.js +5482 -5478
  60. package/src/sso.js +2 -2
  61. package/src/workers/import-export-worker.js +1 -1
  62. package/test/data.history.integration.test.js +264 -192
  63. package/test/data.integration.test.js +149 -3
@@ -1,137 +1,137 @@
1
- import React, {useState, useEffect, useRef, useCallback, forwardRef} from 'react';
2
- import { FaCheck, FaSpinner, FaExclamationTriangle, FaBell, FaTimes, FaTrash } from 'react-icons/fa'; // Example icons
3
- import { useNotificationContext } from './NotificationProvider.jsx'; // Import the context
4
- import './Notification.scss';
5
-
6
- /*
7
- const { addNotification } = useNotificationContext();
8
- const notificationData = {
9
- title: 'New Notification',
10
- message: 'This is a new notification message.',
11
- icon: <FaBell />,
12
- status: ['ongoing','completed','error'][Math.floor(Math.random()*3)]
13
- };
14
- */
15
- // Helper function to generate a unique ID
16
- const generateNotificationId = () => {
17
- return Math.random().toString(36).substring(2, 9);
18
- };
19
-
20
- const Notification = ({ notification, onClick }) => {
21
- const { markAsRead, removeNotification } = useNotificationContext();
22
- const [dismissTimer, setDismissTimer] = useState(null);
23
- const notificationRef = useRef(null);
24
- const isMounted = useRef(false)
25
-
26
- const handleMarkAsRead = useCallback(() => {
27
- markAsRead(notification.id);
28
- }, [markAsRead, notification.id]);
29
-
30
- useEffect(() => {
31
- const t = setTimeout(()=>{
32
- markAsRead(notification.id);
33
- }, notification.timeout || 12000);
34
- return () => {
35
- clearTimeout(t);
36
- }
37
- }, [notification]);
38
-
39
- useEffect(() => {
40
- if (notification.isRead) {
41
- const timer = setTimeout(() => {
42
- removeNotification(notification.id);
43
- }, 30000);
44
-
45
- return () => {
46
- clearTimeout(timer);
47
- };
48
- }
49
- }, [notification.isRead, notification.id, removeNotification]);
50
-
51
- let statusIcon;
52
- switch (notification.status) {
53
- case 'ongoing':
54
- statusIcon = <FaSpinner className="spinner" />;
55
- break;
56
- case 'completed':
57
- statusIcon = <FaCheck />;
58
- break;
59
- case 'error':
60
- statusIcon = <FaExclamationTriangle />;
61
- break;
62
- default:
63
- statusIcon = null;
64
- }
65
-
66
- const removeBtn = notification.isRead ? <button onClick={() => {
67
- removeNotification(notification.id);
68
- }}><FaTrash /></button> : <></>
69
- return (
70
- <div ref={notificationRef} onClick={onClick} className={`notification ${notification.isExpanded ? 'expanded' : 'collapsed'} ${notification.status}`}>
71
- <div className="notification-header">
72
- {notification.icon && <span className="notification-icon">{notification.icon}</span>}
73
- <span className="notification-title">{notification.title}</span>
74
- {statusIcon && <span className="notification-status">{statusIcon}</span>}
75
- {removeBtn}
76
- </div>
77
- {<div className="notification-content">
78
- <p className="notification-message">{notification.message}</p>
79
- </div>}
80
- </div>
81
- );
82
- };
83
-
84
- const NotificationList = forwardRef((props, ref) => {
85
- const { notifications, markAsRead, removeNotification, addNotification, unreadCount } = useNotificationContext();
86
- const [showBubble, setShowBubble] = useState(false);
87
-
88
-
89
- const toggleBubble = useCallback(() => {
90
- setShowBubble(!showBubble)
91
- }, [showBubble]);
92
-
93
- useEffect(() => {
94
- if( unreadCount > 0 ){
95
- if (!showBubble)
96
- setShowBubble(true);
97
- }else{
98
- if (showBubble)
99
- setShowBubble(false);
100
- }
101
- }, [unreadCount]);
102
-
103
- const readNotifications = notifications.filter(n => n.isRead) || [];
104
- const unreadNotifications = notifications.filter(n => !n.isRead) || [];
105
- return (
106
- <div className="notification-container">
107
- <div className="notifications-right">
108
- {unreadNotifications.map(notification => (
109
- <Notification
110
- onClick={() => {
111
- markAsRead(notification.id)
112
- }}
113
- key={notification.id}
114
- notification={notification}
115
- />
116
- ))}
117
- {unreadCount > 0 && <div className={"notification-bubble-count"}>{unreadCount}</div>}
118
- </div>
119
- <div className={`notification-bubble ${showBubble ? 'visible' : ''}`}>
120
- <button onClick={toggleBubble} className="notification-bubble-btn">
121
- <FaBell/>
122
- {unreadCount > 0 && <span className="notification-bubble-count">{unreadCount}</span>}
123
- </button>
124
- {showBubble && <div className='notifications-bubble-content'>
125
- {readNotifications.map(notification => (
126
- <Notification
127
- key={notification.id}
128
- notification={notification}
129
- />
130
- ))}
131
- </div>}
132
- </div>
133
- </div>
134
- );
135
- });
136
- NotificationList.displayName = "NotificationList";
1
+ import React, {useState, useEffect, useRef, useCallback, forwardRef} from 'react';
2
+ import { FaCheck, FaSpinner, FaExclamationTriangle, FaBell, FaTimes, FaTrash } from 'react-icons/fa'; // Example icons
3
+ import { useNotificationContext } from './NotificationProvider.jsx'; // Import the context
4
+ import './Notification.scss';
5
+
6
+ /*
7
+ const { addNotification } = useNotificationContext();
8
+ const notificationData = {
9
+ title: 'New Notification',
10
+ message: 'This is a new notification message.',
11
+ icon: <FaBell />,
12
+ status: ['ongoing','completed','error'][Math.floor(Math.random()*3)]
13
+ };
14
+ */
15
+ // Helper function to generate a unique ID
16
+ const generateNotificationId = () => {
17
+ return Math.random().toString(36).substring(2, 9);
18
+ };
19
+
20
+ const Notification = ({ notification, onClick }) => {
21
+ const { markAsRead, removeNotification } = useNotificationContext();
22
+ const [dismissTimer, setDismissTimer] = useState(null);
23
+ const notificationRef = useRef(null);
24
+ const isMounted = useRef(false)
25
+
26
+ const handleMarkAsRead = useCallback(() => {
27
+ markAsRead(notification.id);
28
+ }, [markAsRead, notification.id]);
29
+
30
+ useEffect(() => {
31
+ const t = setTimeout(()=>{
32
+ markAsRead(notification.id);
33
+ }, notification.timeout || 12000);
34
+ return () => {
35
+ clearTimeout(t);
36
+ }
37
+ }, [notification]);
38
+
39
+ useEffect(() => {
40
+ if (notification.isRead) {
41
+ const timer = setTimeout(() => {
42
+ removeNotification(notification.id);
43
+ }, 30000);
44
+
45
+ return () => {
46
+ clearTimeout(timer);
47
+ };
48
+ }
49
+ }, [notification.isRead, notification.id, removeNotification]);
50
+
51
+ let statusIcon;
52
+ switch (notification.status) {
53
+ case 'ongoing':
54
+ statusIcon = <FaSpinner className="spinner" />;
55
+ break;
56
+ case 'completed':
57
+ statusIcon = <FaCheck />;
58
+ break;
59
+ case 'error':
60
+ statusIcon = <FaExclamationTriangle />;
61
+ break;
62
+ default:
63
+ statusIcon = null;
64
+ }
65
+
66
+ const removeBtn = notification.isRead ? <button onClick={() => {
67
+ removeNotification(notification.id);
68
+ }}><FaTrash /></button> : <></>
69
+ return (
70
+ <div ref={notificationRef} onClick={onClick} className={`notification ${notification.isExpanded ? 'expanded' : 'collapsed'} ${notification.status}`}>
71
+ <div className="notification-header">
72
+ {notification.icon && <span className="notification-icon">{notification.icon}</span>}
73
+ <span className="notification-title">{notification.title}</span>
74
+ {statusIcon && <span className="notification-status">{statusIcon}</span>}
75
+ {removeBtn}
76
+ </div>
77
+ {<div className="notification-content">
78
+ <p className="notification-message">{notification.message}</p>
79
+ </div>}
80
+ </div>
81
+ );
82
+ };
83
+
84
+ const NotificationList = forwardRef((props, ref) => {
85
+ const { notifications, markAsRead, removeNotification, addNotification, unreadCount } = useNotificationContext();
86
+ const [showBubble, setShowBubble] = useState(false);
87
+
88
+ const toggleBubble = useCallback(() => {
89
+ // Lorsque l'on ouvre la bulle, on marque toutes les notifications comme lues.
90
+ if (!showBubble) {
91
+ notifications.forEach(n => {
92
+ if (!n.isRead) {
93
+ markAsRead(n.id);
94
+ }
95
+ });
96
+ }
97
+ // Ensuite, on bascule la visibilité du contenu de la bulle.
98
+ setShowBubble(prev => !prev);
99
+ }, [showBubble, notifications, markAsRead]);
100
+
101
+ const readNotifications = notifications.filter(n => n.isRead) || [];
102
+ const unreadNotifications = notifications.filter(n => !n.isRead) || [];
103
+ return (
104
+ <><div className="notification-container">
105
+ <div className="notifications-right">
106
+ {unreadNotifications.map(notification => (
107
+ <Notification
108
+ onClick={() => {
109
+ markAsRead(notification.id)
110
+ }}
111
+ key={notification.id}
112
+ notification={notification}
113
+ />
114
+ ))}
115
+ {unreadCount > 0 && <div className={"notification-bubble-count"}>{unreadCount}</div>}
116
+ </div>
117
+ </div>
118
+
119
+ {unreadCount > 0 && <button onClick={toggleBubble} className={`notification-bubble fab ${showBubble ? 'visible' : ''}`}>
120
+ <div>
121
+ <FaBell/>
122
+ {unreadCount > 0 && <span className="notification-bubble-count">{unreadCount}</span>}
123
+ </div>
124
+ {showBubble && <div className='notifications-bubble-content'>
125
+ {readNotifications.map(notification => (
126
+ <Notification
127
+ key={notification.id}
128
+ notification={notification}
129
+ />
130
+ ))}
131
+ </div>}
132
+ </button>}
133
+ </>
134
+ );
135
+ });
136
+ NotificationList.displayName = "NotificationList";
137
137
  export {NotificationList, generateNotificationId}; // Export for use elsewherex
@@ -74,24 +74,6 @@
74
74
  }
75
75
  }
76
76
 
77
- .notification-bubble {
78
- position: fixed;
79
- bottom: 20px;
80
- right: 20px;
81
- background-color: #007bff;
82
- color: #fff;
83
- border-radius: 50%;
84
- width: 50px;
85
- height: 50px;
86
- justify-content: center;
87
- align-items: center;
88
- cursor: pointer;
89
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
90
- z-index: 1000;
91
- transition: all 0.3s ease;
92
- pointer-events: all;
93
- display: none;
94
- }
95
77
 
96
78
  .notification-bubble.visible {
97
79
  display: flex;
@@ -14,9 +14,11 @@ export const Pagination = ({
14
14
  page,
15
15
  setPage,
16
16
  useParam = false,
17
- showElementsPerPage=false
17
+ showElementsPerPage=false,
18
+ elementsPerPage: propElementsPerPage
18
19
  }) => {
19
- const { elementsPerPage, setElementsPerPage } = useModelContext();
20
+ const { elementsPerPage: contextElementsPerPage, setElementsPerPage } = useModelContext();
21
+ const elementsPerPage = propElementsPerPage || contextElementsPerPage;
20
22
  let pageCount = Math.ceil(totalCount / elementsPerPage);
21
23
  const [searchParams, setSearchParams] = useSearchParams();
22
24
 
@@ -109,7 +111,7 @@ export const Pagination = ({
109
111
  (_, i) => page + i - parseInt(visibleItemsCount / 2, 10),
110
112
  ).map((p, i) => {
111
113
  return p >= 1 && p <= pageCount ? (
112
- <Button disabled={p === page} onClick={() => handleChange(p)}>
114
+ <Button key={"paginate-"+i} disabled={p === page} onClick={() => handleChange(p)}>
113
115
  {p}
114
116
  </Button>
115
117
  ) : (