@topconsultnpm/sdkui-react 6.22.0-dev2.2 → 6.22.0-dev2.20
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.
- package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +1 -1
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +1 -1
- package/lib/components/base/TMButton.d.ts +13 -0
- package/lib/components/base/TMButton.js +137 -5
- package/lib/components/base/TMDataGrid.d.ts +2 -0
- package/lib/components/base/TMDataGrid.js +68 -4
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMModal.d.ts +4 -0
- package/lib/components/base/TMModal.js +42 -11
- package/lib/components/base/TMPanel.d.ts +1 -0
- package/lib/components/base/TMPanel.js +79 -20
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +23 -6
- package/lib/components/base/TMTreeView.js +108 -67
- package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
- package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
- package/lib/components/choosers/TMDistinctValues.js +149 -142
- package/lib/components/choosers/TMMetadataChooser.js +1 -1
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
- package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
- package/lib/components/editors/TMMetadataEditor.js +8 -3
- package/lib/components/editors/TMTextBox.js +15 -15
- package/lib/components/features/documents/TMBatchUpdateForm.js +19 -5
- package/lib/components/features/documents/TMDcmtForm.d.ts +7 -0
- package/lib/components/features/documents/TMDcmtForm.js +104 -42
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
- package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
- package/lib/components/features/documents/TMMasterDetailDcmts.js +95 -33
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +19 -0
- package/lib/components/features/documents/TMMasterInfoFields.js +172 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +40 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +256 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +352 -0
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +221 -0
- package/lib/components/features/documents/TMRelationViewer.d.ts +14 -1
- package/lib/components/features/documents/TMRelationViewer.js +69 -20
- package/lib/components/features/search/TMSearch.js +29 -16
- package/lib/components/features/search/TMSearchQueryEditor.js +5 -3
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -1
- package/lib/components/features/search/TMSearchQueryPanel.js +28 -7
- package/lib/components/features/search/TMSearchResult.d.ts +9 -0
- package/lib/components/features/search/TMSearchResult.js +323 -92
- package/lib/components/features/search/TMTreeSelector.js +18 -5
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
- package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -0
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +24 -14
- package/lib/components/layout/panelManager/TMPanelWrapper.js +2 -2
- package/lib/components/layout/panelManager/types.d.ts +3 -0
- package/lib/components/viewers/TMMidViewer.js +4 -1
- package/lib/components/viewers/TMTidViewer.js +25 -11
- package/lib/helper/SDKUI_Globals.d.ts +55 -0
- package/lib/helper/SDKUI_Globals.js +82 -0
- package/lib/helper/SDKUI_Localizator.d.ts +23 -0
- package/lib/helper/SDKUI_Localizator.js +230 -0
- package/lib/helper/TMIcons.d.ts +1 -0
- package/lib/helper/TMIcons.js +3 -0
- package/lib/helper/dataGridSearchHelper.d.ts +28 -0
- package/lib/helper/dataGridSearchHelper.js +51 -0
- package/lib/helper/dcmtsHelper.d.ts +20 -0
- package/lib/helper/dcmtsHelper.js +58 -1
- package/lib/helper/helpers.d.ts +20 -0
- package/lib/helper/helpers.js +40 -0
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/helper/queryHelper.d.ts +2 -0
- package/lib/helper/queryHelper.js +3 -1
- package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
- package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
- package/lib/hooks/useArchiveListForm.d.ts +39 -0
- package/lib/hooks/useArchiveListForm.js +46 -0
- package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
- package/lib/hooks/useCaseFlowApprove.js +157 -0
- package/lib/hooks/useDataUserIdItem.d.ts +1 -0
- package/lib/hooks/useDataUserIdItem.js +1 -0
- package/lib/hooks/useDocumentOperations.d.ts +2 -0
- package/lib/hooks/useDocumentOperations.js +28 -5
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +97 -0
- package/lib/hooks/useMultiMasterDetailDcmts.js +555 -0
- package/lib/hooks/useRelatedDocuments.js +2 -26
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/services/caseflow/CaseFlowService.d.ts +236 -0
- package/lib/services/caseflow/CaseFlowService.js +693 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
- package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
- package/lib/services/caseflow/caseFlowNameCache.js +116 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
- package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/index.js +4 -0
- package/lib/services/platform_services.d.ts +1 -1
- 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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
59
|
-
|
|
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
|
|
227
|
-
const
|
|
228
|
-
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
344
|
+
onFocusedItemChangedRef.current?.(node); // Chiama onFocusedItemChanged immediatamente
|
|
306
345
|
}
|
|
307
|
-
}, [
|
|
346
|
+
}, []);
|
|
308
347
|
const handleCheckboxChange = useCallback((node, checked) => {
|
|
309
|
-
// Usa
|
|
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 &&
|
|
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 (
|
|
357
|
-
const parentsToAdd = findAndCheckParents(
|
|
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 &&
|
|
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 (
|
|
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(
|
|
430
|
+
const parentsToRemove = removeParentContainers(currentDataSource);
|
|
390
431
|
newSelectedItems = newSelectedItems.filter(item => !parentsToRemove.includes(item.key));
|
|
391
432
|
}
|
|
392
433
|
}
|
|
393
|
-
|
|
394
|
-
}, [
|
|
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 (!
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
436
|
-
|
|
437
|
-
}, [
|
|
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:
|
|
12
|
+
onSelectionChanged?: (e: TMDistinctValuesEventArgs) => void;
|
|
12
13
|
onClosePanelCallback?: () => void;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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;
|