ui-soxo-bootstrap-core 2.4.25-dev.25 → 2.4.25-dev.27
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/core/lib/components/sidemenu/sidemenu.js +5 -1
- package/core/lib/elements/basic/dragabble-wrapper/draggable-wrapper.js +82 -84
- package/core/models/menus/components/menu-lists/menu-lists.scss +3 -2
- package/core/models/roles/components/role-add/role-add.js +76 -18
- package/core/models/roles/components/role-add/role-add.scss +4 -0
- package/core/modules/index.js +0 -4
- package/core/modules/reporting/components/reporting-dashboard/reporting-dashboard.js +2 -3
- package/package.json +1 -1
|
@@ -163,6 +163,10 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
163
163
|
const onMenuClick = (menu, index) => {
|
|
164
164
|
const key = menu.path || `menu-${menu.id || index}`;
|
|
165
165
|
|
|
166
|
+
if (menu.isRoot) {
|
|
167
|
+
setOpenKeys([]);
|
|
168
|
+
}
|
|
169
|
+
|
|
166
170
|
setSelectedKeys([key]);
|
|
167
171
|
|
|
168
172
|
if (menu.path) {
|
|
@@ -447,7 +451,7 @@ export default function SideMenu({ loading, modules = [], callback, appSettings,
|
|
|
447
451
|
// }}
|
|
448
452
|
|
|
449
453
|
onClick={() => {
|
|
450
|
-
onMenuClick({ ...menu, parentKey: menu.path || menu.caption }, index);
|
|
454
|
+
onMenuClick({ ...menu, parentKey: menu.path || menu.caption, isRoot: true }, index);
|
|
451
455
|
}}
|
|
452
456
|
// key={`${menu.id}-${randomIndex}`}
|
|
453
457
|
key={menu.path || menu.caption}
|
|
@@ -2,26 +2,25 @@ import React, { useRef } from 'react';
|
|
|
2
2
|
import { useDrag, useDrop } from 'react-dnd';
|
|
3
3
|
|
|
4
4
|
export default function DraggableWrapper({ id, index, movePanel, item, dragEnabled, level, parentId, onCrossLevelMove, canAcceptChildren }) {
|
|
5
|
-
|
|
6
5
|
const autoScrollWindow = (monitor) => {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const offset = monitor.getClientOffset();
|
|
7
|
+
if (!offset) return;
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const EDGE = 80;
|
|
10
|
+
const SPEED = 20;
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
const viewportHeight = window.innerHeight;
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
// 🔼 scroll UP
|
|
15
|
+
if (offset.y < EDGE) {
|
|
16
|
+
window.scrollBy(0, -SPEED);
|
|
17
|
+
}
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
19
|
+
// 🔽 scroll DOWN
|
|
20
|
+
if (offset.y > viewportHeight - EDGE) {
|
|
21
|
+
window.scrollBy(0, SPEED);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
25
24
|
|
|
26
25
|
const [{ isDragging }, drag] = useDrag({
|
|
27
26
|
type: 'PANEL',
|
|
@@ -34,36 +33,30 @@ export default function DraggableWrapper({ id, index, movePanel, item, dragEnabl
|
|
|
34
33
|
|
|
35
34
|
const [{ isOver, canDrop }, drop] = useDrop({
|
|
36
35
|
accept: 'PANEL',
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
dragItem.index = index; // keep in sync
|
|
49
|
-
}
|
|
50
|
-
},
|
|
36
|
+
hover: (dragItem, monitor) => {
|
|
37
|
+
// THIS FIXES BOTTOM → TOP
|
|
38
|
+
autoScrollWindow(monitor);
|
|
39
|
+
|
|
40
|
+
if (dragItem.index === index) return;
|
|
41
|
+
|
|
42
|
+
if (dragItem.level === level && dragItem.parentId === parentId) {
|
|
43
|
+
movePanel(dragItem.index, index);
|
|
44
|
+
dragItem.index = index; // keep in sync
|
|
45
|
+
}
|
|
46
|
+
},
|
|
51
47
|
|
|
52
48
|
canDrop: (item) => dragEnabled,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
},
|
|
49
|
+
drop: (dragItem, monitor) => {
|
|
50
|
+
if (monitor.didDrop()) return;
|
|
51
|
+
|
|
52
|
+
if (dragItem.level !== level || dragItem.parentId !== parentId) {
|
|
53
|
+
onCrossLevelMove?.(dragItem, {
|
|
54
|
+
targetLevel: level,
|
|
55
|
+
targetParentId: parentId,
|
|
56
|
+
targetIndex: index,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
},
|
|
67
60
|
collect: (monitor) => ({
|
|
68
61
|
isOver: monitor.isOver({ shallow: true }),
|
|
69
62
|
canDrop: monitor.canDrop(),
|
|
@@ -75,7 +68,7 @@ export default function DraggableWrapper({ id, index, movePanel, item, dragEnabl
|
|
|
75
68
|
accept: 'PANEL',
|
|
76
69
|
canDrop: (item) => dragEnabled && item.id !== id && canAcceptChildren,
|
|
77
70
|
drop: (item, monitor) => {
|
|
78
|
-
if (monitor.didDrop()) return;
|
|
71
|
+
// if (monitor.didDrop()) return;
|
|
79
72
|
|
|
80
73
|
if (onCrossLevelMove && item.id !== id) {
|
|
81
74
|
// Drop as child of this item
|
|
@@ -88,51 +81,56 @@ export default function DraggableWrapper({ id, index, movePanel, item, dragEnabl
|
|
|
88
81
|
}),
|
|
89
82
|
});
|
|
90
83
|
|
|
91
|
-
const backgroundColor = isOver && canDrop ? '#bae7ff' : isDragging ? '#
|
|
84
|
+
const backgroundColor = isOver && canDrop ? '#bae7ff' : isDragging ? '#ffff' : 'transparent';
|
|
92
85
|
const childZoneBackgroundColor = isOverChild && canDropChild ? '#d4f4dd' : 'transparent';
|
|
93
86
|
|
|
94
87
|
return (
|
|
95
|
-
<div
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
ref={dropChild}
|
|
119
|
-
onClick={(e) => e.stopPropagation()}
|
|
120
|
-
style={{
|
|
121
|
-
padding: '4px 12px',
|
|
122
|
-
marginLeft: 8,
|
|
123
|
-
backgroundColor: childZoneBackgroundColor,
|
|
124
|
-
border: isOverChild && canDropChild ? '2px solid #52c41a' : '1px dashed #d9d9d9',
|
|
125
|
-
borderRadius: 4,
|
|
126
|
-
fontSize: 11,
|
|
127
|
-
color: isOverChild && canDropChild ? '#52c41a' : '#999',
|
|
128
|
-
cursor: 'default',
|
|
129
|
-
transition: 'all 0.2s ease',
|
|
130
|
-
}}
|
|
131
|
-
>
|
|
132
|
-
{isOverChild && canDropChild ? '✓ Drop as child' : '↳ Drop here'}
|
|
88
|
+
<div style={{ width: '100%', display: 'flex' }}>
|
|
89
|
+
{/* HEADER DROP — reorder only */}
|
|
90
|
+
<div ref={drop}>
|
|
91
|
+
<div
|
|
92
|
+
ref={drag}
|
|
93
|
+
style={{
|
|
94
|
+
opacity: isDragging ? 0.5 : 1,
|
|
95
|
+
cursor: dragEnabled ? 'move' : 'default',
|
|
96
|
+
backgroundColor,
|
|
97
|
+
border: isOver && canDrop ? '2px dashed #1890ff' : '2px solid transparent',
|
|
98
|
+
display: 'flex',
|
|
99
|
+
justifyContent: 'space-between',
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
<div style={{ flex: 1 }}>
|
|
104
|
+
{dragEnabled && <span style={{ marginRight: 8 }}>⋮⋮</span>}
|
|
105
|
+
<span>{item.name}</span>
|
|
106
|
+
{dragEnabled ? (
|
|
107
|
+
<span style={{ marginLeft: 8, fontSize: 11, color: '#999' }}>(Level {level})</span>
|
|
108
|
+
) : (
|
|
109
|
+
<span style={{ marginLeft: 8, fontSize: 11, color: '#999' }}>{item.path}</span>
|
|
110
|
+
)}
|
|
133
111
|
</div>
|
|
134
|
-
|
|
112
|
+
</div>
|
|
135
113
|
</div>
|
|
114
|
+
|
|
115
|
+
{/* CHILD DROP — nesting */}
|
|
116
|
+
{canAcceptChildren && dragEnabled && (
|
|
117
|
+
<div
|
|
118
|
+
ref={dropChild}
|
|
119
|
+
style={{
|
|
120
|
+
marginLeft: 8,
|
|
121
|
+
// flex:1,
|
|
122
|
+
// marginTop: 4,
|
|
123
|
+
padding: '4px 12px',
|
|
124
|
+
backgroundColor: isOverChild && canDropChild ? '#d4f4dd' : 'transparent',
|
|
125
|
+
border: isOverChild && canDropChild ? '2px solid #52c41a' : '1px dashed #d9d9d9',
|
|
126
|
+
borderRadius: 4,
|
|
127
|
+
fontSize: 11,
|
|
128
|
+
color: isOverChild && canDropChild ? '#52c41a' : '#999',
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
{isOverChild && canDropChild ? '✓ Drop as child' : '↳ Drop here'}
|
|
132
|
+
</div>
|
|
133
|
+
)}
|
|
136
134
|
</div>
|
|
137
135
|
);
|
|
138
136
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.ant-collapse {
|
|
7
|
-
background-color: #
|
|
7
|
+
background-color: #ffff !important;
|
|
8
8
|
border: none !important;
|
|
9
9
|
}
|
|
10
10
|
.ant-collapse > .ant-collapse-item {
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
box-shadow: 0 1px 4px rgba(0,0,0,0.04);
|
|
40
40
|
}
|
|
41
41
|
.ant-collapse > .ant-collapse-item > .ant-collapse-heade{
|
|
42
|
-
align-items: center;
|
|
42
|
+
align-items: center !important;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
|
|
@@ -4,6 +4,7 @@ import { Skeleton, Typography, message, Form, Input, Collapse, Checkbox } from '
|
|
|
4
4
|
import { GlobalContext } from './../../../../lib';
|
|
5
5
|
import { Button } from './../../../../lib';
|
|
6
6
|
import { ModelsAPI, PagesAPI, RolesAPI, MenusAPI } from '../../..';
|
|
7
|
+
import './role-add.scss';
|
|
7
8
|
|
|
8
9
|
const { Title } = Typography;
|
|
9
10
|
const { Panel } = Collapse;
|
|
@@ -59,7 +60,7 @@ const RoleAdd = ({ model, callback, edit, formContent = {}, match, additional_qu
|
|
|
59
60
|
|
|
60
61
|
setSelectedMenus(menus);
|
|
61
62
|
// keep original copy for deselect comparison
|
|
62
|
-
setOriginalMenus(menus);
|
|
63
|
+
setOriginalMenus(menus);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
setLoading(false);
|
|
@@ -203,48 +204,105 @@ export default RoleAdd;
|
|
|
203
204
|
// ------------------------
|
|
204
205
|
// Recursive Nested Menu Component
|
|
205
206
|
// ------------------------
|
|
206
|
-
|
|
207
|
+
// ------------------------
|
|
208
|
+
// Recursive Nested Menu Component
|
|
209
|
+
// ------------------------
|
|
210
|
+
const MenuTree = ({ menus, selectedMenus, toggleMenu, parentId = null }) => {
|
|
211
|
+
// Helper: check if parent should be checked
|
|
212
|
+
const isParentChecked = (menu) => {
|
|
213
|
+
if (!menu.sub_menus || menu.sub_menus.length === 0) {
|
|
214
|
+
return selectedMenus.includes(menu.id);
|
|
215
|
+
}
|
|
216
|
+
const allChildIds = menu.sub_menus.map((c) => c.id);
|
|
217
|
+
return allChildIds.every((id) => selectedMenus.includes(id));
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Helper: check if parent is indeterminate
|
|
221
|
+
const isParentIndeterminate = (menu) => {
|
|
222
|
+
if (!menu.sub_menus || menu.sub_menus.length === 0) return false;
|
|
223
|
+
const allChildIds = menu.sub_menus.map((c) => c.id);
|
|
224
|
+
const checkedCount = allChildIds.filter((id) => selectedMenus.includes(id)).length;
|
|
225
|
+
return checkedCount > 0 && checkedCount < allChildIds.length;
|
|
226
|
+
};
|
|
227
|
+
|
|
207
228
|
return (
|
|
208
229
|
<>
|
|
209
230
|
{menus.map((menu) => {
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
const children = menu.sub_menus || [];
|
|
232
|
+
const parentChecked = isParentChecked(menu);
|
|
233
|
+
const parentIndeterminate = isParentIndeterminate(menu);
|
|
234
|
+
|
|
235
|
+
const onParentChange = (checked) => {
|
|
236
|
+
toggleMenu(menu.id, checked);
|
|
237
|
+
// toggle children recursively
|
|
238
|
+
children.forEach((c) => toggleMenuRecursive(c, checked));
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const toggleMenuRecursive = (menu, checked) => {
|
|
242
|
+
toggleMenu(menu.id, checked);
|
|
243
|
+
if (menu.sub_menus && menu.sub_menus.length > 0) {
|
|
244
|
+
menu.sub_menus.forEach((c) => toggleMenuRecursive(c, checked));
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
if (children.length === 0) {
|
|
214
249
|
return (
|
|
215
250
|
<div
|
|
216
251
|
key={menu.id}
|
|
217
252
|
style={{
|
|
218
|
-
|
|
253
|
+
border: '1px solid rgba(198, 195, 195, 0.85)',
|
|
254
|
+
// borderRadius: 6,
|
|
255
|
+
padding: '12px 16px',
|
|
256
|
+
marginBottom: 6,
|
|
257
|
+
background: '#fff',
|
|
219
258
|
display: 'flex',
|
|
220
259
|
alignItems: 'center',
|
|
221
260
|
gap: 8,
|
|
222
|
-
borderBottom: '1px solid #f0f0f0',
|
|
223
261
|
}}
|
|
224
262
|
>
|
|
225
|
-
<Checkbox
|
|
263
|
+
<Checkbox
|
|
264
|
+
checked={selectedMenus.includes(menu.id)}
|
|
265
|
+
onChange={(e) => {
|
|
266
|
+
const checked = e.target.checked;
|
|
267
|
+
|
|
268
|
+
toggleMenu(menu.id, checked);
|
|
269
|
+
|
|
270
|
+
// ✅ FORCE parent selection
|
|
271
|
+
if (checked && parentId) {
|
|
272
|
+
toggleMenu(parentId, true);
|
|
273
|
+
}
|
|
274
|
+
}}
|
|
275
|
+
/>
|
|
226
276
|
<span>{menu.title || menu.caption}</span>
|
|
227
277
|
</div>
|
|
228
278
|
);
|
|
229
279
|
}
|
|
230
280
|
|
|
231
|
-
// HAS CHILD → COLLAPSE WITH ICON
|
|
232
281
|
return (
|
|
233
|
-
<Collapse
|
|
282
|
+
<Collapse
|
|
283
|
+
key={menu.id}
|
|
284
|
+
style={{ marginBottom: 6 }}
|
|
285
|
+
// defaultActiveKey={[menu.id]}
|
|
286
|
+
>
|
|
234
287
|
<Panel
|
|
235
288
|
key={menu.id}
|
|
236
289
|
header={
|
|
237
|
-
<div
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
290
|
+
<div
|
|
291
|
+
style={{
|
|
292
|
+
display: 'flex',
|
|
293
|
+
alignItems: 'center',
|
|
294
|
+
gap: 8,
|
|
295
|
+
}}
|
|
296
|
+
onClick={(e) => e.stopPropagation()}
|
|
297
|
+
>
|
|
298
|
+
<Checkbox checked={parentChecked} indeterminate={parentIndeterminate} onChange={(e) => onParentChange(e.target.checked)} />
|
|
243
299
|
<span>{menu.title || menu.caption}</span>
|
|
244
300
|
</div>
|
|
245
301
|
}
|
|
246
302
|
>
|
|
247
|
-
<
|
|
303
|
+
<div style={{ paddingLeft: 20 }}>
|
|
304
|
+
<MenuTree menus={children} selectedMenus={selectedMenus} toggleMenu={toggleMenu} parentId={menu.id} />
|
|
305
|
+
</div>
|
|
248
306
|
</Panel>
|
|
249
307
|
</Collapse>
|
|
250
308
|
);
|
package/core/modules/index.js
CHANGED
|
@@ -16,8 +16,6 @@ import PopQueryDashboard from './dashboard/components/pop-query-dashboard/pop-qu
|
|
|
16
16
|
|
|
17
17
|
import HomePageAPI from './../pages/homepage-api/homepage-api';
|
|
18
18
|
|
|
19
|
-
import { Profile, ChangePassword } from './../lib';
|
|
20
|
-
|
|
21
19
|
import ReportingDashboard from '../modules/reporting/components/reporting-dashboard/reporting-dashboard';
|
|
22
20
|
|
|
23
21
|
import ChangeInfo from './Informations/change-info/change-info';
|
|
@@ -34,9 +32,7 @@ export {
|
|
|
34
32
|
DashboardCard,
|
|
35
33
|
PopQueryDashboard,
|
|
36
34
|
HomePageAPI,
|
|
37
|
-
Profile,
|
|
38
35
|
ReportingDashboard,
|
|
39
|
-
ChangePassword,
|
|
40
36
|
ChangeInfo,
|
|
41
37
|
};
|
|
42
38
|
|
|
@@ -220,7 +220,7 @@ export default function ReportingDashboard({
|
|
|
220
220
|
if (['reference-select', 'reference-search', 'select'].indexOf(record.type) !== -1) {
|
|
221
221
|
// let model = "";
|
|
222
222
|
let model = CustomModels[record.modelName];
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
return {
|
|
225
225
|
...record,
|
|
226
226
|
model,
|
|
@@ -800,8 +800,7 @@ function GuestList({
|
|
|
800
800
|
field: entry.field,
|
|
801
801
|
title: entry.title,
|
|
802
802
|
key: entry.field,
|
|
803
|
-
width: entry.width
|
|
804
|
-
ellipsis: true,
|
|
803
|
+
width: entry.width ? parseInt(entry.width) : undefined,
|
|
805
804
|
fixed: entry.isFixedColumn ? entry.isFixedColumn : null, // Conditionally setting the 'fixed' key to 'left' if 'isColumnStatic' is true; otherwise, setting it to null.
|
|
806
805
|
// Check if filtering is enabled and patients is an array
|
|
807
806
|
filters:
|