@topconsultnpm/sdkui-react 6.21.0-t3 → 6.21.0-t4

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 (47) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +23 -18
  2. package/lib/components/base/TMPopUp.js +3 -3
  3. package/lib/components/base/TMTreeView.d.ts +16 -13
  4. package/lib/components/base/TMTreeView.js +230 -64
  5. package/lib/components/choosers/TMDistinctValues.js +1 -1
  6. package/lib/components/editors/TMTextBox.d.ts +1 -0
  7. package/lib/components/editors/TMTextBox.js +2 -1
  8. package/lib/components/features/documents/TMDcmtForm.d.ts +2 -0
  9. package/lib/components/features/documents/TMDcmtForm.js +2 -1
  10. package/lib/components/features/documents/TMDcmtIcon.d.ts +3 -1
  11. package/lib/components/features/documents/TMDcmtIcon.js +5 -32
  12. package/lib/components/features/documents/TMFileUploader.js +1 -1
  13. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  14. package/lib/components/features/documents/TMMasterDetailDcmts.js +54 -14
  15. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +2 -1
  16. package/lib/components/features/documents/TMMergeToPdfForm.js +91 -48
  17. package/lib/components/features/documents/TMRelationViewer.d.ts +12 -10
  18. package/lib/components/features/documents/TMRelationViewer.js +401 -96
  19. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +4 -3
  20. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +47 -23
  21. package/lib/components/features/documents/mergePdfUtils.d.ts +52 -0
  22. package/lib/components/features/documents/mergePdfUtils.js +268 -0
  23. package/lib/components/features/search/TMSearch.d.ts +2 -0
  24. package/lib/components/features/search/TMSearch.js +2 -2
  25. package/lib/components/features/search/TMSearchResult.d.ts +2 -0
  26. package/lib/components/features/search/TMSearchResult.js +58 -9
  27. package/lib/components/viewers/TMTidViewer.js +14 -2
  28. package/lib/helper/Enum_Localizator.js +1 -0
  29. package/lib/helper/SDKUI_Globals.d.ts +1 -0
  30. package/lib/helper/SDKUI_Globals.js +1 -0
  31. package/lib/helper/SDKUI_Localizator.d.ts +34 -0
  32. package/lib/helper/SDKUI_Localizator.js +352 -12
  33. package/lib/helper/TMUtils.d.ts +33 -1
  34. package/lib/helper/TMUtils.js +104 -1
  35. package/lib/helper/certificateImportHelper.d.ts +43 -0
  36. package/lib/helper/certificateImportHelper.js +403 -0
  37. package/lib/helper/helpers.js +9 -0
  38. package/lib/helper/index.d.ts +1 -0
  39. package/lib/helper/index.js +1 -0
  40. package/lib/hooks/useDcmtOperations.d.ts +2 -1
  41. package/lib/hooks/useDcmtOperations.js +10 -2
  42. package/lib/hooks/useDocumentOperations.d.ts +2 -0
  43. package/lib/hooks/useDocumentOperations.js +28 -6
  44. package/lib/services/platform_services.d.ts +1 -1
  45. package/lib/ts/types.d.ts +2 -1
  46. package/lib/ts/types.js +1 -0
  47. package/package.json +3 -2
@@ -395,26 +395,31 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
395
395
  ];
396
396
  });
397
397
  };
398
- // Caps overflowing submenus with max-height + scroll so every item stays reachable.
399
398
  useLayoutEffect(() => {
400
399
  if (hoveredSubmenus.length === 0)
401
400
  return;
402
- const padding = 8;
403
- const submenus = document.querySelectorAll('[data-submenu="true"]');
404
- submenus.forEach(el => {
405
- const rect = el.getBoundingClientRect();
406
- const overflowsTop = rect.top < padding;
407
- const overflowsBottom = rect.bottom > window.innerHeight - padding;
408
- if (!overflowsTop && !overflowsBottom)
409
- return;
410
- const available = overflowsTop
411
- ? rect.bottom - padding
412
- : window.innerHeight - rect.top - padding;
413
- const newMax = Math.max(80, available);
414
- el.style.maxHeight = `${newMax}px`;
415
- el.style.overflowY = 'auto';
416
- el.style.overflowX = 'hidden';
417
- });
401
+ const capSubmenus = () => {
402
+ const padding = 8;
403
+ const submenus = document.querySelectorAll('[data-submenu="true"]');
404
+ submenus.forEach(el => {
405
+ el.style.maxHeight = '';
406
+ el.style.overflowY = '';
407
+ el.style.overflowX = '';
408
+ const rect = el.getBoundingClientRect();
409
+ const opensUp = el.dataset.openUp === 'true';
410
+ const available = opensUp
411
+ ? rect.bottom - padding
412
+ : window.innerHeight - rect.top - padding;
413
+ if (rect.height <= available)
414
+ return;
415
+ el.style.maxHeight = `${Math.max(80, available)}px`;
416
+ el.style.overflowY = 'auto';
417
+ el.style.overflowX = 'hidden';
418
+ });
419
+ };
420
+ capSubmenus();
421
+ window.addEventListener('resize', capSubmenus);
422
+ return () => window.removeEventListener('resize', capSubmenus);
418
423
  }, [hoveredSubmenus]);
419
424
  const handleMouseLeave = (depth = 0) => {
420
425
  if (isMobile)
@@ -495,6 +500,6 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
495
500
  // display: 'inline-block',
496
501
  WebkitTouchCallout: isIOS ? 'none' : undefined,
497
502
  WebkitUserSelect: isIOS ? 'none' : undefined,
498
- }, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
503
+ }, children: children })), menuState.visible && createPortal(_jsxs(_Fragment, { children: [_jsxs(S.MenuContainer, { ref: menuRef, "$x": menuState.position.x, "$y": menuState.position.y, "$openLeft": openLeft, "$openUp": openUp, "$isPositioned": isCalculated, "$externalControl": !!externalControl, "$needsScroll": needsScroll, "$maxHeight": maxHeight, children: [isMobile && menuState.parentNames.length > 0 && (_jsxs(S.MobileMenuHeader, { children: [_jsx(S.BackButton, { onClick: handleBack, "aria-label": "Go back", children: _jsx(IconArrowLeft, {}) }), _jsx(S.HeaderTitle, { children: currentParentName })] })), renderMenuItems(currentMenu, 0)] }), !isMobile && hoveredSubmenus.map((submenu, idx) => (_jsx(S.Submenu, { "$parentRect": submenu.parentRect, "$openUp": submenu.openUp, "data-submenu": "true", "data-open-up": submenu.openUp ? 'true' : 'false', onMouseEnter: handleSubmenuMouseEnter, onMouseLeave: () => handleMouseLeave(submenu.depth), children: renderMenuItems(submenu.items, submenu.depth) }, `submenu-${submenu.depth}-${idx}`)))] }), document.body)] }));
499
504
  };
500
505
  export default TMContextMenu;
@@ -23,8 +23,8 @@ export var ButtonNames;
23
23
  // Dimensioni minime di default per i popup
24
24
  const DEFAULT_MIN_WIDTH = 500;
25
25
  const DEFAULT_MIN_HEIGHT = 400;
26
- // filtr password from all errors.
27
- const SENSITIVE_KEY = 'password';
26
+ // filtr sensitive keys from all errors.
27
+ const SENSITIVE_KEYS = ['password', 'username'];
28
28
  const redactSensitiveJsonString = (value) => {
29
29
  const trimmed = value.trim();
30
30
  const looksLikeJson = (trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'));
@@ -46,7 +46,7 @@ const redactSensitiveValue = (value) => {
46
46
  return value;
47
47
  const result = {};
48
48
  for (const key of Object.keys(value)) {
49
- result[key] = key.toLowerCase() === SENSITIVE_KEY ? '***' : redactSensitiveValue(value[key]);
49
+ result[key] = SENSITIVE_KEYS.includes(key.toLowerCase()) ? '***' : redactSensitiveValue(value[key]);
50
50
  }
51
51
  return result;
52
52
  };
@@ -11,25 +11,28 @@ export interface ITMTreeItem {
11
11
  currentPage?: number;
12
12
  totalItemsCount?: number;
13
13
  }
14
- interface ITMTreeViewProps<T extends ITMTreeItem> {
15
- dataSource?: T[];
16
- focusedItem?: T | null;
17
- selectedItems?: T[];
14
+ interface ITMTreeViewProps {
15
+ dataSource?: ITMTreeItem[];
16
+ focusedItem?: ITMTreeItem | null;
17
+ selectedItems?: ITMTreeItem[];
18
18
  allowMultipleSelection?: boolean;
19
- calculateItemsForNode?: (node: T) => Promise<T[] | undefined>;
20
- itemRender: (item: T | null) => JSX.Element;
21
- onFocusedItemChanged?: (item: T | null) => void;
22
- onSelectionChanged?: (selectedItems: T[]) => void;
23
- onNodeUpdate?: (updatedNode: T) => void;
24
- onDataChanged?: (items: T[]) => void;
25
- shouldDelayFocusOnEvent?: (node: T, event: React.MouseEvent) => boolean;
26
- onItemContextMenu?: (item: T, e: React.MouseEvent) => void;
19
+ calculateItemsForNode?: (node: ITMTreeItem) => Promise<ITMTreeItem[] | undefined>;
20
+ itemRender: (item: ITMTreeItem | null) => JSX.Element;
21
+ onFocusedItemChanged?: (item: ITMTreeItem | null) => void;
22
+ onSelectionChanged?: (selectedItems: ITMTreeItem[]) => void;
23
+ onNodeUpdate?: (updatedNode: ITMTreeItem) => void;
24
+ onDataChanged?: (items: ITMTreeItem[]) => void;
25
+ shouldDelayFocusOnEvent?: (node: ITMTreeItem, event: React.MouseEvent) => boolean;
26
+ onItemContextMenu?: (item: ITMTreeItem, e: React.MouseEvent) => void;
27
27
  autoSelectChildren?: boolean;
28
28
  itemsPerPage?: number;
29
29
  showLoadMoreButton?: boolean;
30
+ enableVirtualization?: boolean;
30
31
  }
31
- declare const TMTreeView: <T extends ITMTreeItem>({ dataSource, focusedItem, selectedItems, allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren, itemsPerPage, showLoadMoreButton }: ITMTreeViewProps<T>) => React.JSX.Element;
32
+ declare const TMTreeView: ({ dataSource, focusedItem, selectedItems, allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren, itemsPerPage, showLoadMoreButton, enableVirtualization }: ITMTreeViewProps) => React.JSX.Element;
32
33
  export default TMTreeView;
34
+ export declare const StyledTreeContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
35
+ export declare const StyledItemContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
33
36
  export declare const StyledTreeNode: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "$isSelected"> & {
34
37
  $isSelected?: boolean;
35
38
  }, never> & Partial<Pick<import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "$isSelected"> & {
@@ -1,9 +1,147 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef } from 'react';
2
+ import React, { useCallback, useEffect, useMemo, useRef, memo } from 'react';
3
+ import { List } from 'react-window';
3
4
  import styled from 'styled-components';
4
5
  import { IconArrowLeft, IconArrowRight, IconChevronDown, IconChevronRight, SDKUI_Localizator } from '../../helper';
5
6
  import TMButton from './TMButton';
6
- const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren = true, itemsPerPage = 100, showLoadMoreButton = true }) => {
7
+ // Componente riga virtualizzata memoizzato
8
+ const VirtualRowComponent = memo(({ ariaAttributes, index, style, flattenedItems, focusedItemKey, selectedItemKeys, allowMultipleSelection, hasVisibleItems, handleNodeToggle, handleNodeClick, handleCheckboxChange, hasPartialChildSelection, itemRender, onItemContextMenu }) => {
9
+ const item = flattenedItems[index];
10
+ if (!item)
11
+ return null;
12
+ const { node, depth } = item;
13
+ const isSelected = node.key === focusedItemKey;
14
+ return (_jsx("div", { ...ariaAttributes, "data-node-key": node.key, style: {
15
+ ...style,
16
+ paddingLeft: depth * 20,
17
+ display: 'flex',
18
+ alignItems: 'center',
19
+ width: 'fit-content',
20
+ minWidth: '100%',
21
+ paddingRight: 10,
22
+ boxSizing: 'border-box'
23
+ }, children: _jsxs(StyledTreeNode, { "$isSelected": isSelected, children: [_jsx("div", { style: {
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ justifyContent: 'center',
27
+ minHeight: '18px',
28
+ minWidth: '18px',
29
+ maxHeight: '18px',
30
+ maxWidth: '18px',
31
+ flexShrink: 0
32
+ }, onClick: (e) => { handleNodeToggle(node.key, e.ctrlKey); }, children: hasVisibleItems(node)
33
+ ? node.expanded
34
+ ? _jsx(IconChevronDown, { cursor: 'pointer', fontSize: 14 })
35
+ : _jsx(IconChevronRight, { cursor: 'pointer', fontSize: 14 })
36
+ : _jsx("div", { style: { height: '18px', width: '18px' } }) }), allowMultipleSelection && (_jsx("input", { type: "checkbox", checked: selectedItemKeys.has(node.key), onChange: (e) => handleCheckboxChange(node, e.target.checked), onClick: (e) => e.stopPropagation(), style: { flexShrink: 0 }, ref: input => {
37
+ if (input) {
38
+ // Imposta lo stato visuale "trattino" sulla checkbox quando il container
39
+ // ha alcuni figli selezionati ma non tutti. Necessario usare ref perché
40
+ // "indeterminate" è una proprietà DOM, non un attributo HTML.
41
+ input.indeterminate = hasPartialChildSelection(node);
42
+ }
43
+ } })), _jsx(StyledItemContent, { onClick: (e) => { handleNodeClick(node, e); }, onContextMenu: (e) => {
44
+ if (onItemContextMenu) {
45
+ e.preventDefault();
46
+ onItemContextMenu(node, e);
47
+ }
48
+ }, children: itemRender(node) })] }) }));
49
+ }, (prevProps, nextProps) => {
50
+ // Custom comparison: re-render solo se i dati rilevanti per questa riga cambiano
51
+ const prevItem = prevProps.flattenedItems[prevProps.index];
52
+ const nextItem = nextProps.flattenedItems[nextProps.index];
53
+ if (!prevItem || !nextItem)
54
+ return prevItem === nextItem;
55
+ const prevNode = prevItem.node;
56
+ const nextNode = nextItem.node;
57
+ // Controlla se questa riga specifica è cambiata
58
+ return (prevNode.key === nextNode.key &&
59
+ prevNode.expanded === nextNode.expanded &&
60
+ prevItem.depth === nextItem.depth &&
61
+ (prevNode.key === prevProps.focusedItemKey) === (nextNode.key === nextProps.focusedItemKey) &&
62
+ prevProps.selectedItemKeys.has(prevNode.key) === nextProps.selectedItemKeys.has(nextNode.key) &&
63
+ prevProps.allowMultipleSelection === nextProps.allowMultipleSelection);
64
+ });
65
+ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren = true, itemsPerPage = 100, showLoadMoreButton = true, enableVirtualization = false }) => {
66
+ // Altezza fissa per ogni riga nella virtualizzazione
67
+ const VIRTUAL_ROW_HEIGHT = 26;
68
+ const listRef = useRef(null);
69
+ const containerRef = useRef(null);
70
+ const [containerSize, setContainerSize] = React.useState({ width: 0, height: 0 });
71
+ // Ref per selectedItems - permette alle callback memoizzate di accedere sempre al valore più recente
72
+ const selectedItemsRef = useRef(selectedItems);
73
+ selectedItemsRef.current = selectedItems;
74
+ // Ref per handleCheckboxChange - permette all'useEffect di accedere alla funzione prima che sia definita
75
+ const handleCheckboxChangeRef = useRef(() => { });
76
+ // Filtra gli items da mostrare in base alla paginazione (definito prima per essere usato da flattenTreeWithDepth)
77
+ const getVisibleItems = useCallback((node) => {
78
+ if (!node.items)
79
+ return [];
80
+ const totalItems = node.items.length;
81
+ // Se non c'è paginazione attiva o gli items sono pochi, mostra tutti
82
+ if (totalItems <= itemsPerPage || !showLoadMoreButton) {
83
+ return node.items;
84
+ }
85
+ // Altrimenti mostra solo gli items della pagina corrente
86
+ const currentPage = node.currentPage ?? 0;
87
+ const startIndex = currentPage * itemsPerPage;
88
+ const endIndex = startIndex + itemsPerPage;
89
+ return node.items.slice(startIndex, endIndex);
90
+ }, [itemsPerPage, showLoadMoreButton]);
91
+ // Misura le dimensioni del container per react-window
92
+ useEffect(() => {
93
+ if (!enableVirtualization || !containerRef.current)
94
+ return;
95
+ const resizeObserver = new ResizeObserver((entries) => {
96
+ for (const entry of entries) {
97
+ const { width, height } = entry.contentRect;
98
+ setContainerSize({ width, height });
99
+ }
100
+ });
101
+ resizeObserver.observe(containerRef.current);
102
+ return () => resizeObserver.disconnect();
103
+ }, [enableVirtualization]);
104
+ // Flatten tree con informazioni di profondità per la virtualizzazione
105
+ const flattenTreeWithDepth = useCallback((nodes, depth = 0, parentKey) => {
106
+ let flatList = [];
107
+ nodes.forEach(node => {
108
+ if (!node.hidden) {
109
+ flatList.push({ node, depth, parentKey });
110
+ if (node.expanded && node.items) {
111
+ const visibleItems = getVisibleItems(node);
112
+ flatList = flatList.concat(flattenTreeWithDepth(visibleItems, depth + 1, node.key));
113
+ }
114
+ }
115
+ });
116
+ return flatList;
117
+ }, [getVisibleItems]);
118
+ // Lista piatta per la virtualizzazione
119
+ const flattenedItems = useMemo(() => {
120
+ if (!enableVirtualization)
121
+ return [];
122
+ return flattenTreeWithDepth(dataSource);
123
+ }, [enableVirtualization, dataSource, flattenTreeWithDepth]);
124
+ // Scroll verso l'elemento focalizzato quando cambia (navigazione con frecce)
125
+ useEffect(() => {
126
+ if (!focusedItem?.key)
127
+ return;
128
+ if (enableVirtualization) {
129
+ // Lista virtualizzata: usa scrollToRow per garantire che l'elemento sia visibile
130
+ const index = flattenedItems.findIndex(item => item.node.key === focusedItem.key);
131
+ if (index >= 0 && listRef.current) {
132
+ listRef.current.scrollToRow({ index, align: 'smart' });
133
+ }
134
+ }
135
+ else {
136
+ // Lista standard: usa scrollIntoView
137
+ if (containerRef.current) {
138
+ const element = containerRef.current.querySelector(`[data-node-key="${focusedItem.key}"]`);
139
+ if (element) {
140
+ element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
141
+ }
142
+ }
143
+ }
144
+ }, [focusedItem?.key, enableVirtualization, flattenedItems]);
7
145
  useEffect(() => {
8
146
  const handleKeyDown = (event) => {
9
147
  if (!focusedItem)
@@ -33,9 +171,14 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
33
171
  handled = true;
34
172
  }
35
173
  break;
36
- // case ' ':
37
- // allowMultipleSelection && handleCheckboxChange(focusedItem, !selectedItems.some(item => item.key === focusedItem.key));
38
- // break;
174
+ case ' ':
175
+ case 'Spacebar': // IE/Edge legacy
176
+ if (allowMultipleSelection) {
177
+ const isCurrentlySelected = selectedItemsRef.current.some(item => item.key === focusedItem.key);
178
+ handleCheckboxChangeRef.current(focusedItem, !isCurrentlySelected);
179
+ handled = true;
180
+ }
181
+ break;
39
182
  // case '*':
40
183
  // handleExpandAllNodes();
41
184
  // break;
@@ -57,7 +200,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
57
200
  return () => {
58
201
  window.removeEventListener('keydown', handleKeyDown, true);
59
202
  };
60
- }, [focusedItem, dataSource, onFocusedItemChanged]);
203
+ }, [focusedItem, dataSource, onFocusedItemChanged, allowMultipleSelection]);
61
204
  const findNextItem = (nodes, currentItem) => {
62
205
  const flatList = flattenTree(nodes);
63
206
  const currentIndex = flatList.findIndex(item => item.key === currentItem.key);
@@ -162,7 +305,9 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
162
305
  onFocusedItemChanged?.(node); // Chiama onFocusedItemChanged immediatamente
163
306
  }
164
307
  }, [onFocusedItemChanged, calculateItemsForNode, onNodeUpdate]);
165
- const handleCheckboxChange = (node, checked) => {
308
+ const handleCheckboxChange = useCallback((node, checked) => {
309
+ // Usa la ref per accedere sempre al valore più recente di selectedItems
310
+ const currentSelectedItems = selectedItemsRef.current;
166
311
  // Funzione helper per trovare il parent di un nodo e verificare se tutti i suoi figli sono selezionati
167
312
  const findAndCheckParents = (items, targetNode, currentSelection) => {
168
313
  const parentsToAdd = [];
@@ -199,11 +344,14 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
199
344
  if (node.isContainer && autoSelectChildren) {
200
345
  // Quando selezioni un container, aggiungi il container stesso + tutti i figli (se autoSelectChildren è true)
201
346
  const allChildren = flattenTree(node.items || []);
202
- newSelectedItems = [...selectedItems, node, ...allChildren];
347
+ // Rimuovi eventuali duplicati: filtra gli elementi già presenti nella selezione
348
+ const childrenKeys = new Set(allChildren.map(child => child.key));
349
+ const filteredSelectedItems = currentSelectedItems.filter(item => !childrenKeys.has(item.key) && item.key !== node.key);
350
+ newSelectedItems = [...filteredSelectedItems, node, ...allChildren];
203
351
  }
204
- else if (!selectedItems.some(item => item.key === node.key)) {
352
+ else if (!currentSelectedItems.some(item => item.key === node.key)) {
205
353
  // Quando selezioni un figlio o un container con autoSelectChildren=false, aggiungi solo il nodo
206
- newSelectedItems = [...selectedItems, node];
354
+ newSelectedItems = [...currentSelectedItems, node];
207
355
  // Verifica se selezionando questo figlio sono ora selezionati tutti i figli del parent (solo se autoSelectChildren è true)
208
356
  if (autoSelectChildren) {
209
357
  const parentsToAdd = findAndCheckParents(dataSource, node, newSelectedItems);
@@ -211,17 +359,17 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
211
359
  }
212
360
  }
213
361
  else {
214
- newSelectedItems = selectedItems;
362
+ newSelectedItems = currentSelectedItems;
215
363
  }
216
364
  }
217
365
  else if (node.isContainer && autoSelectChildren) {
218
366
  // Quando deselezioni un container, rimuovi il container stesso + tutti i figli (solo se autoSelectChildren è true)
219
367
  const childKeys = flattenTree(node.items || []).map(item => item.key);
220
- newSelectedItems = selectedItems.filter(item => item.key !== node.key && !childKeys.includes(item.key));
368
+ newSelectedItems = currentSelectedItems.filter(item => item.key !== node.key && !childKeys.includes(item.key));
221
369
  }
222
370
  else {
223
371
  // Quando deselezioni un figlio o un container con autoSelectChildren=false, rimuovi solo il nodo
224
- newSelectedItems = selectedItems.filter(item => item.key !== node.key);
372
+ newSelectedItems = currentSelectedItems.filter(item => item.key !== node.key);
225
373
  // Se il figlio apparteneva a un parent che era selezionato, rimuovi anche il parent (solo se autoSelectChildren è true)
226
374
  if (autoSelectChildren && !node.isContainer) {
227
375
  const removeParentContainers = (items) => {
@@ -243,28 +391,10 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
243
391
  }
244
392
  }
245
393
  onSelectionChanged?.(newSelectedItems);
246
- };
247
- // const handleExpandAllNodes = () => {
248
- // const expandAll = (nodes: T[]): T[] => {
249
- // return nodes.map(node => ({
250
- // ...node,
251
- // expanded: true,
252
- // items: node.items ? expandAll(node.items as T[]) : node.items
253
- // }));
254
- // };
255
- // setTreeData(prevData => expandAll(prevData));
256
- // };
257
- // const handleCollapseAllNodes = () => {
258
- // const collapseAll = (nodes: T[]): T[] => {
259
- // return nodes.map(node => ({
260
- // ...node,
261
- // expanded: false,
262
- // items: node.items ? collapseAll(node.items as T[]) : node.items
263
- // }));
264
- // };
265
- // setTreeData(prevData => collapseAll(prevData));
266
- // };
267
- const isIndeterminate = (node) => {
394
+ }, [autoSelectChildren, dataSource, onSelectionChanged]);
395
+ // Aggiorna la ref con l'ultima versione di handleCheckboxChange
396
+ handleCheckboxChangeRef.current = handleCheckboxChange;
397
+ const hasPartialChildSelection = (node) => {
268
398
  // Lo stato indeterminate ha senso solo quando autoSelectChildren è true
269
399
  if (!autoSelectChildren)
270
400
  return false;
@@ -275,13 +405,6 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
275
405
  const selectedCount = childKeys.filter(key => selectedChildKeys.includes(key)).length;
276
406
  return selectedCount > 0 && selectedCount < childKeys.length;
277
407
  };
278
- const isFullySelected = (node) => {
279
- if (!node.isContainer || !node.items)
280
- return false;
281
- const childKeys = flattenTree(node.items).map(item => item.key);
282
- const selectedChildKeys = selectedItems.map(item => item.key);
283
- return childKeys.every(key => selectedChildKeys.includes(key));
284
- };
285
408
  const hasVisibleItems = (node) => {
286
409
  // If node has explicit isExpandible value, use that
287
410
  if (node.isExpandible !== undefined) {
@@ -312,21 +435,6 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
312
435
  const updatedData = updateNodePage(dataSource);
313
436
  onDataChanged?.(updatedData);
314
437
  }, [dataSource, onDataChanged, onNodeUpdate]);
315
- // Filtra gli items da mostrare in base alla paginazione
316
- const getVisibleItems = useCallback((node) => {
317
- if (!node.items)
318
- return [];
319
- const totalItems = node.items.length;
320
- // Se non c'è paginazione attiva o gli items sono pochi, mostra tutti
321
- if (totalItems <= itemsPerPage || !showLoadMoreButton) {
322
- return node.items;
323
- }
324
- // Altrimenti mostra solo gli items della pagina corrente
325
- const currentPage = node.currentPage ?? 0;
326
- const startIndex = currentPage * itemsPerPage;
327
- const endIndex = startIndex + itemsPerPage;
328
- return node.items.slice(startIndex, endIndex);
329
- }, [itemsPerPage, showLoadMoreButton]);
330
438
  // Verifica se c'è bisogno del paginatore
331
439
  const needsPagination = useCallback((node) => {
332
440
  if (!showLoadMoreButton || !node.items)
@@ -340,7 +448,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
340
448
  return Math.ceil(node.items.length / itemsPerPage);
341
449
  }, [itemsPerPage]);
342
450
  const renderTree = useCallback((nodes) => {
343
- return nodes.map(node => !node.hidden && (_jsxs("div", { style: { width: '100%', margin: 0, padding: 0 }, children: [_jsxs(StyledTreeNode, { "$isSelected": node.key === focusedItem?.key, children: [_jsx("div", { style: {
451
+ return nodes.map(node => !node.hidden && (_jsxs("div", { style: { width: 'fit-content', minWidth: '100%', margin: 0, padding: 0 }, children: [_jsxs(StyledTreeNode, { "$isSelected": node.key === focusedItem?.key, "data-node-key": node.key, children: [_jsx("div", { style: {
344
452
  display: 'flex',
345
453
  alignItems: 'center',
346
454
  justifyContent: 'center',
@@ -355,28 +463,86 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
355
463
  : _jsx(IconChevronRight, { cursor: 'pointer', fontSize: 14 })
356
464
  : _jsx("div", { style: { height: '18px', width: '18px' } }) }), allowMultipleSelection && (_jsx("input", { type: "checkbox", checked: selectedItems.some(item => item.key === node.key), onChange: (e) => handleCheckboxChange(node, e.target.checked), onClick: (e) => e.stopPropagation(), style: { flexShrink: 0 }, ref: input => {
357
465
  if (input) {
358
- input.indeterminate = isIndeterminate(node);
466
+ // Imposta lo stato visuale "trattino" () sulla checkbox quando il container
467
+ // ha alcuni figli selezionati ma non tutti. Necessario usare ref perché
468
+ // "indeterminate" è una proprietà DOM, non un attributo HTML.
469
+ input.indeterminate = hasPartialChildSelection(node);
359
470
  }
360
- } })), _jsx("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, onClick: (e) => { handleNodeClick(node, e); }, onContextMenu: (e) => {
471
+ } })), _jsx(StyledItemContent, { onClick: (e) => { handleNodeClick(node, e); }, onContextMenu: (e) => {
361
472
  if (onItemContextMenu) {
362
473
  e.preventDefault();
363
474
  onItemContextMenu(node, e);
364
475
  }
365
- }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: '100%' }, children: [renderTree(getVisibleItems(node)), needsPagination(node) && (_jsxs(StyledStickyPaginator, { children: [_jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) - 1), showTooltip: false, caption: "\u25C4", icon: _jsx(IconArrowLeft, { color: 'white' }), disabled: (node.currentPage ?? 0) <= 0 }), _jsx("span", { style: { fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, color: 'white' }, children: SDKUI_Localizator.PaginationInfo.replaceParams((node.currentPage ?? 0) + 1, getTotalPages(node), node.items?.length ?? 0) }), _jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) + 1), showTooltip: false, caption: "\u25BA", icon: _jsx(IconArrowRight, { color: 'white' }), disabled: (node.currentPage ?? 0) >= getTotalPages(node) - 1 })] }))] }))] }, node.key)));
476
+ }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: 'fit-content', minWidth: '100%' }, children: [renderTree(getVisibleItems(node)), needsPagination(node) && (_jsxs(StyledStickyPaginator, { children: [_jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) - 1), showTooltip: false, caption: "\u25C4", icon: _jsx(IconArrowLeft, { color: 'white' }), disabled: (node.currentPage ?? 0) <= 0 }), _jsx("span", { style: { fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0, color: 'white' }, children: SDKUI_Localizator.PaginationInfo.replaceParams((node.currentPage ?? 0) + 1, getTotalPages(node), node.items?.length ?? 0) }), _jsx(TMButton, { btnStyle: 'icon', onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) + 1), showTooltip: false, caption: "\u25BA", icon: _jsx(IconArrowRight, { color: 'white' }), disabled: (node.currentPage ?? 0) >= getTotalPages(node) - 1 })] }))] }))] }, node.key)));
366
477
  }, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsPagination, handlePageChange, getTotalPages, onItemContextMenu]);
367
- return (_jsx("div", { style: { height: '100%', width: '100%', overflowY: 'auto', overflowX: 'hidden', padding: '0px 5px 2px 2px' }, children: renderTree(dataSource) }));
478
+ // Calcola selectedItemKeys ad ogni render per garantire sincronizzazione con selectedItems
479
+ const selectedItemKeys = new Set(selectedItems.map(s => s.key));
480
+ // Memoizza rowPropsData per evitare re-render della List
481
+ const rowPropsData = useMemo(() => ({
482
+ flattenedItems,
483
+ focusedItemKey: focusedItem?.key,
484
+ selectedItemKeys,
485
+ allowMultipleSelection,
486
+ hasVisibleItems,
487
+ handleNodeToggle,
488
+ handleNodeClick,
489
+ handleCheckboxChange,
490
+ hasPartialChildSelection: hasPartialChildSelection,
491
+ itemRender,
492
+ onItemContextMenu
493
+ }), [
494
+ flattenedItems,
495
+ focusedItem?.key,
496
+ selectedItemKeys,
497
+ allowMultipleSelection,
498
+ hasVisibleItems,
499
+ handleNodeToggle,
500
+ handleNodeClick,
501
+ handleCheckboxChange,
502
+ hasPartialChildSelection,
503
+ itemRender,
504
+ onItemContextMenu
505
+ ]);
506
+ // Render virtualizzato con react-window v2
507
+ if (enableVirtualization) {
508
+ return (_jsx(StyledTreeContainer, { ref: containerRef, children: containerSize.height > 0 && (_jsx(List, { listRef: listRef, rowCount: flattenedItems.length, rowHeight: VIRTUAL_ROW_HEIGHT, rowComponent: VirtualRowComponent, rowProps: rowPropsData, style: { height: containerSize.height, width: '100%' }, overscanCount: 5 })) }));
509
+ }
510
+ // Render standard (non virtualizzato) con scrolling orizzontale
511
+ return (_jsx(StyledTreeContainer, { ref: containerRef, children: _jsx("div", { children: renderTree(dataSource) }) }));
368
512
  };
369
513
  export default TMTreeView;
514
+ // Container principale con scrolling orizzontale
515
+ export const StyledTreeContainer = styled.div `
516
+ height: 100%;
517
+ width: 100%;
518
+ overflow-y: auto;
519
+ overflow-x: auto;
520
+ padding: 0px 0px 2px 2px;
521
+
522
+ /* Contenitore interno che si espande per accomodare nodi annidati */
523
+ & > div {
524
+ width: fit-content;
525
+ min-width: 100%;
526
+ }
527
+ `;
528
+ // Contenuto dell'item - niente ellipsis per permettere scrolling orizzontale del container
529
+ export const StyledItemContent = styled.div `
530
+ display: flex;
531
+ align-items: center;
532
+ flex-shrink: 0;
533
+ white-space: nowrap;
534
+ `;
370
535
  export const StyledTreeNode = styled.div `
371
536
  display: flex;
372
537
  flex-direction: row;
373
- width: 100%;
374
- min-width: 0;
538
+ width: fit-content;
539
+ min-width: 100%;
375
540
  min-height: 22px;
376
541
  max-height: 30px;
377
542
  gap: 5px;
378
543
  align-items: center;
379
544
  padding: 0;
545
+ padding-right: 10px; /* Spazio extra a destra per evitare che il testo tocchi il bordo */
380
546
  margin: 0;
381
547
  background: ${(props) => props.$isSelected ? 'oklch(from var(--dx-color-primary) l c h / .2) !important' : 'transparent'};
382
548
 
@@ -11,7 +11,7 @@ import TMPanel from '../base/TMPanel';
11
11
  import TMModal from '../base/TMModal';
12
12
  import { useDataListItem } from '../../hooks/useDataListItem';
13
13
  import { useDataUserIdItem } from '../../hooks/useDataUserIdItem';
14
- const StyledDistinctValues = styled.div `display: flex; flex-direction: column; height: 100%; overflow: hidden; gap: 10px;`;
14
+ const StyledDistinctValues = styled.div `display: flex; flex-direction: column; height: 100%; overflow: hidden; gap: 10px; position: relative;`;
15
15
  const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppendMode = true, showHeader = true, isModal, separator = " ", onSelectionChanged, onClosePanelCallback }) => {
16
16
  const [focusedItem, setFocusedItem] = useState();
17
17
  const [dataSource, setDataSource] = useState([]);
@@ -17,6 +17,7 @@ export interface ITMTextBox extends ITMEditorBase {
17
17
  onClick?: () => void;
18
18
  onValueChanged?: (e: React.ChangeEvent<HTMLInputElement>) => void;
19
19
  onBlur?: (value: string | undefined) => void;
20
+ onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
20
21
  }
21
22
  declare const TMTextBox: React.FunctionComponent<ITMTextBox>;
22
23
  export default TMTextBox;
@@ -34,7 +34,7 @@ const StyledTextBoxEditorButton = styled.div `
34
34
  border-bottom-color: ${TMColors.primary};
35
35
  }
36
36
  `;
37
- const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onClick, onValueChanged, onBlur, borderRadius, allowedPattern }) => {
37
+ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onClick, onValueChanged, onBlur, onKeyDown, borderRadius, allowedPattern }) => {
38
38
  const [initialType, setInitialType] = useState(type);
39
39
  const [currentType, setCurrentType] = useState(type);
40
40
  const [currentValue, setCurrentValue] = useState(value);
@@ -283,6 +283,7 @@ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, pre
283
283
  if (!scale && (e.key == "." || e.key == ","))
284
284
  e.preventDefault();
285
285
  }
286
+ onKeyDown?.(e);
286
287
  }, "$isMobile": deviceType === DeviceType.MOBILE, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$maxValue": maxValue, "$width": width, "$type": currentType, "$borderRadius": borderRadius, style: { paddingRight: `${calculateRightPadding()}px`, cursor: onClick ? 'pointer' : undefined } }), (initialType === 'password' || initialType === 'secureText') && _jsx(StyledShowPasswordIcon, { onClick: toggleShowPassword, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: showPasswordIcon() }), initialType !== 'password' &&
287
288
  _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: type === 'number' ? '25px' : '6px', top: label.length > 0 ? '20px' : '3px', pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
288
289
  _jsx(StyledTextBoxEditorButton, { onClick: () => {
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { DcmtTypeDescriptor, HomeBlogPost, LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
3
3
  import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
4
+ import { IntesiCertificateData } from '../../../helper';
4
5
  /**
5
6
  * Definisce il contesto da cui è stato invocato il TMDcmtForm.
6
7
  * Permette di gestire logiche diverse in base alla provenienza.
@@ -75,6 +76,7 @@ interface ITMDcmtFormProps {
75
76
  mid: number;
76
77
  value: string;
77
78
  }>, tid?: number) => void;
79
+ fetchRemoteCertificates?: (email: string) => Promise<IntesiCertificateData[]>;
78
80
  datagridUtility?: {
79
81
  onRefreshSearchAsyncDatagrid?: () => Promise<void>;
80
82
  onRefreshDataRowsAsync?: (() => Promise<void>);
@@ -57,7 +57,7 @@ export var InvocationContext;
57
57
  let abortControllerLocal = new AbortController();
58
58
  ;
59
59
  //#endregion
60
- const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, datagridUtility }) => {
60
+ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, fetchRemoteCertificates, datagridUtility }) => {
61
61
  const { onRefreshSearchAsyncDatagrid, onRefreshBlogDatagrid, onRefreshPreviewDatagrid } = datagridUtility || {};
62
62
  const floatingBarContainerRef = useRef(null);
63
63
  const [id, setID] = useState('');
@@ -395,6 +395,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
395
395
  currentSearchResults,
396
396
  currentMetadataValues: formData,
397
397
  allUsers,
398
+ fetchRemoteCertificates,
398
399
  datagridUtility: {
399
400
  onRefreshBlogDatagrid,
400
401
  onRefreshPreviewDatagrid,
@@ -14,6 +14,8 @@ interface ITMDcmtIconProps {
14
14
  tooltipContent?: JSX.Element | string;
15
15
  openInOffice?: (selectedDcmtsOrFocused: Array<DcmtInfo>) => Promise<void>;
16
16
  onDownloadDcmtsAsync?: (inputDcmts: DcmtInfo[] | undefined, downloadType: DownloadTypes, downloadMode: DownloadModes, onFileDownloaded?: (dcmtFile: File | undefined) => void, confirmAttachments?: (list: FileDescriptor[]) => Promise<string[] | undefined>) => Promise<void>;
17
+ /** Se true, renderizza il wait panel nel body tramite Portal (centrato a schermo intero) */
18
+ usePortal?: boolean;
17
19
  }
18
- declare const TMDcmtIcon: ({ fileExtension, fileCount, isLexProt, isSigned, isMail, isShared, tid, did, downloadMode, tooltipContent, openInOffice, onDownloadDcmtsAsync }: ITMDcmtIconProps) => React.JSX.Element;
20
+ declare const TMDcmtIcon: ({ fileExtension, fileCount, isLexProt, isSigned, isMail, isShared, tid, did, downloadMode, tooltipContent, openInOffice, onDownloadDcmtsAsync, usePortal }: ITMDcmtIconProps) => React.JSX.Element;
19
21
  export default TMDcmtIcon;