@topconsultnpm/sdkui-react 6.22.0-dev2.2 → 6.22.0-dev2.21

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 (109) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
  2. package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
  3. package/lib/components/base/TMButton.d.ts +13 -0
  4. package/lib/components/base/TMButton.js +137 -5
  5. package/lib/components/base/TMDataGrid.d.ts +2 -0
  6. package/lib/components/base/TMDataGrid.js +68 -4
  7. package/lib/components/base/TMEditorBase.d.ts +2 -0
  8. package/lib/components/base/TMModal.d.ts +4 -0
  9. package/lib/components/base/TMModal.js +42 -11
  10. package/lib/components/base/TMPanel.d.ts +1 -0
  11. package/lib/components/base/TMPanel.js +79 -20
  12. package/lib/components/base/TMTooltip.d.ts +2 -1
  13. package/lib/components/base/TMTooltip.js +23 -6
  14. package/lib/components/base/TMTreeView.js +108 -67
  15. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  16. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  17. package/lib/components/choosers/TMDistinctValues.js +149 -142
  18. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  19. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  20. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  21. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  22. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  23. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  24. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  25. package/lib/components/editors/TMDropDown.d.ts +3 -0
  26. package/lib/components/editors/TMDropDown.js +197 -5
  27. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  28. package/lib/components/editors/TMMetadataEditor.js +8 -3
  29. package/lib/components/editors/TMTextBox.js +15 -15
  30. package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
  31. package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
  32. package/lib/components/features/documents/TMDcmtForm.js +104 -42
  33. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
  34. package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
  35. package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
  36. package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
  37. package/lib/components/features/documents/TMMasterInfoFields.js +172 -0
  38. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +40 -0
  39. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +277 -0
  40. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +354 -0
  41. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +234 -0
  42. package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
  43. package/lib/components/features/documents/TMRelationViewer.js +69 -20
  44. package/lib/components/features/search/TMSearch.js +29 -16
  45. package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
  46. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -1
  47. package/lib/components/features/search/TMSearchQueryPanel.js +28 -7
  48. package/lib/components/features/search/TMSearchResult.d.ts +9 -0
  49. package/lib/components/features/search/TMSearchResult.js +323 -92
  50. package/lib/components/features/search/TMTreeSelector.js +18 -5
  51. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
  52. package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
  53. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
  54. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
  55. package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
  56. package/lib/components/layout/panelManager/types.d.ts +3 -0
  57. package/lib/components/viewers/TMMidViewer.js +4 -1
  58. package/lib/components/viewers/TMTidViewer.js +25 -11
  59. package/lib/helper/SDKUI_Globals.d.ts +55 -0
  60. package/lib/helper/SDKUI_Globals.js +82 -0
  61. package/lib/helper/SDKUI_Localizator.d.ts +24 -0
  62. package/lib/helper/SDKUI_Localizator.js +240 -0
  63. package/lib/helper/TMIcons.d.ts +1 -0
  64. package/lib/helper/TMIcons.js +3 -0
  65. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  66. package/lib/helper/dataGridSearchHelper.js +51 -0
  67. package/lib/helper/dcmtsHelper.d.ts +20 -0
  68. package/lib/helper/dcmtsHelper.js +58 -1
  69. package/lib/helper/helpers.d.ts +20 -0
  70. package/lib/helper/helpers.js +40 -0
  71. package/lib/helper/index.d.ts +1 -0
  72. package/lib/helper/index.js +1 -0
  73. package/lib/helper/queryHelper.d.ts +2 -0
  74. package/lib/helper/queryHelper.js +3 -1
  75. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  76. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  77. package/lib/hooks/useArchiveListForm.d.ts +39 -0
  78. package/lib/hooks/useArchiveListForm.js +46 -0
  79. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  80. package/lib/hooks/useCaseFlowApprove.js +157 -0
  81. package/lib/hooks/useDataUserIdItem.d.ts +1 -0
  82. package/lib/hooks/useDataUserIdItem.js +1 -0
  83. package/lib/hooks/useDocumentOperations.d.ts +2 -0
  84. package/lib/hooks/useDocumentOperations.js +28 -5
  85. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +98 -0
  86. package/lib/hooks/useMultiMasterDetailDcmts.js +567 -0
  87. package/lib/hooks/useRelatedDocuments.js +2 -26
  88. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  89. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  90. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  91. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  92. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  93. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  94. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  95. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  96. package/lib/index.d.ts +1 -0
  97. package/lib/index.js +1 -0
  98. package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
  99. package/lib/services/caseflow/CaseFlowService.js +693 -0
  100. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  101. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  102. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  103. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  104. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  105. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  106. package/lib/services/index.d.ts +4 -0
  107. package/lib/services/index.js +4 -0
  108. package/lib/services/platform_services.d.ts +1 -1
  109. package/package.json +66 -66
@@ -1,20 +1,37 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
2
+ import { useEffect, useRef, useState } from 'react';
3
3
  import { Tooltip } from 'devextreme-react/tooltip';
4
4
  import { genUniqueId } from '../../helper';
5
5
  import { DeviceType, useDeviceType } from './TMDeviceProvider';
6
- const TMTooltip = ({ children, position, content, hideAfterDelay, parentStyle, childStyle }) => {
6
+ /** Tempo per spostare il mouse dall'elemento al contenuto del tooltip, quando è interattivo */
7
+ const HIDE_DELAY_MS = 400;
8
+ const TMTooltip = ({ children, position, content, hideAfterDelay, parentStyle, childStyle, allowContentInteraction = false }) => {
7
9
  const [showTooltip, setShowTooltip] = useState(false);
8
10
  const [id, setID] = useState('');
11
+ const hideTimerRef = useRef();
9
12
  useEffect(() => { setID(genUniqueId()); }, [children]);
10
13
  useEffect(() => {
11
- window.addEventListener('click', () => setShowTooltip(false));
12
- return () => window.removeEventListener('click', () => setShowTooltip(false));
14
+ const hide = () => setShowTooltip(false);
15
+ window.addEventListener('click', hide);
16
+ return () => window.removeEventListener('click', hide);
13
17
  }, []);
18
+ useEffect(() => { return () => clearTimeout(hideTimerRef.current); }, []);
14
19
  const deviceType = useDeviceType();
15
- return (_jsxs("div", { style: parentStyle, children: [_jsx("div", { id: `idContainerTooltip${id}`, style: { display: 'flex', alignItems: 'center', height: 'max-content', width: 'max-content', ...childStyle }, onMouseEnter: () => { setShowTooltip(true); }, onMouseLeave: () => { setShowTooltip(false); }, onTouchStart: () => { setShowTooltip(true); }, onClick: () => { if (deviceType === DeviceType.DESKTOP || !hideAfterDelay)
20
+ const cancelHide = () => clearTimeout(hideTimerRef.current);
21
+ const show = () => { cancelHide(); setShowTooltip(true); };
22
+ const hide = () => {
23
+ cancelHide();
24
+ if (!allowContentInteraction) {
25
+ setShowTooltip(false);
26
+ return;
27
+ }
28
+ hideTimerRef.current = setTimeout(() => setShowTooltip(false), HIDE_DELAY_MS);
29
+ };
30
+ return (_jsxs("div", { style: parentStyle, children: [_jsx("div", { id: `idContainerTooltip${id}`, style: { display: 'flex', alignItems: 'center', height: 'max-content', width: 'max-content', ...childStyle }, onMouseEnter: show, onMouseLeave: hide, onTouchStart: show, onClick: () => { if (deviceType === DeviceType.DESKTOP || !hideAfterDelay)
16
31
  return; setTimeout(() => { setShowTooltip(false); }, 1500); }, onTouchEnd: () => { if (deviceType === DeviceType.DESKTOP || !hideAfterDelay)
17
32
  return; setTimeout(() => { setShowTooltip(false); }, 1500); }, children: children }), content &&
18
- _jsx(Tooltip, { target: `#idContainerTooltip${id}`, hideOnOutsideClick: true, visible: showTooltip, position: position ?? 'bottom', onHidden: () => setShowTooltip(false), children: content })] }));
33
+ _jsx(Tooltip, { target: `#idContainerTooltip${id}`, hideOnOutsideClick: true, visible: showTooltip, position: position ?? 'bottom', onHidden: () => setShowTooltip(false), children: allowContentInteraction
34
+ ? _jsx("div", { style: { pointerEvents: 'all' }, onMouseEnter: cancelHide, onMouseLeave: hide, children: content })
35
+ : content })] }));
19
36
  };
20
37
  export default TMTooltip;
@@ -54,13 +54,16 @@ const VirtualRowComponent = memo(({ ariaAttributes, index, style, flattenedItems
54
54
  return prevItem === nextItem;
55
55
  const prevNode = prevItem.node;
56
56
  const nextNode = nextItem.node;
57
- // Controlla se questa riga specifica è cambiata
58
- return (prevNode.key === nextNode.key &&
59
- prevNode.expanded === nextNode.expanded &&
57
+ // Controlla se questa riga specifica è cambiata: confronta l'identità del nodo (non i soli
58
+ // campi key/expanded) per non lasciare visualizzato un nodo obsoleto. Gli handler non servono:
59
+ // hanno identità stabile e leggono lo stato dalle ref.
60
+ return (prevNode === nextNode &&
60
61
  prevItem.depth === nextItem.depth &&
61
62
  (prevNode.key === prevProps.focusedItemKey) === (nextNode.key === nextProps.focusedItemKey) &&
62
63
  prevProps.selectedItemKeys.has(prevNode.key) === nextProps.selectedItemKeys.has(nextNode.key) &&
63
- prevProps.allowMultipleSelection === nextProps.allowMultipleSelection);
64
+ prevProps.allowMultipleSelection === nextProps.allowMultipleSelection &&
65
+ prevProps.itemRender === nextProps.itemRender &&
66
+ prevProps.onItemContextMenu === nextProps.onItemContextMenu);
64
67
  });
65
68
  const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMultipleSelection, onDataChanged, calculateItemsForNode, itemRender, onNodeUpdate, onFocusedItemChanged, onSelectionChanged, shouldDelayFocusOnEvent, onItemContextMenu, autoSelectChildren = true, itemsPerPage = 100, showLoadMoreButton = true, enableVirtualization = false }) => {
66
69
  // Altezza fissa per ogni riga nella virtualizzazione
@@ -71,12 +74,35 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
71
74
  // Ref per selectedItems - permette alle callback memoizzate di accedere sempre al valore più recente
72
75
  const selectedItemsRef = useRef(selectedItems);
73
76
  selectedItemsRef.current = selectedItems;
77
+ // Ref per props e callback usate dagli handler: una riga virtualizzata memoizzata conserva le
78
+ // props del render precedente, quindi gli handler non devono catturare lo stato nella closure.
79
+ const dataSourceRef = useRef(dataSource);
80
+ dataSourceRef.current = dataSource;
81
+ const autoSelectChildrenRef = useRef(autoSelectChildren);
82
+ autoSelectChildrenRef.current = autoSelectChildren;
83
+ const calculateItemsForNodeRef = useRef(calculateItemsForNode);
84
+ calculateItemsForNodeRef.current = calculateItemsForNode;
85
+ const onNodeUpdateRef = useRef(onNodeUpdate);
86
+ onNodeUpdateRef.current = onNodeUpdate;
87
+ const onDataChangedRef = useRef(onDataChanged);
88
+ onDataChangedRef.current = onDataChanged;
89
+ const onFocusedItemChangedRef = useRef(onFocusedItemChanged);
90
+ onFocusedItemChangedRef.current = onFocusedItemChanged;
91
+ const onSelectionChangedRef = useRef(onSelectionChanged);
92
+ onSelectionChangedRef.current = onSelectionChanged;
93
+ const shouldDelayFocusOnEventRef = useRef(shouldDelayFocusOnEvent);
94
+ shouldDelayFocusOnEventRef.current = shouldDelayFocusOnEvent;
74
95
  // Ref per handleCheckboxChange - permette all'useEffect di accedere alla funzione prima che sia definita
75
96
  const handleCheckboxChangeRef = useRef(() => { });
76
97
  // Filtra gli items da mostrare in base alla paginazione (definito prima per essere usato da flattenTreeWithDepth)
77
98
  const getVisibleItems = useCallback((node) => {
78
99
  if (!node.items)
79
100
  return [];
101
+ // Con la virtualizzazione react-window renderizza già solo le righe visibili:
102
+ // la paginazione nasconderebbe gli items oltre itemsPerPage senza renderizzare
103
+ // il paginatore, presente solo nel render standard (renderTree).
104
+ if (enableVirtualization)
105
+ return node.items;
80
106
  const totalItems = node.items.length;
81
107
  // Se non c'è paginazione attiva o gli items sono pochi, mostra tutti
82
108
  if (totalItems <= itemsPerPage || !showLoadMoreButton) {
@@ -87,7 +113,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
87
113
  const startIndex = currentPage * itemsPerPage;
88
114
  const endIndex = startIndex + itemsPerPage;
89
115
  return node.items.slice(startIndex, endIndex);
90
- }, [itemsPerPage, showLoadMoreButton]);
116
+ }, [itemsPerPage, showLoadMoreButton, enableVirtualization]);
91
117
  // Misura le dimensioni del container per react-window
92
118
  useEffect(() => {
93
119
  if (!enableVirtualization || !containerRef.current)
@@ -211,7 +237,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
211
237
  const currentIndex = flatList.findIndex(item => item.key === currentItem.key);
212
238
  return flatList[currentIndex - 1] || null;
213
239
  };
214
- const flattenTree = (nodes) => {
240
+ const flattenTree = useCallback((nodes) => {
215
241
  let flatList = [];
216
242
  nodes.forEach(node => {
217
243
  if (!node.hidden) {
@@ -222,45 +248,57 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
222
248
  }
223
249
  });
224
250
  return flatList;
225
- };
226
- const handleNodeToggle = async (key, ctrlKey) => {
227
- const updateNodeRecursively = async (nodes) => {
228
- const updatedNodes = await Promise.all(nodes.map(async (node) => {
229
- if (node.key === key) {
230
- if (node.expanded) {
231
- // Collassa il nodo
232
- const updatedNode = { ...node, expanded: false };
233
- onNodeUpdate?.(updatedNode);
234
- return updatedNode;
235
- }
236
- else {
237
- // Espandi il nodo
238
- let newItems = node.items;
239
- // Solo se calculateItemsForNode è definito E (ctrl è premuto O non è già caricato)
240
- if (calculateItemsForNode && (ctrlKey || !node.isLoaded)) {
241
- // Se ctrl è premuto, passa un nodo con isLoaded resettato per forzare il refresh
242
- const nodeForCalculation = ctrlKey ? { ...node, isLoaded: false } : node;
243
- newItems = await calculateItemsForNode(nodeForCalculation);
244
- const updatedNode = { ...node, expanded: true, items: newItems, isLoaded: true };
245
- onNodeUpdate?.(updatedNode);
246
- return updatedNode;
247
- }
248
- // Altrimenti usa semplicemente gli items esistenti
249
- return { ...node, expanded: true };
250
- }
251
- }
252
- if (node.items) {
253
- const updatedItems = await updateNodeRecursively(node.items);
254
- return { ...node, items: updatedItems };
255
- }
251
+ }, []);
252
+ const findNodeByKey = useCallback((nodes, key) => {
253
+ for (const node of nodes) {
254
+ if (node.key === key)
256
255
  return node;
257
- }));
258
- return updatedNodes;
259
- };
260
- updateNodeRecursively(dataSource).then(updatedData => {
261
- onDataChanged?.(updatedData);
256
+ if (node.items) {
257
+ const found = findNodeByKey(node.items, key);
258
+ if (found)
259
+ return found;
260
+ }
261
+ }
262
+ return null;
263
+ }, []);
264
+ const handleNodeToggle = useCallback(async (key, ctrlKey) => {
265
+ // dataSourceRef è letta alla chiamata, non alla creazione della closure
266
+ const target = findNodeByKey(dataSourceRef.current, key);
267
+ if (!target)
268
+ return;
269
+ const calculateItems = calculateItemsForNodeRef.current;
270
+ let updatedNode;
271
+ if (target.expanded) {
272
+ // Collassa il nodo
273
+ updatedNode = { ...target, expanded: false };
274
+ onNodeUpdateRef.current?.(updatedNode);
275
+ }
276
+ else if (calculateItems && (ctrlKey || !target.isLoaded)) {
277
+ // Espandi il nodo caricando gli items.
278
+ // Solo se calculateItemsForNode è definito E (ctrl è premuto O non è già caricato).
279
+ // Se ctrl è premuto, passa un nodo con isLoaded resettato per forzare il refresh.
280
+ const nodeForCalculation = ctrlKey ? { ...target, isLoaded: false } : target;
281
+ const newItems = await calculateItems(nodeForCalculation);
282
+ updatedNode = { ...target, expanded: true, items: newItems, isLoaded: true };
283
+ onNodeUpdateRef.current?.(updatedNode);
284
+ }
285
+ else {
286
+ // Altrimenti usa semplicemente gli items esistenti
287
+ updatedNode = { ...target, expanded: true };
288
+ }
289
+ // Rimpiazzo sull'albero riletto dopo l'await: non sovrascrive i toggle fatti durante la fetch
290
+ let replaced = false;
291
+ const replaceNode = (nodes) => nodes.map(node => {
292
+ if (!replaced && node.key === key) {
293
+ replaced = true;
294
+ return updatedNode;
295
+ }
296
+ if (node.items)
297
+ return { ...node, items: replaceNode(node.items) };
298
+ return node;
262
299
  });
263
- };
300
+ onDataChangedRef.current?.(replaceNode(dataSourceRef.current));
301
+ }, [findNodeByKey]);
264
302
  // Ref per distinguere click singolo/doppio sulla riga (esempio TMDcmtIcon)
265
303
  const clickTimeoutRef = useRef(null);
266
304
  const lastClickedNodeKeyRef = useRef(undefined);
@@ -271,7 +309,8 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
271
309
  return;
272
310
  }
273
311
  // Se shouldDelayFocusOnEvent non è fornita, il comportamento predefinito è il focus immediato (false)
274
- const delayFocus = shouldDelayFocusOnEvent ? shouldDelayFocusOnEvent(node, e) : false;
312
+ const shouldDelay = shouldDelayFocusOnEventRef.current;
313
+ const delayFocus = shouldDelay ? shouldDelay(node, e) : false;
275
314
  // Reset del timer se il click è su un nodo diverso dal precedente
276
315
  if (lastClickedNodeKeyRef.current && lastClickedNodeKeyRef.current !== node.key) {
277
316
  if (clickTimeoutRef.current) {
@@ -287,7 +326,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
287
326
  // Primo click: imposta il timer per il focus
288
327
  lastClickedNodeKeyRef.current = node.key;
289
328
  clickTimeoutRef.current = setTimeout(() => {
290
- onFocusedItemChanged?.(node);
329
+ onFocusedItemChangedRef.current?.(node);
291
330
  clickTimeoutRef.current = null;
292
331
  lastClickedNodeKeyRef.current = undefined;
293
332
  }, 200);
@@ -302,12 +341,14 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
302
341
  clickTimeoutRef.current = null;
303
342
  lastClickedNodeKeyRef.current = undefined;
304
343
  }
305
- onFocusedItemChanged?.(node); // Chiama onFocusedItemChanged immediatamente
344
+ onFocusedItemChangedRef.current?.(node); // Chiama onFocusedItemChanged immediatamente
306
345
  }
307
- }, [onFocusedItemChanged, calculateItemsForNode, onNodeUpdate]);
346
+ }, []);
308
347
  const handleCheckboxChange = useCallback((node, checked) => {
309
- // Usa la ref per accedere sempre al valore più recente di selectedItems
348
+ // Usa le ref per accedere sempre ai valori più recenti
310
349
  const currentSelectedItems = selectedItemsRef.current;
350
+ const currentDataSource = dataSourceRef.current;
351
+ const autoSelect = autoSelectChildrenRef.current;
311
352
  // Funzione helper per trovare il parent di un nodo e verificare se tutti i suoi figli sono selezionati
312
353
  const findAndCheckParents = (items, targetNode, currentSelection) => {
313
354
  const parentsToAdd = [];
@@ -341,7 +382,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
341
382
  };
342
383
  let newSelectedItems;
343
384
  if (checked) {
344
- if (node.isContainer && autoSelectChildren) {
385
+ if (node.isContainer && autoSelect) {
345
386
  // Quando selezioni un container, aggiungi il container stesso + tutti i figli (se autoSelectChildren è true)
346
387
  const allChildren = flattenTree(node.items || []);
347
388
  // Rimuovi eventuali duplicati: filtra gli elementi già presenti nella selezione
@@ -353,8 +394,8 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
353
394
  // Quando selezioni un figlio o un container con autoSelectChildren=false, aggiungi solo il nodo
354
395
  newSelectedItems = [...currentSelectedItems, node];
355
396
  // Verifica se selezionando questo figlio sono ora selezionati tutti i figli del parent (solo se autoSelectChildren è true)
356
- if (autoSelectChildren) {
357
- const parentsToAdd = findAndCheckParents(dataSource, node, newSelectedItems);
397
+ if (autoSelect) {
398
+ const parentsToAdd = findAndCheckParents(currentDataSource, node, newSelectedItems);
358
399
  newSelectedItems = [...newSelectedItems, ...parentsToAdd];
359
400
  }
360
401
  }
@@ -362,7 +403,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
362
403
  newSelectedItems = currentSelectedItems;
363
404
  }
364
405
  }
365
- else if (node.isContainer && autoSelectChildren) {
406
+ else if (node.isContainer && autoSelect) {
366
407
  // Quando deselezioni un container, rimuovi il container stesso + tutti i figli (solo se autoSelectChildren è true)
367
408
  const childKeys = flattenTree(node.items || []).map(item => item.key);
368
409
  newSelectedItems = currentSelectedItems.filter(item => item.key !== node.key && !childKeys.includes(item.key));
@@ -371,7 +412,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
371
412
  // Quando deselezioni un figlio o un container con autoSelectChildren=false, rimuovi solo il nodo
372
413
  newSelectedItems = currentSelectedItems.filter(item => item.key !== node.key);
373
414
  // Se il figlio apparteneva a un parent che era selezionato, rimuovi anche il parent (solo se autoSelectChildren è true)
374
- if (autoSelectChildren && !node.isContainer) {
415
+ if (autoSelect && !node.isContainer) {
375
416
  const removeParentContainers = (items) => {
376
417
  const parentsToRemove = [];
377
418
  items.forEach(item => {
@@ -386,26 +427,26 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
386
427
  });
387
428
  return parentsToRemove;
388
429
  };
389
- const parentsToRemove = removeParentContainers(dataSource);
430
+ const parentsToRemove = removeParentContainers(currentDataSource);
390
431
  newSelectedItems = newSelectedItems.filter(item => !parentsToRemove.includes(item.key));
391
432
  }
392
433
  }
393
- onSelectionChanged?.(newSelectedItems);
394
- }, [autoSelectChildren, dataSource, onSelectionChanged]);
434
+ onSelectionChangedRef.current?.(newSelectedItems);
435
+ }, [flattenTree]);
395
436
  // Aggiorna la ref con l'ultima versione di handleCheckboxChange
396
437
  handleCheckboxChangeRef.current = handleCheckboxChange;
397
- const hasPartialChildSelection = (node) => {
438
+ const hasPartialChildSelection = useCallback((node) => {
398
439
  // Lo stato indeterminate ha senso solo quando autoSelectChildren è true
399
- if (!autoSelectChildren)
440
+ if (!autoSelectChildrenRef.current)
400
441
  return false;
401
442
  if (!node.isContainer || !node.items)
402
443
  return false;
403
444
  const childKeys = flattenTree(node.items).map(item => item.key);
404
- const selectedChildKeys = selectedItems.map(item => item.key);
445
+ const selectedChildKeys = selectedItemsRef.current.map(item => item.key);
405
446
  const selectedCount = childKeys.filter(key => selectedChildKeys.includes(key)).length;
406
447
  return selectedCount > 0 && selectedCount < childKeys.length;
407
- };
408
- const hasVisibleItems = (node) => {
448
+ }, [flattenTree]);
449
+ const hasVisibleItems = useCallback((node) => {
409
450
  // If node has explicit isExpandible value, use that
410
451
  if (node.isExpandible !== undefined) {
411
452
  return node.isExpandible;
@@ -416,14 +457,14 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
416
457
  if (node.items.length <= 0)
417
458
  return false;
418
459
  return node.items.filter(o => !o.hidden).length > 0;
419
- };
460
+ }, []);
420
461
  // Gestisce il cambio di pagina per un nodo
421
462
  const handlePageChange = useCallback((nodeKey, newPage) => {
422
463
  const updateNodePage = (nodes) => {
423
464
  return nodes.map(node => {
424
465
  if (node.key === nodeKey) {
425
466
  const updatedNode = { ...node, currentPage: newPage };
426
- onNodeUpdate?.(updatedNode);
467
+ onNodeUpdateRef.current?.(updatedNode);
427
468
  return updatedNode;
428
469
  }
429
470
  if (node.items) {
@@ -432,9 +473,9 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
432
473
  return node;
433
474
  });
434
475
  };
435
- const updatedData = updateNodePage(dataSource);
436
- onDataChanged?.(updatedData);
437
- }, [dataSource, onDataChanged, onNodeUpdate]);
476
+ const updatedData = updateNodePage(dataSourceRef.current);
477
+ onDataChangedRef.current?.(updatedData);
478
+ }, []);
438
479
  // Verifica se c'è bisogno del paginatore
439
480
  const needsPagination = useCallback((node) => {
440
481
  if (!showLoadMoreButton || !node.items)
@@ -474,7 +515,7 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
474
515
  onItemContextMenu(node, e);
475
516
  }
476
517
  }, 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)));
477
- }, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsPagination, handlePageChange, getTotalPages, onItemContextMenu]);
518
+ }, [handleNodeClick, handleNodeToggle, handleCheckboxChange, hasVisibleItems, hasPartialChildSelection, itemRender, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsPagination, handlePageChange, getTotalPages, onItemContextMenu]);
478
519
  // Calcola selectedItemKeys ad ogni render per garantire sincronizzazione con selectedItems
479
520
  const selectedItemKeys = new Set(selectedItems.map(s => s.key));
480
521
  // Memoizza rowPropsData per evitare re-render della List
@@ -3,11 +3,12 @@ import { useEffect, useState } from 'react';
3
3
  import { AccessLevelsEx, DcmtTypeListCacheService, SDK_Globals, SDK_Localizator } from '@topconsultnpm/sdk-ts';
4
4
  import TMSpinner from '../base/TMSpinner';
5
5
  import { IconSearch, SDKUI_Localizator } from '../../helper';
6
+ import { FontSize } from '../../utils/theme';
6
7
  import { StyledDivHorizontal } from '../base/Styled';
7
8
  import TMTidViewer, { TMDcmtTypeIcon } from '../viewers/TMTidViewer';
8
9
  import TMSummary from '../editors/TMSummary';
9
10
  import TMChooserForm from '../forms/TMChooserForm';
10
- const TMDcmtTypeChooser = ({ tmSession, dataSource, disabled, backgroundColor, filter, accessFilter = 'all', showEditButton = true, borderRadius = '4px', buttons = [], placeHolder = `<${SDKUI_Localizator.NoneSelection}>`, openEditorOnSummaryClick, showBorder = true, showId = false, elementStyle, allowMultipleSelection, ShowOnlyDcmtTypes, ShowOnlySAP, filterTemplateTID, values, isModifiedWhen, label, width, height, showClearButton = false, validationItems = [], onValueChanged, updateIsModalOpen }) => {
11
+ const TMDcmtTypeChooser = ({ tmSession, dataSource, disabled, backgroundColor, icon, filter, accessFilter = 'all', showEditButton = true, borderRadius = '4px', fontSize = FontSize.defaultFontSize, buttons = [], placeHolder = `<${SDKUI_Localizator.NoneSelection}>`, openEditorOnSummaryClick, showBorder = true, showId = false, elementStyle, allowMultipleSelection, ShowOnlyDcmtTypes, ShowOnlySAP, filterTemplateTID, values, isModifiedWhen, label, width, height, showClearButton = false, validationItems = [], onValueChanged, updateIsModalOpen }) => {
11
12
  const [showChooser, setShowChooser] = useState(false);
12
13
  useEffect(() => {
13
14
  TMSpinner.show({ description: `${SDKUI_Localizator.Loading} - ${SDK_Localizator.ListDcmtTypeOrView} ...` });
@@ -15,9 +16,9 @@ const TMDcmtTypeChooser = ({ tmSession, dataSource, disabled, backgroundColor, f
15
16
  DcmtTypeListCacheService.GetFromTIDsAsync(values, false, tms).then(() => { TMSpinner.hide(); });
16
17
  }, [values]);
17
18
  const renderTemplate = () => {
18
- return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && _jsx(TMTidViewer, { tmSession: tmSession, tid: values[0], showIcon: true, showId: showId, noneSelectionText: placeHolder }), values && values.length > 1 && _jsx("p", { style: { marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` })] }));
19
+ return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && _jsx(TMTidViewer, { tmSession: tmSession, tid: values[0], color: 'inherit', showIcon: true, showId: showId, noneSelectionText: placeHolder }), values && values.length > 1 && _jsx("p", { style: { margin: 0, marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` })] }));
19
20
  };
20
- return (_jsxs(_Fragment, { children: [_jsx(TMSummary, { backgroundColor: backgroundColor, buttons: buttons, showBorder: showBorder, borderRadius: borderRadius, hasValue: values && values.length > 0, showClearButton: showClearButton, showEditButton: showEditButton, iconEditButton: _jsx(IconSearch, { fontSize: 16 }), onEditorClick: () => {
21
+ return (_jsxs(_Fragment, { children: [_jsx(TMSummary, { backgroundColor: backgroundColor, icon: icon, disabled: disabled, fontSize: fontSize, buttons: buttons, showBorder: showBorder, borderRadius: borderRadius, hasValue: values && values.length > 0, showClearButton: showClearButton, showEditButton: showEditButton, iconEditButton: _jsx(IconSearch, { fontSize: 16 }), onEditorClick: () => {
21
22
  if (!disabled) {
22
23
  setShowChooser(true);
23
24
  updateIsModalOpen?.(true);
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { LayoutModes } from '@topconsultnpm/sdk-ts';
3
+ import { TMDistinctValuesEventArgs } from '../../hooks/useTMDistinctValuesSelection';
3
4
  interface ITMDistinctValues {
4
5
  tid: number | undefined;
5
6
  mid: number | undefined;
@@ -8,14 +9,15 @@ interface ITMDistinctValues {
8
9
  allowAppendMode?: boolean;
9
10
  showHeader?: boolean;
10
11
  isModal?: boolean;
11
- onSelectionChanged?: (e: DistinctValuesEventArgs) => void;
12
+ onSelectionChanged?: (e: TMDistinctValuesEventArgs) => void;
12
13
  onClosePanelCallback?: () => void;
13
14
  }
14
- type DistinctValuesEventArgs = {
15
- tid: number | undefined;
16
- mid: number | undefined;
17
- newValue: string | undefined;
18
- isAppendMode: boolean;
19
- };
15
+ /**
16
+ * Pannello da cui si preleva il valore di un campo del form scegliendolo fra quelli già archiviati.
17
+ *
18
+ * Le due sorgenti (valori distinti del metadato e ricerca rapida su una ricerca salvata) stanno in due hook
19
+ * dedicati che espongono la stessa interfaccia (righe, colonne, conteggi): qui restano la composizione,
20
+ * la scelta della sorgente da mostrare e il render.
21
+ */
20
22
  declare const TMDistinctValues: React.FC<ITMDistinctValues>;
21
23
  export default TMDistinctValues;