@topconsultnpm/sdkui-react 6.20.0-dev1.76 → 6.20.0-dev1.78
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/lib/components/NewComponents/ContextMenu/TMContextMenu.js +25 -12
- package/lib/components/NewComponents/ContextMenu/hooks.d.ts +3 -1
- package/lib/components/NewComponents/ContextMenu/hooks.js +42 -4
- package/lib/components/NewComponents/ContextMenu/styles.d.ts +4 -0
- package/lib/components/NewComponents/ContextMenu/styles.js +101 -9
- package/lib/components/features/search/TMSearchResult.js +9 -9
- package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
- package/lib/components/features/tasks/TMTasksUtils.js +52 -62
- package/lib/components/features/tasks/TMTasksView.js +4 -4
- package/lib/components/features/workflow/TMWorkflowPopup.js +5 -10
- package/lib/components/features/workflow/diagram/WFDiagram.d.ts +1 -0
- package/lib/components/features/workflow/diagram/WFDiagram.js +139 -7
- package/lib/components/query/TMQueryEditor.d.ts +2 -1
- package/lib/components/query/TMQueryEditor.js +92 -92
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +4 -3
- package/package.json +1 -1
|
@@ -19,7 +19,9 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
19
19
|
const submenuTimeoutRef = useRef(null);
|
|
20
20
|
const longPressTimeoutRef = useRef(null);
|
|
21
21
|
const touchStartPos = useRef(null);
|
|
22
|
-
|
|
22
|
+
// Get current menu to pass items count to positioning hook
|
|
23
|
+
const currentMenu = menuState.submenuStack.at(-1) || items;
|
|
24
|
+
const { openLeft, openUp, isCalculated, needsScroll, maxHeight } = useMenuPosition(menuRef, menuState.position, currentMenu.length);
|
|
23
25
|
const handleClose = () => {
|
|
24
26
|
if (externalControl) {
|
|
25
27
|
externalControl.onClose();
|
|
@@ -232,20 +234,26 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
232
234
|
};
|
|
233
235
|
document.addEventListener('mousedown', handleClickOutside);
|
|
234
236
|
document.addEventListener('touchstart', handleClickOutside);
|
|
237
|
+
document.addEventListener('contextmenu', handleClickOutside); // Close on right-click outside
|
|
235
238
|
return () => {
|
|
236
239
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
237
240
|
document.removeEventListener('touchstart', handleClickOutside);
|
|
241
|
+
document.removeEventListener('contextmenu', handleClickOutside);
|
|
238
242
|
};
|
|
239
243
|
}, [menuState.visible]);
|
|
240
244
|
const handleContextMenu = (e) => {
|
|
241
245
|
if (trigger === 'right') {
|
|
242
246
|
e.preventDefault();
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
247
|
+
e.stopPropagation(); // Prevent event from bubbling to close other menus prematurely
|
|
248
|
+
// Small delay to ensure other menus receive the contextmenu event and close first
|
|
249
|
+
setTimeout(() => {
|
|
250
|
+
setMenuState({
|
|
251
|
+
visible: true,
|
|
252
|
+
position: { x: e.clientX, y: e.clientY },
|
|
253
|
+
submenuStack: [items],
|
|
254
|
+
parentNames: [],
|
|
255
|
+
});
|
|
256
|
+
}, 0);
|
|
249
257
|
}
|
|
250
258
|
};
|
|
251
259
|
const handleClick = (e) => {
|
|
@@ -343,13 +351,17 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
343
351
|
submenuTimeoutRef.current = null;
|
|
344
352
|
}
|
|
345
353
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
346
|
-
// Calculate
|
|
347
|
-
// Estimate submenu height: ~35px per item (accounting for smaller padding) + container padding
|
|
354
|
+
// Calculate submenu height dynamically
|
|
348
355
|
const estimatedSubmenuHeight = (item.submenu.length * 35) + 8;
|
|
349
356
|
const spaceBelow = window.innerHeight - rect.top;
|
|
350
357
|
const spaceAbove = rect.bottom;
|
|
351
|
-
|
|
358
|
+
const padding = 8;
|
|
359
|
+
// Determine if submenu should open upward
|
|
352
360
|
const shouldOpenUp = spaceBelow < estimatedSubmenuHeight && spaceAbove > spaceBelow;
|
|
361
|
+
// Calculate if submenu needs scroll and max-height
|
|
362
|
+
const availableSpace = shouldOpenUp ? spaceAbove : spaceBelow;
|
|
363
|
+
const needsScroll = estimatedSubmenuHeight > availableSpace - padding;
|
|
364
|
+
const maxHeight = needsScroll ? availableSpace - padding : undefined;
|
|
353
365
|
// Remove all submenus at this depth and deeper
|
|
354
366
|
setHoveredSubmenus(prev => {
|
|
355
367
|
const filtered = prev.filter(sub => sub.depth < depth);
|
|
@@ -362,6 +374,8 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
362
374
|
parentRect: rect,
|
|
363
375
|
depth: depth,
|
|
364
376
|
openUp: shouldOpenUp,
|
|
377
|
+
needsScroll,
|
|
378
|
+
maxHeight,
|
|
365
379
|
}
|
|
366
380
|
];
|
|
367
381
|
});
|
|
@@ -413,7 +427,6 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
413
427
|
return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), title: item.tooltip, children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
|
|
414
428
|
});
|
|
415
429
|
};
|
|
416
|
-
const currentMenu = menuState.submenuStack.at(-1) || items;
|
|
417
430
|
const currentParentName = menuState.parentNames.at(-1) || '';
|
|
418
431
|
return (_jsxs(_Fragment, { children: [!externalControl && children && (_jsx("div", { ref: triggerRef, onContextMenu: handleContextMenu, onClick: handleClick, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchEnd, onKeyDown: (e) => {
|
|
419
432
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
@@ -423,6 +436,6 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
423
436
|
display: 'inline-block',
|
|
424
437
|
WebkitTouchCallout: isIOS ? 'none' : undefined,
|
|
425
438
|
WebkitUserSelect: isIOS ? 'none' : undefined,
|
|
426
|
-
}, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
|
|
439
|
+
}, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
|
|
427
440
|
};
|
|
428
441
|
export default TMContextMenu;
|
|
@@ -5,10 +5,12 @@ interface Position {
|
|
|
5
5
|
x: number;
|
|
6
6
|
y: number;
|
|
7
7
|
}
|
|
8
|
-
export declare const useMenuPosition: (menuRef: React.RefObject<HTMLDivElement | null>, position: Position) => {
|
|
8
|
+
export declare const useMenuPosition: (menuRef: React.RefObject<HTMLDivElement | null>, position: Position, itemsCount?: number) => {
|
|
9
9
|
isCalculated: boolean;
|
|
10
10
|
openLeft: boolean;
|
|
11
11
|
openUp: boolean;
|
|
12
|
+
needsScroll: boolean;
|
|
13
|
+
maxHeight: number | undefined;
|
|
12
14
|
};
|
|
13
15
|
export declare const getContextMenuTarget: <T extends {
|
|
14
16
|
id: string;
|
|
@@ -38,8 +38,8 @@ export const useClickOutside = (callback) => {
|
|
|
38
38
|
}, [callback]);
|
|
39
39
|
return ref;
|
|
40
40
|
};
|
|
41
|
-
export const useMenuPosition = (menuRef, position) => {
|
|
42
|
-
const [adjustedPosition, setAdjustedPosition] = useState({ openLeft: false, openUp: false });
|
|
41
|
+
export const useMenuPosition = (menuRef, position, itemsCount) => {
|
|
42
|
+
const [adjustedPosition, setAdjustedPosition] = useState({ openLeft: false, openUp: false, needsScroll: false, maxHeight: undefined });
|
|
43
43
|
const [isCalculated, setIsCalculated] = useState(false);
|
|
44
44
|
useLayoutEffect(() => {
|
|
45
45
|
if (!menuRef.current) {
|
|
@@ -49,14 +49,52 @@ export const useMenuPosition = (menuRef, position) => {
|
|
|
49
49
|
const menuRect = menuRef.current.getBoundingClientRect();
|
|
50
50
|
const viewportWidth = window.innerWidth;
|
|
51
51
|
const viewportHeight = window.innerHeight;
|
|
52
|
+
const isMobile = viewportWidth <= 768;
|
|
52
53
|
const spaceRight = viewportWidth - position.x;
|
|
53
54
|
const spaceBottom = viewportHeight - position.y;
|
|
55
|
+
const spaceAbove = position.y;
|
|
56
|
+
const padding = 8; // Minimal padding from viewport edges - be more aggressive about using available space
|
|
57
|
+
// Use scrollHeight to get natural content height, not constrained height
|
|
58
|
+
const menuHeight = menuRef.current.scrollHeight;
|
|
59
|
+
// Mobile: Always calculate max-height based on position to prevent overflow
|
|
60
|
+
if (isMobile) {
|
|
61
|
+
const maxHeightFromBottom = spaceBottom - padding;
|
|
62
|
+
const maxHeightFromTop = spaceAbove - padding;
|
|
63
|
+
const mobileMaxHeight = Math.max(maxHeightFromBottom, maxHeightFromTop);
|
|
64
|
+
setAdjustedPosition({
|
|
65
|
+
openLeft: spaceRight < menuRect.width + 20,
|
|
66
|
+
openUp: maxHeightFromTop > maxHeightFromBottom && menuHeight > maxHeightFromBottom,
|
|
67
|
+
needsScroll: menuHeight > mobileMaxHeight,
|
|
68
|
+
maxHeight: mobileMaxHeight,
|
|
69
|
+
});
|
|
70
|
+
setIsCalculated(true);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Desktop: Check if menu is too tall to fit in either direction
|
|
74
|
+
const fitsBelow = menuHeight + padding <= spaceBottom;
|
|
75
|
+
const fitsAbove = menuHeight + padding <= spaceAbove;
|
|
76
|
+
const needsScroll = !fitsBelow && !fitsAbove;
|
|
77
|
+
// Calculate max height when scrolling is needed
|
|
78
|
+
let maxHeight = undefined;
|
|
79
|
+
let shouldOpenUp = false;
|
|
80
|
+
if (needsScroll) {
|
|
81
|
+
// When scrolling is needed, open in the direction with MORE space
|
|
82
|
+
const availableSpace = Math.max(spaceBottom, spaceAbove);
|
|
83
|
+
maxHeight = availableSpace - padding;
|
|
84
|
+
shouldOpenUp = spaceAbove > spaceBottom; // Open upward if more space above
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Normal behavior: open up only if it fits above but not below
|
|
88
|
+
shouldOpenUp = !fitsBelow && fitsAbove;
|
|
89
|
+
}
|
|
54
90
|
setAdjustedPosition({
|
|
55
91
|
openLeft: spaceRight < menuRect.width + 20,
|
|
56
|
-
openUp:
|
|
92
|
+
openUp: shouldOpenUp,
|
|
93
|
+
needsScroll,
|
|
94
|
+
maxHeight,
|
|
57
95
|
});
|
|
58
96
|
setIsCalculated(true);
|
|
59
|
-
}, [position, menuRef]);
|
|
97
|
+
}, [position, menuRef, itemsCount]); // Added itemsCount to recalculate when menu content changes
|
|
60
98
|
return { ...adjustedPosition, isCalculated };
|
|
61
99
|
};
|
|
62
100
|
export const getContextMenuTarget = (event, focusedItem, selectedItem, dataSource, idPrefix, isMobile) => {
|
|
@@ -5,6 +5,8 @@ export declare const MenuContainer: import("styled-components/dist/types").IStyl
|
|
|
5
5
|
$openUp: boolean;
|
|
6
6
|
$isPositioned: boolean;
|
|
7
7
|
$externalControl?: boolean;
|
|
8
|
+
$needsScroll?: boolean;
|
|
9
|
+
$maxHeight?: number;
|
|
8
10
|
}>> & string;
|
|
9
11
|
export declare const MenuItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
10
12
|
$disabled?: boolean;
|
|
@@ -23,6 +25,8 @@ export declare const SubmenuIndicator: import("styled-components/dist/types").IS
|
|
|
23
25
|
export declare const Submenu: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
24
26
|
$parentRect: DOMRect;
|
|
25
27
|
$openUp?: boolean;
|
|
28
|
+
$needsScroll?: boolean;
|
|
29
|
+
$maxHeight?: number;
|
|
26
30
|
}>> & string;
|
|
27
31
|
export declare const MobileMenuHeader: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
28
32
|
export declare const BackButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
@@ -38,6 +38,35 @@ export const MenuContainer = styled.div `
|
|
|
38
38
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
39
39
|
opacity: ${props => props.$isPositioned ? 1 : 0};
|
|
40
40
|
transition: opacity 0.05s ease-in;
|
|
41
|
+
|
|
42
|
+
/* Add scrolling when menu is too tall to fit in either direction */
|
|
43
|
+
${props => props.$needsScroll && props.$maxHeight && `
|
|
44
|
+
max-height: ${props.$maxHeight}px;
|
|
45
|
+
overflow-y: auto;
|
|
46
|
+
overflow-x: hidden;
|
|
47
|
+
|
|
48
|
+
/* Smooth scrolling */
|
|
49
|
+
scroll-behavior: smooth;
|
|
50
|
+
|
|
51
|
+
/* Custom scrollbar styling */
|
|
52
|
+
&::-webkit-scrollbar {
|
|
53
|
+
width: 8px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
&::-webkit-scrollbar-track {
|
|
57
|
+
background: rgba(0, 0, 0, 0.05);
|
|
58
|
+
border-radius: 4px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&::-webkit-scrollbar-thumb {
|
|
62
|
+
background: rgba(0, 0, 0, 0.2);
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
67
|
+
background: rgba(0, 0, 0, 0.3);
|
|
68
|
+
}
|
|
69
|
+
`}
|
|
41
70
|
|
|
42
71
|
/* Reset color inheritance from parent with !important to override panel header styles */
|
|
43
72
|
& *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
@@ -57,9 +86,9 @@ export const MenuContainer = styled.div `
|
|
|
57
86
|
|
|
58
87
|
${props => props.$externalControl && `
|
|
59
88
|
@media (max-width: 768px) {
|
|
60
|
-
left:
|
|
61
|
-
right:
|
|
62
|
-
max-width: calc(100vw -
|
|
89
|
+
left: 75px !important;
|
|
90
|
+
right: 75px !important;
|
|
91
|
+
max-width: calc(100vw - 150px);
|
|
63
92
|
width: auto;
|
|
64
93
|
min-width: auto;
|
|
65
94
|
}
|
|
@@ -74,7 +103,7 @@ export const MenuItem = styled.div `
|
|
|
74
103
|
transition: all 0.15s ease;
|
|
75
104
|
position: relative;
|
|
76
105
|
user-select: none;
|
|
77
|
-
font-size: 13px;
|
|
106
|
+
font-size: var(--base-font-size, 13px);
|
|
78
107
|
color: ${props => props.$disabled ? '#999' : '#1a1a1a'};
|
|
79
108
|
font-weight: 500;
|
|
80
109
|
${props => props.$beginGroup && `
|
|
@@ -134,7 +163,7 @@ export const MenuItem = styled.div `
|
|
|
134
163
|
|
|
135
164
|
@media (max-width: 768px) {
|
|
136
165
|
padding: 4px 10px;
|
|
137
|
-
font-size:
|
|
166
|
+
font-size: calc(var(--base-font-size, 13px) * 0.92);
|
|
138
167
|
}
|
|
139
168
|
`;
|
|
140
169
|
export const MenuItemContent = styled.div `
|
|
@@ -147,7 +176,7 @@ export const IconWrapper = styled.span `
|
|
|
147
176
|
display: flex;
|
|
148
177
|
align-items: center;
|
|
149
178
|
justify-content: center;
|
|
150
|
-
font-size:
|
|
179
|
+
font-size: calc(var(--base-font-size, 13px) * 1.08);
|
|
151
180
|
width: 18px;
|
|
152
181
|
height: 18px;
|
|
153
182
|
`;
|
|
@@ -170,7 +199,7 @@ export const RightIconButton = styled.button.attrs({
|
|
|
170
199
|
padding: 4px 8px;
|
|
171
200
|
margin-left: 8px;
|
|
172
201
|
border-radius: 6px;
|
|
173
|
-
font-size:
|
|
202
|
+
font-size: calc(var(--base-font-size, 13px) * 1.08);
|
|
174
203
|
opacity: 0 !important;
|
|
175
204
|
transition: opacity 0.15s ease, background 0.15s ease, transform 0.15s ease;
|
|
176
205
|
|
|
@@ -192,7 +221,7 @@ export const RightIconButton = styled.button.attrs({
|
|
|
192
221
|
export const SubmenuIndicator = styled.span `
|
|
193
222
|
display: flex;
|
|
194
223
|
align-items: center;
|
|
195
|
-
font-size:
|
|
224
|
+
font-size: calc(var(--base-font-size, 13px) * 0.92);
|
|
196
225
|
margin-left: 8px;
|
|
197
226
|
opacity: 0.6;
|
|
198
227
|
transition: transform 0.15s ease;
|
|
@@ -272,6 +301,69 @@ export const Submenu = styled.div `
|
|
|
272
301
|
[data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
273
302
|
color: #e0e0e0 !important;
|
|
274
303
|
}
|
|
304
|
+
|
|
305
|
+
/* Dynamic scroll handling when submenu is too tall */
|
|
306
|
+
${props => props.$needsScroll && props.$maxHeight ? `
|
|
307
|
+
max-height: ${props.$maxHeight}px;
|
|
308
|
+
overflow-y: auto;
|
|
309
|
+
overflow-x: hidden;
|
|
310
|
+
|
|
311
|
+
/* Custom scrollbar styling for submenus */
|
|
312
|
+
&::-webkit-scrollbar {
|
|
313
|
+
width: 8px;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
&::-webkit-scrollbar-track {
|
|
317
|
+
background: rgba(0, 0, 0, 0.05);
|
|
318
|
+
border-radius: 4px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
&::-webkit-scrollbar-thumb {
|
|
322
|
+
background: rgba(0, 0, 0, 0.2);
|
|
323
|
+
border-radius: 4px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
327
|
+
background: rgba(0, 0, 0, 0.3);
|
|
328
|
+
}
|
|
329
|
+
` : `
|
|
330
|
+
/* Fallback max-height for submenus that fit */
|
|
331
|
+
max-height: calc(100vh - 40px);
|
|
332
|
+
overflow-y: auto;
|
|
333
|
+
overflow-x: hidden;
|
|
334
|
+
|
|
335
|
+
&::-webkit-scrollbar {
|
|
336
|
+
width: 8px;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
&::-webkit-scrollbar-track {
|
|
340
|
+
background: rgba(0, 0, 0, 0.05);
|
|
341
|
+
border-radius: 4px;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
&::-webkit-scrollbar-thumb {
|
|
345
|
+
background: rgba(0, 0, 0, 0.2);
|
|
346
|
+
border-radius: 4px;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
350
|
+
background: rgba(0, 0, 0, 0.3);
|
|
351
|
+
}
|
|
352
|
+
`}
|
|
353
|
+
|
|
354
|
+
[data-theme='dark'] & {
|
|
355
|
+
&::-webkit-scrollbar-track {
|
|
356
|
+
background: rgba(255, 255, 255, 0.05);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
&::-webkit-scrollbar-thumb {
|
|
360
|
+
background: rgba(255, 255, 255, 0.2);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
364
|
+
background: rgba(255, 255, 255, 0.3);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
275
367
|
`;
|
|
276
368
|
export const MobileMenuHeader = styled.div `
|
|
277
369
|
display: flex;
|
|
@@ -307,7 +399,7 @@ export const BackButton = styled.button `
|
|
|
307
399
|
`;
|
|
308
400
|
export const HeaderTitle = styled.h3 `
|
|
309
401
|
margin: 0;
|
|
310
|
-
font-size:
|
|
402
|
+
font-size: calc(var(--base-font-size, 13px) * 1.23);
|
|
311
403
|
font-weight: 600;
|
|
312
404
|
color: #1a1a1a;
|
|
313
405
|
flex: 1;
|
|
@@ -48,6 +48,7 @@ import { useCheckInOutOperations } from '../../../hooks/useCheckInOutOperations'
|
|
|
48
48
|
import TMDcmtCheckoutInfoForm from './TMDcmtCheckoutInfoForm';
|
|
49
49
|
import { useDataListItem } from '../../../hooks/useDataListItem';
|
|
50
50
|
import { useDataUserIdItem } from '../../../hooks/useDataUserIdItem';
|
|
51
|
+
import { LoadIndicator } from 'devextreme-react';
|
|
51
52
|
let abortControllerLocal = new AbortController();
|
|
52
53
|
//#region Helper Methods
|
|
53
54
|
export const getSearchResultCountersSingleCategory = (searchResults) => {
|
|
@@ -795,9 +796,6 @@ const TMSearchResult = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, a
|
|
|
795
796
|
}, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), (showSignSettingsForm && fromDTD) && _jsx(TMSignSettingsForm, { fromDTD: fromDTD, inputDcmts: allFieldSelectedDocs, onCloseSignSettingsForm: closeSignSettingsForm, onSavedAsyncCallback: handleSavedAsyncCallback }), (showHistory && fromDTD && getSelectedDcmtsOrFocused(selectedItems, focusedItem).length > 0) && _jsx(TMViewHistoryDcmt, { fromDTD: fromDTD, deviceType: deviceType, inputDcmt: getSelectedDcmtsOrFocused(selectedItems, focusedItem)[0], onClose: hideHistoryCallback, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), (commentFormState.show && getSelectedDcmtsOrFocused(selectedItems, focusedItem).length > 0) && _jsx(TMBlogCommentForm, { context: { engine: 'SearchEngine', object: { tid: getSelectedDcmtsOrFocused(selectedItems, focusedItem)[0].TID, did: getSelectedDcmtsOrFocused(selectedItems, focusedItem)[0].DID } }, onClose: hideCommentFormCallback, refreshCallback: triggerBlogRefresh, participants: [], showAttachmentsSection: true, allArchivedDocumentsFileItems: convertSearchResultDescriptorToFileItems(currentSearchResults ?? []), isCommentRequired: commentFormState.isRequired, removeAndEditAttachment: commentFormState.removeAndEditAttachment, selectedAttachmentDid: [Number(getSelectedDcmtsOrFocused(selectedItems, focusedItem)[0].DID)] })] }));
|
|
796
797
|
};
|
|
797
798
|
export default TMSearchResult;
|
|
798
|
-
const renderDcmtIcon = (cellData, onDownloadDcmtsAsync, openInOffice) => {
|
|
799
|
-
return _jsx(TMDcmtIcon, { tid: cellData.data.TID, did: cellData.data.DID, fileExtension: cellData.data.FILEEXT, fileCount: cellData.data.FILECOUNT, isLexProt: cellData.data.IsLexProt, isMail: cellData.data.ISMAIL, isShared: cellData.data.ISSHARED, isSigned: cellData.data.ISSIGNED, downloadMode: 'openInNewWindow', onDownloadDcmtsAsync: onDownloadDcmtsAsync, openInOffice: openInOffice });
|
|
800
|
-
};
|
|
801
799
|
const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem, showSearch, allowMultipleSelection = true, showExportForm = false, onCloseExportForm, onFocusedItemChanged, onDownloadDcmtsAsync, onVisibleItemChanged, inputSelectedItems = [], lastUpdateSearchTime, searchResult, floatingMenuItems, onSelectionChanged, onDblClick }) => {
|
|
802
800
|
const [dataSource, setDataSource] = useState();
|
|
803
801
|
const [columns, setColumns] = useState([]);
|
|
@@ -806,6 +804,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
806
804
|
const [focusedItem, setFocusedItem] = useState();
|
|
807
805
|
const [visibleItems, setVisibleItems] = useState([]);
|
|
808
806
|
const [pageSize, setPageSize] = useState(SDKUI_Globals.userSettings.searchSettings?.pageSize ?? TMDataGridPageSize.Large);
|
|
807
|
+
const [isDataGridReady, setIsDataGridReady] = useState(false);
|
|
809
808
|
const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
|
|
810
809
|
const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
|
|
811
810
|
useEffect(() => {
|
|
@@ -882,6 +881,9 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
882
881
|
}
|
|
883
882
|
}
|
|
884
883
|
}, [inputSelectedItems, inputFocusedItem, dataSource]);
|
|
884
|
+
const cellRenderDcmtIcon = useCallback((cellData, onDownloadDcmtsAsync, openInOffice) => {
|
|
885
|
+
return _jsx(TMDcmtIcon, { tid: cellData.data.TID, did: cellData.data.DID, fileExtension: cellData.data.FILEEXT, fileCount: cellData.data.FILECOUNT, isLexProt: cellData.data.IsLexProt, isMail: cellData.data.ISMAIL, isShared: cellData.data.ISSHARED, isSigned: cellData.data.ISSIGNED, downloadMode: 'openInNewWindow', onDownloadDcmtsAsync: onDownloadDcmtsAsync, openInOffice: openInOffice });
|
|
886
|
+
}, []);
|
|
885
887
|
const cellRender = useCallback((cellData, dataDomain, dataListID, dataListViewMode) => {
|
|
886
888
|
if (!cellData || cellData.value === undefined)
|
|
887
889
|
return null;
|
|
@@ -1040,6 +1042,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
1040
1042
|
const loadColumnsAndData = async () => {
|
|
1041
1043
|
// Resetta l'elemento focalizzato quando si caricano nuovi dati
|
|
1042
1044
|
setFocusedItem(undefined);
|
|
1045
|
+
setIsDataGridReady(false);
|
|
1043
1046
|
// Set per raccogliere gli ID univoci da precaricare
|
|
1044
1047
|
const dataListIDs = new Set();
|
|
1045
1048
|
const userIDs = new Set();
|
|
@@ -1076,6 +1079,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
1076
1079
|
// Converte i risultati di ricerca in un array semplice per la griglia
|
|
1077
1080
|
let newDataSource = searchResultDescriptorToSimpleArray(searchResult);
|
|
1078
1081
|
setDataSource(newDataSource);
|
|
1082
|
+
setIsDataGridReady(true);
|
|
1079
1083
|
};
|
|
1080
1084
|
loadColumnsAndData();
|
|
1081
1085
|
}, [searchResult, fromDTD, allUsers, loadDataListsAsync, loadUsersAsync, generateColumns]);
|
|
@@ -1126,10 +1130,6 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
1126
1130
|
onDblClick();
|
|
1127
1131
|
}, [onDblClick]);
|
|
1128
1132
|
const dataColumns = useMemo(() => {
|
|
1129
|
-
// Aspetta che le colonne siano completamente caricate
|
|
1130
|
-
if (!columns || columns.length === 0) {
|
|
1131
|
-
return [];
|
|
1132
|
-
}
|
|
1133
1133
|
return [
|
|
1134
1134
|
{
|
|
1135
1135
|
dataType: "object",
|
|
@@ -1137,7 +1137,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
1137
1137
|
caption: '',
|
|
1138
1138
|
visible: true,
|
|
1139
1139
|
width: 50,
|
|
1140
|
-
cellRender: (cellData) =>
|
|
1140
|
+
cellRender: (cellData) => cellRenderDcmtIcon(cellData, onDownloadDcmtsAsync, openInOffice),
|
|
1141
1141
|
allowResizing: false,
|
|
1142
1142
|
filterOperations: ['=', "anyof"],
|
|
1143
1143
|
allowHiding: false,
|
|
@@ -1154,7 +1154,7 @@ const TMSearchResultGrid = ({ openInOffice, fromDTD, allUsers, inputFocusedItem,
|
|
|
1154
1154
|
setVisibleItems(visibleRows.map((row) => { return row.data; }));
|
|
1155
1155
|
}, []);
|
|
1156
1156
|
useEffect(() => { onVisibleItemChanged?.(visibleItems); }, [visibleItems]);
|
|
1157
|
-
return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx(TMDataGrid, { id: "tm-search-result", keyExpr: "rowIndex", dataColumns: dataColumns, dataSource: dataSource, repaintChangesOnly: true, selectedRowKeys: selectedRowKeys, focusedRowKey: Number(focusedItem?.rowIndex ?? 0), showSearchPanel: showSearch, showFilterPanel: true, sorting: { mode: "multiple" }, selection: { mode: allowMultipleSelection ? 'multiple' : 'single' }, pageSize: pageSize, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: floatingMenuItems, counterConfig: { show: true } }), (showExportForm && searchResult && onCloseExportForm) && _jsx(TMDataGridExportForm, { dataColumns: dataColumns, dataSource: dataSource, selectedRowKeys: selectedRowKeys, onCloseExportForm: onCloseExportForm, searchResult: searchResult })] });
|
|
1157
|
+
return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [!isDataGridReady && (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', width: '100%', gap: '10px' }, children: [_jsx(LoadIndicator, { height: 60, width: 60 }), _jsx("div", { children: SDKUI_Localizator.Loading })] })), isDataGridReady && _jsx(TMDataGrid, { id: "tm-search-result", keyExpr: "rowIndex", dataColumns: dataColumns, dataSource: dataSource, repaintChangesOnly: true, selectedRowKeys: selectedRowKeys, focusedRowKey: Number(focusedItem?.rowIndex ?? 0), showSearchPanel: showSearch, showFilterPanel: true, sorting: { mode: "multiple" }, selection: { mode: allowMultipleSelection ? 'multiple' : 'single' }, pageSize: pageSize, onSelectionChanged: handleSelectionChange, onFocusedRowChanged: handleFocusedRowChange, onRowDblClick: onRowDblClick, onContentReady: onContentReady, showHeaderColumnChooser: true, onKeyDown: onKeyDown, customContextMenuItems: floatingMenuItems, counterConfig: { show: true } }), (showExportForm && searchResult && onCloseExportForm) && _jsx(TMDataGridExportForm, { dataColumns: dataColumns, dataSource: dataSource, selectedRowKeys: selectedRowKeys, onCloseExportForm: onCloseExportForm, searchResult: searchResult })] });
|
|
1158
1158
|
};
|
|
1159
1159
|
//#region TMSearchResultSelector
|
|
1160
1160
|
const StyledItemTemplate = styled.div `
|
|
@@ -2,7 +2,7 @@ import { Appointment } from 'devextreme/ui/scheduler';
|
|
|
2
2
|
import { ContextMenuTypes } from 'devextreme-react/context-menu';
|
|
3
3
|
import { TaskDescriptor, Task_States, PdGs, Priorities, ValidationItem } from '@topconsultnpm/sdk-ts';
|
|
4
4
|
import { FormModes, TaskContext } from '../../../ts';
|
|
5
|
-
import {
|
|
5
|
+
import { TMDataGridContextMenuItem } from '../../base/TMDataGrid';
|
|
6
6
|
export declare const TEXT_SELECTED_COLOR = "#ff5e1a";
|
|
7
7
|
export declare const BG_COLOR_INACTIVE_WIDGET = "#fff";
|
|
8
8
|
export declare const BG_COLOR_ACTIVE_WIDGET = "#fff0b7";
|
|
@@ -100,7 +100,7 @@ export declare const gotoPDGExtendedLabel: (gotoVisible: boolean, pdg: PdGs, iD1
|
|
|
100
100
|
export declare const convertToSchedulerAppointments: (tasks: Array<TaskDescriptor>) => Array<Appointment>;
|
|
101
101
|
export declare const formatDate: (date: Date) => string;
|
|
102
102
|
export declare const areDifferentIDs: (fromID: number | undefined, userID: number | undefined) => boolean;
|
|
103
|
-
export declare const createTasksMenuItems: (taskDescriptor: TaskDescriptor | undefined, showId: boolean, setShowId: React.Dispatch<React.SetStateAction<boolean>>, showSearch: boolean, setShowSearch: React.Dispatch<React.SetStateAction<boolean>>, openTaskForm: (formMode: FormModes, task?: TaskDescriptor, isContextual?: boolean) => void, openEditTaskForm: (rowId: number | undefined) => void, openDuplicateTaskForm: (rowId: number | undefined) => void, onDeleteCallback: (rowIds: Array<number>) => void, markAsStatus: (rowIds: Array<number>, status: Task_States) => void, getAllTasks: () => Promise<void>, fromWG: boolean, showContextualWG: boolean, setShowContextualWG: React.Dispatch<React.SetStateAction<boolean>>, fromDossier: boolean, showContextualDossier: boolean, setShowContextualDossier: React.Dispatch<React.SetStateAction<boolean>>, fromDocument: boolean, showContextualDocument: boolean, setShowContextualDocument: React.Dispatch<React.SetStateAction<boolean>>, showGoToToday: boolean, handleGoToToday?: () => void, fromDatagrid?: boolean) =>
|
|
103
|
+
export declare const createTasksMenuItems: (taskDescriptor: TaskDescriptor | undefined, showId: boolean, setShowId: React.Dispatch<React.SetStateAction<boolean>>, showSearch: boolean, setShowSearch: React.Dispatch<React.SetStateAction<boolean>>, openTaskForm: (formMode: FormModes, task?: TaskDescriptor, isContextual?: boolean) => void, openEditTaskForm: (rowId: number | undefined) => void, openDuplicateTaskForm: (rowId: number | undefined) => void, onDeleteCallback: (rowIds: Array<number>) => void, markAsStatus: (rowIds: Array<number>, status: Task_States) => void, getAllTasks: () => Promise<void>, fromWG: boolean, showContextualWG: boolean, setShowContextualWG: React.Dispatch<React.SetStateAction<boolean>>, fromDossier: boolean, showContextualDossier: boolean, setShowContextualDossier: React.Dispatch<React.SetStateAction<boolean>>, fromDocument: boolean, showContextualDocument: boolean, setShowContextualDocument: React.Dispatch<React.SetStateAction<boolean>>, showGoToToday: boolean, handleGoToToday?: () => void, fromDatagrid?: boolean) => Array<TMDataGridContextMenuItem>;
|
|
104
104
|
export declare const checkIfNew: (fromId: number | undefined, isNew: number | undefined) => boolean;
|
|
105
105
|
export declare const getNewTaskCount: (tasks: Array<TaskDescriptor>) => number;
|
|
106
106
|
export declare const isTaskAssignedToAnotherUser: (task: TaskDescriptor) => boolean;
|