@topconsultnpm/sdkui-react 6.20.0-dev2.53 → 6.20.0-dev2.54
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/styles.d.ts +3 -1
- package/lib/components/NewComponents/ContextMenu/styles.js +7 -5
- package/lib/components/features/documents/TMRelationViewer.js +27 -23
- package/lib/components/features/tasks/TMTaskForm.js +18 -6
- package/lib/components/features/workflow/diagram/ConnectionComponent.d.ts +1 -0
- package/lib/components/features/workflow/diagram/ConnectionComponent.js +6 -2
- package/lib/components/features/workflow/diagram/WFDiagram.js +74 -4
- package/lib/helper/SDKUI_Localizator.d.ts +1 -0
- package/lib/helper/SDKUI_Localizator.js +10 -0
- package/package.json +1 -1
|
@@ -14,7 +14,9 @@ export declare const MenuItem: import("styled-components/dist/types").IStyledCom
|
|
|
14
14
|
$beginGroup?: boolean;
|
|
15
15
|
}>> & string;
|
|
16
16
|
export declare const MenuItemContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
17
|
-
export declare const IconWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>,
|
|
17
|
+
export declare const IconWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
|
|
18
|
+
ref?: ((instance: HTMLSpanElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLSpanElement> | null | undefined;
|
|
19
|
+
}>, never>, never>> & string;
|
|
18
20
|
export declare const MenuItemName: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>> & string;
|
|
19
21
|
export declare const RightIconButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
|
|
20
22
|
ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
|
|
@@ -69,7 +69,7 @@ export const MenuContainer = styled.div `
|
|
|
69
69
|
`}
|
|
70
70
|
|
|
71
71
|
/* Reset color inheritance from parent with !important to override panel header styles */
|
|
72
|
-
& *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
72
|
+
& *:not(svg):not(.right-icon-btn):not(.right-icon-btn *):not(.icon-wrapper):not(.icon-wrapper *) {
|
|
73
73
|
color: #1a1a1a !important;
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -80,7 +80,7 @@ export const MenuContainer = styled.div `
|
|
|
80
80
|
0 2px 8px rgba(0, 0, 0, 0.3);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
[data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
83
|
+
[data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *):not(.icon-wrapper):not(.icon-wrapper *) {
|
|
84
84
|
color: #e0e0e0 !important;
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -174,7 +174,9 @@ export const MenuItemContent = styled.div `
|
|
|
174
174
|
gap: 10px;
|
|
175
175
|
flex: 1;
|
|
176
176
|
`;
|
|
177
|
-
export const IconWrapper = styled.span
|
|
177
|
+
export const IconWrapper = styled.span.attrs({
|
|
178
|
+
className: 'icon-wrapper'
|
|
179
|
+
}) `
|
|
178
180
|
display: flex;
|
|
179
181
|
align-items: center;
|
|
180
182
|
justify-content: center;
|
|
@@ -289,7 +291,7 @@ export const Submenu = styled.div `
|
|
|
289
291
|
}
|
|
290
292
|
|
|
291
293
|
/* Reset color inheritance from parent with !important to override panel header styles */
|
|
292
|
-
& *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
294
|
+
& *:not(svg):not(.right-icon-btn):not(.right-icon-btn *):not(.icon-wrapper):not(.icon-wrapper *) {
|
|
293
295
|
color: #1a1a1a !important;
|
|
294
296
|
}
|
|
295
297
|
|
|
@@ -300,7 +302,7 @@ export const Submenu = styled.div `
|
|
|
300
302
|
0 2px 8px rgba(0, 0, 0, 0.3);
|
|
301
303
|
}
|
|
302
304
|
|
|
303
|
-
[data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *) {
|
|
305
|
+
[data-theme='dark'] & *:not(svg):not(.right-icon-btn):not(.right-icon-btn *):not(.icon-wrapper):not(.icon-wrapper *) {
|
|
304
306
|
color: #e0e0e0 !important;
|
|
305
307
|
}
|
|
306
308
|
|
|
@@ -154,10 +154,12 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
154
154
|
const [expansionAbortController, setExpansionAbortController] = useState(undefined);
|
|
155
155
|
// Ref to track last loaded input to prevent unnecessary reloads
|
|
156
156
|
const lastLoadedInputRef = React.useRef('');
|
|
157
|
+
// State to track loaded input key - triggers re-render for focus selection
|
|
158
|
+
const [loadedInputKey, setLoadedInputKey] = React.useState('');
|
|
157
159
|
// Ref to track if user has manually expanded/collapsed static items
|
|
158
160
|
const userInteractedWithStaticItemsRef = React.useRef(false);
|
|
159
|
-
// Ref to track
|
|
160
|
-
const
|
|
161
|
+
// Ref to track the last inputKey for which we set the focused item
|
|
162
|
+
const lastFocusedInputRef = React.useRef('');
|
|
161
163
|
/**
|
|
162
164
|
* Generate a stable key from inputDcmts to detect real changes
|
|
163
165
|
*/
|
|
@@ -657,16 +659,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
657
659
|
if (!inputDcmts || inputDcmts.length === 0 || dcmtTypes.length === 0) {
|
|
658
660
|
setTreeData([]);
|
|
659
661
|
lastLoadedInputRef.current = '';
|
|
662
|
+
lastFocusedInputRef.current = '';
|
|
663
|
+
setLoadedInputKey('');
|
|
660
664
|
userInteractedWithStaticItemsRef.current = false; // Reset interaction flag
|
|
661
665
|
return;
|
|
662
666
|
}
|
|
663
667
|
// Generate current input key
|
|
664
668
|
const currentKey = getInputKey();
|
|
665
|
-
// Skip if we already loaded this exact data
|
|
669
|
+
// Skip if we already loaded or are loading this exact data
|
|
666
670
|
if (currentKey === lastLoadedInputRef.current && treeData.length > 0) {
|
|
667
671
|
return;
|
|
668
672
|
}
|
|
669
|
-
// Mark as loading this key
|
|
673
|
+
// Mark as loading this key to prevent duplicate loads
|
|
670
674
|
lastLoadedInputRef.current = currentKey;
|
|
671
675
|
// Reset interaction flag when loading new data
|
|
672
676
|
userInteractedWithStaticItemsRef.current = false;
|
|
@@ -675,6 +679,9 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
675
679
|
setWaitPanelValuePrimary(0);
|
|
676
680
|
// Call loadData and use .then() instead of await to allow React to render
|
|
677
681
|
loadData().then(() => {
|
|
682
|
+
// Mark as loaded AFTER data is ready - state update triggers re-render for focus selection
|
|
683
|
+
lastLoadedInputRef.current = currentKey;
|
|
684
|
+
setLoadedInputKey(currentKey);
|
|
678
685
|
setShowWaitPanel(false);
|
|
679
686
|
setWaitPanelTextPrimary('');
|
|
680
687
|
setWaitPanelMaxValuePrimary(0);
|
|
@@ -689,18 +696,21 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
689
696
|
setTreeData(prevData => updateHiddenProperty(prevData));
|
|
690
697
|
}, [showZeroDcmts, updateHiddenProperty]);
|
|
691
698
|
/**
|
|
692
|
-
* Set
|
|
693
|
-
* Focuses on the
|
|
694
|
-
*
|
|
699
|
+
* Set focused item when data finishes loading
|
|
700
|
+
* Focuses on the first document (under root) every time new data is loaded
|
|
701
|
+
* Works both on initial load and on navigation (onPrev/onNext)
|
|
695
702
|
*/
|
|
696
703
|
useEffect(() => {
|
|
697
|
-
|
|
698
|
-
//
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
+
const currentInputKey = getInputKey();
|
|
705
|
+
// Ensure data has finished loading for current input
|
|
706
|
+
if (loadedInputKey !== currentInputKey) {
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
if (!showMainDocument || !onFocusedItemChanged || !treeData.length || !inputDcmts?.length) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
// Skip if we already focused for this inputKey
|
|
713
|
+
if (lastFocusedInputRef.current === currentInputKey) {
|
|
704
714
|
return;
|
|
705
715
|
}
|
|
706
716
|
// Helper function to recursively find the first document with isRoot=true
|
|
@@ -722,17 +732,11 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
722
732
|
// Find the first document marked as root (set by setupInitialTreeExpansion)
|
|
723
733
|
const docNode = findFirstRootDocument(treeData);
|
|
724
734
|
if (docNode) {
|
|
725
|
-
// Set the focused item
|
|
735
|
+
// Set the focused item and mark this inputKey as focused
|
|
726
736
|
onFocusedItemChanged(docNode);
|
|
727
|
-
|
|
737
|
+
lastFocusedInputRef.current = currentInputKey;
|
|
728
738
|
}
|
|
729
|
-
}, [treeData, showMainDocument, onFocusedItemChanged, inputDcmts]);
|
|
730
|
-
/**
|
|
731
|
-
* Reset initial focus flag when input documents change
|
|
732
|
-
*/
|
|
733
|
-
useEffect(() => {
|
|
734
|
-
initialFocusSetRef.current = false;
|
|
735
|
-
}, [getInputKey()]);
|
|
739
|
+
}, [treeData, loadedInputKey, showMainDocument, onFocusedItemChanged, inputDcmts, getInputKey]);
|
|
736
740
|
/**
|
|
737
741
|
* Sync static items state when additionalStaticItems change
|
|
738
742
|
* IMPORTANT: Only update if user hasn't manually interacted with the tree,
|
|
@@ -93,8 +93,12 @@ const TMTaskForm = (props) => {
|
|
|
93
93
|
};
|
|
94
94
|
fetchUsers();
|
|
95
95
|
}, []);
|
|
96
|
+
// Imposta i campi readonly in base al ruolo utente e al contesto
|
|
96
97
|
useEffect(() => {
|
|
97
|
-
if (formDataOrig
|
|
98
|
+
if (!formDataOrig)
|
|
99
|
+
return;
|
|
100
|
+
// UPDATE: se l'utente è receiver (destinatario del task), i campi principali sono readonly
|
|
101
|
+
if (formMode === FormModes.Update) {
|
|
98
102
|
const taskRole = getCurrentUserTaskRole(formDataOrig);
|
|
99
103
|
setFieldsReadOnly({
|
|
100
104
|
name: taskRole === 'receiver',
|
|
@@ -108,12 +112,9 @@ const TMTaskForm = (props) => {
|
|
|
108
112
|
remTime: false,
|
|
109
113
|
response: false
|
|
110
114
|
});
|
|
111
|
-
const newTaskDescriptor = new TaskDescriptor();
|
|
112
|
-
Object.assign(newTaskDescriptor, formDataOrig);
|
|
113
|
-
newTaskDescriptor.isNew = 0;
|
|
114
|
-
editTaskCallback(newTaskDescriptor);
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
// CREATE/DUPLICATE da DossierAction: il nome è precompilato e bloccato
|
|
117
|
+
if ((formMode === FormModes.Create || formMode === FormModes.Duplicate) && taskContext?.dossier && taskContext?.dossier?.origin === 'DossierAction' && currentTask) {
|
|
117
118
|
setFieldsReadOnly({
|
|
118
119
|
name: true,
|
|
119
120
|
description: false,
|
|
@@ -128,6 +129,17 @@ const TMTaskForm = (props) => {
|
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
}, [formDataOrig, formMode]);
|
|
132
|
+
// Notifica il task come "non nuovo" quando si è in modalità Update
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (!formDataOrig)
|
|
135
|
+
return;
|
|
136
|
+
if (formMode !== FormModes.Update)
|
|
137
|
+
return;
|
|
138
|
+
const newTaskDescriptor = new TaskDescriptor();
|
|
139
|
+
Object.assign(newTaskDescriptor, formDataOrig);
|
|
140
|
+
newTaskDescriptor.isNew = 0;
|
|
141
|
+
editTaskCallback(newTaskDescriptor);
|
|
142
|
+
}, [formDataOrig, formMode]);
|
|
131
143
|
// Function to handle changes in the priority value of a TM Drop Down
|
|
132
144
|
const onPriorityValueChange = (e) => {
|
|
133
145
|
if (!e?.target?.value)
|
|
@@ -9,6 +9,7 @@ interface ConnectionComponentProps {
|
|
|
9
9
|
onClick: (id: string, event: React.MouseEvent) => void;
|
|
10
10
|
onDoubleClick: (id: string) => void;
|
|
11
11
|
onConnectionEndpointMouseDown?: (connectionId: string, endpointType: 'source' | 'sink', mouseEvent: React.MouseEvent) => void;
|
|
12
|
+
onContextMenu?: (id: string, event: React.MouseEvent) => void;
|
|
12
13
|
}
|
|
13
14
|
declare const _default: React.NamedExoticComponent<ConnectionComponentProps>;
|
|
14
15
|
export default _default;
|
|
@@ -37,7 +37,7 @@ const StyledSquareConnector = styled.rect `
|
|
|
37
37
|
stroke-width: 1;
|
|
38
38
|
pointer-events: all;
|
|
39
39
|
`;
|
|
40
|
-
const ConnectionComponent = ({ connection, isSelected, sourcePoint, sinkPoint, isTemporary, onClick, onDoubleClick, onConnectionEndpointMouseDown }) => {
|
|
40
|
+
const ConnectionComponent = ({ connection, isSelected, sourcePoint, sinkPoint, isTemporary, onClick, onDoubleClick, onConnectionEndpointMouseDown, onContextMenu }) => {
|
|
41
41
|
const connectionColor = getConnectionColor(connection.OutputStatus);
|
|
42
42
|
// Funzione per renderizzare la forma della freccia
|
|
43
43
|
const renderArrow = useCallback((arrowType, angle) => {
|
|
@@ -82,7 +82,11 @@ const ConnectionComponent = ({ connection, isSelected, sourcePoint, sinkPoint, i
|
|
|
82
82
|
event.stopPropagation();
|
|
83
83
|
onDoubleClick?.(connection.ID);
|
|
84
84
|
}, [onDoubleClick, connection.ID]);
|
|
85
|
-
|
|
85
|
+
const handleContextMenu = useCallback((event) => {
|
|
86
|
+
event.stopPropagation();
|
|
87
|
+
onContextMenu?.(connection.ID, event);
|
|
88
|
+
}, [onContextMenu, connection.ID]);
|
|
89
|
+
return (_jsxs("g", { children: [_jsx(StyledPathHitArea, { d: connection.PathGeometry, onClick: (e) => onClick(connection.ID, e), onDoubleClick: handleDoubleClick, onContextMenu: handleContextMenu }), _jsx(StyledPath, { d: connection.PathGeometry, "$isSelected": isSelected, "$isTemporary": isTemporary, "$outputStatus": connection.OutputStatus, onClick: (e) => onClick(connection.ID, e), onDoubleClick: handleDoubleClick, onContextMenu: handleContextMenu }), connection.SinkArrowSymbol !== ArrowSymbol.None && (_jsxs("g", { transform: calculateArrowTransform(true), children: [renderArrow(connection.SinkArrowSymbol, 0), " "] })), connection.SourceArrowSymbol !== ArrowSymbol.None && (_jsx("g", { transform: calculateArrowTransform(false) + ' rotate(180)', children: renderArrow(connection.SourceArrowSymbol, 0) })), isSelected && (_jsxs(_Fragment, { children: [_jsx(StyledSquareConnector, { "$color": connectionColor, x: sourcePoint.x - 5, y: sourcePoint.y - 5, width: 10, height: 10 }), _jsx(StyledSquareConnector, { "$color": connectionColor, x: sinkPoint.x - 5, y: sinkPoint.y - 5, width: 10, height: 10, cursor: 'move', onMouseDown: (e) => {
|
|
86
90
|
e.stopPropagation(); // Impedisce la propagazione dell'evento a elementi sottostanti
|
|
87
91
|
onConnectionEndpointMouseDown?.(connection.ID, 'sink', e);
|
|
88
92
|
} })] }))] }));
|
|
@@ -8,13 +8,15 @@ import ConnectionComponent from './ConnectionComponent';
|
|
|
8
8
|
import DiagramItemComponent from './DiagramItemComponent';
|
|
9
9
|
import DiagramItemSvgContent from './DiagramItemSvgContent';
|
|
10
10
|
import { calculateArrowAngle, downloadFile, getConnectionPoint, getNewWfDiagram, isConnectionNonLinear, validateDiagram } from './workflowHelpers';
|
|
11
|
-
import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport, IconWindowMaximize, IconZoomIn, IconZoomOut, IconPencil, IconLock, LocalizeDiagramItemType, IconWindowMinimize, IconZoomAuto } from '../../../../helper';
|
|
11
|
+
import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport, IconWindowMaximize, IconZoomIn, IconZoomOut, IconPencil, IconLock, LocalizeDiagramItemType, IconWindowMinimize, IconZoomAuto, IconCloseCircle, IconSuccess } from '../../../../helper';
|
|
12
12
|
import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../../../base/TMPopUp';
|
|
13
13
|
import { StyledLoadingContainer, StyledSpinner } from '../../../base/Styled';
|
|
14
14
|
import DiagramItemForm from './DiagramItemForm';
|
|
15
15
|
import ReactDOM from 'react-dom';
|
|
16
16
|
import ConnectionForm from './ConnectionForm';
|
|
17
17
|
import TMFloatingMenuBar from '../../../NewComponents/FloatingMenuBar';
|
|
18
|
+
import TMContextMenu from '../../../NewComponents/ContextMenu/TMContextMenu';
|
|
19
|
+
import { TMColors } from '../../../../utils/theme';
|
|
18
20
|
const ZoomLevelText = styled.span `
|
|
19
21
|
font-size: 0.9em;
|
|
20
22
|
color: #555;
|
|
@@ -331,6 +333,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
331
333
|
const [wfDiagram, setWfDiagram] = useState(null);
|
|
332
334
|
const [selectedItems, setSelectedItems] = useState(new Set());
|
|
333
335
|
const [selectedConnections, setSelectedConnections] = useState(new Set());
|
|
336
|
+
// Context menu per le connections
|
|
337
|
+
const [connectionContextMenuPosition, setConnectionContextMenuPosition] = useState({ x: 0, y: 0 });
|
|
338
|
+
const [contextMenuConnectionId, setContextMenuConnectionId] = useState(null);
|
|
334
339
|
const [wfDiagramHistory, setWfDiagramHistory] = useState([]);
|
|
335
340
|
const [historyIndex, setHistoryIndex] = useState(-1);
|
|
336
341
|
const isUndoingRedoing = useRef(false);
|
|
@@ -1311,6 +1316,62 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
1311
1316
|
if (!isCtrlPressed)
|
|
1312
1317
|
setSelectedItems(new Set());
|
|
1313
1318
|
}, [isReadOnly]);
|
|
1319
|
+
const handleConnectionContextMenu = useCallback((id, event) => {
|
|
1320
|
+
if (isReadOnly)
|
|
1321
|
+
return;
|
|
1322
|
+
event.preventDefault();
|
|
1323
|
+
event.stopPropagation();
|
|
1324
|
+
// Trova la connection
|
|
1325
|
+
const connection = wfDiagram?.Connections.find(conn => conn.ID === id);
|
|
1326
|
+
if (!connection)
|
|
1327
|
+
return;
|
|
1328
|
+
// Verifica se esce da un DiagramItemTypes.Condition o Approval
|
|
1329
|
+
const sourceItem = wfDiagram?.DiagramItems.find(item => item.ID === connection.Source.ParentDiagramItem.ID);
|
|
1330
|
+
if (!sourceItem || ![DiagramItemTypes.Condition, DiagramItemTypes.Approval].includes(sourceItem.Type))
|
|
1331
|
+
return;
|
|
1332
|
+
// Mostra il context menu
|
|
1333
|
+
setContextMenuConnectionId(id);
|
|
1334
|
+
setConnectionContextMenuPosition({ x: event.clientX, y: event.clientY });
|
|
1335
|
+
}, [isReadOnly, wfDiagram]);
|
|
1336
|
+
const handleChangeConnectionOutputStatus = useCallback((connectionId) => {
|
|
1337
|
+
if (isReadOnly || !wfDiagram)
|
|
1338
|
+
return;
|
|
1339
|
+
const connection = wfDiagram.Connections.find(conn => conn.ID === connectionId);
|
|
1340
|
+
if (!connection)
|
|
1341
|
+
return;
|
|
1342
|
+
// Cambia l'OutputStatus da Completed a Rejected e viceversa
|
|
1343
|
+
const newStatus = connection.OutputStatus === WorkItemStatus.Completed
|
|
1344
|
+
? WorkItemStatus.Rejected
|
|
1345
|
+
: WorkItemStatus.Completed;
|
|
1346
|
+
const updatedDiagram = {
|
|
1347
|
+
...wfDiagram,
|
|
1348
|
+
Connections: wfDiagram.Connections.map(conn => conn.ID === connectionId ? { ...conn, OutputStatus: newStatus } : conn)
|
|
1349
|
+
};
|
|
1350
|
+
updateDiagram(updatedDiagram);
|
|
1351
|
+
setWfDiagram(updatedDiagram);
|
|
1352
|
+
setContextMenuConnectionId(null);
|
|
1353
|
+
}, [isReadOnly, wfDiagram, updateDiagram]);
|
|
1354
|
+
const closeConnectionContextMenu = useCallback(() => {
|
|
1355
|
+
setContextMenuConnectionId(null);
|
|
1356
|
+
}, []);
|
|
1357
|
+
// Menu items per il context menu delle connections
|
|
1358
|
+
const connectionContextMenuItems = useMemo(() => {
|
|
1359
|
+
if (!contextMenuConnectionId || !wfDiagram)
|
|
1360
|
+
return [];
|
|
1361
|
+
const connection = wfDiagram.Connections.find(conn => conn.ID === contextMenuConnectionId);
|
|
1362
|
+
if (!connection)
|
|
1363
|
+
return [];
|
|
1364
|
+
const targetStatus = connection.OutputStatus === WorkItemStatus.Completed
|
|
1365
|
+
? SDKUI_Localizator.WorkItemStatus_Rejected
|
|
1366
|
+
: SDKUI_Localizator.WorkItemStatus_Completed;
|
|
1367
|
+
return [{
|
|
1368
|
+
icon: connection.OutputStatus === WorkItemStatus.Completed
|
|
1369
|
+
? _jsx(IconCloseCircle, { color: TMColors.success, fontSize: 16 })
|
|
1370
|
+
: _jsx(IconSuccess, { color: TMColors.error, fontSize: 16 }),
|
|
1371
|
+
name: SDKUI_Localizator.ChangeStatusTo.replaceParams(targetStatus),
|
|
1372
|
+
onClick: () => handleChangeConnectionOutputStatus(contextMenuConnectionId)
|
|
1373
|
+
}];
|
|
1374
|
+
}, [contextMenuConnectionId, wfDiagram, handleChangeConnectionOutputStatus]);
|
|
1314
1375
|
const handleDrag = useCallback((id, newX, newY) => {
|
|
1315
1376
|
if (isReadOnly)
|
|
1316
1377
|
return;
|
|
@@ -1393,10 +1454,15 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
1393
1454
|
if (sourceItem.Type === DiagramItemTypes.Condition || sourceItem.Type === DiagramItemTypes.Approval) {
|
|
1394
1455
|
const existingConnectionsFromSource = wfDiagram.Connections.filter(conn => conn.Source.ParentDiagramItem.ID === sourceItem.ID);
|
|
1395
1456
|
if (existingConnectionsFromSource.length === 0) {
|
|
1457
|
+
// Prima connessione → Completed
|
|
1396
1458
|
outputStatus = WorkItemStatus.Completed;
|
|
1397
1459
|
}
|
|
1398
1460
|
else if (existingConnectionsFromSource.length === 1) {
|
|
1399
|
-
|
|
1461
|
+
// Seconda connessione → contrario della prima
|
|
1462
|
+
const firstConnection = existingConnectionsFromSource[0];
|
|
1463
|
+
outputStatus = firstConnection.OutputStatus === WorkItemStatus.Completed
|
|
1464
|
+
? WorkItemStatus.Rejected
|
|
1465
|
+
: WorkItemStatus.Completed;
|
|
1400
1466
|
}
|
|
1401
1467
|
}
|
|
1402
1468
|
const newConnection = {
|
|
@@ -1842,8 +1908,12 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
1842
1908
|
const sinkPoint = getConnectionPoint(sinkItem, connection.Sink.ConnectorName);
|
|
1843
1909
|
// Determina se questa è la connessione che stiamo trascinando
|
|
1844
1910
|
const isThisConnectionBeingDragged = isDraggingExistingConnectionEndpoint && draggingConnectionId === connection.ID;
|
|
1845
|
-
return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onDoubleClick: handleDoubleClickConnection, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown }, connection.ID));
|
|
1846
|
-
}), isDrawingConnection && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDraggingExistingConnectionEndpoint && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDrawingSelectionRect && currentSelectionRect && (_jsx(SelectionRect, { x: currentSelectionRect.x, y: currentSelectionRect.y, width: currentSelectionRect.width, height: currentSelectionRect.height }))] }) })) : (_jsx(DiagramMessage, { children: `${SDKUI_Localizator.WorkflowDiagramMissingOrInvalid} ...` })) }), isModalOpen && itemToEdit && (_jsx(DiagramItemForm, { itemToEdit: itemToEdit, wf: wfDiagram?.Info, onClose: handleCloseModal, onApply: handleUpdateDiagramItem })), isConnectionModalOpen && connectionToEdit && (_jsx(ConnectionForm, { connectionToEdit: connectionToEdit, onClose: () => setIsConnectionModalOpen(false), onApply: handleUpdateConnection }))
|
|
1911
|
+
return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onDoubleClick: handleDoubleClickConnection, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown, onContextMenu: handleConnectionContextMenu }, connection.ID));
|
|
1912
|
+
}), isDrawingConnection && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDraggingExistingConnectionEndpoint && tempConnectionPathData && (_jsx(TempConnectionPath, { d: tempConnectionPathData })), isDrawingSelectionRect && currentSelectionRect && (_jsx(SelectionRect, { x: currentSelectionRect.x, y: currentSelectionRect.y, width: currentSelectionRect.width, height: currentSelectionRect.height }))] }) })) : (_jsx(DiagramMessage, { children: `${SDKUI_Localizator.WorkflowDiagramMissingOrInvalid} ...` })) }), isModalOpen && itemToEdit && (_jsx(DiagramItemForm, { itemToEdit: itemToEdit, wf: wfDiagram?.Info, onClose: handleCloseModal, onApply: handleUpdateDiagramItem })), isConnectionModalOpen && connectionToEdit && (_jsx(ConnectionForm, { connectionToEdit: connectionToEdit, onClose: () => setIsConnectionModalOpen(false), onApply: handleUpdateConnection })), _jsx(TMContextMenu, { items: connectionContextMenuItems, externalControl: {
|
|
1913
|
+
visible: contextMenuConnectionId !== null,
|
|
1914
|
+
position: connectionContextMenuPosition,
|
|
1915
|
+
onClose: closeConnectionContextMenu
|
|
1916
|
+
} })] }));
|
|
1847
1917
|
return (_jsxs(_Fragment, { children: [!isFullScreen && (_jsx(DiagramWrapper, { ref: diagramRef, children: diagramContent })), isFullScreen && ReactDOM.createPortal(_jsx(FullScreenContainer, { ref: fullScreenRef, tabIndex: 0, onKeyDown: handleFullScreenKeyDown, children: diagramContent }), document.body)] }));
|
|
1848
1918
|
};
|
|
1849
1919
|
export default WFDiagram;
|
|
@@ -85,6 +85,7 @@ export declare class SDKUI_Localizator {
|
|
|
85
85
|
static get CancelCheckOut(): string;
|
|
86
86
|
static get Cancel(): "Abbrechen" | "Cancel" | "Anular" | "Annuler" | "Cancelar" | "Annulla";
|
|
87
87
|
static get ChangePassword(): "Kennwort ändern" | "Change password" | "Cambiar la contraseña" | "Changer le mot de passe" | "Alterar a senha" | "Cambia password";
|
|
88
|
+
static get ChangeStatusTo(): string;
|
|
88
89
|
static get CharactersRemaining(): "verbleibende Zeichen" | "characters remaining" | "caracteres restantes" | "caractères restants" | "caratteri rimanenti";
|
|
89
90
|
static get CheckIn(): "Check in" | "Enregistrement";
|
|
90
91
|
static get CheckInElementConfirm(): string;
|
|
@@ -805,6 +805,16 @@ export class SDKUI_Localizator {
|
|
|
805
805
|
default: return "Cambia password";
|
|
806
806
|
}
|
|
807
807
|
}
|
|
808
|
+
static get ChangeStatusTo() {
|
|
809
|
+
switch (this._cultureID) {
|
|
810
|
+
case CultureIDs.De_DE: return "Ändern in {{0}}";
|
|
811
|
+
case CultureIDs.En_US: return "Change to {{0}}";
|
|
812
|
+
case CultureIDs.Es_ES: return "Cambiar a {{0}}";
|
|
813
|
+
case CultureIDs.Fr_FR: return "Changer en {{0}}";
|
|
814
|
+
case CultureIDs.Pt_PT: return "Alterar para {{0}}";
|
|
815
|
+
default: return "Cambia in {{0}}";
|
|
816
|
+
}
|
|
817
|
+
}
|
|
808
818
|
static get CharactersRemaining() {
|
|
809
819
|
switch (this._cultureID) {
|
|
810
820
|
case CultureIDs.De_DE: return "verbleibende Zeichen";
|