@topconsultnpm/sdkui-react-beta 6.16.99 → 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.
@@ -294,3 +294,197 @@ export const getNewWfDiagram = (info) => {
294
294
  };
295
295
  return newWfDiagram;
296
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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.16.99",
3
+ "version": "6.16.100",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",