@topconsultnpm/sdkui-react-beta 6.16.76 → 6.16.78

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,10 +8,10 @@ import { DownloadTypes, FormModes } from '../../../ts';
8
8
  import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
9
9
  import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
10
10
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
11
- import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, svgToString, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconZoomIn, IconZoomOut } from '../../../helper';
11
+ import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, svgToString, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow } from '../../../helper';
12
12
  import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
13
13
  import { Gutters, TMColors } from '../../../utils/theme';
14
- import { StyledClickableIconWrapper, StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
14
+ import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
15
15
  import ShowAlert from '../../base/TMAlert';
16
16
  import TMButton from '../../base/TMButton';
17
17
  import { TMExceptionBoxManager, TMMessageBoxManager, ButtonNames } from '../../base/TMPopUp';
@@ -74,7 +74,6 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
74
74
  const [workItems, setWorkItems] = useState([]);
75
75
  const [workflows, setWorkflows] = useState([]);
76
76
  const [showCommentForm, setShowCommentForm] = useState(false);
77
- const [zoomLevel, setZoomLevel] = useState(1);
78
77
  const { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog } = useInputAttachmentsDialog();
79
78
  const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync } = useDcmtOperations();
80
79
  // Custom hook to manage workflow approval data
@@ -155,9 +154,6 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
155
154
  TMSpinner.hide();
156
155
  }
157
156
  };
158
- const handleZoomIn = () => setZoomLevel(z => Math.min(z + 0.2, 2));
159
- const handleZoomOut = () => setZoomLevel(z => Math.max(z - 0.2, 0.4));
160
- const formattedZoomLevel = `${Math.round(zoomLevel * 100)}%`;
161
157
  useEffect(() => { setID(genUniqueId()); }, []);
162
158
  useEffect(() => {
163
159
  if (!inputFile || inputFile === null)
@@ -555,7 +551,7 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
555
551
  }, children: _jsxs(StyledLoadingContainer, { children: [_jsx(StyledSpinner, {}), _jsx("span", { children: `${'Caricamento dati workflow'}...` })] }) }));
556
552
  }
557
553
  return (_jsxs("div", { style: { position: 'relative', width: '100%', height: '100%', display: 'flex', flexDirection: 'column', gap: 3 }, children: [workItems.length > 0
558
- ? _jsx(WFDiagram, { xmlDiagramString: workflows?.[0]?.diagram || '', currentSetID: workitemSetID, readOnly: true, zoomLevel: zoomLevel, translateX: 0, translateY: 0 })
554
+ ? _jsx(WFDiagram, { xmlDiagramString: workflows?.[0]?.diagram || '', allowEdit: false, currentSetID: workitemSetID })
559
555
  : _jsx("div", { style: {
560
556
  position: 'absolute',
561
557
  top: '50%',
@@ -564,35 +560,13 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
564
560
  fontSize: '1.1rem',
565
561
  color: TMColors.primaryColor,
566
562
  textAlign: 'center',
567
- }, children: SDKUI_Localizator.WorkitemsToApproveNone }), workItems.length > 0 && _jsxs("div", { style: {
568
- position: 'absolute',
569
- left: 16,
570
- bottom: workitemSetID || workItems.length <= 0 ? 16 : 64,
571
- display: 'flex',
572
- flexDirection: 'row',
573
- background: 'transparent linear-gradient(180deg, #E03A8B 9%, #C2388B 34%, #A63B8D 60%, #943C8D 83%, #8F3C8D 100%) 0% 0% no-repeat padding-box',
574
- gap: 5,
575
- padding: 5,
576
- borderRadius: 8,
577
- color: 'white',
578
- zIndex: 10,
579
- alignItems: 'center'
580
- }, children: [_jsx(StyledClickableIconWrapper, { onClick: handleZoomIn, "$disabled": zoomLevel >= 2, children: _jsx(IconZoomIn, { fontSize: 22 }) }), _jsx(StyledClickableIconWrapper, { onClick: handleZoomOut, "$disabled": zoomLevel <= 0.4, children: _jsx(IconZoomOut, { fontSize: 22 }) }), _jsx("span", { style: {
581
- backgroundColor: 'white',
582
- color: '#555',
583
- fontSize: '0.9rem',
584
- height: 32,
585
- display: 'flex',
586
- alignItems: 'center',
587
- padding: '0 8px',
588
- borderRadius: 4
589
- }, children: formattedZoomLevel })] }), !workitemSetID && workItems.length > 0 &&
563
+ }, children: SDKUI_Localizator.WorkitemsToApproveNone }), !workitemSetID && workItems.length > 0 &&
590
564
  _jsx("div", { style: {
591
565
  padding: 5,
592
566
  backgroundColor: 'khaki',
593
567
  borderRadius: 8
594
568
  }, children: SDKUI_Localizator.WorkItemTechnicalNote_SetID })] }));
595
- }, [workflows, formData, workitemSetID, workItems, zoomLevel, isWFDataLoading, handleZoomIn, handleZoomOut]);
569
+ }, [workflows, formData, workitemSetID, workItems, isWFDataLoading]);
596
570
  const normalizedTID = TID !== undefined ? Number(TID) : undefined;
597
571
  const defaultPanelDimensions = {
598
572
  'tmDcmtForm': { width: '20%', height: '100%' },
@@ -1,11 +1,9 @@
1
1
  import React from 'react';
2
2
  interface IWFDiagramProps {
3
3
  xmlDiagramString: string;
4
- readOnly?: boolean;
5
- zoomLevel?: number;
6
- translateX?: number;
7
- translateY?: number;
8
4
  currentSetID?: string;
5
+ allowEdit?: boolean;
6
+ onDiagramChange?: (newXmlDiagram: string) => void;
9
7
  }
10
8
  declare const WFDiagram: React.FC<IWFDiagramProps>;
11
9
  export default WFDiagram;
@@ -1,17 +1,76 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
3
3
  import { DiagramItemTypes, ArrowSymbol } from './interfaces';
4
4
  import { parseWfDiagramXml, serializeWfDiagramToXml } from './xmlParser';
5
- import styled from 'styled-components';
5
+ import styled, { keyframes } from 'styled-components';
6
6
  import { CultureIDs, SearchEngine, WFAppTypes, WorkItemStatus } from "@topconsultnpm/sdk-ts-beta";
7
7
  import ConnectionComponent from './ConnectionComponent';
8
8
  import DiagramItemComponent from './DiagramItemComponent';
9
9
  import DiagramItemSvgContent from './DiagramItemSvgContent';
10
10
  import { calculateArrowAngle, downloadFile, getConnectionPoint, isConnectionNonLinear, validateDiagram } from './workflowHelpers';
11
- import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport } from '../../../../helper';
12
- import { TMExceptionBoxManager } from '../../../base/TMPopUp';
11
+ import { IconFlowChart, IconUndo, IconRestore, IconAdjust, IconCopy, IconCut, IconPaste, IconPin, IconUnpin, IconChevronRight, IconCloseOutline, IconNew, SDKUI_Localizator, generateUUID, IconExport, IconImport, IconWindowMaximize, IconZoomIn, IconZoomOut, IconPencil, IconLock } from '../../../../helper';
12
+ import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../../../base/TMPopUp';
13
13
  import { StyledLoadingContainer, StyledSpinner } from '../../../base/Styled';
14
14
  import DiagramItemForm from './DiagramItemForm';
15
+ import ReactDOM from 'react-dom';
16
+ const ZoomLevelText = styled.span `
17
+ font-size: 0.9em;
18
+ color: #555;
19
+ white-space: nowrap;
20
+ background-color: white;
21
+ padding: 2px 4px; /* Aggiunto un leggero padding per chiarezza */
22
+ border-radius: 4px;
23
+
24
+ /* A. Modalità Compressa (non Floating & Collapsed) */
25
+ ${props => !props.$isFloating && props.$isCollapsed
26
+ ? `
27
+ padding: 0 2px;
28
+ margin: 0;
29
+ display: inline-block;
30
+ line-height: 20px;
31
+ `
32
+ // B. Modalità Flottante (Verticale)
33
+ : props.$isFloating
34
+ ? `
35
+ display: block;
36
+ text-align: center;
37
+ margin: 4px 0;
38
+ padding: 2px 4px;
39
+ `
40
+ // C. Modalità Standard (Orizzontale & non Collapsed)
41
+ : `
42
+ display: flex;
43
+ align-items: center;
44
+ margin: 0 8px;
45
+ padding: 2px 4px;
46
+ `}
47
+ `;
48
+ const DiagramWrapper = styled.div `
49
+ height: 100%;
50
+ width: 100%;
51
+ border: 1px solid #ddd;
52
+ border-radius: 8px;
53
+ overflow: hidden;
54
+ background-color: white;
55
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
56
+ display: flex;
57
+ flex-direction: column;
58
+ position: relative;
59
+ transition: all 0.3s ease-in-out;
60
+ `;
61
+ const FullScreenContainer = styled.div `
62
+ position: fixed;
63
+ top: 0;
64
+ left: 0;
65
+ width: 100vw;
66
+ height: 100vh;
67
+ z-index: 1500;
68
+ background-color: white;
69
+ display: flex;
70
+ flex-direction: column;
71
+ justify-content: center;
72
+ align-items: center;
73
+ `;
15
74
  const CanvasContainer = styled.div `
16
75
  position: relative;
17
76
  width: 100%;
@@ -21,10 +80,23 @@ const CanvasContainer = styled.div `
21
80
  display: flex;
22
81
  overflow: hidden; /* Ensure content doesn't overflow when panels are collapsed */
23
82
  `;
83
+ const pulse = keyframes `
84
+ 0% {
85
+ box-shadow: 0 0 0 0px rgba(0, 123, 255, 0.7); /* Colore #007bff */
86
+ }
87
+ 70% {
88
+ box-shadow: 0 0 0 10px rgba(0, 123, 255, 0);
89
+ }
90
+ 100% {
91
+ box-shadow: 0 0 0 0px rgba(0, 123, 255, 0);
92
+ }
93
+ `;
24
94
  const ToolbarContainer = styled.div `
25
95
  display: flex;
26
96
  gap: 5px;
27
- background: transparent linear-gradient(180deg, #E03A8B 9%, #C2388B 34%, #A63B8D 60%, #943C8D 83%, #8F3C8D 100%) 0% 0% no-repeat padding-box;
97
+ background: ${props => props.$isReadOnly
98
+ ? 'transparent linear-gradient(180deg, #007bff 0%, #1E90FF 45%, #0056b3 100%) 0% 0% no-repeat padding-box'
99
+ : 'transparent linear-gradient(180deg, #E03A8B 9%, #C2388B 34%, #A63B8D 60%, #943C8D 83%, #8F3C8D 100%) 0% 0% no-repeat padding-box'};
28
100
  padding: 8px;
29
101
  border-radius: 4px;
30
102
  z-index: 10;
@@ -34,19 +106,21 @@ const ToolbarContainer = styled.div `
34
106
  ${props => props.$isFloating ? `
35
107
  position: absolute;
36
108
  bottom: 20px;
37
- left: ${props.$isToolboxVisible ? '160px' : '20px'};
38
- flex-direction: row; // Orizzontale in modalità floating
39
- width: auto; // Lascia che il contenuto determini la larghezza
109
+ left: ${props.$isReadOnly ? '20px' : props.$isToolboxVisible ? '160px' : '20px'};
110
+ flex-direction: row;
111
+ width: auto;
40
112
  box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
41
- padding: 5px 8px; // Padding leggermente ridotto per la modalità floating
113
+ padding: 5px 8px;
42
114
  ` : `
43
- position: relative; // O 'absolute; top: 8px; left: 8px;' a seconda del layout del CanvasContainer
44
- flex-direction: column; // Verticale in modalità ancorata
115
+ position: relative;
116
+ flex-direction: column;
45
117
  width: ${props.$isCollapsed ? '40px' : 'auto'};
46
118
  `}
47
119
  overflow-y: auto;
48
120
 
49
121
  button {
122
+
123
+
50
124
  background: none;
51
125
  border: none;
52
126
  cursor: pointer;
@@ -55,6 +129,8 @@ const ToolbarContainer = styled.div `
55
129
  align-items: center;
56
130
  justify-content: ${props => props.$isCollapsed || props.$isFloating ? 'center' : 'flex-start'}; // Centra icone in entrambe le modalità
57
131
  white-space: nowrap;
132
+ position: relative;
133
+ transition: background-color 0.3s, box-shadow 0.3s;
58
134
 
59
135
  svg {
60
136
  color: white;
@@ -205,7 +281,12 @@ const DiagramMessage = styled.div `
205
281
  color: #555;
206
282
  text-align: center;
207
283
  `;
208
- const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel = 1, translateX = 0, translateY = 0 }) => {
284
+ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagramChange }) => {
285
+ const [isReadOnly, setIsReadOnly] = useState(true);
286
+ const [isFullScreen, setIsFullScreen] = useState(false);
287
+ const [zoomLevel, setZoomLevel] = useState(1);
288
+ const [translateX, setTranslateX] = useState(0);
289
+ const [translateY, setTranslateY] = useState(0);
209
290
  const [isLoading, setIsLoading] = useState(true);
210
291
  const [wfDiagram, setWfDiagram] = useState(null);
211
292
  const [selectedItems, setSelectedItems] = useState(new Set());
@@ -214,6 +295,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
214
295
  const [historyIndex, setHistoryIndex] = useState(-1);
215
296
  const isUndoingRedoing = useRef(false);
216
297
  const initialDiagramRef = useRef(null);
298
+ const notifiedXmlRef = useRef(null);
217
299
  const svgRef = useRef(null);
218
300
  const [isDrawingConnection, setIsDrawingConnection] = useState(false);
219
301
  const [tempConnectionSource, setTempConnectionSource] = useState(null);
@@ -271,7 +353,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
271
353
  return { svgWidth: Math.max(0, totalWidth * zoomLevel), svgHeight: Math.max(0, totalHeight * zoomLevel) };
272
354
  }, [wfDiagram, zoomLevel]);
273
355
  const updateDiagram = useCallback((newDiagram, validate = true) => {
274
- if (readOnly)
356
+ if (isReadOnly)
275
357
  return;
276
358
  try {
277
359
  if (validate) {
@@ -283,13 +365,28 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
283
365
  setHistoryIndex(newHistory.length);
284
366
  }
285
367
  setWfDiagram(newDiagram);
368
+ (async () => {
369
+ try {
370
+ // await è necessario per attendere il risultato stringa
371
+ const newXml = await serializeWfDiagramToXml(newDiagram);
372
+ notifiedXmlRef.current = newXml;
373
+ // Chiama il callback per notificare TMWFEditor
374
+ // L'invio dell'XML al genitore avviene solo a serializzazione completata.
375
+ onDiagramChange?.(newXml);
376
+ }
377
+ catch (e) {
378
+ console.error("Errore durante la serializzazione del diagramma:", e);
379
+ // Puoi gestire l'errore di serializzazione qui, ad esempio mostrando una notifica
380
+ // TMExceptionBoxManager.show({ exception: new Error("Errore serializzazione WF") });
381
+ }
382
+ })();
286
383
  }
287
384
  catch (e) {
288
385
  TMExceptionBoxManager.show({ exception: e });
289
386
  }
290
- }, [wfDiagramHistory, historyIndex, isUndoingRedoing, setWfDiagramHistory, setHistoryIndex, setWfDiagram, readOnly]);
387
+ }, [wfDiagramHistory, historyIndex, isUndoingRedoing, setWfDiagramHistory, setHistoryIndex, setWfDiagram, isReadOnly]);
291
388
  const handleUndo = useCallback(() => {
292
- if (readOnly)
389
+ if (isReadOnly)
293
390
  return;
294
391
  if (historyIndex > 0) {
295
392
  isUndoingRedoing.current = true;
@@ -297,9 +394,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
297
394
  setHistoryIndex(newIndex);
298
395
  setWfDiagram(wfDiagramHistory[newIndex]);
299
396
  }
300
- }, [historyIndex, wfDiagramHistory, setHistoryIndex, setWfDiagram, readOnly]);
397
+ }, [historyIndex, wfDiagramHistory, setHistoryIndex, setWfDiagram, isReadOnly]);
301
398
  const handleRedo = useCallback(() => {
302
- if (readOnly)
399
+ if (isReadOnly)
303
400
  return;
304
401
  if (historyIndex < wfDiagramHistory.length - 1) {
305
402
  isUndoingRedoing.current = true;
@@ -307,9 +404,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
307
404
  setHistoryIndex(newIndex);
308
405
  setWfDiagram(wfDiagramHistory[newIndex]);
309
406
  }
310
- }, [historyIndex, wfDiagramHistory, setHistoryIndex, setWfDiagram, readOnly]);
407
+ }, [historyIndex, wfDiagramHistory, setHistoryIndex, setWfDiagram, isReadOnly]);
311
408
  const handleDelete = useCallback(() => {
312
- if (readOnly)
409
+ if (isReadOnly)
313
410
  return;
314
411
  if (!wfDiagram || (selectedItems.size === 0 && selectedConnections.size === 0)) {
315
412
  return;
@@ -338,9 +435,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
338
435
  setSelectedItems(new Set([...deletableSelectedItems, ...[...selectedItems].filter(id => nonDeletableItems.some(item => item.ID === id))]));
339
436
  setSelectedConnections(new Set());
340
437
  updateDiagram(newWfDiagram, false);
341
- }, [wfDiagram, selectedItems, selectedConnections, setWfDiagram, setSelectedItems, setSelectedConnections, updateDiagram, readOnly]);
438
+ }, [wfDiagram, selectedItems, selectedConnections, setWfDiagram, setSelectedItems, setSelectedConnections, updateDiagram, isReadOnly]);
342
439
  const handleCopy = useCallback(() => {
343
- if (readOnly)
440
+ if (isReadOnly)
344
441
  return;
345
442
  if (!wfDiagram || selectedItems.size === 0) {
346
443
  return;
@@ -351,9 +448,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
351
448
  setCopiedItems(itemsToCopy);
352
449
  setCopiedConnections(connectionsToCopy);
353
450
  setIsCutOperation(false);
354
- }, [wfDiagram, selectedItems, readOnly]);
451
+ }, [wfDiagram, selectedItems, isReadOnly]);
355
452
  const handleCut = useCallback(() => {
356
- if (readOnly)
453
+ if (isReadOnly)
357
454
  return;
358
455
  if (!wfDiagram || selectedItems.size === 0) {
359
456
  return;
@@ -375,9 +472,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
375
472
  setSelectedItems(new Set());
376
473
  setSelectedConnections(new Set());
377
474
  updateDiagram(newWfDiagram, false);
378
- }, [wfDiagram, selectedItems, setSelectedItems, setSelectedConnections, updateDiagram, readOnly]);
475
+ }, [wfDiagram, selectedItems, setSelectedItems, setSelectedConnections, updateDiagram, isReadOnly]);
379
476
  const handlePaste = useCallback(() => {
380
- if (readOnly)
477
+ if (isReadOnly)
381
478
  return;
382
479
  if (!wfDiagram || (copiedItems.length === 0 && copiedConnections.length === 0)) {
383
480
  return;
@@ -425,9 +522,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
425
522
  Connections: combinedConnections,
426
523
  };
427
524
  updateDiagram(newWfDiagram, false);
428
- }, [wfDiagram, copiedItems, copiedConnections, isCutOperation, updateDiagram, setSelectedItems, setSelectedConnections, readOnly]);
525
+ }, [wfDiagram, copiedItems, copiedConnections, isCutOperation, updateDiagram, setSelectedItems, setSelectedConnections, isReadOnly]);
429
526
  const handleNew = useCallback(() => {
430
- if (readOnly)
527
+ if (isReadOnly)
431
528
  return;
432
529
  const startItem = {
433
530
  ID: generateUUID(),
@@ -463,7 +560,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
463
560
  setCopiedItems([]);
464
561
  setCopiedConnections([]);
465
562
  setIsCutOperation(false);
466
- }, [wfDiagram, readOnly]);
563
+ }, [wfDiagram, isReadOnly]);
467
564
  const handleToggleToolbarMode = () => {
468
565
  setIsToolbarFloating(prev => !prev);
469
566
  };
@@ -471,23 +568,23 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
471
568
  setIsToolboxVisible(prev => !prev);
472
569
  };
473
570
  const handleDoubleClickItem = useCallback((itemId) => {
474
- if (readOnly)
571
+ if (isReadOnly)
475
572
  return;
476
573
  const itemFound = wfDiagram?.DiagramItems.find(item => item.ID === itemId);
477
574
  if (itemFound) {
478
575
  setItemToEdit(itemFound);
479
576
  setIsModalOpen(true);
480
577
  }
481
- }, [wfDiagram, readOnly]);
578
+ }, [wfDiagram, isReadOnly]);
482
579
  const handleCloseModal = useCallback(() => {
483
- if (readOnly)
580
+ if (isReadOnly)
484
581
  return;
485
582
  setIsModalOpen(prevIsModalOpen => {
486
583
  return false;
487
584
  });
488
- }, [readOnly]);
585
+ }, [isReadOnly]);
489
586
  const handleKeyDown = useCallback((event) => {
490
- if (readOnly)
587
+ if (isReadOnly)
491
588
  return;
492
589
  if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Delete', 'Backspace', 'z', 'y'].includes(event.key)) {
493
590
  // Prevent the event from bubbling up to parent components (like the TabPanel)
@@ -563,7 +660,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
563
660
  handleDelete();
564
661
  return;
565
662
  }
566
- }, [wfDiagram, selectedItems, selectedConnections, handleUndo, handleRedo, handleDelete, updateDiagram, handleCopy, handleCut, handlePaste, readOnly]);
663
+ }, [wfDiagram, selectedItems, selectedConnections, handleUndo, handleRedo, handleDelete, updateDiagram, handleCopy, handleCut, handlePaste, isReadOnly]);
567
664
  const handleExportDiagram = useCallback(async () => {
568
665
  if (!wfDiagram) {
569
666
  // Visualizza un errore se il diagramma non è stato caricato o è vuoto
@@ -581,16 +678,13 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
581
678
  catch (e) {
582
679
  TMExceptionBoxManager.show({ exception: e });
583
680
  }
584
- }, [wfDiagram]); // Dipende dallo stato attuale del diagramma
681
+ }, [wfDiagram]);
585
682
  const fileInputRef = useRef(null);
586
- // Gestore dell'evento click sul bottone (apre la finestra di selezione file)
587
683
  const handleImportDiagramClick = useCallback(() => {
588
684
  if (fileInputRef.current) {
589
685
  fileInputRef.current.click();
590
686
  }
591
687
  }, []);
592
- // Gestore dell'evento di selezione file (esegue il parse e chiama il genitore)
593
- // Gestore dell'evento di selezione file (esegue il parse e chiama il genitore)
594
688
  const handleFileChange = useCallback((event) => {
595
689
  const file = event.target.files?.[0];
596
690
  if (!file) {
@@ -600,23 +694,15 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
600
694
  reader.onload = (e) => {
601
695
  try {
602
696
  const xmlContent = e.target?.result;
603
- // 1. Esegui il parse per ottenere il nuovo oggetto WfDiagram.
604
697
  const newWfDiagram = parseWfDiagramXml(xmlContent);
605
- // 2. TRATTA L'IMPORT COME UNA MODIFICA:
606
- // Usa updateDiagram per aggiornare lo stato interno (wfDiagram) e la history (wfDiagramHistory).
607
- // L'originale xmlDiagramString del genitore resta intatto.
608
- // Passiamo false per 'validate' in quanto il file importato è già stato validato da parseWfDiagramXml.
609
698
  updateDiagram(newWfDiagram, false);
610
- // 3. Resetta l'input per permettere re-import dello stesso file
611
699
  if (fileInputRef.current) {
612
700
  fileInputRef.current.value = '';
613
701
  }
614
702
  }
615
703
  catch (error) {
616
- // Gestione dell'errore di parsing (es. file non valido)
617
704
  const errorMessage = 'Error importing diagram. Invalid XML format.';
618
705
  TMExceptionBoxManager.show({ exception: new Error(errorMessage + `\n${error.message}`) });
619
- // Resetta l'input anche in caso di errore
620
706
  if (fileInputRef.current) {
621
707
  fileInputRef.current.value = '';
622
708
  }
@@ -851,14 +937,14 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
851
937
  return "";
852
938
  }, [isDrawingConnection, tempConnectionSource, tempConnectionEnd, wfDiagram, isDraggingExistingConnectionEndpoint, draggingConnectionFixedPoint]);
853
939
  const handleRestore = useCallback(() => {
854
- if (readOnly)
940
+ if (isReadOnly)
855
941
  return;
856
942
  if (initialDiagramRef.current) {
857
943
  setWfDiagram(initialDiagramRef.current);
858
944
  setWfDiagramHistory([initialDiagramRef.current]);
859
945
  setHistoryIndex(0);
860
946
  }
861
- }, [readOnly]);
947
+ }, [isReadOnly]);
862
948
  const autoAdjustDiagram = (diagram) => {
863
949
  if (!diagram)
864
950
  return diagram;
@@ -974,13 +1060,13 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
974
1060
  return { ...adjustedItemsDiagram, Connections: adjustedConnections };
975
1061
  }, [calculateConnectionPath]);
976
1062
  const handleAutoAdjust = useCallback(() => {
977
- if (readOnly || !wfDiagram)
1063
+ if (isReadOnly || !wfDiagram)
978
1064
  return;
979
1065
  const finalDiagram = getAdjustedAndRecalculatedDiagram(wfDiagram);
980
1066
  updateDiagram(finalDiagram, false);
981
- }, [wfDiagram, readOnly, updateDiagram, getAdjustedAndRecalculatedDiagram]);
1067
+ }, [wfDiagram, isReadOnly, updateDiagram, getAdjustedAndRecalculatedDiagram]);
982
1068
  const handleMouseDown = useCallback((event) => {
983
- if (readOnly)
1069
+ if (isReadOnly)
984
1070
  return;
985
1071
  if (event.target === svgRef.current) {
986
1072
  setSelectedItems(new Set());
@@ -989,9 +1075,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
989
1075
  setSelectionRectStart({ x: event.nativeEvent.offsetX, y: event.nativeEvent.offsetY });
990
1076
  setSelectionRectEnd(null);
991
1077
  }
992
- }, [readOnly]);
1078
+ }, [isReadOnly]);
993
1079
  const handleMouseMove = useCallback((event) => {
994
- if (readOnly)
1080
+ if (isReadOnly)
995
1081
  return;
996
1082
  // Questa parte gestisce la transizione da "clic potenziale" a "trascinamento".
997
1083
  // Viene eseguita solo se un mousedown è avvenuto ma il drag non è ancora iniziato.
@@ -1070,9 +1156,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1070
1156
  // Logica per il trascinamento di un elemento dalla toolbox.
1071
1157
  setTempConnectionEnd({ x: event.nativeEvent.offsetX, y: event.nativeEvent.offsetY });
1072
1158
  }
1073
- }, [isDrawingConnection, tempConnectionSource, isDrawingSelectionRect, selectionRectStart, wfDiagram, zoomLevel, translateX, translateY, isDraggingFromToolbox, draggedItemType, readOnly, isDraggingExistingConnectionEndpoint, draggingConnectionFixedPoint, mouseDownPos]);
1159
+ }, [isDrawingConnection, tempConnectionSource, isDrawingSelectionRect, selectionRectStart, wfDiagram, zoomLevel, translateX, translateY, isDraggingFromToolbox, draggedItemType, isReadOnly, isDraggingExistingConnectionEndpoint, draggingConnectionFixedPoint, mouseDownPos]);
1074
1160
  const handleMouseUp = useCallback((event) => {
1075
- if (readOnly)
1161
+ if (isReadOnly)
1076
1162
  return;
1077
1163
  if (isDrawingConnection) {
1078
1164
  // Logica per una nuova connessione, rimane invariata
@@ -1097,9 +1183,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1097
1183
  }
1098
1184
  setIsDraggingFromToolbox(false);
1099
1185
  setDraggedItemType(null);
1100
- }, [isDrawingConnection, tempConnectionSource, tempConnectionEnd, isDrawingSelectionRect, selectionRectStart, selectionRectEnd, wfDiagram, zoomLevel, translateX, translateY, readOnly, isDraggingExistingConnectionEndpoint, draggingConnectionId, draggingEndpointType, draggingConnectionFixedPoint]);
1186
+ }, [isDrawingConnection, tempConnectionSource, tempConnectionEnd, isDrawingSelectionRect, selectionRectStart, selectionRectEnd, wfDiagram, zoomLevel, translateX, translateY, isReadOnly, isDraggingExistingConnectionEndpoint, draggingConnectionId, draggingEndpointType, draggingConnectionFixedPoint]);
1101
1187
  const handleDiagramItemClick = useCallback((id, event) => {
1102
- if (readOnly)
1188
+ if (isReadOnly)
1103
1189
  return;
1104
1190
  event.stopPropagation();
1105
1191
  const isCtrlPressed = event.ctrlKey || event.metaKey;
@@ -1121,9 +1207,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1121
1207
  });
1122
1208
  if (!isCtrlPressed)
1123
1209
  setSelectedConnections(new Set());
1124
- }, [readOnly]);
1210
+ }, [isReadOnly]);
1125
1211
  const handleConnectionClick = useCallback((id, event) => {
1126
- if (readOnly)
1212
+ if (isReadOnly)
1127
1213
  return;
1128
1214
  event.stopPropagation();
1129
1215
  const isCtrlPressed = event.ctrlKey || event.metaKey;
@@ -1145,9 +1231,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1145
1231
  });
1146
1232
  if (!isCtrlPressed)
1147
1233
  setSelectedItems(new Set());
1148
- }, [readOnly]);
1234
+ }, [isReadOnly]);
1149
1235
  const handleDrag = useCallback((id, newX, newY) => {
1150
- if (readOnly)
1236
+ if (isReadOnly)
1151
1237
  return;
1152
1238
  setWfDiagram(prevDiagram => {
1153
1239
  if (!prevDiagram)
@@ -1157,9 +1243,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1157
1243
  DiagramItems: prevDiagram.DiagramItems.map(item => item.ID === id ? { ...item, Left: newX, Top: newY } : item),
1158
1244
  };
1159
1245
  });
1160
- }, [readOnly]);
1246
+ }, [isReadOnly]);
1161
1247
  const handleDragEnd = useCallback((id, finalX, finalY) => {
1162
- if (readOnly)
1248
+ if (isReadOnly)
1163
1249
  return;
1164
1250
  setWfDiagram(prevDiagram => {
1165
1251
  if (!prevDiagram)
@@ -1171,9 +1257,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1171
1257
  updateDiagram(updatedDiagram);
1172
1258
  return updatedDiagram;
1173
1259
  });
1174
- }, [updateDiagram, readOnly]);
1260
+ }, [updateDiagram, isReadOnly]);
1175
1261
  const handleConnectorMouseDown = useCallback((itemId, connectorName, event) => {
1176
- if (readOnly || !wfDiagram)
1262
+ if (isReadOnly || !wfDiagram)
1177
1263
  return;
1178
1264
  event.stopPropagation();
1179
1265
  // Salva la posizione iniziale del mouse.
@@ -1181,9 +1267,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1181
1267
  // Imposta il connettore di partenza per un potenziale drag.
1182
1268
  setTempConnectionSource({ item: wfDiagram.DiagramItems.find(i => i.ID === itemId), connectorName });
1183
1269
  // NON avviare il drag qui. Lo faremo in base al movimento del mouse.
1184
- }, [wfDiagram, readOnly]);
1270
+ }, [wfDiagram, isReadOnly]);
1185
1271
  const handleConnectionEndpointMouseDown = useCallback((connectionId, endpointType, event) => {
1186
- if (readOnly)
1272
+ if (isReadOnly)
1187
1273
  return;
1188
1274
  event.stopPropagation();
1189
1275
  setIsDraggingExistingConnectionEndpoint(true);
@@ -1209,9 +1295,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1209
1295
  }
1210
1296
  }
1211
1297
  setTempConnectionEnd({ x: event.nativeEvent.offsetX, y: event.nativeEvent.offsetY });
1212
- }, [wfDiagram, readOnly]);
1298
+ }, [wfDiagram, isReadOnly]);
1213
1299
  const handleConnectorMouseUp = useCallback((targetItemId, targetConnectorName) => {
1214
- if (readOnly)
1300
+ if (isReadOnly)
1215
1301
  return;
1216
1302
  // Se isDrawingConnection è false, significa che il mouseup è avvenuto
1217
1303
  // prima che il drag fosse avviato (cioè, il mouse non si è mosso oltre la soglia).
@@ -1275,16 +1361,16 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1275
1361
  setTempConnectionSource(null);
1276
1362
  setTempConnectionEnd(null);
1277
1363
  setMouseDownPos(null);
1278
- }, [isDrawingConnection, tempConnectionSource, wfDiagram, updateDiagram, readOnly, isDraggingExistingConnectionEndpoint, draggingConnectionId, draggingEndpointType, draggingConnectionFixedPoint]);
1364
+ }, [isDrawingConnection, tempConnectionSource, wfDiagram, updateDiagram, isReadOnly, isDraggingExistingConnectionEndpoint, draggingConnectionId, draggingEndpointType, draggingConnectionFixedPoint]);
1279
1365
  const handleDragOver = useCallback((event) => {
1280
- if (readOnly) {
1366
+ if (isReadOnly) {
1281
1367
  event.preventDefault();
1282
1368
  return;
1283
1369
  }
1284
1370
  event.preventDefault();
1285
- }, [readOnly]);
1371
+ }, [isReadOnly]);
1286
1372
  const handleDropOnCanvas = useCallback((event) => {
1287
- if (readOnly)
1373
+ if (isReadOnly)
1288
1374
  return;
1289
1375
  event.preventDefault();
1290
1376
  if (isDraggingFromToolbox && draggedItemType !== null && wfDiagram) {
@@ -1319,7 +1405,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1319
1405
  setIsDraggingFromToolbox(false);
1320
1406
  setDraggedItemType(null);
1321
1407
  }
1322
- }, [isDraggingFromToolbox, draggedItemType, wfDiagram, updateDiagram, zoomLevel, readOnly]);
1408
+ }, [isDraggingFromToolbox, draggedItemType, wfDiagram, updateDiagram, zoomLevel, isReadOnly]);
1323
1409
  const currentSelectionRect = useMemo(() => {
1324
1410
  if (isDrawingSelectionRect && selectionRectStart && selectionRectEnd) {
1325
1411
  const x = Math.min(selectionRectStart.x, selectionRectEnd.x);
@@ -1331,16 +1417,16 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1331
1417
  return null;
1332
1418
  }, [isDrawingSelectionRect, selectionRectStart, selectionRectEnd]);
1333
1419
  const handleToolboxDragStart = useCallback((event, itemType) => {
1334
- if (readOnly) {
1420
+ if (isReadOnly) {
1335
1421
  event.preventDefault();
1336
1422
  return;
1337
1423
  }
1338
1424
  setIsDraggingFromToolbox(true);
1339
1425
  setDraggedItemType(itemType);
1340
1426
  event.dataTransfer.setData("text/plain", itemType.toString());
1341
- }, [readOnly]);
1427
+ }, [isReadOnly]);
1342
1428
  const handleToolboxDragEnd = () => {
1343
- if (readOnly)
1429
+ if (isReadOnly)
1344
1430
  return;
1345
1431
  setIsDraggingFromToolbox(false);
1346
1432
  setDraggedItemType(null);
@@ -1388,7 +1474,56 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1388
1474
  // DiagramItemTypes.SignAndTimeStamp
1389
1475
  ];
1390
1476
  }, []);
1477
+ const toggleReadOnlyMode = useCallback(() => {
1478
+ if (isReadOnly) {
1479
+ setIsReadOnly(false);
1480
+ return;
1481
+ }
1482
+ // Condizione per mostrare il messaggio di conferma
1483
+ const hasPendingState = wfDiagramHistory.length > 1 || selectedItems.size > 0 || selectedConnections.size > 0;
1484
+ if (hasPendingState) {
1485
+ TMMessageBoxManager.show({
1486
+ title: "Progettazione diagramma",
1487
+ message: "Attenzione: Stai uscendo dalla modalità di progettazione. Tutte le selezioni attive verranno annullate. Vuoi continuare?",
1488
+ buttons: [ButtonNames.YES, ButtonNames.NO],
1489
+ onButtonClick: async (e) => {
1490
+ try {
1491
+ if (e !== ButtonNames.YES)
1492
+ return;
1493
+ setIsReadOnly(true);
1494
+ setSelectedItems(new Set());
1495
+ setSelectedConnections(new Set());
1496
+ }
1497
+ catch (error) {
1498
+ console.error("Errore nel cambio modalità:", error);
1499
+ }
1500
+ }
1501
+ });
1502
+ }
1503
+ else {
1504
+ // Nessuna modifica pendente o elemento selezionato, cambia direttamente
1505
+ setIsReadOnly(true);
1506
+ }
1507
+ }, [isReadOnly, wfDiagramHistory, selectedItems, selectedConnections]);
1508
+ const toggleFullScreenMode = useCallback(() => {
1509
+ setIsFullScreen(prev => !prev);
1510
+ }, []);
1511
+ const handleZoomIn = useCallback(() => {
1512
+ setZoomLevel(prev => Math.min(prev + 0.1, 2.0)); // Limite max a 2.0
1513
+ }, []);
1514
+ const handleZoomOut = useCallback(() => {
1515
+ setZoomLevel(prev => Math.max(prev - 0.1, 0.5)); // Limite min a 0.5
1516
+ }, []);
1517
+ const formattedZoomLevel = useMemo(() => {
1518
+ return `${Math.round(zoomLevel * 100)}%`;
1519
+ }, [zoomLevel]);
1391
1520
  useEffect(() => {
1521
+ // Se l'XML che ho appena ricevuto (xmlDiagramString) è lo stesso che ho notificato al genitore,
1522
+ // significa che la modifica è partita da me ed è solo un ciclo di riconciliazione.
1523
+ if (xmlDiagramString && notifiedXmlRef.current === xmlDiagramString) {
1524
+ notifiedXmlRef.current = null;
1525
+ return;
1526
+ }
1392
1527
  // se undo/redo, il `xmlDiagramString` è cambiato ma la storia non deve essere resettata.
1393
1528
  if (isUndoingRedoing.current) {
1394
1529
  isUndoingRedoing.current = false;
@@ -1427,9 +1562,9 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1427
1562
  isUndoingRedoing.current = false;
1428
1563
  }
1429
1564
  }, [wfDiagram]);
1430
- return (_jsxs(CanvasContainer, { children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".xml" // Filtra per file XML
1431
- , onChange: handleFileChange, style: { display: 'none' } }), !readOnly && (_jsxs(ToolbarContainer, { "$isCollapsed": isToolbarCollapsed, "$isFloating": isToolbarFloating, "$isToolboxVisible": isToolboxVisible, children: [_jsx(ButtonGroup, { "$isFloating": isToolbarFloating, children: _jsxs("button", { onClick: handleToggleToolboxVisibility, title: "Show toolbox", children: [_jsx(IconFlowChart, {}), !isToolbarCollapsed && _jsx("span", { children: "Mostra/nascondi toolbox" })] }) }), _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [_jsxs("button", { onClick: handleUndo, disabled: historyIndex === 0, title: "Undo", children: [_jsx(IconUndo, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Undo" })] }), _jsxs("button", { onClick: handleRedo, disabled: historyIndex === wfDiagramHistory.length - 1, title: "Redo", children: [_jsx(IconUndo, { style: { transform: 'scaleX(-1)' } }), " ", !isToolbarCollapsed && _jsx("span", { children: "Redo" })] }), _jsxs("button", { onClick: handleRestore, title: "Restore", children: [_jsx(IconRestore, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Restore" })] }), _jsxs("button", { onClick: handleNew, title: "New diagram", disabled: readOnly, children: [_jsx(IconNew, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "New" })] }), _jsxs("button", { onClick: handleExportDiagram, disabled: readOnly || !wfDiagram, title: SDKUI_Localizator.Export || 'Export Diagram', children: [_jsx(IconExport, {}), _jsx("span", { children: SDKUI_Localizator.Export || 'Export' })] }), _jsxs("button", { onClick: handleImportDiagramClick, disabled: readOnly, title: SDKUI_Localizator.Import || 'Import Diagram', children: [_jsx(IconImport, {}), _jsx("span", { children: SDKUI_Localizator.Import || 'Import' })] })] }), _jsx(ButtonGroup, { "$isFloating": isToolbarFloating, children: _jsxs("button", { onClick: handleAutoAdjust, title: "Auto adjust", children: [_jsx(IconAdjust, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Auto Adjust" })] }) }), _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [_jsxs("button", { onClick: handleCopy, disabled: selectedItems.size === 0, title: "Copy", children: [_jsx(IconCopy, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Copy" })] }), _jsxs("button", { onClick: handleCut, disabled: selectedItems.size === 0, title: "Cut", children: [_jsx(IconCut, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Cut" })] }), _jsxs("button", { onClick: handlePaste, disabled: copiedItems.length === 0 && copiedConnections.length === 0, title: "Paste", children: [_jsx(IconPaste, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Paste" })] })] }), _jsxs("button", { onClick: handleToggleToolbarMode, title: isToolbarFloating ? "Dock Toolbar" : "Float Toolbar", children: [isToolbarFloating ? _jsx(IconPin, {}) : _jsx(IconUnpin, {}), !isToolbarCollapsed && !isToolbarFloating && _jsx("span", { children: "Toggle Mode" })] }), !isToolbarFloating && _jsx(ToolbarToggle, { onClick: () => setIsToolbarCollapsed(!isToolbarCollapsed), title: isToolbarCollapsed ? "Expand Toolbar" : "Collapse Toolbar", children: isToolbarCollapsed ? _jsx(IconChevronRight, {}) : _jsx(IconCloseOutline, {}) })] })), !readOnly && (_jsx(ToolboxContainer, { "$isVisible": isToolboxVisible, children: isToolboxVisible && availableItemTypes.map(type => (_jsxs(ToolboxItem, { draggable: true, onDragStart: (e) => handleToolboxDragStart(e, type), onDragEnd: handleToolboxDragEnd, children: [_jsx(DiagramItemSvgContent, { itemType: type, width: 40, height: 40, isToolboxPreview: true }), _jsx("span", { children: DiagramItemTypes[type] })] }, type))) })), _jsx(SvgScrollContainer, { children: isLoading ?
1432
- (_jsxs(StyledLoadingContainer, { children: [_jsx(StyledSpinner, {}), _jsx("span", { children: `${'Caricamento diagramma'}...` })] })) : wfDiagram ? (_jsx(StyledSvg, { ref: svgRef, tabIndex: 0, onKeyDownCapture: handleKeyDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseDown: handleMouseDown, onDrop: handleDropOnCanvas, onDragOver: handleDragOver, width: svgWidth, height: svgHeight, children: _jsxs(ScalableGroup, { "$scale": zoomLevel, "$translateX": translateX, "$translateY": translateY, children: [wfDiagram?.DiagramItems.map(item => (_jsx(DiagramItemComponent, { wf: wfDiagram?.Info, readOnly: readOnly, item: item, isSelected: selectedItems.has(item.ID), isCurrent: item.ID === currentSetID, onClick: handleDiagramItemClick, onDrag: handleDrag, onDragEnd: handleDragEnd, onConnectorMouseDown: handleConnectorMouseDown, onConnectorMouseUp: handleConnectorMouseUp, onDimensionsChange: handleItemDimensionsChange, onDoubleClick: handleDoubleClickItem }, item.ID))), calculatedConnections.map(connection => {
1565
+ const diagramContent = (_jsxs(CanvasContainer, { children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".xml" // Filtra per file XML
1566
+ , onChange: handleFileChange, style: { display: 'none' } }), _jsxs(ToolbarContainer, { "$isCollapsed": isToolbarCollapsed, "$isFloating": isToolbarFloating, "$isToolboxVisible": isToolboxVisible, "$isReadOnly": isReadOnly, children: [allowEdit && _jsx(ButtonGroup, { "$isFloating": isToolbarFloating, children: _jsxs("button", { onClick: toggleReadOnlyMode, title: "Progettazione", children: [isReadOnly ? _jsx(IconPencil, {}) : _jsx(IconLock, {}), !isToolbarCollapsed && _jsx("span", { children: isReadOnly ? 'Progettazione' : 'Sola lettura' })] }) }), allowEdit && _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [!isReadOnly && _jsxs("button", { onClick: handleToggleToolboxVisibility, title: "Show toolbox", children: [_jsx(IconFlowChart, {}), !isToolbarCollapsed && _jsx("span", { children: "Mostra/nascondi toolbox" })] }), _jsxs("button", { onClick: toggleFullScreenMode, title: "Show full screen", children: [_jsx(IconWindowMaximize, {}), !isToolbarCollapsed && _jsx("span", { children: "Mostra tutto schermo" })] })] }), _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [_jsxs("button", { onClick: handleZoomIn, title: "Zoom in", children: [_jsx(IconZoomIn, {}), !isToolbarCollapsed && _jsx("span", { children: "Zoom in" })] }), _jsxs("button", { onClick: handleZoomOut, title: "Zoom out", children: [_jsx(IconZoomOut, {}), !isToolbarCollapsed && _jsx("span", { children: "Zoom out" })] }), _jsx(ZoomLevelText, { "$isFloating": isToolbarFloating, "$isCollapsed": isToolbarCollapsed, children: formattedZoomLevel })] }), !isReadOnly && _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [_jsxs("button", { onClick: handleUndo, disabled: historyIndex === 0, title: "Undo", children: [_jsx(IconUndo, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Undo" })] }), _jsxs("button", { onClick: handleRedo, disabled: historyIndex === wfDiagramHistory.length - 1, title: "Redo", children: [_jsx(IconUndo, { style: { transform: 'scaleX(-1)' } }), " ", !isToolbarCollapsed && _jsx("span", { children: "Redo" })] }), _jsxs("button", { onClick: handleRestore, title: "Restore", children: [_jsx(IconRestore, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Restore" })] }), _jsxs("button", { onClick: handleNew, title: "New diagram", disabled: isReadOnly, children: [_jsx(IconNew, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "New" })] }), _jsxs("button", { onClick: handleExportDiagram, disabled: isReadOnly || !wfDiagram, title: SDKUI_Localizator.Export || 'Export Diagram', children: [_jsx(IconExport, {}), _jsx("span", { children: SDKUI_Localizator.Export || 'Export' })] }), _jsxs("button", { onClick: handleImportDiagramClick, disabled: isReadOnly, title: SDKUI_Localizator.Import || 'Import Diagram', children: [_jsx(IconImport, {}), _jsx("span", { children: SDKUI_Localizator.Import || 'Import' })] })] }), !isReadOnly && _jsx(ButtonGroup, { "$isFloating": isToolbarFloating, children: _jsxs("button", { onClick: handleAutoAdjust, title: "Auto adjust", children: [_jsx(IconAdjust, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Auto Adjust" })] }) }), !isReadOnly && _jsxs(ButtonGroup, { "$isFloating": isToolbarFloating, children: [_jsxs("button", { onClick: handleCopy, disabled: selectedItems.size === 0, title: "Copy", children: [_jsx(IconCopy, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Copy" })] }), _jsxs("button", { onClick: handleCut, disabled: selectedItems.size === 0, title: "Cut", children: [_jsx(IconCut, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Cut" })] }), _jsxs("button", { onClick: handlePaste, disabled: copiedItems.length === 0 && copiedConnections.length === 0, title: "Paste", children: [_jsx(IconPaste, {}), " ", !isToolbarCollapsed && _jsx("span", { children: "Paste" })] })] }), allowEdit && _jsxs("button", { onClick: handleToggleToolbarMode, title: isToolbarFloating ? "Dock Toolbar" : "Float Toolbar", children: [isToolbarFloating ? _jsx(IconPin, {}) : _jsx(IconUnpin, {}), !isToolbarCollapsed && !isToolbarFloating && _jsx("span", { children: "Toggle Mode" })] }), !isToolbarFloating && _jsx(ToolbarToggle, { onClick: () => setIsToolbarCollapsed(!isToolbarCollapsed), title: isToolbarCollapsed ? "Expand Toolbar" : "Collapse Toolbar", children: isToolbarCollapsed ? _jsx(IconChevronRight, {}) : _jsx(IconCloseOutline, {}) })] }), !isReadOnly && (_jsx(ToolboxContainer, { "$isVisible": isToolboxVisible, children: isToolboxVisible && availableItemTypes.map(type => (_jsxs(ToolboxItem, { draggable: true, onDragStart: (e) => handleToolboxDragStart(e, type), onDragEnd: handleToolboxDragEnd, children: [_jsx(DiagramItemSvgContent, { itemType: type, width: 40, height: 40, isToolboxPreview: true }), _jsx("span", { children: DiagramItemTypes[type] })] }, type))) })), _jsx(SvgScrollContainer, { children: isLoading ?
1567
+ (_jsxs(StyledLoadingContainer, { children: [_jsx(StyledSpinner, {}), _jsx("span", { children: `${'Caricamento diagramma'}...` })] })) : wfDiagram ? (_jsx(StyledSvg, { ref: svgRef, tabIndex: 0, onKeyDownCapture: handleKeyDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseDown: handleMouseDown, onDrop: handleDropOnCanvas, onDragOver: handleDragOver, width: svgWidth, height: svgHeight, children: _jsxs(ScalableGroup, { "$scale": zoomLevel, "$translateX": translateX, "$translateY": translateY, children: [wfDiagram?.DiagramItems.map(item => (_jsx(DiagramItemComponent, { wf: wfDiagram?.Info, readOnly: isReadOnly, item: item, isSelected: selectedItems.has(item.ID), isCurrent: item.ID === currentSetID, onClick: handleDiagramItemClick, onDrag: handleDrag, onDragEnd: handleDragEnd, onConnectorMouseDown: handleConnectorMouseDown, onConnectorMouseUp: handleConnectorMouseUp, onDimensionsChange: handleItemDimensionsChange, onDoubleClick: handleDoubleClickItem }, item.ID))), calculatedConnections.map(connection => {
1433
1568
  const sourceItem = wfDiagram?.DiagramItems.find(item => item.ID === connection.Source.ParentDiagramItem.ID);
1434
1569
  const sinkItem = wfDiagram?.DiagramItems.find(item => item.ID === connection.Sink.ParentDiagramItem.ID);
1435
1570
  if (!sourceItem || !sinkItem)
@@ -1441,5 +1576,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, readOnly = false, zoomLevel
1441
1576
  const isThisConnectionBeingDragged = isDraggingExistingConnectionEndpoint && draggingConnectionId === connection.ID;
1442
1577
  return (_jsx(ConnectionComponent, { connection: connection, isSelected: selectedConnections.has(connection.ID), sourcePoint: sourcePoint, sinkPoint: sinkPoint, isTemporary: isThisConnectionBeingDragged, onClick: handleConnectionClick, onConnectionEndpointMouseDown: handleConnectionEndpointMouseDown }, connection.ID));
1443
1578
  }), 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 }))] }));
1579
+ const diagramRef = useRef(null);
1580
+ return (_jsxs(_Fragment, { children: [!isFullScreen && (_jsx(DiagramWrapper, { ref: diagramRef, children: diagramContent })), isFullScreen && ReactDOM.createPortal(_jsx(FullScreenContainer, { children: diagramContent }), document.body)] }));
1444
1581
  };
1445
1582
  export default WFDiagram;
@@ -8,7 +8,7 @@ const PasswordStrengthChecker = ({ password, onValidationChange }) => {
8
8
  return [
9
9
  {
10
10
  label: SDKUI_Localizator.PasswordRule_Length,
11
- test: (pw) => pw.length >= 10 && pw.length <= 128,
11
+ test: (pw) => pw.length >= 16 && pw.length <= 128,
12
12
  },
13
13
  {
14
14
  label: SDKUI_Localizator.PasswordRule_Lowercase,
@@ -359,13 +359,13 @@ export declare class SDKUI_Localizator {
359
359
  static get PasswordContainsUsernameError(): "Das Passwort darf den Benutzernamen nicht enthalten" | "The password cannot contain the username" | "La contraseña no puede contener el nombre de usuario" | "Le mot de passe ne peut pas contenir le nom d'utilisateur" | "A senha não pode conter o nome de usuário" | "La password non può contenere il nome utente";
360
360
  static get PasswordConfirmError(): "Entspricht nicht dem neuen Passwort" | "Does not match the new password" | "No coincide con la nueva contraseña" | "Ne correspond pas au nouveau mot de passe" | "Não corresponde à nova senha" | "Non corrisponde alla nuova password";
361
361
  static get PasswordEqualsUsernameError(): "Das Passwort darf nicht mit dem Benutzernamen identisch sein" | "The password cannot be the same as the username" | "La contraseña no puede ser la misma que el nombre de usuario" | "Le mot de passe ne peut pas être identique au nom d'utilisateur" | "A senha não pode ser igual ao nome do usuário" | "La password non può coincidere con il nome utente";
362
- static get PasswordLengthError(): "Das Passwort muss zwischen 10 und 128 Zeichen enthalten" | "Password must contain between 10 and 128 characters" | "La contraseña debe contener entre 10 y 128 caracteres" | "Le mot de passe doit contenir entre 10 et 128 caractères" | "A senha deve conter entre 10 e 128 caracteres" | "La password deve contenere tra 10 e 128 caratteri";
362
+ static get PasswordLengthError(): "Das Passwort muss zwischen 16 und 128 Zeichen enthalten" | "Password must contain between 16 and 128 characters" | "La contraseña debe contener entre 16 y 128 caracteres" | "Le mot de passe doit contenir entre 16 et 128 caractères" | "A senha deve conter entre 16 e 128 caracteres" | "La password deve contenere tra 16 e 128 caratteri";
363
363
  static get PasswordLowercaseError(): "Das Passwort muss Kleinbuchstaben enthalten (a-z)" | "Password must include lowercase character (a-z)" | "La contraseña debe incluir caracteres en minúscula (a-z)" | "Le mot de passe doit inclure un caractère minuscule (a-z)" | "A senha deve incluir caracteres minúsculos (a-z)" | "La password deve includere caratteri minuscoli (a-z)";
364
364
  static get PasswordNumberError(): "Das Passwort muss Zahlen enthalten (0-9)" | "Password must include number (0-9)" | "La contraseña debe incluir números (0-9)" | "Le mot de passe doit inclure des chiffres (0-9)" | "A senha deve incluir números (0-9)" | "La password deve includere numeri (0-9)";
365
365
  static get PasswordSymbolError(): "Das Passwort muss mindestens ein Sonderzeichen enthalten (!\"#$%&'()*+,-./:;<=>?@[]^_{|})" | "The password must contain at least one special character (!\"#$%&'()*+,-./:;<=>?@[]^_{|})" | "La contraseña debe contener al menos un carácter especial. (!\"#$%&'()*+,-./:;<=>?@[]^_{|})" | "Le mot de passe doit contenir au moins un caractère spécial (!\"#$%&'()*+,-./:;<=>?@[]^_{|})" | "A senha deve conter pelo menos um caractere especial (!\"#$%&'()*+,-./:;<=>?@[]^_{|})" | "La password deve contenere almeno un carattere speciale (!\"#$%&'()*+,-./:;<=>?@[]^_{|})";
366
366
  static get PasswordUppercaseError(): "Das Passwort muss Großbuchstaben enthalten (A-Z)" | "Password must include uppercase character (A-Z)" | "La contraseña debe incluir caracteres en mayúscula (A-Z)" | "Le mot de passe doit inclure un caractère majuscule (A-Z)" | "A senha deve incluir caracteres maiúsculos (A-Z)" | "La password deve includere caratteri maiuscoli (A-Z)";
367
367
  static get PasswordRule_Requirement(): "Das neue Passwort muss enthalten:" | "The new password must contain:" | "La nueva contraseña debe contener:" | "Le nouveau mot de passe doit contenir :" | "A nova senha deve conter:" | "La nuova password deve contenere:";
368
- static get PasswordRule_Length(): "Zwischen 10 und 128 Zeichen." | "Between 10 and 128 characters." | "Entre 10 y 128 caracteres." | "Entre 10 et 128 caractères." | "Entre 10 e 128 caracteres." | "Tra 10 e 128 caratteri.";
368
+ static get PasswordRule_Length(): "Zwischen 16 und 128 Zeichen." | "Between 16 and 128 characters." | "Entre 16 y 128 caracteres." | "Entre 16 et 128 caractères." | "Entre 16 e 128 caracteres." | "Tra 16 e 128 caratteri.";
369
369
  static get PasswordRule_Lowercase(): "Kleinbuchstaben (a–z)." | "Lowercase characters (a–z)." | "Letras minúsculas (a–z)." | "Caractères minuscules (a–z)." | "Lettere minuscole (a–z).";
370
370
  static get PasswordRule_Uppercase(): "Großbuchstaben (A–Z)." | "Uppercase character (A–Z)." | "Letra mayúscula (A–Z)." | "Caractère majuscule (A–Z)." | "Letra maiúscula (A–Z)." | "Lettere maiuscole (A–Z).";
371
371
  static get PasswordRule_Number(): "Zahlen (0–9)." | "Number (0–9)." | "Números (0–9)." | "Chiffre (0–9)." | "Numeri (0–9).";
@@ -3549,12 +3549,12 @@ export class SDKUI_Localizator {
3549
3549
  }
3550
3550
  static get PasswordLengthError() {
3551
3551
  switch (this._cultureID) {
3552
- case CultureIDs.De_DE: return "Das Passwort muss zwischen 10 und 128 Zeichen enthalten";
3553
- case CultureIDs.En_US: return "Password must contain between 10 and 128 characters";
3554
- case CultureIDs.Es_ES: return "La contraseña debe contener entre 10 y 128 caracteres";
3555
- case CultureIDs.Fr_FR: return "Le mot de passe doit contenir entre 10 et 128 caractères";
3556
- case CultureIDs.Pt_PT: return "A senha deve conter entre 10 e 128 caracteres";
3557
- default: return "La password deve contenere tra 10 e 128 caratteri";
3552
+ case CultureIDs.De_DE: return "Das Passwort muss zwischen 16 und 128 Zeichen enthalten";
3553
+ case CultureIDs.En_US: return "Password must contain between 16 and 128 characters";
3554
+ case CultureIDs.Es_ES: return "La contraseña debe contener entre 16 y 128 caracteres";
3555
+ case CultureIDs.Fr_FR: return "Le mot de passe doit contenir entre 16 et 128 caractères";
3556
+ case CultureIDs.Pt_PT: return "A senha deve conter entre 16 e 128 caracteres";
3557
+ default: return "La password deve contenere tra 16 e 128 caratteri";
3558
3558
  }
3559
3559
  }
3560
3560
  static get PasswordLowercaseError() {
@@ -3609,12 +3609,12 @@ export class SDKUI_Localizator {
3609
3609
  }
3610
3610
  static get PasswordRule_Length() {
3611
3611
  switch (this._cultureID) {
3612
- case CultureIDs.De_DE: return "Zwischen 10 und 128 Zeichen.";
3613
- case CultureIDs.En_US: return "Between 10 and 128 characters.";
3614
- case CultureIDs.Es_ES: return "Entre 10 y 128 caracteres.";
3615
- case CultureIDs.Fr_FR: return "Entre 10 et 128 caractères.";
3616
- case CultureIDs.Pt_PT: return "Entre 10 e 128 caracteres.";
3617
- default: return "Tra 10 e 128 caratteri.";
3612
+ case CultureIDs.De_DE: return "Zwischen 16 und 128 Zeichen.";
3613
+ case CultureIDs.En_US: return "Between 16 and 128 characters.";
3614
+ case CultureIDs.Es_ES: return "Entre 16 y 128 caracteres.";
3615
+ case CultureIDs.Fr_FR: return "Entre 16 et 128 caractères.";
3616
+ case CultureIDs.Pt_PT: return "Entre 16 e 128 caracteres.";
3617
+ default: return "Tra 16 e 128 caratteri.";
3618
3618
  }
3619
3619
  }
3620
3620
  static get PasswordRule_Lowercase() {
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState } from "react";
2
2
  import { FormModes } from "../ts";
3
3
  import { TMExceptionBoxManager, TMSpinner } from "../components";
4
- import { ArchiveConstraints, AreaEngine, BasketTypeEngine, DataListEngine, DcmtTypeEngine, DiskEngine, EncryptionModes, GroupEngine, JobEngine, JobTypes, LDAPDescriptor, LDAPProviders, MembershipConstraints, NumeratorDescriptor, ObjectClasses, ProcessEngine, RelationEngine, ResultTypes, SAPEngine, SavedQueryEngine, SignCertDescriptor, TaskEngine, TreeDescriptor, TSADescriptor, UserEngine, UserLevels, UserTypes, WorkingGroupDescriptor } from "@topconsultnpm/sdk-ts-beta";
4
+ import { AreaEngine, BasketTypeEngine, DataListEngine, DcmtTypeEngine, DiskEngine, GroupEngine, JobEngine, JobTypes, LDAPDescriptor, LDAPProviders, NumeratorDescriptor, ObjectClasses, ProcessEngine, RelationEngine, ResultTypes, SAPEngine, SavedQueryEngine, SignCertDescriptor, TaskEngine, TreeDescriptor, TSADescriptor, UserEngine, WorkingGroupDescriptor } from "@topconsultnpm/sdk-ts-beta";
5
5
  import { PlatformObjectService } from "../services";
6
6
  import { SDKUI_Localizator, calcIsModified } from "../helper";
7
7
  export class SaveFormOptions {
@@ -16,21 +16,6 @@ export function useSaveForm(formMode, id, sfo, validator, onSaved, onStatusChang
16
16
  const [exception, setException] = useState();
17
17
  const [validationItems, setValidationItems] = useState([]);
18
18
  // #region Normalize object
19
- function normalizeDcmtType(d) {
20
- d.archiveConstraint = ArchiveConstraints.None;
21
- d.encryptionMode = EncryptionModes.None;
22
- d.indexes = [];
23
- d.metadata = [];
24
- d.trgSharedArk = 0;
25
- d.wfAppr = 0;
26
- d.hasBlog = 0;
27
- d.cico = 0;
28
- return d;
29
- }
30
- function normalizeGroup(d) {
31
- d.membershipConstraint = MembershipConstraints.Mixed;
32
- return d;
33
- }
34
19
  function normalizeLDAP(d) {
35
20
  d.provider = LDAPProviders.MSActiveDirectory;
36
21
  return d;
@@ -39,16 +24,6 @@ export function useSaveForm(formMode, id, sfo, validator, onSaved, onStatusChang
39
24
  d.isAuto = 1;
40
25
  return d;
41
26
  }
42
- function normalizeUser(d) {
43
- d.level = UserLevels.Member;
44
- d.type = UserTypes.TopMedia;
45
- d.secureAuth = 1;
46
- d.canDST = 0;
47
- d.disabled = false;
48
- d.neutralNames = 0;
49
- d.onlyOnBehalfOf = 0;
50
- return d;
51
- }
52
27
  // #endregion
53
28
  const getDataAsync = async (id, fm) => {
54
29
  switch (fm) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.16.76",
3
+ "version": "6.16.78",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",