@topconsultnpm/sdkui-react-beta 6.16.98 → 6.16.100

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.
@@ -7,6 +7,7 @@ interface ConnectionComponentProps {
7
7
  sinkPoint: Point;
8
8
  isTemporary?: boolean;
9
9
  onClick: (id: string, event: React.MouseEvent) => void;
10
+ onDoubleClick: (id: string) => void;
10
11
  onConnectionEndpointMouseDown?: (connectionId: string, endpointType: 'source' | 'sink', mouseEvent: React.MouseEvent) => void;
11
12
  }
12
13
  declare const _default: React.NamedExoticComponent<ConnectionComponentProps>;
@@ -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, onConnectionEndpointMouseDown }) => {
40
+ const ConnectionComponent = ({ connection, isSelected, sourcePoint, sinkPoint, isTemporary, onClick, onDoubleClick, onConnectionEndpointMouseDown }) => {
41
41
  const connectionColor = getConnectionColor(connection.OutputStatus);
42
42
  // Funzione per renderizzare la forma della freccia
43
43
  const renderArrow = useCallback((arrowType, angle) => {
@@ -78,7 +78,11 @@ const ConnectionComponent = ({ connection, isSelected, sourcePoint, sinkPoint, i
78
78
  // Sposta l'origine della rotazione al punto della freccia
79
79
  return `translate(${point.x}, ${point.y}) rotate(${angleDeg})`;
80
80
  }, [connection.PathGeometry]);
81
- return (_jsxs("g", { children: [_jsx(StyledPathHitArea, { d: connection.PathGeometry, onClick: (e) => onClick(connection.ID, e) }), _jsx(StyledPath, { d: connection.PathGeometry, "$isSelected": isSelected, "$isTemporary": isTemporary, "$outputStatus": connection.OutputStatus, onClick: (e) => onClick(connection.ID, e) }), 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) => {
81
+ const handleDoubleClick = useCallback((event) => {
82
+ event.stopPropagation();
83
+ onDoubleClick?.(connection.ID);
84
+ }, [onDoubleClick, connection.ID]);
85
+ return (_jsxs("g", { children: [_jsx(StyledPathHitArea, { d: connection.PathGeometry, onClick: (e) => onClick(connection.ID, e), onDoubleClick: handleDoubleClick }), _jsx(StyledPath, { d: connection.PathGeometry, "$isSelected": isSelected, "$isTemporary": isTemporary, "$outputStatus": connection.OutputStatus, onClick: (e) => onClick(connection.ID, e), onDoubleClick: handleDoubleClick }), 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) => {
82
86
  e.stopPropagation(); // Impedisce la propagazione dell'evento a elementi sottostanti
83
87
  onConnectionEndpointMouseDown?.(connection.ID, 'sink', e);
84
88
  } })] }))] }));
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { Connection } from './interfaces';
3
+ interface IConnectionFormProps {
4
+ connectionToEdit: Connection;
5
+ onClose: () => void;
6
+ onApply: (updatedConnection: Connection) => void;
7
+ }
8
+ declare const ConnectionForm: React.FC<IConnectionFormProps>;
9
+ export default ConnectionForm;
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // filepath: c:\TM6\Sorgenti\WebClient\tm-sdkui-react\src\components\features\workflow\diagram\ConnectionForm.tsx
3
+ import { useState, useCallback, useMemo } from 'react';
4
+ import styled from 'styled-components';
5
+ import { calcIsModified, IconApply, IconUndo, SDKUI_Localizator } from '../../../../helper';
6
+ import TMButton from '../../../base/TMButton';
7
+ import TMModal from '../../../base/TMModal';
8
+ import { TMColors } from '../../../../utils/theme';
9
+ import { CultureIDs } from '@topconsultnpm/sdk-ts-beta';
10
+ import TMLocalizedTextBox from '../../../editors/TMLocalizedTextBox';
11
+ const FormContainer = styled.div `
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 5px;
15
+ padding: 10px;
16
+ `;
17
+ const ModalContent = styled.div `
18
+ background: white;
19
+ padding: 20px;
20
+ border-radius: 8px;
21
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
22
+ width: 500px;
23
+ max-width: 90%;
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: 15px;
27
+ `;
28
+ const ModalHeader = styled.h3 `
29
+ margin-top: 0;
30
+ border-bottom: 1px solid #eee;
31
+ padding-bottom: 10px;
32
+ `;
33
+ const ModalFooter = styled.div `
34
+ display: flex;
35
+ justify-content: flex-end;
36
+ gap: 10px;
37
+ margin-top: 20px;
38
+ `;
39
+ const ConnectionForm = ({ connectionToEdit, onClose, onApply }) => {
40
+ const [localItem, setLocalItem] = useState(connectionToEdit);
41
+ const [localItemOrig] = useState(structuredClone(connectionToEdit));
42
+ const isModified = useMemo(() => calcIsModified(localItem, localItemOrig), [localItem, localItemOrig]);
43
+ const handleCancel = () => {
44
+ setLocalItem(localItemOrig);
45
+ };
46
+ const handleSave = () => {
47
+ onApply(localItem);
48
+ onClose();
49
+ };
50
+ const handleLocalizedDescriptionChange = useCallback((lang, newValue) => {
51
+ setLocalItem(prevLocalItem => {
52
+ const updatedItem = { ...prevLocalItem };
53
+ // Aggiungi la logica per aggiornare il campo corretto
54
+ switch (lang) {
55
+ case CultureIDs.It_IT:
56
+ updatedItem.Description_IT = newValue;
57
+ break;
58
+ case CultureIDs.En_US:
59
+ updatedItem.Description_EN = newValue;
60
+ break;
61
+ case CultureIDs.Fr_FR:
62
+ updatedItem.Description_FR = newValue;
63
+ break;
64
+ case CultureIDs.Pt_PT:
65
+ updatedItem.Description_PT = newValue;
66
+ break;
67
+ case CultureIDs.Es_ES:
68
+ updatedItem.Description_ES = newValue;
69
+ break;
70
+ case CultureIDs.De_DE:
71
+ updatedItem.Description_DE = newValue;
72
+ break;
73
+ default:
74
+ updatedItem.Description = newValue;
75
+ break;
76
+ }
77
+ return updatedItem;
78
+ });
79
+ }, []);
80
+ return (_jsx(TMModal, { title: "Modifica Connessione", onClose: onClose, isModal: true, width: "500px", height: "175px", children: _jsxs(FormContainer, { onClick: (e) => e.stopPropagation(), children: [_jsx(TMLocalizedTextBox, { label: SDKUI_Localizator.Description, value: localItem.Description, value_IT: localItem.Description_IT, value_EN: localItem.Description_EN, value_FR: localItem.Description_FR, value_PT: localItem.Description_PT, value_ES: localItem.Description_ES, value_DE: localItem.Description_DE, isModifiedWhen: localItem.Description !== localItemOrig.Description, onValueChanged: handleLocalizedDescriptionChange }), _jsxs(ModalFooter, { children: [_jsx(TMButton, { caption: SDKUI_Localizator.Apply, btnStyle: 'advanced', advancedColor: TMColors.tertiary, icon: _jsx(IconApply, {}), showTooltip: false, disabled: !isModified, onClick: handleSave }), _jsx(TMButton, { caption: SDKUI_Localizator.Cancel, btnStyle: 'toolbar', color: 'primary', icon: _jsx(IconUndo, {}), showTooltip: false, disabled: !isModified, onClick: handleCancel })] })] }) }));
81
+ };
82
+ export default ConnectionForm;
@@ -10,7 +10,7 @@ import TMTextBox from '../../../editors/TMTextBox';
10
10
  import TMButton from '../../../base/TMButton';
11
11
  import styled from 'styled-components';
12
12
  import TMQuerySummary from '../../../query/TMQuerySummary';
13
- import { CultureIDs, DcmtTypeListCacheService, FromItem, MetadataDataDomains, PlatformObjectValidator, QueryValidatorOptions, ResultTypes, SDK_Globals, SearchEngine, Severities, TMPropertyNames, ValidationItem, WFAppTypes, WorkItemSetRules } from '@topconsultnpm/sdk-ts-beta';
13
+ import { CultureIDs, DcmtTypeListCacheService, FromItem, MetadataDataDomains, SDK_Globals, SearchEngine, Severities, WFAppTypes, WorkItemSetRules } from '@topconsultnpm/sdk-ts-beta';
14
14
  import TMLocalizedTextBox from '../../../editors/TMLocalizedTextBox';
15
15
  import TMDataListItemPicker from '../../../choosers/TMDataListItemPicker';
16
16
  import WorkitemRecipientsEditor, { actorsToTos, RecipientsContainer, tosToActors } from './WorkitemRecipientsEditor';
@@ -26,6 +26,7 @@ import TMCultureIDPicker from '../../../choosers/TMCultureIDPicker';
26
26
  import RecipientList, { WorkItemActorTypes } from './RecipientList';
27
27
  import TMRadioButton from '../../../editors/TMRadioButton';
28
28
  import TMVilViewer from '../../../base/TMVilViewer';
29
+ import { DiagramItemProps, wfDiagramItemValidator } from './workflowHelpers';
29
30
  const FormContainer = styled.div `
30
31
  display: flex;
31
32
  flex-direction: column;
@@ -136,53 +137,8 @@ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
136
137
  }
137
138
  return { calculatedWidth: width, calculatedHeight: height };
138
139
  }, [localItem.Type]);
139
- const validator = async (d) => {
140
- let vil = [];
141
- switch (d.Type) {
142
- case DiagramItemTypes.Start:
143
- if (d.StartAfterArchive !== 1 && d.StartAfterUpdate !== 1 && d.StartManual !== 1)
144
- vil.push(new ValidationItem(ResultTypes.ERROR, "*", "Indicare la modalità di avvio dell'istanza di workflow"));
145
- if (d.StartAfterUpdate === 1 && (d.StartAfterUpdateMIDs === undefined || d.StartAfterUpdateMIDs.length <= 0))
146
- vil.push(new ValidationItem(ResultTypes.ERROR, DiagramItemProps.StartAfterUpdateMIDs, "Indicare almeno un metadato la cui modifica avvii l'istanza"));
147
- break;
148
- case DiagramItemTypes.Approval:
149
- PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
150
- PlatformObjectValidator.RequiredStringValidator(d.Description, DiagramItemProps.Description, vil, SDKUI_Localizator.Description);
151
- PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
152
- break;
153
- case DiagramItemTypes.ExecTask:
154
- PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
155
- PlatformObjectValidator.RequiredStringValidator(d.Description, DiagramItemProps.Description, vil, SDKUI_Localizator.Description);
156
- PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
157
- PlatformObjectValidator.RequiredStringValidator(d.AppName, DiagramItemProps.AppName, vil, SDKUI_Localizator.WorkflowAppName);
158
- PlatformObjectValidator.RequiredStringValidator(d.AppType, DiagramItemProps.AppType, vil, SDKUI_Localizator.WorkflowAppType);
159
- break;
160
- case DiagramItemTypes.Notification:
161
- PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
162
- PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
163
- PlatformObjectValidator.RequiredStringValidator(d.Severity, DiagramItemProps.Severity, vil, SDKUI_Localizator.Severity);
164
- break;
165
- case DiagramItemTypes.RunApp:
166
- PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
167
- PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
168
- PlatformObjectValidator.RequiredStringValidator(d.AppName, DiagramItemProps.AppName, vil, SDKUI_Localizator.WorkflowAppName);
169
- PlatformObjectValidator.RequiredStringValidator(d.AppType, DiagramItemProps.AppType, vil, SDKUI_Localizator.WorkflowAppType);
170
- break;
171
- case DiagramItemTypes.Condition:
172
- PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
173
- let qvo = new QueryValidatorOptions();
174
- qvo.DoSelectValidation = false;
175
- qvo.DoOrderByValidation = false;
176
- await PlatformObjectValidator.QueryValidatorAsync(localItem.QD, vil, qvo);
177
- if (localItem.QD?.where === undefined || localItem.QD.where.length <= 0) {
178
- vil.push(new ValidationItem(ResultTypes.ERROR, TMPropertyNames.where, "La query della condizione non contiene criteri di selezione", [DiagramItemProps.QD]));
179
- }
180
- break;
181
- }
182
- return vil;
183
- };
184
140
  useEffect(() => {
185
- validator(localItem).then((vil) => setValidationItems(vil));
141
+ wfDiagramItemValidator(localItem).then((vil) => setValidationItems(vil));
186
142
  }, [localItem]);
187
143
  const isModified = useMemo(() => calcIsModified(localItem, localItemOrig), [localItem, localItemOrig]);
188
144
  const handleCancel = () => {
@@ -723,54 +679,3 @@ const DiagramItemForm = ({ itemToEdit, wf, onClose, onApply }) => {
723
679
  return (_jsx(TMModal, { title: DiagramItemTypes[localItem.Type].toString(), onClose: onClose, isModal: true, width: calculatedWidth, height: calculatedHeight, children: renderForm() }));
724
680
  };
725
681
  export default DiagramItemForm;
726
- const DiagramItemProps = {
727
- ID: 'ID',
728
- Left: 'Left',
729
- Top: 'Top',
730
- Width: 'Width',
731
- Height: 'Height',
732
- Type: 'Type',
733
- ItemName: 'ItemName',
734
- ItemName_IT: 'ItemName_IT',
735
- ItemName_EN: 'ItemName_EN',
736
- ItemName_FR: 'ItemName_FR',
737
- ItemName_PT: 'ItemName_PT',
738
- ItemName_ES: 'ItemName_ES',
739
- ItemName_DE: 'ItemName_DE',
740
- Description: 'Description',
741
- Description_IT: 'Description_IT',
742
- Description_EN: 'Description_EN',
743
- Description_FR: 'Description_FR',
744
- Description_PT: 'Description_PT',
745
- Description_ES: 'Description_ES',
746
- Description_DE: 'Description_DE',
747
- StatusValue: 'StatusValue',
748
- RegisterPost: 'RegisterPost',
749
- AllowZeroTos: 'AllowZeroTos',
750
- Tos: 'Tos',
751
- SetRule: 'SetRule',
752
- StartAfterArchive: 'StartAfterArchive',
753
- StartAfterUpdate: 'StartAfterUpdate',
754
- StartAfterUpdateMIDs: 'StartAfterUpdateMIDs',
755
- StartManual: 'StartManual',
756
- Hist: 'Hist',
757
- EndWFInstance: 'EndWFInstance',
758
- QD: 'QD',
759
- SOD: 'SOD',
760
- MetadataValues: 'MetadataValues',
761
- Severity: 'Severity',
762
- RegAsWfInstPart: 'RegAsWfInstPart',
763
- FormatCultureID: 'FormatCultureID',
764
- Tos2: 'Tos2',
765
- QD2: 'QD2',
766
- PlatformObjName: 'PlatformObjName',
767
- PlatformObjDescr: 'PlatformObjDescr',
768
- Value1asInt: 'Value1asInt',
769
- Value2asInt: 'Value2asInt',
770
- Value3asInt: 'Value3asInt',
771
- Value1asString: 'Value1asString',
772
- AppType: 'AppType',
773
- AppName: 'AppName',
774
- AppArgs: 'AppArgs',
775
- Trunc: 'Trunc',
776
- };
@@ -13,6 +13,7 @@ import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../../.
13
13
  import { StyledLoadingContainer, StyledSpinner } from '../../../base/Styled';
14
14
  import DiagramItemForm from './DiagramItemForm';
15
15
  import ReactDOM from 'react-dom';
16
+ import ConnectionForm from './ConnectionForm';
16
17
  const ZoomLevelText = styled.span `
17
18
  font-size: 0.9em;
18
19
  color: #555;
@@ -340,6 +341,8 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
340
341
  const [isToolboxVisible, setIsToolboxVisible] = useState(true);
341
342
  const [isModalOpen, setIsModalOpen] = useState(false);
342
343
  const [itemToEdit, setItemToEdit] = useState(null);
344
+ const [isConnectionModalOpen, setIsConnectionModalOpen] = useState(false);
345
+ const [connectionToEdit, setConnectionToEdit] = useState(null);
343
346
  const { svgWidth, svgHeight } = useMemo(() => {
344
347
  if (!wfDiagram) {
345
348
  return { svgWidth: 0, svgHeight: 0 };
@@ -580,6 +583,25 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
580
583
  return false;
581
584
  });
582
585
  }, [isReadOnly]);
586
+ const handleDoubleClickConnection = useCallback((connectionId) => {
587
+ if (isReadOnly)
588
+ return;
589
+ const connFound = wfDiagram?.Connections.find(c => c.ID === connectionId);
590
+ if (connFound) {
591
+ const sinkItem = wfDiagram?.DiagramItems.find(item => item.ID === connFound.Sink.ParentDiagramItem.ID);
592
+ if (sinkItem) {
593
+ const canOpen = [
594
+ DiagramItemTypes.Approval,
595
+ DiagramItemTypes.DataEntry,
596
+ DiagramItemTypes.ExecTask
597
+ ].includes(sinkItem.Type);
598
+ if (canOpen) {
599
+ setConnectionToEdit(connFound);
600
+ setIsConnectionModalOpen(true);
601
+ }
602
+ }
603
+ }
604
+ }, [wfDiagram, isReadOnly]);
583
605
  const handleKeyDown = useCallback((event) => {
584
606
  if (isReadOnly)
585
607
  return;
@@ -1453,6 +1475,21 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1453
1475
  return { ...prevDiagram, DiagramItems: updatedDiagramItems };
1454
1476
  });
1455
1477
  }, []);
1478
+ const handleUpdateConnection = useCallback((updatedConnection) => {
1479
+ setWfDiagram(prevDiagram => {
1480
+ if (!prevDiagram)
1481
+ return null;
1482
+ const updatedConnections = prevDiagram.Connections.map(conn => {
1483
+ if (conn.ID === updatedConnection.ID) {
1484
+ return updatedConnection;
1485
+ }
1486
+ return conn;
1487
+ });
1488
+ const newDiagram = { ...prevDiagram, Connections: updatedConnections };
1489
+ updateDiagram(newDiagram);
1490
+ return newDiagram;
1491
+ });
1492
+ }, [updateDiagram]);
1456
1493
  const availableItemTypes = useMemo(() => {
1457
1494
  return [
1458
1495
  DiagramItemTypes.Approval,
@@ -1571,8 +1608,8 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
1571
1608
  const sinkPoint = getConnectionPoint(sinkItem, connection.Sink.ConnectorName);
1572
1609
  // Determina se questa è la connessione che stiamo trascinando
1573
1610
  const isThisConnectionBeingDragged = isDraggingExistingConnectionEndpoint && draggingConnectionId === connection.ID;
1574
- return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown }, connection.ID));
1575
- }), 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 }))] }));
1611
+ return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onDoubleClick: handleDoubleClickConnection, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown }, connection.ID));
1612
+ }), 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 }))] }));
1576
1613
  const diagramRef = useRef(null);
1577
1614
  return (_jsxs(_Fragment, { children: [!isFullScreen && (_jsx(DiagramWrapper, { ref: diagramRef, children: diagramContent })), isFullScreen && ReactDOM.createPortal(_jsx(FullScreenContainer, { children: diagramContent }), document.body)] }));
1578
1615
  };
@@ -94,6 +94,12 @@ export interface Connection {
94
94
  Sink: ConnectionPoint;
95
95
  OutputStatus: WorkItemStatus;
96
96
  Description: string;
97
+ Description_IT?: string;
98
+ Description_EN?: string;
99
+ Description_FR?: string;
100
+ Description_PT?: string;
101
+ Description_ES?: string;
102
+ Description_DE?: string;
97
103
  PathGeometry: string;
98
104
  SourceArrowSymbol: ArrowSymbol;
99
105
  SinkArrowSymbol: ArrowSymbol;
@@ -1,4 +1,4 @@
1
- import { WorkItemStatus } from '@topconsultnpm/sdk-ts-beta';
1
+ import { ValidationItem, WorkItemStatus } from '@topconsultnpm/sdk-ts-beta';
2
2
  import { Point, Rect, DiagramItem, WfDiagram, TextDimensions, Connection, WfInfo } from './interfaces';
3
3
  /**
4
4
  * Calculates the angle in degrees of an arrow based on two points.
@@ -67,3 +67,56 @@ export declare const getConnectionColor: (status: WorkItemStatus) => string;
67
67
  export declare const validateDiagram: (diagram: WfDiagram, newConnection?: Connection) => void;
68
68
  export declare const downloadFile: (data: string, filename: string, type: string) => void;
69
69
  export declare const getNewWfDiagram: (info: WfInfo | null) => WfDiagram;
70
+ export declare const workflowValidator: (wf: WfDiagram) => Promise<ValidationItem[]>;
71
+ export declare const DiagramItemProps: {
72
+ ID: string;
73
+ Left: string;
74
+ Top: string;
75
+ Width: string;
76
+ Height: string;
77
+ Type: string;
78
+ ItemName: string;
79
+ ItemName_IT: string;
80
+ ItemName_EN: string;
81
+ ItemName_FR: string;
82
+ ItemName_PT: string;
83
+ ItemName_ES: string;
84
+ ItemName_DE: string;
85
+ Description: string;
86
+ Description_IT: string;
87
+ Description_EN: string;
88
+ Description_FR: string;
89
+ Description_PT: string;
90
+ Description_ES: string;
91
+ Description_DE: string;
92
+ StatusValue: string;
93
+ RegisterPost: string;
94
+ AllowZeroTos: string;
95
+ Tos: string;
96
+ SetRule: string;
97
+ StartAfterArchive: string;
98
+ StartAfterUpdate: string;
99
+ StartAfterUpdateMIDs: string;
100
+ StartManual: string;
101
+ Hist: string;
102
+ EndWFInstance: string;
103
+ QD: string;
104
+ SOD: string;
105
+ MetadataValues: string;
106
+ Severity: string;
107
+ RegAsWfInstPart: string;
108
+ FormatCultureID: string;
109
+ Tos2: string;
110
+ QD2: string;
111
+ PlatformObjName: string;
112
+ PlatformObjDescr: string;
113
+ Value1asInt: string;
114
+ Value2asInt: string;
115
+ Value3asInt: string;
116
+ Value1asString: string;
117
+ AppType: string;
118
+ AppName: string;
119
+ AppArgs: string;
120
+ Trunc: string;
121
+ };
122
+ export declare const wfDiagramItemValidator: (d: DiagramItem) => Promise<ValidationItem[]>;
@@ -1,6 +1,6 @@
1
- import { WorkItemStatus } from '@topconsultnpm/sdk-ts-beta';
1
+ import { PlatformObjectValidator, QueryValidatorOptions, ResultTypes, TMPropertyNames, ValidationItem, WorkItemStatus } from '@topconsultnpm/sdk-ts-beta';
2
2
  import { DiagramItemTypes, ArrowSymbol } from './interfaces'; // Assicurati che il percorso sia corretto
3
- import { generateUUID } from '../../../../helper';
3
+ import { generateUUID, SDKUI_Localizator } from '../../../../helper';
4
4
  /**
5
5
  * Calculates the angle in degrees of an arrow based on two points.
6
6
  * @param prevPoint The previous point on the trajectory.
@@ -259,9 +259,10 @@ export const getNewWfDiagram = (info) => {
259
259
  ID: generateUUID(),
260
260
  Left: 100,
261
261
  Top: 100,
262
- Width: 64,
263
- Height: 64,
262
+ Width: 32,
263
+ Height: 32,
264
264
  Type: DiagramItemTypes.Start,
265
+ StartAfterArchive: 1,
265
266
  ItemName: '',
266
267
  Description: '',
267
268
  };
@@ -269,9 +270,10 @@ export const getNewWfDiagram = (info) => {
269
270
  ID: generateUUID(),
270
271
  Left: 300,
271
272
  Top: 100,
272
- Width: 64,
273
- Height: 64,
273
+ Width: 32,
274
+ Height: 32,
274
275
  Type: DiagramItemTypes.End,
276
+ Hist: 1,
275
277
  ItemName: '',
276
278
  Description: '',
277
279
  };
@@ -292,3 +294,197 @@ export const getNewWfDiagram = (info) => {
292
294
  };
293
295
  return newWfDiagram;
294
296
  };
297
+ export const workflowValidator = async (wf) => {
298
+ const validationItems = [];
299
+ if (!wf.Info) {
300
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "info", "Il workflow deve avere informazioni generali valide."));
301
+ }
302
+ if (!wf.DiagramItems || wf.DiagramItems.length === 0) {
303
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "diagramItems", "Il workflow deve contenere almeno un elemento nel diagramma."));
304
+ }
305
+ if (!wf.Connections || wf.Connections.length === 0) {
306
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "connections", "Il workflow deve contenere almeno una connessione tra gli elementi."));
307
+ }
308
+ const startItems = wf.DiagramItems.filter(item => item.Type === DiagramItemTypes.Start);
309
+ if (startItems.length === 0) {
310
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "startItems", "Il workflow deve contenere esattamente un elemento di tipo 'Start'."));
311
+ }
312
+ if (startItems.length > 1) {
313
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "startItems", "Il workflow non può contenere più di un elemento di tipo 'Start'."));
314
+ }
315
+ const endItems = wf.DiagramItems.filter(item => item.Type === DiagramItemTypes.End);
316
+ if (endItems.length === 0) {
317
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, "endItems", "Il workflow deve contenere almeno un elemento di tipo 'End'."));
318
+ }
319
+ for (const item of wf.DiagramItems) {
320
+ const vil = await wfDiagramItemValidator(item);
321
+ vil.forEach(v => v.PropertyScopes = ['diagramItem']);
322
+ validationItems.push(...vil);
323
+ switch (item.Type) {
324
+ case DiagramItemTypes.Start:
325
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
326
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, "L'elemento 'Start' deve avere almeno una connessione in uscita.", ['diagramItem']));
327
+ }
328
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length > 0) {
329
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, "L'elemento 'Start' non può avere connessioni in ingresso.", ['diagramItem']));
330
+ }
331
+ break;
332
+ case DiagramItemTypes.End:
333
+ case DiagramItemTypes.Exit:
334
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
335
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, `L'elemento '${DiagramItemTypes[item.Type]}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
336
+ }
337
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length > 0) {
338
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, `L'elemento '${DiagramItemTypes[item.Type]}' non può avere connessioni in uscita.`, ['diagramItem']));
339
+ }
340
+ break;
341
+ case DiagramItemTypes.Condition:
342
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 2) {
343
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, "L'elemento 'Condition' deve avere esattamente due connessioni in uscita.", ['diagramItem']));
344
+ }
345
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
346
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, `item-${item.ID}`, "L'elemento 'Condition' deve avere almeno una connessione in ingresso.", ['diagramItem']));
347
+ }
348
+ break;
349
+ case DiagramItemTypes.Approval:
350
+ case DiagramItemTypes.ExecTask:
351
+ case DiagramItemTypes.DataEntry:
352
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 2) {
353
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere esattamente due connessioni in uscita.`, ['diagramItem']));
354
+ }
355
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
356
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
357
+ }
358
+ break;
359
+ case DiagramItemTypes.Notification:
360
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
361
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere almeno una connessione in uscita.`, ['diagramItem']));
362
+ }
363
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
364
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
365
+ }
366
+ break;
367
+ case DiagramItemTypes.UpdateDcmt:
368
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 1) {
369
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere esattamente una connessione in uscita.`, ['diagramItem']));
370
+ }
371
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
372
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
373
+ }
374
+ break;
375
+ case DiagramItemTypes.Status:
376
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length !== 1) {
377
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere esattamente una connessione in uscita.`, ['diagramItem']));
378
+ }
379
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
380
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
381
+ }
382
+ break;
383
+ case DiagramItemTypes.RunApp:
384
+ if (wf.Connections.filter(c => c.Source.ParentDiagramItem.ID === item.ID).length === 0) {
385
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' dovrebbe avere almeno una connessione in uscita.`, ['diagramItem']));
386
+ }
387
+ if (wf.Connections.filter(c => c.Sink.ParentDiagramItem.ID === item.ID).length === 0) {
388
+ validationItems.push(new ValidationItem(ResultTypes.WARNING, `item-${item.ID}`, `L'elemento '${item.ItemName}' deve avere almeno una connessione in ingresso.`, ['diagramItem']));
389
+ }
390
+ break;
391
+ }
392
+ }
393
+ // Tutte le validazioni sono passate
394
+ return validationItems;
395
+ };
396
+ export const DiagramItemProps = {
397
+ ID: 'ID',
398
+ Left: 'Left',
399
+ Top: 'Top',
400
+ Width: 'Width',
401
+ Height: 'Height',
402
+ Type: 'Type',
403
+ ItemName: 'ItemName',
404
+ ItemName_IT: 'ItemName_IT',
405
+ ItemName_EN: 'ItemName_EN',
406
+ ItemName_FR: 'ItemName_FR',
407
+ ItemName_PT: 'ItemName_PT',
408
+ ItemName_ES: 'ItemName_ES',
409
+ ItemName_DE: 'ItemName_DE',
410
+ Description: 'Description',
411
+ Description_IT: 'Description_IT',
412
+ Description_EN: 'Description_EN',
413
+ Description_FR: 'Description_FR',
414
+ Description_PT: 'Description_PT',
415
+ Description_ES: 'Description_ES',
416
+ Description_DE: 'Description_DE',
417
+ StatusValue: 'StatusValue',
418
+ RegisterPost: 'RegisterPost',
419
+ AllowZeroTos: 'AllowZeroTos',
420
+ Tos: 'Tos',
421
+ SetRule: 'SetRule',
422
+ StartAfterArchive: 'StartAfterArchive',
423
+ StartAfterUpdate: 'StartAfterUpdate',
424
+ StartAfterUpdateMIDs: 'StartAfterUpdateMIDs',
425
+ StartManual: 'StartManual',
426
+ Hist: 'Hist',
427
+ EndWFInstance: 'EndWFInstance',
428
+ QD: 'QD',
429
+ SOD: 'SOD',
430
+ MetadataValues: 'MetadataValues',
431
+ Severity: 'Severity',
432
+ RegAsWfInstPart: 'RegAsWfInstPart',
433
+ FormatCultureID: 'FormatCultureID',
434
+ Tos2: 'Tos2',
435
+ QD2: 'QD2',
436
+ PlatformObjName: 'PlatformObjName',
437
+ PlatformObjDescr: 'PlatformObjDescr',
438
+ Value1asInt: 'Value1asInt',
439
+ Value2asInt: 'Value2asInt',
440
+ Value3asInt: 'Value3asInt',
441
+ Value1asString: 'Value1asString',
442
+ AppType: 'AppType',
443
+ AppName: 'AppName',
444
+ AppArgs: 'AppArgs',
445
+ Trunc: 'Trunc',
446
+ };
447
+ export const wfDiagramItemValidator = async (d) => {
448
+ let vil = [];
449
+ switch (d.Type) {
450
+ case DiagramItemTypes.Start:
451
+ if (d.StartAfterArchive !== 1 && d.StartAfterUpdate !== 1 && d.StartManual !== 1)
452
+ vil.push(new ValidationItem(ResultTypes.ERROR, "*", "Indicare la modalità di avvio dell'istanza di workflow"));
453
+ if (d.StartAfterUpdate === 1 && (d.StartAfterUpdateMIDs === undefined || d.StartAfterUpdateMIDs.length <= 0))
454
+ vil.push(new ValidationItem(ResultTypes.ERROR, DiagramItemProps.StartAfterUpdateMIDs, "Indicare almeno un metadato la cui modifica avvii l'istanza"));
455
+ break;
456
+ case DiagramItemTypes.Approval:
457
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
458
+ PlatformObjectValidator.RequiredStringValidator(d.Description, DiagramItemProps.Description, vil, SDKUI_Localizator.Description);
459
+ PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
460
+ break;
461
+ case DiagramItemTypes.ExecTask:
462
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
463
+ PlatformObjectValidator.RequiredStringValidator(d.Description, DiagramItemProps.Description, vil, SDKUI_Localizator.Description);
464
+ PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
465
+ PlatformObjectValidator.RequiredStringValidator(d.AppName, DiagramItemProps.AppName, vil, SDKUI_Localizator.WorkflowAppName);
466
+ PlatformObjectValidator.RequiredStringValidator(d.AppType, DiagramItemProps.AppType, vil, SDKUI_Localizator.WorkflowAppType);
467
+ break;
468
+ case DiagramItemTypes.Notification:
469
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
470
+ PlatformObjectValidator.RequiredStringValidator(d.Tos, DiagramItemProps.Tos, vil, SDKUI_Localizator.Recipients);
471
+ PlatformObjectValidator.RequiredStringValidator(d.Severity, DiagramItemProps.Severity, vil, SDKUI_Localizator.Severity);
472
+ break;
473
+ case DiagramItemTypes.RunApp:
474
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
475
+ PlatformObjectValidator.RequiredStringValidator(d.AppName, DiagramItemProps.AppName, vil, SDKUI_Localizator.WorkflowAppName);
476
+ PlatformObjectValidator.RequiredStringValidator(d.AppType, DiagramItemProps.AppType, vil, SDKUI_Localizator.WorkflowAppType);
477
+ break;
478
+ case DiagramItemTypes.Condition:
479
+ PlatformObjectValidator.RequiredStringValidator(d.ItemName, DiagramItemProps.ItemName, vil, SDKUI_Localizator.Name);
480
+ let qvo = new QueryValidatorOptions();
481
+ qvo.DoSelectValidation = false;
482
+ qvo.DoOrderByValidation = false;
483
+ await PlatformObjectValidator.QueryValidatorAsync(d.QD, vil, qvo);
484
+ if (d.QD?.where === undefined || d.QD.where.length <= 0) {
485
+ vil.push(new ValidationItem(ResultTypes.ERROR, TMPropertyNames.where, "La query della condizione non contiene criteri di selezione", [DiagramItemProps.QD]));
486
+ }
487
+ break;
488
+ }
489
+ return vil;
490
+ };
@@ -165,7 +165,12 @@ const TMPage = ({ id, objClass = ObjectClasses.None, listDisabled = false, lastR
165
165
  canPrev: canPrev(visibleItems, selectedItems),
166
166
  onPrev: () => { setSelectedItems([getPrev(visibleItems, selectedItems)]); },
167
167
  onShowList: (value) => { setShowList(value); },
168
- onCancel: () => {
168
+ onCancel: (withoutConfirm) => {
169
+ if (withoutConfirm) {
170
+ setFormMode(FormModes.Update);
171
+ setSelectionListDisabled(false);
172
+ return;
173
+ }
169
174
  TMMessageBoxManager.show({
170
175
  title: SDKUI_Localizator.Cancel, message: SDKUI_Localizator.ConfirmOnCancel, buttons: [ButtonNames.YES, ButtonNames.NO],
171
176
  onButtonClick: async (e) => {
package/lib/ts/types.d.ts CHANGED
@@ -162,7 +162,7 @@ export interface ITMSaveFormBaseProps {
162
162
  canNext?: boolean;
163
163
  canPrev?: boolean;
164
164
  /** Se presente, delegate che contiene la logica quando si abbandona la modalità Create o Duplicate */
165
- onCancel?: () => void;
165
+ onCancel?: (withoutConfirm?: boolean) => void;
166
166
  /** Se isModal = true, delegate per la chiusura del form */
167
167
  onClose?: () => void;
168
168
  /** Delegate che contiene la logica del salvataggio del descrittore */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.16.98",
3
+ "version": "6.16.100",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -39,7 +39,7 @@
39
39
  "lib"
40
40
  ],
41
41
  "dependencies": {
42
- "@topconsultnpm/sdk-ts-beta": "6.16.16",
42
+ "@topconsultnpm/sdk-ts-beta": "6.16.17",
43
43
  "buffer": "^6.0.3",
44
44
  "devextreme": "25.1.4",
45
45
  "devextreme-react": "25.1.4",