@topconsultnpm/sdkui-react 6.22.0-dev3.4 → 6.22.0-dev3.6

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.
@@ -90,12 +90,19 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
90
90
  setIsCheckingFirstLoad(false);
91
91
  handleBack();
92
92
  }, [handleBack]);
93
+ // Avanzamento del calcolo correlazioni, mostrato nell'overlay di primo caricamento
94
+ const [relationsProgress, setRelationsProgress] = useState({ value: 0, max: 0 });
95
+ const handleRelationsProgress = useCallback((value, max) => {
96
+ setRelationsProgress({ value, max });
97
+ }, []);
93
98
  // Notifica all'utente che i dati mostrati sono parziali (non quando si sta uscendo)
94
- const handleRelationsCalculationStopped = useCallback(() => {
99
+ const handleRelationsCalculationStopped = useCallback((loadedCount, totalCount) => {
95
100
  if (isLeavingRef.current)
96
101
  return;
102
+ // Con piu' documenti in input, indica quanti sono stati completati (es. "3/10")
103
+ const progress = totalCount > 1 ? ` (${loadedCount}/${totalCount})` : '';
97
104
  ShowAlert({
98
- message: SDKUI_Localizator.RelationsCalculationStopped,
105
+ message: `${SDKUI_Localizator.RelationsCalculationStopped}${progress}`,
99
106
  title: SDKUI_Localizator.Attention,
100
107
  duration: 4000,
101
108
  mode: 'info',
@@ -379,7 +386,7 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
379
386
  setContextMenuVisible(true);
380
387
  }, children: [_jsx(TMRelationViewerWrapper, { refreshKey: refreshKey, inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, showZeroDcmts: showZeroDcmts,
381
388
  // customItemRender={customItemRender}
382
- allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged, onNoRelationsFound: handleNoRelationsFound, onItemContextMenu: isRelationViewerLoading ? undefined : onItemContextMenu, focusedItemFormData: focusedItemFormData, onLoadingStateChanged: setIsRelationViewerLoading, onStopCalculationReady: handleStopCalculationReady, onCalculationStopped: handleRelationsCalculationStopped }), _jsx(TMContextMenu, { items: operationItems, externalControl: {
389
+ allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged, onNoRelationsFound: handleNoRelationsFound, onItemContextMenu: isRelationViewerLoading ? undefined : onItemContextMenu, focusedItemFormData: focusedItemFormData, onLoadingStateChanged: setIsRelationViewerLoading, onLoadingProgress: handleRelationsProgress, onStopCalculationReady: handleStopCalculationReady, onCalculationStopped: handleRelationsCalculationStopped }), _jsx(TMContextMenu, { items: operationItems, externalControl: {
383
390
  visible: contextMenuVisible,
384
391
  position: contextMenuPosition,
385
392
  onClose: () => setContextMenuVisible(false)
@@ -463,7 +470,9 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
463
470
  toolbarOptions: { icon: _jsx(IconSearchCheck, { fontSize: 24 }), visible: false, orderNumber: 2, isActive: allInitialPanelVisibility['tmFormOrResult'] }
464
471
  }
465
472
  ], [tmTreeView, tmFormOrResult, focusedItem?.isDcmt, dtdMaster]);
466
- return (_jsxs("div", { style: { width: '100%', height: '100%', position: 'relative' }, children: [isCheckingFirstLoad && (_jsx(TMLoadingOverlay, { onCancel: handleCancelFirstLoad, onStop: handleStopRelationsCalculation })), _jsxs("div", { style: isCheckingFirstLoad ? { position: 'absolute', width: 0, height: 0, overflow: 'hidden', opacity: 0, pointerEvents: 'none' } : { width: '100%', height: '100%' }, children: [_jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }) }), renderDcmtOperations, renderFloatingBar] })] }));
473
+ return (_jsxs("div", { style: { width: '100%', height: '100%', position: 'relative' }, children: [isCheckingFirstLoad && (_jsx(TMLoadingOverlay, { onCancel: handleCancelFirstLoad, onStop: handleStopRelationsCalculation, description: relationsProgress.max > 1
474
+ ? `${isForMaster ? SDKUI_Localizator.LoadingMasterDocuments : SDKUI_Localizator.LoadingDetailDocuments} (${relationsProgress.value}/${relationsProgress.max})`
475
+ : undefined, progressValue: relationsProgress.value, progressMax: relationsProgress.max })), _jsxs("div", { style: isCheckingFirstLoad ? { position: 'absolute', width: 0, height: 0, overflow: 'hidden', opacity: 0, pointerEvents: 'none' } : { width: '100%', height: '100%' }, children: [_jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, showWaitPanelSecondary: showSecondary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, waitPanelTextSecondary: waitPanelTextSecondary, waitPanelValueSecondary: waitPanelValueSecondary, waitPanelMaxValueSecondary: waitPanelMaxValueSecondary, isCancelable: true, abortController: abortController, children: _jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }) }), renderDcmtOperations, renderFloatingBar] })] }));
467
476
  };
468
477
  export default TMMasterDetailDcmts;
469
478
  /**
@@ -472,7 +481,7 @@ export default TMMasterDetailDcmts;
472
481
  * - Panel visibility toggling
473
482
  * - Focus delay handling
474
483
  */
475
- const TMRelationViewerWrapper = ({ refreshKey, inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, customItemRender, allowMultipleSelection, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onNoRelationsFound, onItemContextMenu, focusedItemFormData, onLoadingStateChanged, onStopCalculationReady, onCalculationStopped }) => {
484
+ const TMRelationViewerWrapper = ({ refreshKey, inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, customItemRender, allowMultipleSelection, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onNoRelationsFound, onItemContextMenu, focusedItemFormData, onLoadingStateChanged, onLoadingProgress, onStopCalculationReady, onCalculationStopped }) => {
476
485
  const { setPanelVisibilityById, setToolbarButtonVisibility } = useTMPanelManagerContext();
477
486
  // Monitor device type changes to restore panel visibility when switching from mobile to desktop
478
487
  const deviceType = useDeviceType();
@@ -532,7 +541,7 @@ const TMRelationViewerWrapper = ({ refreshKey, inputDcmts, isForMaster, showCurr
532
541
  onItemContextMenu?.(item, e);
533
542
  }, 100);
534
543
  }, [onItemContextMenu, handleFocusedItemChanged]);
535
- return (_jsx(TMRelationViewer, { inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, initialShowZeroDcmts: showZeroDcmts, customItemRender: customItemRender, allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: onSelectedItemsChanged, maxDepthLevel: 1, invertMasterNavigation: false, showExpandAllButton: true, onNoRelationsFound: onNoRelationsFound, onItemContextMenu: onContextMenu, focusedItemFormData: focusedItemFormData, onLoadingStateChanged: onLoadingStateChanged, onStopCalculationReady: onStopCalculationReady, onCalculationStopped: onCalculationStopped }, refreshKey));
544
+ return (_jsx(TMRelationViewer, { inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, initialShowZeroDcmts: showZeroDcmts, customItemRender: customItemRender, allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: onSelectedItemsChanged, maxDepthLevel: 1, invertMasterNavigation: false, showExpandAllButton: true, onNoRelationsFound: onNoRelationsFound, onItemContextMenu: onContextMenu, focusedItemFormData: focusedItemFormData, onLoadingStateChanged: onLoadingStateChanged, onLoadingProgress: onLoadingProgress, onStopCalculationReady: onStopCalculationReady, onCalculationStopped: onCalculationStopped }, refreshKey));
536
545
  };
537
546
  const TMFormOrResultWrapper = ({ refreshKey, deviceType, focusedItem, onTaskCreateRequest, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, onRefreshAfterAddDcmtToFavs, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onRefreshSearchAsyncDatagrid, onRefreshSearchResults, handleNavigateToReference, fetchRemoteCertificates }) => {
538
547
  const { setPanelVisibilityById } = useTMPanelManagerContext();
@@ -542,7 +551,11 @@ const TMFormOrResultWrapper = ({ refreshKey, deviceType, focusedItem, onTaskCrea
542
551
  }, fetchRemoteCertificates: fetchRemoteCertificates }, refreshKey) :
543
552
  focusedItem?.searchResult === undefined ? (_jsx(TMPanel, { title: SDKUI_Localizator.SearchResult, children: _jsx(TMToppyMessage, { message: SDKUI_Localizator.SelectDocumentToViewSearchResults }) })) : (_jsx(TMSearchResult, { groupId: 'tmFormOrResult', isClosable: deviceType !== DeviceType.MOBILE, context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, allowRelations: false, openDcmtFormAsModal: true, searchResults: focusedItem?.searchResult ?? [], showSearchResultSidebar: false, showDcmtFormSidebar: false, autoFocusFirstRow: false, onTaskCreateRequest: onTaskCreateRequest, onClose: () => { setPanelVisibilityById('tmTreeView', true); }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, enablePinIcons: false, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, showBackButton: false, onRefreshSearchAsyncDatagrid: onRefreshSearchResults, onReferenceClick: handleNavigateToReference, fetchRemoteCertificates: fetchRemoteCertificates }, refreshKey)) }));
544
553
  };
545
- const TMLoadingOverlay = ({ onCancel, onStop, description, cancelText, stopText }) => {
554
+ const TMLoadingOverlay = ({ onCancel, onStop, description, cancelText, stopText, progressValue, progressMax }) => {
555
+ // Stesso calcolo di TMWaitPanel: 0 quando il massimo non è ancora noto
556
+ const progressPercent = (progressMax ?? 0) > 0
557
+ ? Math.min(100, ((progressValue ?? 0) / (progressMax ?? 1)) * 100)
558
+ : 0;
546
559
  return (_jsx("div", { style: {
547
560
  position: 'absolute',
548
561
  top: 0,
@@ -612,7 +625,7 @@ const TMLoadingOverlay = ({ onCancel, onStop, description, cancelText, stopText
612
625
  .tm-spinner-animation div:nth-child(7):after { top: 63px; left: 17px; background: #782b7d; }
613
626
  .tm-spinner-animation div:nth-child(8) { animation-delay: -0.288s; }
614
627
  .tm-spinner-animation div:nth-child(8):after { top: 56px; left: 12px; background: #782b7d; }
615
- ` }), _jsxs("div", { className: "tm-spinner-animation", children: [_jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {})] })] }), _jsx("span", { style: { fontSize: '14px', color: '#334155', textAlign: 'center' }, children: description ?? SDKUI_Localizator.Loading }), (onStop || onCancel) && (_jsxs("div", { style: { marginTop: '4px', display: 'flex', alignItems: 'center', justifyContent: 'center', flexWrap: 'wrap', gap: '10px' }, children: [onStop && (_jsx("button", { onClick: onStop, title: SDKUI_Localizator.StopRelationsCalculation, style: {
628
+ ` }), _jsxs("div", { className: "tm-spinner-animation", children: [_jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {}), _jsx("div", {})] })] }), _jsx("span", { style: { fontSize: '14px', color: '#334155', textAlign: 'center' }, children: description ?? SDKUI_Localizator.Loading }), (progressMax ?? 0) > 1 && (_jsxs("div", { style: { width: '260px' }, children: [_jsx("div", { style: { width: '100%', height: '20px', background: '#e0e0e0', borderRadius: '10px', overflow: 'hidden' }, children: _jsx("div", { style: { width: `${progressPercent.toFixed(2)}%`, height: '100%', background: '#4caf50', transition: 'width 0.3s ease' } }) }), _jsxs("p", { style: { fontWeight: 'bold', color: '#333', margin: '8px 0 0', textAlign: 'center' }, children: [progressPercent.toFixed(2), "%"] })] })), (onStop || onCancel) && (_jsxs("div", { style: { marginTop: '4px', display: 'flex', alignItems: 'center', justifyContent: 'center', flexWrap: 'wrap', gap: '10px' }, children: [onStop && (_jsx("button", { onClick: onStop, title: SDKUI_Localizator.StopRelationsCalculation, style: {
616
629
  padding: '8px 24px',
617
630
  fontSize: '13px',
618
631
  fontWeight: 500,
@@ -132,6 +132,11 @@ export interface TMRelationViewerProps {
132
132
  * Useful to disable interactions (like context menu) during loading.
133
133
  */
134
134
  onLoadingStateChanged?: (isLoading: boolean) => void;
135
+ /**
136
+ * Invoked while the initial correlations load progresses, with how many input
137
+ * documents have been processed out of the total.
138
+ */
139
+ onLoadingProgress?: (value: number, max: number) => void;
135
140
  /**
136
141
  * Invoked on mount to hand over a function that stops the ongoing correlations
137
142
  * calculation: no further GetMetadata calls are performed and only the
@@ -143,8 +148,9 @@ export interface TMRelationViewerProps {
143
148
  /**
144
149
  * Callback invoked when the calculation has actually been stopped
145
150
  * (loadData terminated after an abort request).
151
+ * Riceve quanti documenti di input sono stati completati sul totale.
146
152
  */
147
- onCalculationStopped?: () => void;
153
+ onCalculationStopped?: (loadedCount: number, totalCount: number) => void;
148
154
  }
149
155
  /**
150
156
  * Check if document type has detail relations
@@ -160,8 +166,10 @@ export declare const hasMasterRelations: (dTID: number | undefined) => Promise<b
160
166
  export declare const getDisplayValueByColumn: (col: DataColumnDescriptor | undefined, value: any) => any;
161
167
  /**
162
168
  * Convert SearchResultDescriptor to structured data source with metadata
163
- * For each document, fetches complete metadata using GetMetadataAsync to ensure
164
- * all metadata properties (isSpecialSearchOutput, permissions, etc.) are available
169
+ * I valori dei documenti sono GIÀ presenti nelle righe restituite dalla ricerca:
170
+ * qui vengono solo abbinati ai rispettivi MetadataDescriptor (perm,
171
+ * isSpecialSearchOutput, ...), risolti UNA SOLA VOLTA per tipo documento.
172
+ * Nessuna chiamata al server per riga.
165
173
  */
166
174
  export declare const searchResultToDataSource: (searchResult: SearchResultDescriptor | undefined, hideSysMetadata?: boolean, signal?: AbortSignal) => Promise<any[]>;
167
175
  export declare const DEFAULT_RELATION_EXPAND_LEVEL = 4;
@@ -67,8 +67,10 @@ export const getDisplayValueByColumn = (col, value) => {
67
67
  };
68
68
  /**
69
69
  * Convert SearchResultDescriptor to structured data source with metadata
70
- * For each document, fetches complete metadata using GetMetadataAsync to ensure
71
- * all metadata properties (isSpecialSearchOutput, permissions, etc.) are available
70
+ * I valori dei documenti sono GIÀ presenti nelle righe restituite dalla ricerca:
71
+ * qui vengono solo abbinati ai rispettivi MetadataDescriptor (perm,
72
+ * isSpecialSearchOutput, ...), risolti UNA SOLA VOLTA per tipo documento.
73
+ * Nessuna chiamata al server per riga.
72
74
  */
73
75
  export const searchResultToDataSource = async (searchResult, hideSysMetadata, signal) => {
74
76
  const rows = searchResult?.dtdResult?.rows ?? [];
@@ -77,27 +79,28 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata, si
77
79
  const columns = searchResult?.dtdResult?.columns ?? [];
78
80
  const tidColIndex = columns.findIndex(col => col.caption?.toUpperCase() === 'TID');
79
81
  const didColIndex = columns.findIndex(col => col.caption?.toUpperCase() === 'DID');
82
+ const firstRow = rows[0] ?? [];
83
+ const tid = tidColIndex >= 0 && firstRow.length > 0 ? Number(firstRow[tidColIndex]) : searchResult?.fromTID;
84
+ const firstDid = didColIndex >= 0 && firstRow.length > 0 ? Number(firstRow[didColIndex]) : undefined;
85
+ const dtdWithMetadata = await DcmtTypeListCacheService.GetWithNotGrantedAsync(tid, firstDid, searchResult);
86
+ const mdList = dtdWithMetadata?.metadata ?? [];
87
+ // Posizione di ogni MID nelle colonne del risultato: identica per tutte le righe,
88
+ // quindi calcolata una volta sola invece di una find() per metadato per riga.
89
+ const mids = columns.map(col => Number(col.extendedProperties?.["MID"] ?? "0"));
90
+ const columnByMid = new Map();
91
+ columns.forEach((col, i) => { if (!columnByMid.has(mids[i]))
92
+ columnByMid.set(mids[i], col); });
93
+ const dtdResult = searchResult?.dtdResult;
80
94
  for (let index = 0; index < rows.length; index++) {
81
95
  // Interruzione richiesta dall'utente: restituisce i documenti già elaborati
82
96
  if (signal?.aborted)
83
97
  break;
84
98
  const row = rows[index];
85
- // Extract TID and DID from row
86
- const tid = tidColIndex >= 0 ? Number(row[tidColIndex]) : searchResult?.fromTID;
87
- const did = didColIndex >= 0 ? Number(row[didColIndex]) : undefined;
88
- // Fetch complete metadata for this specific document (like getFilteredMetadata does)
89
- const metadata = await SDK_Globals.tmSession?.NewSearchEngine().GetMetadataAsync(tid, did, true);
90
- if (metadata) {
91
- // Get full DTD with metadata for this document
92
- const dtdResult = metadata.dtdResult;
93
- const metadataRows = dtdResult?.rows?.[0] ?? [];
94
- const mids = metadata.selectMIDs;
95
- const dtdWithMetadata = await DcmtTypeListCacheService.GetWithNotGrantedAsync(tid, did, metadata);
96
- const mdList = dtdWithMetadata?.metadata ?? [];
99
+ const item = { rowIndex: index };
100
+ if (mdList.length > 0) {
97
101
  // Convert to MetadataValueDescriptorEx array
98
- const metadataList = searchResultToMetadataValues(tid, dtdResult, metadataRows, mids, mdList, LayoutModes.Update);
102
+ const metadataList = searchResultToMetadataValues(tid, dtdResult, row, mids, mdList, LayoutModes.Update);
99
103
  // Convert to DcmtMetadataMap format (like getFilteredMetadata does)
100
- const item = { rowIndex: index };
101
104
  for (const mvd of metadataList) {
102
105
  if (hideSysMetadata && mvd.mid !== undefined && mvd.mid < 100)
103
106
  continue;
@@ -106,23 +109,18 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata, si
106
109
  : (mvd.md?.name ?? '');
107
110
  if (key) {
108
111
  // Find the corresponding column by MID to format the value
109
- const column = dtdResult?.columns?.find(c => Number(c.extendedProperties?.["MID"] ?? "0") === mvd.mid);
110
112
  item[key] = {
111
113
  md: mvd.md,
112
- value: getDisplayValueByColumn(column, mvd.value)
114
+ value: getDisplayValueByColumn(columnByMid.get(mvd.mid ?? 0), mvd.value)
113
115
  };
114
116
  }
115
117
  }
116
- output.push(item);
117
118
  }
118
119
  else {
119
- // Fallback: use original row data with basic parsing
120
- const item = { rowIndex: index };
121
- const fallbackTid = searchResult?.fromTID;
122
- const dtd = await DcmtTypeListCacheService.GetWithNotGrantedAsync(fallbackTid, undefined, searchResult);
120
+ // Fallback: il DTD non è risolvibile, usa le colonne grezze del risultato
123
121
  for (let i = 0; i < row.length; i++) {
124
- const column = searchResult?.dtdResult?.columns?.[i];
125
- const mid = Number(column?.extendedProperties?.["MID"] ?? "0");
122
+ const column = columns[i];
123
+ const mid = mids[i];
126
124
  if (hideSysMetadata && mid < 100)
127
125
  continue;
128
126
  let key = column?.caption ?? '';
@@ -134,20 +132,18 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata, si
134
132
  key = `${key}_${mid}`;
135
133
  }
136
134
  }
137
- const value = row[i];
138
- const md = dtd?.metadata?.find(o => o.id == mid);
139
135
  item[key] = {
140
- md: md,
141
- value: getDisplayValueByColumn(column, value)
136
+ md: undefined,
137
+ value: getDisplayValueByColumn(column, row[i])
142
138
  };
143
139
  }
144
- output.push(item);
145
140
  }
141
+ output.push(item);
146
142
  }
147
143
  return output;
148
144
  };
149
145
  export const DEFAULT_RELATION_EXPAND_LEVEL = 4; // Default maximum depth level for expansion (can be adjusted)
150
- const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onAllItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, onNoRelationsFound, onItemContextMenu, focusedItemFormData = [], showExpandAllButton = false, defaultExpandAll = false, onLoadingStateChanged, onStopCalculationReady, onCalculationStopped }) => {
146
+ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onAllItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, onNoRelationsFound, onItemContextMenu, focusedItemFormData = [], showExpandAllButton = false, defaultExpandAll = false, onLoadingStateChanged, onLoadingProgress, onStopCalculationReady, onCalculationStopped }) => {
151
147
  // State
152
148
  const [dcmtTypes, setDcmtTypes] = useState([]);
153
149
  const [treeData, setTreeData] = useState([]);
@@ -196,6 +192,11 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
196
192
  const isLoading = showWaitPanel || showExpansionWaitPanel;
197
193
  onLoadingStateChanged?.(isLoading);
198
194
  }, [showWaitPanel, showExpansionWaitPanel, onLoadingStateChanged]);
195
+ // Notifica al padre l'avanzamento del caricamento iniziale (documenti processati
196
+ // sul totale), così può mostrarlo nel proprio overlay che copre il wait panel interno
197
+ useEffect(() => {
198
+ onLoadingProgress?.(waitPanelValuePrimary, waitPanelMaxValuePrimary);
199
+ }, [waitPanelValuePrimary, waitPanelMaxValuePrimary, onLoadingProgress]);
199
200
  // Mantiene l'AbortController dell'espansione in corso accessibile da callback stabili
200
201
  const expansionAbortControllerRef = React.useRef(undefined);
201
202
  useEffect(() => {
@@ -638,6 +639,11 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
638
639
  }
639
640
  }
640
641
  }
642
+ // Interruzione richiesta dall'utente: il documento corrente non è stato
643
+ // caricato per intero, quindi non viene aggiunto all'albero. Il parziale
644
+ // resta così a granularità di documento (es. 3 completi su 10).
645
+ if (abortController.signal.aborted)
646
+ break;
641
647
  // Aggiungi i master come root, raggruppando per TID e relationId
642
648
  for (const masterContainer of masterDocs) {
643
649
  const existingContainer = tree.find(c => c.tid === masterContainer.tid && c.relationId === masterContainer.relationId && c.isContainer);
@@ -666,6 +672,9 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
666
672
  const relatedDocs = isForMaster
667
673
  ? await getMasterDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel, abortController.signal)
668
674
  : await getDetailDcmtsAsync(dcmt.TID, dcmt.DID, maxDepthLevel, abortController.signal);
675
+ // Interruzione richiesta dall'utente
676
+ if (abortController.signal.aborted)
677
+ break;
669
678
  // Se showMainDocument è false, mostra i container dei dettagli direttamente sotto il container principale
670
679
  if (!showMainDocument) {
671
680
  // Check if a container for this TID already exists in the tree
@@ -817,7 +826,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
817
826
  const wasStopped = abortController.signal.aborted;
818
827
  if (wasStopped) {
819
828
  setLoadStoppedByUser(true);
820
- onCalculationStopped?.();
829
+ onCalculationStopped?.(processedCount, inputDcmts.length);
821
830
  }
822
831
  // If no relations found, notify parent
823
832
  if (!wasStopped && hasNoRelations && onNoRelationsFound) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.22.0-dev3.4",
3
+ "version": "6.22.0-dev3.6",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",