@topconsultnpm/sdkui-react 6.20.0-dev1.66 → 6.20.0-dev1.68
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 +23 -6
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +44 -2
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +1 -0
- package/lib/components/NewComponents/FloatingMenuBar/styles.js +45 -11
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +2 -1
- package/lib/components/features/workflow/TMWorkflowPopup.js +24 -12
- package/package.json +1 -1
|
@@ -59,6 +59,8 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
59
59
|
const touchEvent = e;
|
|
60
60
|
const element = e.currentTarget;
|
|
61
61
|
const touch = touchEvent.touches[0];
|
|
62
|
+
// Prevent text selection during long press
|
|
63
|
+
e.preventDefault();
|
|
62
64
|
let state = touchStateMap.get(element);
|
|
63
65
|
if (!state) {
|
|
64
66
|
state = { timeout: null, startX: 0, startY: 0, longPressTriggered: false };
|
|
@@ -75,16 +77,27 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
75
77
|
// Haptic feedback
|
|
76
78
|
if ('vibrate' in navigator)
|
|
77
79
|
navigator.vibrate(50);
|
|
78
|
-
|
|
80
|
+
// First, trigger a click to select/focus the item
|
|
81
|
+
const clickEvent = new MouseEvent('click', {
|
|
79
82
|
bubbles: true,
|
|
80
83
|
cancelable: true,
|
|
81
84
|
clientX: touch.clientX,
|
|
82
85
|
clientY: touch.clientY,
|
|
83
86
|
});
|
|
84
|
-
element.dispatchEvent(
|
|
87
|
+
element.dispatchEvent(clickEvent);
|
|
88
|
+
// Small delay to ensure click is processed before opening context menu
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
const syntheticEvent = new MouseEvent('contextmenu', {
|
|
91
|
+
bubbles: true,
|
|
92
|
+
cancelable: true,
|
|
93
|
+
clientX: touch.clientX,
|
|
94
|
+
clientY: touch.clientY,
|
|
95
|
+
});
|
|
96
|
+
element.dispatchEvent(syntheticEvent);
|
|
97
|
+
}, 10);
|
|
85
98
|
if (state)
|
|
86
99
|
state.timeout = null;
|
|
87
|
-
},
|
|
100
|
+
}, 400);
|
|
88
101
|
};
|
|
89
102
|
const handleTouchMove = (e) => {
|
|
90
103
|
const touchEvent = e;
|
|
@@ -122,14 +135,16 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
122
135
|
// Attach listeners to all matching elements
|
|
123
136
|
elements.forEach(element => {
|
|
124
137
|
const el = element;
|
|
125
|
-
// Prevent iOS native callout
|
|
138
|
+
// Prevent iOS native callout and text selection
|
|
126
139
|
const style = el.style;
|
|
127
140
|
style.webkitTouchCallout = 'none';
|
|
128
141
|
style.webkitUserSelect = 'none';
|
|
129
|
-
|
|
142
|
+
style.userSelect = 'none';
|
|
143
|
+
el.addEventListener('touchstart', handleTouchStart, { passive: false });
|
|
130
144
|
el.addEventListener('touchmove', handleTouchMove, { passive: true });
|
|
131
145
|
el.addEventListener('touchend', handleTouchEnd);
|
|
132
146
|
el.addEventListener('touchcancel', handleTouchEnd);
|
|
147
|
+
el.addEventListener('contextmenu', (e) => e.preventDefault(), { capture: true });
|
|
133
148
|
el.addEventListener('click', handleClick, { capture: true });
|
|
134
149
|
});
|
|
135
150
|
return () => {
|
|
@@ -138,6 +153,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
138
153
|
const style = el.style;
|
|
139
154
|
style.webkitTouchCallout = '';
|
|
140
155
|
style.webkitUserSelect = '';
|
|
156
|
+
style.userSelect = '';
|
|
141
157
|
el.removeEventListener('touchstart', handleTouchStart);
|
|
142
158
|
el.removeEventListener('touchmove', handleTouchMove);
|
|
143
159
|
el.removeEventListener('touchend', handleTouchEnd);
|
|
@@ -268,7 +284,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
268
284
|
parentNames: [],
|
|
269
285
|
});
|
|
270
286
|
}
|
|
271
|
-
},
|
|
287
|
+
}, 400);
|
|
272
288
|
};
|
|
273
289
|
const handleTouchMove = (e) => {
|
|
274
290
|
if (!isIOS || trigger !== 'right' || !touchStartPos.current)
|
|
@@ -411,6 +427,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
411
427
|
display: 'inline-block',
|
|
412
428
|
WebkitTouchCallout: isIOS ? 'none' : undefined,
|
|
413
429
|
WebkitUserSelect: isIOS ? 'none' : undefined,
|
|
430
|
+
userSelect: isIOS ? 'none' : undefined,
|
|
414
431
|
}, 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)] }));
|
|
415
432
|
};
|
|
416
433
|
export default TMContextMenu;
|
|
@@ -4,7 +4,8 @@ import { ContextMenu } from '../ContextMenu';
|
|
|
4
4
|
import ShowAlert from '../../base/TMAlert';
|
|
5
5
|
import TMTooltip from '../../base/TMTooltip';
|
|
6
6
|
import * as S from './styles';
|
|
7
|
-
import { IconAdd,
|
|
7
|
+
import { IconAdd, IconCloseOutline, IconMenuVertical, IconPin, IconSave, IconSeparator, IconUndo, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
|
|
8
|
+
import { ButtonNames, TMMessageBoxManager } from '../../base/TMPopUp';
|
|
8
9
|
const Separator = (props) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M12 2v20", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }) }));
|
|
9
10
|
const IconDraggableDots = (props) => (_jsx("svg", { fontSize: 18, viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M9 3a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm10-18a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0z" }) }));
|
|
10
11
|
const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 100, y: 100 }, maxItems = 100, }) => {
|
|
@@ -603,6 +604,45 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
603
604
|
const snapshotIds = stateSnapshot.current.items.map(i => i.id).join(',');
|
|
604
605
|
return currentIds !== snapshotIds;
|
|
605
606
|
};
|
|
607
|
+
const handleClose = () => {
|
|
608
|
+
// If all items removed, exit without asking and restore last items
|
|
609
|
+
if (state.items.length === 0 && stateSnapshot.current) {
|
|
610
|
+
setState(s => ({
|
|
611
|
+
...s,
|
|
612
|
+
items: [...stateSnapshot.current.items],
|
|
613
|
+
orientation: stateSnapshot.current.orientation,
|
|
614
|
+
position: { ...stateSnapshot.current.position },
|
|
615
|
+
isConfigMode: false,
|
|
616
|
+
}));
|
|
617
|
+
stateSnapshot.current = null;
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
// If no changes, simply exit config mode
|
|
621
|
+
if (!hasChanges()) {
|
|
622
|
+
stateSnapshot.current = null;
|
|
623
|
+
const cleanedItems = removeTrailingSeparators(state.items);
|
|
624
|
+
setState(s => ({ ...s, isConfigMode: false, items: cleanedItems }));
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
// If there are changes, ask for confirmation
|
|
628
|
+
TMMessageBoxManager.show({
|
|
629
|
+
message: 'Perderai le tue modifiche, sei sicuro?',
|
|
630
|
+
buttons: [ButtonNames.YES, ButtonNames.NO],
|
|
631
|
+
onButtonClick: (buttonName) => {
|
|
632
|
+
if (buttonName === ButtonNames.YES && stateSnapshot.current) {
|
|
633
|
+
// Restore snapshot and exit config mode
|
|
634
|
+
setState(s => ({
|
|
635
|
+
...s,
|
|
636
|
+
items: [...stateSnapshot.current.items],
|
|
637
|
+
orientation: stateSnapshot.current.orientation,
|
|
638
|
+
position: { ...stateSnapshot.current.position },
|
|
639
|
+
isConfigMode: false,
|
|
640
|
+
}));
|
|
641
|
+
stateSnapshot.current = null;
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
});
|
|
645
|
+
};
|
|
606
646
|
const toggleOrientation = () => {
|
|
607
647
|
const newOrientation = state.orientation === 'horizontal' ? 'vertical' : 'horizontal';
|
|
608
648
|
if (state.orientation === 'horizontal' && newOrientation === 'vertical') {
|
|
@@ -740,6 +780,8 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
740
780
|
currentOnClick();
|
|
741
781
|
}
|
|
742
782
|
}, disabled: state.isConfigMode ? isDisabled && !state.isConfigMode : isDisabled, children: item.icon }) }), state.isConfigMode && (_jsx(S.RemoveButton, { onClick: () => removeItem(item.id), children: "\u00D7" }))] }, item.id));
|
|
743
|
-
}), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: true, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) })), state.isConfigMode && state.items.length < maxItems && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getPinContextMenuItems(), trigger: "left", keepOpenOnClick: true, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx(S.AddButton, { children: _jsx(IconAdd, {}) }) }) })), state.isConfigMode && (_jsxs(_Fragment, { children: [_jsx(S.Separator, { "$orientation": state.orientation }), _jsxs(S.ButtonGroup, { "$orientation": state.orientation, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Undo, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.UndoButton, { onClick: handleUndo, disabled: !hasChanges(), children: _jsx(IconUndo, { fontSize: 18 }) }) }), _jsx(TMTooltip, { content: state.items.length === 0
|
|
783
|
+
}), !state.isConfigMode && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getContextMenuItemsWithPinIcons(), trigger: "left", keepOpenOnClick: true, children: _jsx(S.ContextMenuButton, { children: _jsx(IconMenuVertical, {}) }) })), state.isConfigMode && state.items.length < maxItems && contextMenuItems.length > 0 && (_jsx(ContextMenu, { items: getPinContextMenuItems(), trigger: "left", keepOpenOnClick: true, children: _jsx(TMTooltip, { content: SDKUI_Localizator.Add, children: _jsx(S.AddButton, { children: _jsx(IconAdd, {}) }) }) })), state.isConfigMode && (_jsxs(_Fragment, { children: [_jsx(S.Separator, { "$orientation": state.orientation }), _jsxs(S.ButtonGroup, { "$orientation": state.orientation, children: [_jsx(TMTooltip, { content: SDKUI_Localizator.Undo, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.UndoButton, { onClick: handleUndo, disabled: !hasChanges(), children: _jsx(IconUndo, { fontSize: 18 }) }) }), _jsx(TMTooltip, { content: state.items.length === 0
|
|
784
|
+
? 'Devi aggiungere almeno un item'
|
|
785
|
+
: SDKUI_Localizator.Save, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.ApplyButton, { onClick: toggleConfigMode, disabled: state.items.length === 0 || !hasChanges(), children: _jsx(IconSave, { fontSize: 20 }) }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.Close, position: state.orientation === 'horizontal' ? 'right' : 'top', children: _jsx(S.CloseButton, { onClick: handleClose, children: _jsx(IconCloseOutline, { fontSize: 20 }) }) })] })] }))] })] }));
|
|
744
786
|
};
|
|
745
787
|
export default TMFloatingMenuBar;
|
|
@@ -33,6 +33,7 @@ export declare const MenuButton: import("styled-components/dist/types").IStyledC
|
|
|
33
33
|
}>> & string;
|
|
34
34
|
export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
35
35
|
export declare const ApplyButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
36
|
+
export declare const CloseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
|
|
36
37
|
export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
|
|
37
38
|
$isActive?: boolean;
|
|
38
39
|
}, "ref"> & {
|
|
@@ -74,7 +74,7 @@ export const GripHandle = styled.div `
|
|
|
74
74
|
display: flex;
|
|
75
75
|
align-items: center;
|
|
76
76
|
justify-content: center;
|
|
77
|
-
padding: ${props => props.$orientation === 'horizontal' ? '
|
|
77
|
+
padding: ${props => props.$orientation === 'horizontal' ? '6px 4px' : '4px 6px'};
|
|
78
78
|
cursor: grab;
|
|
79
79
|
color: rgba(255, 255, 255, 0.7);
|
|
80
80
|
transition: all 0.2s ease;
|
|
@@ -98,7 +98,7 @@ export const GripHandle = styled.div `
|
|
|
98
98
|
export const Separator = styled.div `
|
|
99
99
|
background: rgba(255, 255, 255, 0.25);
|
|
100
100
|
width: ${props => props.$orientation === 'horizontal' ? '1px' : '100%'};
|
|
101
|
-
height: ${props => props.$orientation === 'horizontal' ? '
|
|
101
|
+
height: ${props => props.$orientation === 'horizontal' ? '20px' : '1px'};
|
|
102
102
|
margin: ${props => props.$orientation === 'horizontal' ? '0 4px' : '4px 0'};
|
|
103
103
|
flex-shrink: 0;
|
|
104
104
|
`;
|
|
@@ -111,8 +111,8 @@ export const ItemSeparator = styled.div `
|
|
|
111
111
|
display: flex;
|
|
112
112
|
align-items: center;
|
|
113
113
|
justify-content: center;
|
|
114
|
-
width:
|
|
115
|
-
height:
|
|
114
|
+
width: 30px;
|
|
115
|
+
height: 30px;
|
|
116
116
|
background: transparent;
|
|
117
117
|
border-radius: 8px;
|
|
118
118
|
cursor: grab;
|
|
@@ -122,7 +122,7 @@ export const ItemSeparator = styled.div `
|
|
|
122
122
|
content: '';
|
|
123
123
|
background: rgba(255, 255, 255, 0.25);
|
|
124
124
|
width: ${props.$orientation === 'horizontal' ? '2px' : '100%'};
|
|
125
|
-
height: ${props.$orientation === 'horizontal' ? '
|
|
125
|
+
height: ${props.$orientation === 'horizontal' ? '18px' : '2px'};
|
|
126
126
|
border-radius: 1px;
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -137,7 +137,7 @@ export const ItemSeparator = styled.div `
|
|
|
137
137
|
/* Normal mode: simple line with tight spacing */
|
|
138
138
|
background: rgba(255, 255, 255, 0.25);
|
|
139
139
|
width: ${props.$orientation === 'horizontal' ? '1px' : '100%'};
|
|
140
|
-
height: ${props.$orientation === 'horizontal' ? '
|
|
140
|
+
height: ${props.$orientation === 'horizontal' ? '20px' : '1px'};
|
|
141
141
|
margin: ${props.$orientation === 'horizontal' ? '0 2px' : '2px 0'};
|
|
142
142
|
`}
|
|
143
143
|
`;
|
|
@@ -145,8 +145,8 @@ export const MenuButton = styled.button `
|
|
|
145
145
|
display: flex;
|
|
146
146
|
align-items: center;
|
|
147
147
|
justify-content: center;
|
|
148
|
-
width:
|
|
149
|
-
height:
|
|
148
|
+
width: 30px;
|
|
149
|
+
height: 30px;
|
|
150
150
|
background: transparent;
|
|
151
151
|
border: none;
|
|
152
152
|
border-radius: 8px;
|
|
@@ -243,6 +243,40 @@ export const ApplyButton = styled.button `
|
|
|
243
243
|
height: 20px;
|
|
244
244
|
}
|
|
245
245
|
`;
|
|
246
|
+
export const CloseButton = styled.button `
|
|
247
|
+
display: flex;
|
|
248
|
+
align-items: center;
|
|
249
|
+
justify-content: center;
|
|
250
|
+
width: 24px;
|
|
251
|
+
height: 24px;
|
|
252
|
+
background: transparent;
|
|
253
|
+
border: none;
|
|
254
|
+
border-radius: 4px;
|
|
255
|
+
color: rgba(239, 68, 68, 1);
|
|
256
|
+
font-size: 10px;
|
|
257
|
+
cursor: pointer;
|
|
258
|
+
transition: all 0.2s ease;
|
|
259
|
+
padding: 3px;
|
|
260
|
+
|
|
261
|
+
&:hover:not(:disabled) {
|
|
262
|
+
background: rgba(255, 255, 255, 0.1);
|
|
263
|
+
color: rgba(239, 68, 68, 1);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
&:active:not(:disabled) {
|
|
267
|
+
transform: scale(0.9);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
&:disabled {
|
|
271
|
+
opacity: 0.3;
|
|
272
|
+
cursor: default;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
svg {
|
|
276
|
+
width: 20px;
|
|
277
|
+
height: 20px;
|
|
278
|
+
}
|
|
279
|
+
`;
|
|
246
280
|
export const ContextMenuButton = styled(MenuButton) `
|
|
247
281
|
svg {
|
|
248
282
|
transform: translateY(0);
|
|
@@ -252,13 +286,13 @@ export const AddButton = styled.button `
|
|
|
252
286
|
display: flex;
|
|
253
287
|
align-items: center;
|
|
254
288
|
justify-content: center;
|
|
255
|
-
width:
|
|
256
|
-
height:
|
|
289
|
+
width: 26px;
|
|
290
|
+
height: 26px;
|
|
257
291
|
background: rgba(255, 255, 255, 0.15);
|
|
258
292
|
border: 1px dashed rgba(255, 255, 255, 0.4);
|
|
259
293
|
border-radius: 8px;
|
|
260
294
|
color: white;
|
|
261
|
-
font-size:
|
|
295
|
+
font-size: 18px;
|
|
262
296
|
font-weight: bold;
|
|
263
297
|
line-height: 0;
|
|
264
298
|
cursor: pointer;
|
|
@@ -25,7 +25,7 @@ export declare const WorkFlowApproveRejectPopUp: ({ TID, DID, deviceType, isReje
|
|
|
25
25
|
onClose?: () => void;
|
|
26
26
|
onCompleted?: () => Promise<void>;
|
|
27
27
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
28
|
-
export declare const WorkFlowReAssignPopUp: ({ DID, TID, deviceType, onClose, selectedItems, onCompleted, wf }: {
|
|
28
|
+
export declare const WorkFlowReAssignPopUp: ({ DID, TID, deviceType, onClose, selectedItems, onCompleted, wf, workItemDetail }: {
|
|
29
29
|
TID?: number;
|
|
30
30
|
DID?: number;
|
|
31
31
|
deviceType?: DeviceType;
|
|
@@ -33,6 +33,7 @@ export declare const WorkFlowReAssignPopUp: ({ DID, TID, deviceType, onClose, se
|
|
|
33
33
|
selectedItems?: any[];
|
|
34
34
|
onCompleted?: () => Promise<void>;
|
|
35
35
|
wf?: WFDescriptor;
|
|
36
|
+
workItemDetail?: WorkItemDetail;
|
|
36
37
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
37
38
|
/**
|
|
38
39
|
* Modal per forzare l'approvazione di un work item
|
|
@@ -95,6 +95,7 @@ export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = Devi
|
|
|
95
95
|
for (const { TID, DID } of items) {
|
|
96
96
|
await workflowEngine.WorkItem_CompleteOrRejectAsync(TID, DID, commentValue, isReject);
|
|
97
97
|
}
|
|
98
|
+
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: isReject === 0 ? SDKUI_Localizator.WorkitemApprove : SDKUI_Localizator.WorkitemReject, message: SDKUI_Localizator.OperationSuccess, duration: 3000 });
|
|
98
99
|
}
|
|
99
100
|
catch (e) {
|
|
100
101
|
TMExceptionBoxManager.show({ exception: e });
|
|
@@ -103,7 +104,6 @@ export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = Devi
|
|
|
103
104
|
onCompleted?.();
|
|
104
105
|
onClose?.();
|
|
105
106
|
TMSpinner.hide();
|
|
106
|
-
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: isReject === 0 ? SDKUI_Localizator.WorkitemApprove : SDKUI_Localizator.WorkitemReject, message: SDKUI_Localizator.OperationSuccess, duration: 3000 });
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
109
|
const workflowAction = isReject === 0 ? SDKUI_Localizator.Approve : SDKUI_Localizator.Reject;
|
|
@@ -113,23 +113,33 @@ export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = Devi
|
|
|
113
113
|
? _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: false, onClick: () => completeOrRejectAsync(isReject), advancedColor: TMColors.success })
|
|
114
114
|
: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: disable, onClick: () => { !disable && completeOrRejectAsync(isReject); }, advancedColor: TMColors.error }) })] }) }));
|
|
115
115
|
};
|
|
116
|
-
export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceType.DESKTOP, onClose, selectedItems = [], onCompleted, wf }) => {
|
|
116
|
+
export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceType.DESKTOP, onClose, selectedItems = [], onCompleted, wf, workItemDetail }) => {
|
|
117
117
|
const [commentValue, setCommentValue] = useState('');
|
|
118
118
|
const [selectedUserID, setSelectedUserID] = useState([]);
|
|
119
119
|
const [participants, setParticipants] = useState([]);
|
|
120
120
|
const disable = commentValue.length === 0 || !selectedUserID;
|
|
121
|
+
// Determina se siamo nel contesto CtrlWorkflow (quando abbiamo workItemDetail)
|
|
122
|
+
const isCtrlWorkflowContext = !!workItemDetail;
|
|
121
123
|
const reAssignWorkFlowAsync = async () => {
|
|
122
124
|
try {
|
|
123
125
|
TMSpinner.show();
|
|
124
126
|
const workflowEngine = SDK_Globals.tmSession?.NewWorkflowEngine();
|
|
125
127
|
if (!workflowEngine)
|
|
126
128
|
throw new Error("Workflow engine is not available");
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
for (const { TID, DID } of items) {
|
|
131
|
-
await SDK_Globals.tmSession?.NewWorkflowEngine().WorkItem_ReassignAsync(TID, DID, selectedUserID?.[0], commentValue);
|
|
129
|
+
if (isCtrlWorkflowContext && workItemDetail) {
|
|
130
|
+
// Contesto CtrlWorkflow: usa WFCtrl_ReassignWIAsync
|
|
131
|
+
await workflowEngine.WFCtrl_ReassignWIAsync(workItemDetail.wfid, workItemDetail.did, selectedUserID?.[0], commentValue);
|
|
132
132
|
}
|
|
133
|
+
else {
|
|
134
|
+
// Contesto WorkItem: usa WorkItem_ReassignAsync
|
|
135
|
+
const items = selectedItems.length > 0
|
|
136
|
+
? selectedItems.map(({ TID, DID }) => ({ TID, DID }))
|
|
137
|
+
: [{ TID, DID }];
|
|
138
|
+
for (const { TID, DID } of items) {
|
|
139
|
+
await workflowEngine.WorkItem_ReassignAsync(TID, DID, selectedUserID?.[0], commentValue);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: SDKUI_Localizator.WorkitemReassign, message: SDKUI_Localizator.OperationSuccess, duration: 3000 });
|
|
133
143
|
}
|
|
134
144
|
catch (e) {
|
|
135
145
|
TMExceptionBoxManager.show({ exception: e });
|
|
@@ -138,11 +148,10 @@ export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
|
|
|
138
148
|
onCompleted?.();
|
|
139
149
|
onClose?.();
|
|
140
150
|
TMSpinner.hide();
|
|
141
|
-
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: SDKUI_Localizator.WorkitemReassign, message: SDKUI_Localizator.OperationSuccess, duration: 3000 });
|
|
142
151
|
}
|
|
143
152
|
};
|
|
144
153
|
// Determina il TID da usare
|
|
145
|
-
const tidToUse = selectedItems?.[0]?.TID ?? TID;
|
|
154
|
+
const tidToUse = workItemDetail?.tid ?? selectedItems?.[0]?.TID ?? TID;
|
|
146
155
|
useEffect(() => {
|
|
147
156
|
let isMounted = true;
|
|
148
157
|
const fetchData = async () => {
|
|
@@ -169,8 +178,11 @@ export const WorkFlowReAssignPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
|
|
|
169
178
|
};
|
|
170
179
|
fetchData();
|
|
171
180
|
return () => { isMounted = false; };
|
|
172
|
-
}, [tidToUse, wf]);
|
|
173
|
-
|
|
181
|
+
}, [tidToUse, wf, workItemDetail]);
|
|
182
|
+
// Determina il conteggio degli item da mostrare nel titolo
|
|
183
|
+
const itemCount = workItemDetail ? 1 : selectedItems.length;
|
|
184
|
+
const titleSuffix = itemCount > 0 ? ` (${itemCount} workitem)` : '';
|
|
185
|
+
return (_jsx(TMModal, { onClose: onClose, width: '600px', height: '270px', isModal: true, title: SDKUI_Localizator.Reassign + titleSuffix, children: _jsxs(StyledModalBodyWrapper, { children: [_jsxs(StyledModalContentContainer, { children: [_jsx(TMUserChooser, { dataSource: participants, values: selectedUserID, onValueChanged: (IDs) => {
|
|
174
186
|
setSelectedUserID(IDs ?? []);
|
|
175
187
|
} }), _jsxs("p", { style: { color: commentValue.length === 0 ? TMColors.error : 'black' }, children: [SDKUI_Localizator.CommentText, " ", commentValue.length === 0 && _jsx("span", { children: ` (${SDKUI_Localizator.RequiredField})` }), " "] }), _jsx(StyledTextArea, { maxLength: 200, "$isValid": commentValue.length !== 0, value: commentValue, onChange: (e) => setCommentValue(e.target.value) }), _jsx(CharacterCounter, { children: `${200 - commentValue.length} ${SDKUI_Localizator.CharactersRemaining}` })] }), _jsx(StyledModalFooter, { children: _jsx(TMButton, { btnStyle: 'advanced', showTooltip: false, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: disable, onClick: () => !disable && reAssignWorkFlowAsync(), advancedColor: TMColors.tertiary }) })] }) }));
|
|
176
188
|
};
|
|
@@ -308,6 +320,7 @@ export const WorkFlowMoreInfoPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
|
|
|
308
320
|
name: `${TASK_MORE_INFO_PREFIX_NAME}${nameInput}`
|
|
309
321
|
};
|
|
310
322
|
await SDK_Globals.tmSession?.NewWorkflowEngine().WorkItem_MoreInfoAsync(TID, DID, taskWithPrefix);
|
|
323
|
+
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: SDKUI_Localizator.MoreInformation, message: SDKUI_Localizator.MoreInfoSent, duration: 3000 });
|
|
311
324
|
}
|
|
312
325
|
catch (e) {
|
|
313
326
|
TMExceptionBoxManager.show({ exception: e });
|
|
@@ -316,7 +329,6 @@ export const WorkFlowMoreInfoPopUp = ({ DID = 0, TID = 0, deviceType = DeviceTyp
|
|
|
316
329
|
onCompleted?.();
|
|
317
330
|
onClose?.();
|
|
318
331
|
TMSpinner.hide();
|
|
319
|
-
ShowAlert({ mode: 'success', position: 'TOP_RIGHT', title: SDKUI_Localizator.MoreInformation, message: SDKUI_Localizator.MoreInfoSent, duration: 3000 });
|
|
320
332
|
}
|
|
321
333
|
};
|
|
322
334
|
useEffect(() => {
|