@topconsultnpm/sdkui-react 6.19.0-test2 → 6.20.0-dev1.2

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.
Files changed (57) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.d.ts +4 -0
  2. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +187 -0
  3. package/lib/components/NewComponents/ContextMenu/hooks.d.ts +11 -0
  4. package/lib/components/NewComponents/ContextMenu/hooks.js +48 -0
  5. package/lib/components/NewComponents/ContextMenu/index.d.ts +2 -0
  6. package/lib/components/NewComponents/ContextMenu/index.js +1 -0
  7. package/lib/components/NewComponents/ContextMenu/styles.d.ts +27 -0
  8. package/lib/components/NewComponents/ContextMenu/styles.js +308 -0
  9. package/lib/components/NewComponents/ContextMenu/types.d.ts +26 -0
  10. package/lib/components/NewComponents/ContextMenu/types.js +1 -0
  11. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.d.ts +4 -0
  12. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +370 -0
  13. package/lib/components/NewComponents/FloatingMenuBar/index.d.ts +2 -0
  14. package/lib/components/NewComponents/FloatingMenuBar/index.js +2 -0
  15. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +38 -0
  16. package/lib/components/NewComponents/FloatingMenuBar/styles.js +267 -0
  17. package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +30 -0
  18. package/lib/components/NewComponents/FloatingMenuBar/types.js +1 -0
  19. package/lib/components/NewComponents/Notification/Notification.d.ts +4 -0
  20. package/lib/components/NewComponents/Notification/Notification.js +60 -0
  21. package/lib/components/NewComponents/Notification/NotificationContainer.d.ts +8 -0
  22. package/lib/components/NewComponents/Notification/NotificationContainer.js +33 -0
  23. package/lib/components/NewComponents/Notification/index.d.ts +2 -0
  24. package/lib/components/NewComponents/Notification/index.js +2 -0
  25. package/lib/components/NewComponents/Notification/styles.d.ts +21 -0
  26. package/lib/components/NewComponents/Notification/styles.js +180 -0
  27. package/lib/components/NewComponents/Notification/types.d.ts +18 -0
  28. package/lib/components/NewComponents/Notification/types.js +1 -0
  29. package/lib/components/choosers/TMDynDataListItemChooser.js +5 -4
  30. package/lib/components/editors/TMMetadataValues.js +34 -12
  31. package/lib/components/features/assistant/ToppyDraggableHelpCenter.js +74 -63
  32. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  33. package/lib/components/features/documents/TMDcmtForm.js +12 -5
  34. package/lib/components/features/documents/TMDcmtPreview.js +31 -37
  35. package/lib/components/features/search/TMSavedQuerySelector.js +1 -1
  36. package/lib/components/features/search/TMSearchQueryPanel.js +1 -1
  37. package/lib/components/features/search/TMSearchResult.js +106 -26
  38. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +8 -0
  39. package/lib/components/features/search/TMSearchResultCheckoutInfoForm.js +134 -0
  40. package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +2 -2
  41. package/lib/components/features/search/TMSearchResultsMenuItems.js +40 -62
  42. package/lib/components/features/search/TMTreeSelector.js +1 -1
  43. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +18 -0
  44. package/lib/components/features/search/TMViewHistoryDcmt.js +285 -0
  45. package/lib/components/grids/TMRecentsManager.js +1 -1
  46. package/lib/helper/SDKUI_Globals.d.ts +7 -0
  47. package/lib/helper/SDKUI_Globals.js +1 -0
  48. package/lib/helper/SDKUI_Localizator.d.ts +9 -0
  49. package/lib/helper/SDKUI_Localizator.js +121 -6
  50. package/lib/helper/TMIcons.d.ts +3 -1
  51. package/lib/helper/TMIcons.js +9 -1
  52. package/lib/helper/cicoHelper.d.ts +31 -0
  53. package/lib/helper/cicoHelper.js +155 -0
  54. package/lib/helper/helpers.d.ts +7 -0
  55. package/lib/helper/helpers.js +37 -5
  56. package/lib/helper/queryHelper.js +13 -1
  57. package/package.json +53 -53
@@ -33,7 +33,7 @@ const ToppyButton = styled.div.attrs((props) => ({
33
33
  /* Posizionamento di default quando non è draggato (x e y non sono definiti) */
34
34
  ${(props) => props.$x === undefined || props.$y === undefined
35
35
  ? `
36
- bottom: ${props.$isMobile ? '0px' : '-20px'};
36
+ bottom: ${props.$isMobile ? (props.$isCollapsed ? '-20px' : '-50px') : '-20px'};
37
37
  ${props.$align === 'left' ? 'left: 10px;' : 'right: 10px;'};
38
38
  `
39
39
  : ''}
@@ -48,15 +48,9 @@ const ToppyButton = styled.div.attrs((props) => ({
48
48
  /* Dimensioni dinamiche in base allo stato collassato e al tipo di dispositivo
49
49
  Usa min() per adattarsi su schermi piccoli */
50
50
  width: ${(props) => {
51
- if (props.$isMobile) {
52
- return props.$isCollapsed ? 'min(40px, 100%)' : '80px';
53
- }
54
51
  return props.$isCollapsed ? 'min(60px, 100%)' : '120px';
55
52
  }};
56
53
  height: ${(props) => {
57
- if (props.$isMobile) {
58
- return props.$isCollapsed ? 'min(45px, 100%)' : '95px';
59
- }
60
54
  return props.$isCollapsed ? 'min(70px, 100%)' : '140px';
61
55
  }};
62
56
  max-width: 100%;
@@ -66,18 +60,8 @@ const ToppyButton = styled.div.attrs((props) => ({
66
60
 
67
61
  img {
68
62
  /* Dimensioni dell'immagine in base allo stato collassato e al tipo di dispositivo */
69
- width: ${(props) => {
70
- if (props.$isMobile) {
71
- return props.$isCollapsed ? '40px' : '80px';
72
- }
73
- return props.$isCollapsed ? '60px' : '120px';
74
- }};
75
- height: ${(props) => {
76
- if (props.$isMobile) {
77
- return props.$isCollapsed ? '40px' : '95px';
78
- }
79
- return props.$isCollapsed ? '60px' : '140px';
80
- }};
63
+ width: ${(props) => props.$isCollapsed ? (props.$isMobile ? '40px' : '60px') : (props.$isMobile ? '80px' : '120px')};
64
+ height: ${(props) => props.$isCollapsed ? (props.$isMobile ? '40px' : '60px') : (props.$isMobile ? '100px' : '140px')};
81
65
  pointer-events: ${(props) => (props.$isMobile ? 'auto' : 'none')};
82
66
  border-radius: 50%; /* Rende l'immagine circolare */
83
67
  /* Rotazione leggera in base all'allineamento */
@@ -169,6 +153,16 @@ const DragOverlay = styled.div `
169
153
  * contenitore e può essere collassato/espanso con un doppio click.
170
154
  */
171
155
  const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onToppyImageClick, initialIsCollapsed, isVisible = true, usePortal = false, }) => {
156
+ // Configurazione del layout e dei limiti di posizionamento di Toppy
157
+ const LAYOUT_CONFIG = {
158
+ bottomOffsetDesktop: 20, // Quanto Toppy può uscire dal bordo inferiore su desktop
159
+ bottomOffsetMobileCollapsed: 20, // Quanto Toppy può uscire dal bordo inferiore su mobile quando è collassato
160
+ bottomOffsetMobileExpanded: 50, // Quanto Toppy può uscire dal bordo inferiore su mobile quando è espanso
161
+ buttonOffset: 8, // Spazio extra per i bottoni posizionati a -8px (ExpandButton, CloseButton)
162
+ closeButtonOffset: 8, // Offset dei bottoni che sporgono dalla bubble (CloseButton sulla bubble)
163
+ bubbleBuffer: 5, // Buffer di sicurezza per evitare sovrapposizioni con la bubble
164
+ minTopOffset: 8 // Limite minimo dall'alto per evitare che i bottoni superiori escano
165
+ };
172
166
  // Ref per il contenitore principale
173
167
  const buttonRef = useRef(null);
174
168
  // Stato per controllare se il componente è collassato o espanso
@@ -205,20 +199,16 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
205
199
  return;
206
200
  const rect = buttonRef.current.getBoundingClientRect();
207
201
  // Spazio extra occupato dalla bubble quando non è collassato
208
- // Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
209
- const closeButtonOffset = 8;
210
- const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
211
- const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
202
+ const extraHeight = !isCollapsed ? bubbleSize.height + LAYOUT_CONFIG.closeButtonOffset : 0;
203
+ const extraWidth = !isCollapsed ? bubbleSize.width + LAYOUT_CONFIG.closeButtonOffset : 0;
212
204
  let minX = 0;
213
205
  let maxX;
214
206
  let maxY;
215
- const bubbleBuffer = 5;
216
- const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
217
- const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
207
+ const minY = LAYOUT_CONFIG.minTopOffset;
218
208
  if (usePortal) {
219
209
  // Calcola i limiti usando le dimensioni del viewport
220
- maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
221
- maxY = window.innerHeight - rect.height + 20;
210
+ maxX = window.innerWidth - rect.width - LAYOUT_CONFIG.buttonOffset;
211
+ maxY = window.innerHeight - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
222
212
  }
223
213
  else {
224
214
  // Calcola i limiti usando le dimensioni del parent
@@ -226,8 +216,8 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
226
216
  if (!parent)
227
217
  return;
228
218
  const parentRect = parent.getBoundingClientRect();
229
- maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
230
- maxY = parentRect.height - rect.height + 20;
219
+ maxX = parentRect.width - rect.width - LAYOUT_CONFIG.buttonOffset;
220
+ maxY = parentRect.height - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
231
221
  }
232
222
  if (!isCollapsed) {
233
223
  if (align === 'right') {
@@ -240,12 +230,12 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
240
230
  // Verifica se la posizione corrente è fuori dai limiti
241
231
  const isOutOfBounds = position.x < minX ||
242
232
  position.x > maxX ||
243
- position.y < Math.max(minY, extraHeight + bubbleBuffer) ||
233
+ position.y < Math.max(minY, extraHeight + LAYOUT_CONFIG.bubbleBuffer) ||
244
234
  position.y > maxY;
245
235
  // Se è fuori dai limiti, aggiusta la posizione
246
236
  if (isOutOfBounds) {
247
237
  const adjustedX = Math.max(minX, Math.min(position.x, maxX));
248
- const adjustedY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(position.y, maxY));
238
+ const adjustedY = Math.max(Math.max(minY, extraHeight + LAYOUT_CONFIG.bubbleBuffer), Math.min(position.y, maxY));
249
239
  setPosition({ x: adjustedX, y: adjustedY });
250
240
  }
251
241
  }, [isCollapsed, bubbleSize, usePortal, align]);
@@ -259,27 +249,24 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
259
249
  if (!buttonRef.current || !position)
260
250
  return;
261
251
  const rect = buttonRef.current.getBoundingClientRect();
262
- // Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
263
- const closeButtonOffset = 8;
264
- const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
265
- const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
252
+ // Spazio extra occupato dalla bubble quando non è collassato
253
+ const extraHeight = !isCollapsed ? bubbleSize.height + LAYOUT_CONFIG.closeButtonOffset : 0;
254
+ const extraWidth = !isCollapsed ? bubbleSize.width + LAYOUT_CONFIG.closeButtonOffset : 0;
266
255
  let minX = 0;
267
256
  let maxX;
268
257
  let maxY;
269
- const bubbleBuffer = 5;
270
- const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
271
- const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
258
+ const minY = LAYOUT_CONFIG.minTopOffset;
272
259
  if (usePortal) {
273
- maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
274
- maxY = window.innerHeight - rect.height + 20;
260
+ maxX = window.innerWidth - rect.width - LAYOUT_CONFIG.buttonOffset;
261
+ maxY = window.innerHeight - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
275
262
  }
276
263
  else {
277
264
  const parent = buttonRef.current.offsetParent;
278
265
  if (!parent)
279
266
  return;
280
267
  const parentRect = parent.getBoundingClientRect();
281
- maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
282
- maxY = parentRect.height - rect.height + 20;
268
+ maxX = parentRect.width - rect.width - LAYOUT_CONFIG.buttonOffset;
269
+ maxY = parentRect.height - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
283
270
  }
284
271
  if (!isCollapsed) {
285
272
  if (align === 'right') {
@@ -291,7 +278,7 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
291
278
  }
292
279
  const isOutOfBounds = position.x < minX ||
293
280
  position.x > maxX ||
294
- position.y < Math.max(minY, extraHeight + bubbleBuffer) ||
281
+ position.y < Math.max(minY, extraHeight + LAYOUT_CONFIG.bubbleBuffer) ||
295
282
  position.y > maxY;
296
283
  if (isOutOfBounds) {
297
284
  setPosition(null);
@@ -347,6 +334,22 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
347
334
  setIsDragging(true);
348
335
  e.preventDefault();
349
336
  };
337
+ /**
338
+ * Gestisce l'inizio del trascinamento per eventi touch
339
+ */
340
+ const handleTouchStart = (e) => {
341
+ if (!buttonRef.current)
342
+ return;
343
+ const touch = e.touches[0];
344
+ const rect = buttonRef.current.getBoundingClientRect();
345
+ // Calcola l'offset tra il punto di touch e l'angolo superiore sinistro del componente
346
+ dragOffset.current = {
347
+ x: touch.clientX - rect.left,
348
+ y: touch.clientY - rect.top,
349
+ };
350
+ setIsDragging(true);
351
+ e.preventDefault();
352
+ };
350
353
  /**
351
354
  * Gestisce il movimento durante il trascinamento
352
355
  * Calcola la nuova posizione rispettando i limiti del parent o viewport
@@ -355,24 +358,23 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
355
358
  const handleMouseMove = (e) => {
356
359
  if (!isDragging || !buttonRef.current)
357
360
  return;
361
+ // Estrae le coordinate dal tipo di evento appropriato
362
+ const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
363
+ const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
358
364
  const rect = buttonRef.current.getBoundingClientRect();
359
365
  // Spazio extra occupato dalla bubble quando non è collassato
360
- // Include anche l'offset dei bottoni che sporgono dalla bubble (8px)
361
- const closeButtonOffset = 8;
362
- const extraHeight = !isCollapsed ? bubbleSize.height + closeButtonOffset : 0;
363
- const extraWidth = !isCollapsed ? bubbleSize.width + closeButtonOffset : 0;
366
+ const extraHeight = !isCollapsed ? bubbleSize.height + LAYOUT_CONFIG.closeButtonOffset : 0;
367
+ const extraWidth = !isCollapsed ? bubbleSize.width + LAYOUT_CONFIG.closeButtonOffset : 0;
364
368
  let minX = 0;
365
369
  let maxX;
366
370
  let maxY;
367
371
  let newX;
368
372
  let newY;
369
- const bubbleBuffer = 5;
370
- const buttonOffset = 8; // Spazio extra per i bottoni posizionati a -8px
371
- const minY = buttonOffset; // Limite minimo per evitare che i bottoni superiori escano
373
+ const minY = LAYOUT_CONFIG.minTopOffset;
372
374
  if (usePortal) {
373
375
  // Calcola i limiti usando il viewport
374
- maxX = window.innerWidth - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
375
- maxY = window.innerHeight - rect.height + 20;
376
+ maxX = window.innerWidth - rect.width - LAYOUT_CONFIG.buttonOffset;
377
+ maxY = window.innerHeight - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
376
378
  if (!isCollapsed) {
377
379
  if (align === 'right') {
378
380
  minX = Math.max(0, extraWidth - rect.width);
@@ -381,8 +383,8 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
381
383
  maxX = Math.min(maxX, window.innerWidth - extraWidth);
382
384
  }
383
385
  }
384
- newX = Math.max(minX, Math.min(e.clientX - dragOffset.current.x, maxX));
385
- newY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(e.clientY - dragOffset.current.y, maxY));
386
+ newX = Math.max(minX, Math.min(clientX - dragOffset.current.x, maxX));
387
+ newY = Math.max(Math.max(minY, extraHeight + LAYOUT_CONFIG.bubbleBuffer), Math.min(clientY - dragOffset.current.y, maxY));
386
388
  }
387
389
  else {
388
390
  // Calcola i limiti usando il parent
@@ -390,8 +392,8 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
390
392
  if (!parent)
391
393
  return;
392
394
  const parentRect = parent.getBoundingClientRect();
393
- maxX = parentRect.width - rect.width - buttonOffset; // Restringo per evitare che i bottoni a destra escano
394
- maxY = parentRect.height - rect.height + 20;
395
+ maxX = parentRect.width - rect.width - LAYOUT_CONFIG.buttonOffset;
396
+ maxY = parentRect.height - rect.height + (isMobile ? (isCollapsed ? LAYOUT_CONFIG.bottomOffsetMobileCollapsed : LAYOUT_CONFIG.bottomOffsetMobileExpanded) : LAYOUT_CONFIG.bottomOffsetDesktop);
395
397
  if (!isCollapsed) {
396
398
  if (align === 'right') {
397
399
  minX = Math.max(0, extraWidth - rect.width);
@@ -400,8 +402,8 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
400
402
  maxX = Math.min(maxX, parentRect.width - extraWidth);
401
403
  }
402
404
  }
403
- newX = Math.max(minX, Math.min(e.clientX - parentRect.left - dragOffset.current.x, maxX));
404
- newY = Math.max(Math.max(minY, extraHeight + bubbleBuffer), Math.min(e.clientY - parentRect.top - dragOffset.current.y, maxY));
405
+ newX = Math.max(minX, Math.min(clientX - parentRect.left - dragOffset.current.x, maxX));
406
+ newY = Math.max(Math.max(minY, extraHeight + LAYOUT_CONFIG.bubbleBuffer), Math.min(clientY - parentRect.top - dragOffset.current.y, maxY));
405
407
  }
406
408
  setPosition({ x: newX, y: newY });
407
409
  };
@@ -413,10 +415,13 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
413
415
  const handleMouseUp = (e) => {
414
416
  if (isDragging) {
415
417
  setIsDragging(false);
418
+ // Estrae le coordinate dal tipo di evento appropriato
419
+ const clientX = 'changedTouches' in e ? e.changedTouches[0].clientX : e.clientX;
420
+ const clientY = 'changedTouches' in e ? e.changedTouches[0].clientY : e.clientY;
416
421
  const rect = buttonRef.current?.getBoundingClientRect();
417
422
  if (rect) {
418
423
  // Calcola la distanza totale del movimento usando il teorema di Pitagora
419
- const moveDistance = Math.hypot(e.clientX - (rect.left + dragOffset.current.x), e.clientY - (rect.top + dragOffset.current.y));
424
+ const moveDistance = Math.hypot(clientX - (rect.left + dragOffset.current.x), clientY - (rect.top + dragOffset.current.y));
420
425
  // Se il movimento è stato minimo, trattalo come un click
421
426
  if (moveDistance < 5 && onToppyImageClick) {
422
427
  onToppyImageClick();
@@ -427,22 +432,28 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
427
432
  /**
428
433
  * Effect per gestire gli event listener durante il trascinamento
429
434
  * Gli eventi sono registrati sul document per catturare il movimento
430
- * anche quando il mouse esce dal componente
435
+ * anche quando il mouse o il touch esce dal componente
431
436
  */
432
437
  useEffect(() => {
433
438
  if (isDragging) {
439
+ // Eventi mouse per desktop
434
440
  document.addEventListener('mousemove', handleMouseMove);
435
441
  document.addEventListener('mouseup', handleMouseUp);
442
+ // Eventi touch per mobile
443
+ document.addEventListener('touchmove', handleMouseMove);
444
+ document.addEventListener('touchend', handleMouseUp);
436
445
  return () => {
437
446
  document.removeEventListener('mousemove', handleMouseMove);
438
447
  document.removeEventListener('mouseup', handleMouseUp);
448
+ document.removeEventListener('touchmove', handleMouseMove);
449
+ document.removeEventListener('touchend', handleMouseUp);
439
450
  };
440
451
  }
441
452
  return undefined;
442
453
  }, [isDragging]);
443
454
  // Renderizza l'overlay solo durante il drag
444
455
  const renderDragOverlay = isDragging && _jsx(DragOverlay, {});
445
- const toppyContent = (_jsxs(_Fragment, { children: [renderDragOverlay, _jsxs(ToppyButton, { ref: buttonRef, "$align": align, "$isDragging": isDragging, "$x": position?.x, "$y": position?.y, "$isVisible": isVisible, "$isCollapsed": isCollapsed, "$isMobile": isMobile, "$usePortal": usePortal, onMouseDown: !isMobile ? handleMouseDown : undefined, onContextMenu: (e) => e.preventDefault(), onDoubleClick: !isMobile ? toggleCollapse : undefined, children: [(content && !isCollapsed) && (_jsx(ToppySpeechBubble, { ref: bubbleRef, align: align, onClose: toggleCollapse, children: content })), (content && isCollapsed) && (_jsx(ExpandButton, { onMouseDown: (e) => {
456
+ const toppyContent = (_jsxs(_Fragment, { children: [renderDragOverlay, _jsxs(ToppyButton, { ref: buttonRef, "$align": align, "$isDragging": isDragging, "$x": position?.x, "$y": position?.y, "$isVisible": isVisible, "$isCollapsed": isCollapsed, "$isMobile": isMobile, "$usePortal": usePortal, onMouseDown: !isMobile ? handleMouseDown : undefined, onTouchStart: isMobile ? handleTouchStart : undefined, onContextMenu: (e) => e.preventDefault(), onDoubleClick: !isMobile ? toggleCollapse : undefined, children: [(content && !isCollapsed) && (_jsx(ToppySpeechBubble, { ref: bubbleRef, align: align, onClose: toggleCollapse, children: content })), (content && isCollapsed) && (_jsx(ExpandButton, { onMouseDown: (e) => {
446
457
  isExpandButtonDraggingRef.current = false;
447
458
  expandButtonMouseDownPosRef.current = { x: e.clientX, y: e.clientY };
448
459
  }, onMouseMove: (e) => {
@@ -464,7 +475,7 @@ const ToppyDraggableHelpCenter = ({ content, deviceType, align = 'right', onTopp
464
475
  }
465
476
  e.stopPropagation();
466
477
  toggleCollapse(e);
467
- }, onContextMenu: (e) => e.preventDefault(), "aria-label": SDKUI_Localizator.Maximize, title: SDKUI_Localizator.Maximize, type: "button", children: _jsx(IconWindowMaximize, {}) })), _jsx("img", { src: Toppy, alt: "Toppy Help", draggable: false, onClick: isMobile ? toggleCollapse : undefined })] })] }));
478
+ }, onContextMenu: (e) => e.preventDefault(), "aria-label": SDKUI_Localizator.Maximize, title: SDKUI_Localizator.Maximize, type: "button", children: _jsx(IconWindowMaximize, {}) })), _jsx("img", { src: Toppy, alt: "Toppy Help", draggable: false })] })] }));
468
479
  // Renderizza nel document.body usando un Portal se usePortal è true, altrimenti renderizza normalmente
469
480
  return usePortal ? ReactDOM.createPortal(toppyContent, document.body) : toppyContent;
470
481
  };
@@ -46,6 +46,7 @@ interface ITMDcmtFormProps {
46
46
  mid: number;
47
47
  value: string;
48
48
  }>;
49
+ openS4TViewer?: boolean;
49
50
  onOpenS4TViewerRequest?: (dcmtInfo: Array<DcmtInfo>, onRefreshSearchAsync?: (() => Promise<void>)) => void;
50
51
  s4TViewerDialogComponent?: React.ReactNode;
51
52
  enableDragDropOverlay?: boolean;
@@ -44,7 +44,7 @@ import TMCustomButton from '../../base/TMCustomButton';
44
44
  import ToppyDraggableHelpCenter from '../assistant/ToppyDraggableHelpCenter';
45
45
  let abortControllerLocal = new AbortController();
46
46
  //#endregion
47
- const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true, invokedByTodo = false, titleModal, isModal = false, widthModal = "100%", heightModal = "100%", groupId, onWFOperationCompleted, onTaskCompleted, onTaskCreateRequest, inputFile = null, taskFormDialogComponent, taskMoreInfo, connectorFileSave = undefined, inputMids = [], onOpenS4TViewerRequest, s4TViewerDialogComponent, enableDragDropOverlay = false, passToSearch, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowButtonsRefs = false, onReferenceClick, }) => {
47
+ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true, invokedByTodo = false, titleModal, isModal = false, widthModal = "100%", heightModal = "100%", groupId, onWFOperationCompleted, onTaskCompleted, onTaskCreateRequest, inputFile = null, taskFormDialogComponent, taskMoreInfo, connectorFileSave = undefined, inputMids = [], openS4TViewer = false, onOpenS4TViewerRequest, s4TViewerDialogComponent, enableDragDropOverlay = false, passToSearch, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowButtonsRefs = false, onReferenceClick, }) => {
48
48
  const [id, setID] = useState('');
49
49
  const [showWaitPanelLocal, setShowWaitPanelLocal] = useState(false);
50
50
  const [waitPanelTitleLocal, setWaitPanelTitleLocal] = useState('');
@@ -408,9 +408,11 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
408
408
  }, [inputMids, layoutMode, formData, formDataOrig]);
409
409
  // Memoizza solo il valore WI_SetID per evitare re-render quando altri metadata cambiano
410
410
  const workItemSetIDValue = useMemo(() => formData.find(o => o.md?.name === WorkItemMetadataNames.WI_SetID)?.value, [formData]);
411
+ // Valore derivato: true se formData ha elementi validi
412
+ const hasFormData = useMemo(() => formData.length > 0 && formData.some(md => md.mid && md.mid > 99), [formData]);
411
413
  useEffect(() => {
412
414
  const loadAllWfData = async () => {
413
- if (layoutMode !== LayoutModes.Update || !DID) {
415
+ if (layoutMode !== LayoutModes.Update || !DID || fromDTD?.templateTID !== TemplateTIDs.WF_WIApprView) {
414
416
  setWorkItems([]);
415
417
  setWorkflows([]);
416
418
  return;
@@ -460,7 +462,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
460
462
  setWorkflows(validWorkflows);
461
463
  }
462
464
  catch (error) {
463
- console.error("Errore durante il caricamento dei dati del workflow:", error);
465
+ TMExceptionBoxManager.show({ exception: error });
464
466
  setWorkItems([]);
465
467
  setWorkflows([]);
466
468
  }
@@ -468,9 +470,14 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
468
470
  setIsWFDataLoading(false);
469
471
  }
470
472
  };
473
+ // Usa hasFormData invece di formDataRef.current
474
+ if (!hasFormData || !fromDTD?.id) {
475
+ // console.log("formData is empty or fromDTD not loaded, skipping loadAllWfData");
476
+ return;
477
+ }
471
478
  if (workItemSetIDValue !== undefined || workflowApproveData.length > 0)
472
479
  loadAllWfData();
473
- }, [workItemSetIDValue, workflowApproveData, DID, layoutMode]);
480
+ }, [hasFormData, workItemSetIDValue, workflowApproveData, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
474
481
  const getSelectionDcmtInfo = useCallback(() => {
475
482
  let dcmts = [];
476
483
  dcmts.push({ TID: TID ?? 0, DID: DID ?? 0 });
@@ -1356,7 +1363,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
1356
1363
  isEditable: true,
1357
1364
  value: FormulaHelper.addFormulaTag(newFormula.expression)
1358
1365
  }));
1359
- } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowMoreInfoPopup(false) }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }), _jsx(ToppyDraggableHelpCenter, { initialIsCollapsed: false, deviceType: deviceType, isVisible: showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences, content: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: [showToppyForApprove && (workItems.length === 1 ?
1366
+ } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowMoreInfoPopup(false) }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }), _jsx(ToppyDraggableHelpCenter, { initialIsCollapsed: false, deviceType: deviceType, isVisible: (showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && !openS4TViewer, content: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: [showToppyForApprove && (workItems.length === 1 ?
1360
1367
  _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onSignApprove: handleSignApprove, onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), onMoreInfo: () => setShowMoreInfoPopup(true), dtd: fromDTD })
1361
1368
  :
1362
1369
  _jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`Devi approvare ${workItems.length} workitem(s) per questo documento.`, `Vai alla sezione di approvazione.`] })), showToppyForCompleteMoreInfo && (_jsxs(_Fragment, { children: [_jsx("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: `${SDKUI_Localizator.MoreInfoCompleteRequestSentBy} ${taskMoreInfo?.fromName}!` }), _jsx(TMButton, { caption: SDKUI_Localizator.CommentAndComplete, color: 'success', showTooltip: false, onClick: () => {
@@ -222,43 +222,37 @@ export const TMFileViewer = ({ fileBlob, isResizingActive }) => {
222
222
  if (fileBlob.type.includes('image')) {
223
223
  return (_jsx(ImageViewer, { fileBlob: fileBlob, alt: '' }));
224
224
  }
225
- // Check if device has limited PDF support (only for mobile/tablet devices)
226
- const hasLimitedPDFSupport = () => {
227
- const userAgent = navigator.userAgent || navigator.vendor || window.opera;
228
- // Only check for actual mobile/tablet devices, NOT desktop browsers
229
- const isAndroidMobile = /android/i.test(userAgent) && (/mobile|tablet/i.test(userAgent) || window.screen.width <= 1024);
230
- const isIOSMobile = /iphone|ipad|ipod/i.test(userAgent);
231
- const isOtherMobile = /webos|blackberry|iemobile|opera mini/i.test(userAgent);
232
- // Return true only for actual mobile devices, not desktop browsers
233
- return isMobile && (isAndroidMobile || isIOSMobile || isOtherMobile);
234
- };
235
- if (fileType === 'application/pdf' && hasLimitedPDFSupport()) {
236
- return (_jsxs("div", { style: {
237
- padding: '40px',
238
- textAlign: 'center',
239
- display: 'flex',
240
- flexDirection: 'column',
241
- alignItems: 'center',
242
- justifyContent: 'center',
243
- height: '100%',
244
- gap: '20px'
245
- }, children: [_jsx(IconPreview, { fontSize: 96 }), _jsxs("div", { children: [_jsx("h3", { children: SDKUI_Localizator.PDFDocument }), _jsx("p", { children: SDKUI_Localizator.PreviewNotAvailableOnDevice })] }), _jsxs("div", { style: { display: 'flex', gap: '10px', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'center' }, children: [_jsx("a", { href: blobUrl, download: "document.pdf", style: {
246
- minWidth: '180px',
247
- padding: '12px 24px',
248
- backgroundColor: TMColors.primaryColor,
249
- color: 'white',
250
- textDecoration: 'none',
251
- borderRadius: '4px',
252
- display: 'inline-block'
253
- }, children: SDKUI_Localizator.DownloadFile }), _jsx("a", { href: blobUrl, target: "_blank", rel: "noopener noreferrer", style: {
254
- minWidth: '180px',
255
- padding: '12px 24px',
256
- backgroundColor: TMColors.primaryColor,
257
- color: 'white',
258
- textDecoration: 'none',
259
- borderRadius: '4px',
260
- display: 'inline-block'
261
- }, children: SDKUI_Localizator.OpenInNewTab })] })] }));
225
+ if (fileType === 'application/pdf' && isMobile) {
226
+ return (_jsx("object", { data: blobUrl, type: "application/pdf", width: "100%", height: "100%", style: {
227
+ border: 'none',
228
+ zIndex: 0,
229
+ pointerEvents: isResizingActive === true ? "none" : "auto"
230
+ }, children: _jsxs("div", { style: {
231
+ padding: '40px',
232
+ textAlign: 'center',
233
+ display: 'flex',
234
+ flexDirection: 'column',
235
+ alignItems: 'center',
236
+ justifyContent: 'center',
237
+ height: '100%',
238
+ gap: '20px'
239
+ }, children: [_jsx(IconPreview, { fontSize: 96 }), _jsxs("div", { children: [_jsx("h3", { children: SDKUI_Localizator.PDFDocument }), _jsx("p", { children: SDKUI_Localizator.PreviewNotAvailableOnDevice })] }), _jsxs("div", { style: { display: 'flex', gap: '10px', flexWrap: 'wrap', alignItems: 'center', justifyContent: 'center' }, children: [_jsx("a", { href: blobUrl, download: "document.pdf", style: {
240
+ minWidth: '180px',
241
+ padding: '12px 24px',
242
+ backgroundColor: TMColors.primaryColor,
243
+ color: 'white',
244
+ textDecoration: 'none',
245
+ borderRadius: '4px',
246
+ display: 'inline-block'
247
+ }, children: SDKUI_Localizator.DownloadFile }), _jsx("a", { href: blobUrl, target: "_blank", rel: "noopener noreferrer", style: {
248
+ minWidth: '180px',
249
+ padding: '12px 24px',
250
+ backgroundColor: TMColors.primaryColor,
251
+ color: 'white',
252
+ textDecoration: 'none',
253
+ borderRadius: '4px',
254
+ display: 'inline-block'
255
+ }, children: SDKUI_Localizator.OpenInNewTab })] })] }) }, blobUrl));
262
256
  }
263
257
  return (_jsx("iframe", { srcDoc: formattedXml ? `<html><body>${formattedXml}</body></html>` : undefined, src: !formattedXml
264
258
  ? (fileType === 'application/pdf' ? `${blobUrl}#view=FitH&scrollbar=1` : blobUrl)
@@ -176,7 +176,7 @@ const TMSavedQuerySelector = React.memo(({ items, selectedId, allowShowSearch =
176
176
  TMExceptionBoxManager.show({ exception: ex });
177
177
  }
178
178
  };
179
- return (_jsxs("div", { style: { height: height ?? '100%', width: '100%', display: 'flex', flexDirection: 'column', gap: '5px', paddingTop: allowShowSearch ? '5px' : undefined }, children: [allowShowSearch &&
179
+ return (_jsxs("div", { onContextMenu: (e) => e.preventDefault(), style: { height: height ?? '100%', width: '100%', display: 'flex', flexDirection: 'column', gap: '5px', paddingTop: allowShowSearch ? '5px' : undefined }, children: [allowShowSearch &&
180
180
  _jsx("div", { style: { width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '10px', paddingBottom: '10px', paddingTop: '10px' }, children: _jsx(TMSearchBar, { marginLeft: '0px', maxWidth: '300px', searchValue: searchText, onSearchValueChanged: (e) => setSearchText(e) }) }), _jsx("div", { style: {
181
181
  display: 'flex',
182
182
  flexDirection: 'column',
@@ -314,7 +314,7 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
314
314
  { icon: _jsx(IconMenuCAArchive, { viewBox: '11 11.5 26 27', fontSize: 16, strokeWidth: 2, color: 'black' }), beginGroup: true, text: SDKUI_Localizator.PassToArchive, onClick: handlePassToArchive }
315
315
  ], onMenuShown: () => setIsQueryPanelActive(true) })
316
316
  : _jsx(_Fragment, {}) }), children: [_jsx(ConfirmQueryParamsDialog, {}), SQD
317
- ? _jsxs("div", { style: { height: '100%', width: '100%', position: 'relative', display: 'flex', flexDirection: 'column', gap: 5 }, children: [showAdvancedSearch
317
+ ? _jsxs("div", { onContextMenu: (e) => e.preventDefault(), style: { height: '100%', width: '100%', position: 'relative', display: 'flex', flexDirection: 'column', gap: 5 }, children: [showAdvancedSearch
318
318
  ? _jsx(TMQueryEditor, { formMode: FormModes.Update, showToolbar: false, inputData: qd, validateSelect: true, showApply: false, onQDChanged: handleQdChanged })
319
319
  : _jsx(TMSearchQueryEditor, { qd: qd, dcmtTypesList: dcmtTypesList, isExpertMode: isExpertMode, showAllMdWhere: showAllMdWhere, onQdChanged: handleQdChanged, onFocusedMetadataChanged: setFocusedTidMid, onAdvancedMenuClick: handleAdvancedMenuClick }), _jsxs("div", { style: {
320
320
  display: 'flex',