@topconsultnpm/sdkui-react 6.22.0-dev3.8 → 6.22.0-dev4.10
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/styles.d.ts +43 -45
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +60 -67
- package/lib/components/base/Styled.d.ts +77 -93
- package/lib/components/base/TMAlert.js +6 -8
- package/lib/components/base/TMAreaManager.js +53 -55
- package/lib/components/base/TMButton.js +4 -2
- package/lib/components/base/TMCounterBar.d.ts +2 -2
- package/lib/components/base/TMCounterContainer.d.ts +4 -3
- package/lib/components/base/TMCounterContainer.js +16 -1
- package/lib/components/base/TMCustomButton.d.ts +1 -1
- package/lib/components/base/TMCustomButton.js +40 -48
- package/lib/components/base/TMDataGrid.js +243 -223
- package/lib/components/base/TMDataGridExportForm.d.ts +1 -2
- package/lib/components/base/TMFileManager.d.ts +1 -2
- package/lib/components/base/TMFileManagerDataGridView.d.ts +1 -2
- package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
- package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
- package/lib/components/base/TMFileManagerUtils.d.ts +6 -4
- package/lib/components/base/TMLayout.d.ts +4 -4
- package/lib/components/base/TMList.d.ts +1 -2
- package/lib/components/base/TMListView.d.ts +1 -1
- package/lib/components/base/TMPanel.js +173 -170
- package/lib/components/base/TMSpinner.d.ts +3 -3
- package/lib/components/base/TMSpinner.js +9 -7
- package/lib/components/base/TMTab.d.ts +3 -4
- package/lib/components/base/TMTabControl.d.ts +7 -0
- package/lib/components/base/TMTabControl.js +225 -213
- package/lib/components/base/TMTooltip.d.ts +1 -1
- package/lib/components/base/TMTreeView.d.ts +8 -14
- package/lib/components/base/TMTreeView.js +20 -0
- package/lib/components/base/TMUserAvatar.d.ts +1 -2
- package/lib/components/base/TMVilViewer.d.ts +1 -2
- package/lib/components/base/TMWaitPanel.d.ts +2 -3
- package/lib/components/base/TMWaitPanel.js +1 -1
- package/lib/components/base/waitPanel/TMWaitPanelConfirm.d.ts +12 -0
- package/lib/components/base/waitPanel/TMWaitPanelConfirm.js +185 -0
- package/lib/components/base/waitPanel/TMWaitPanelManager.d.ts +179 -0
- package/lib/components/base/waitPanel/TMWaitPanelManager.js +373 -0
- package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +57 -0
- package/lib/components/base/waitPanel/TMWaitPanelView.js +346 -0
- package/lib/components/base/waitPanel/index.d.ts +1 -0
- package/lib/components/base/waitPanel/index.js +1 -0
- package/lib/components/choosers/TMDistinctValues.js +3 -3
- package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
- package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +1 -2
- package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +1 -2
- package/lib/components/choosers/TMPathChooser.js +17 -34
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +1 -2
- package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
- package/lib/components/choosers/TMUserChooser.d.ts +2 -2
- package/lib/components/editors/TMEditorStyled.d.ts +42 -20
- package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
- package/lib/components/editors/TMHtmlContentDisplay.d.ts +1 -2
- package/lib/components/editors/TMHtmlEditor.d.ts +1 -2
- package/lib/components/editors/TMTextBox.d.ts +4 -0
- package/lib/components/editors/TMTextBox.js +99 -11
- package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
- package/lib/components/features/archive/TMArchive.js +7 -2
- package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +28 -0
- package/lib/components/features/assistant/TMHelpOnLineChat.js +1231 -0
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
- package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -2
- package/lib/components/features/blog/TMBlogCommentForm.d.ts +1 -2
- package/lib/components/features/documents/TMBatchUpdateForm.js +3 -4
- package/lib/components/features/documents/TMCopyToFolderForm.js +50 -42
- package/lib/components/features/documents/TMDcmtForm.js +50 -61
- package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
- package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -4
- package/lib/components/features/documents/TMDcmtIcon.js +3 -5
- package/lib/components/features/documents/TMDcmtPreview.d.ts +6 -8
- package/lib/components/features/documents/TMDcmtPreview.js +5 -3
- package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -2
- package/lib/components/features/documents/TMDcmtTasks.js +2 -9
- package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
- package/lib/components/features/documents/TMFileUploader.js +5 -5
- package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
- package/lib/components/features/documents/TMMasterDetailDcmts.js +53 -141
- package/lib/components/features/documents/TMMasterInfoFields.d.ts +1 -2
- package/lib/components/features/documents/TMMasterInfoFields.js +3 -2
- package/lib/components/features/documents/TMMergeToPdfForm.d.ts +1 -2
- package/lib/components/features/documents/TMMergeToPdfForm.js +59 -56
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +1 -2
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +14 -15
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +5 -5
- package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +3 -3
- package/lib/components/features/documents/TMRelationViewer.d.ts +13 -14
- package/lib/components/features/documents/TMRelationViewer.js +206 -143
- package/lib/components/features/documents/relationTreeState.d.ts +32 -0
- package/lib/components/features/documents/relationTreeState.js +89 -0
- package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +1 -2
- package/lib/components/features/search/TMMetadataOutputForm.d.ts +1 -2
- package/lib/components/features/search/TMMetadataSorterForm.d.ts +1 -2
- package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
- package/lib/components/features/search/TMSearch.d.ts +1 -2
- package/lib/components/features/search/TMSearch.js +3 -4
- package/lib/components/features/search/TMSearchQueryPanel.d.ts +3 -9
- package/lib/components/features/search/TMSearchQueryPanel.js +0 -4
- package/lib/components/features/search/TMSearchResult.d.ts +5 -0
- package/lib/components/features/search/TMSearchResult.js +129 -102
- package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
- package/lib/components/features/search/TMSignatureInfoContent.d.ts +1 -2
- package/lib/components/features/search/TMTreeSelector.js +23 -27
- package/lib/components/features/search/TMViewHistoryDcmt.d.ts +1 -2
- package/lib/components/features/search/TMViewHistoryDcmt.js +15 -26
- package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
- package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
- package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
- package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
- package/lib/components/features/tasks/TMTasksView.js +97 -90
- package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +2 -3
- package/lib/components/features/wg/TMWGsCopyMoveForm.js +95 -91
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +7 -8
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +1 -3
- package/lib/components/forms/Login/ChangePasswordInputs.d.ts +1 -3
- package/lib/components/forms/Login/Chooser.d.ts +2 -2
- package/lib/components/forms/TMChooserForm.d.ts +1 -2
- package/lib/components/forms/TMResultDialog.js +1 -1
- package/lib/components/forms/TMSaveForm.d.ts +4 -4
- package/lib/components/grids/TMBlogAttachments.d.ts +1 -2
- package/lib/components/grids/TMBlogHeader.d.ts +1 -1
- package/lib/components/grids/TMBlogsPost.d.ts +1 -1
- package/lib/components/grids/TMBlogsPost.js +93 -97
- package/lib/components/grids/TMBlogsPostUtils.d.ts +9 -9
- package/lib/components/grids/TMValidationItemsList.d.ts +1 -2
- package/lib/components/index.d.ts +5 -1
- package/lib/components/index.js +4 -1
- package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +1 -2
- package/lib/components/layout/panelManager/TMPanelManagerContainer.js +4 -3
- package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +3 -2
- package/lib/components/layout/panelManager/TMPanelManagerContext.js +5 -1
- package/lib/components/layout/panelManager/TMPanelManagerLoader.d.ts +5 -0
- package/lib/components/layout/panelManager/TMPanelManagerLoader.js +18 -0
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +6 -5
- package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +4 -8
- package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
- package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.js +2 -1
- package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
- package/lib/components/pages/TMPage.d.ts +1 -1
- package/lib/components/pages/TMPage.js +32 -31
- package/lib/components/query/TMQueryEditor.d.ts +13 -14
- package/lib/components/query/TMQueryEditor.js +2 -1
- package/lib/components/settings/SettingsAppearance.d.ts +1 -2
- package/lib/components/sidebar/TMAboutApp.d.ts +1 -2
- package/lib/components/sidebar/TMCommandsPanel.d.ts +4 -4
- package/lib/components/sidebar/TMHeader.d.ts +4 -3
- package/lib/components/sidebar/TMHeader.js +2 -2
- package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -3
- package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +2 -3
- package/lib/components/viewers/TMMidViewer.d.ts +2 -2
- package/lib/components/viewers/TMTidViewer.d.ts +2 -2
- package/lib/helper/Enum_Localizator.js +1 -0
- package/lib/helper/SDKUI_Globals.d.ts +7 -2
- package/lib/helper/SDKUI_Globals.js +7 -2
- package/lib/helper/SDKUI_Localizator.d.ts +31 -6
- package/lib/helper/SDKUI_Localizator.js +301 -51
- package/lib/helper/TMAppUpdatedModal.d.ts +1 -2
- package/lib/helper/TMAppUpdatedModal.js +93 -93
- package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
- package/lib/helper/TMIcons.d.ts +280 -280
- package/lib/helper/TMPdfViewer.d.ts +1 -2
- package/lib/helper/TMToppyMessage.d.ts +2 -2
- package/lib/helper/TMUtils.d.ts +4 -10
- package/lib/helper/ZipManager.d.ts +1 -1
- package/lib/helper/ZipManager.js +2 -1
- package/lib/helper/dcmtsHelper.d.ts +2 -0
- package/lib/helper/dcmtsHelper.js +3 -1
- package/lib/helper/helpers.d.ts +1 -1
- package/lib/hooks/useCheckInOutOperations.d.ts +0 -6
- package/lib/hooks/useCheckInOutOperations.js +14 -34
- package/lib/hooks/useDcmtOperations.d.ts +3 -12
- package/lib/hooks/useDcmtOperations.js +201 -184
- package/lib/hooks/useDocumentOperations.d.ts +1 -0
- package/lib/hooks/useDocumentOperations.js +14 -25
- package/lib/hooks/useInputDialog.d.ts +1 -2
- package/lib/hooks/useMultiMasterDetailDcmts.d.ts +0 -15
- package/lib/hooks/useMultiMasterDetailDcmts.js +70 -68
- package/lib/hooks/usePreventFileDrop.js +9 -0
- package/lib/hooks/useWorkflowApprove.js +33 -17
- package/lib/services/caseflow/CaseFlowService.d.ts +69 -9
- package/lib/services/caseflow/CaseFlowService.js +126 -58
- package/lib/services/platform_services.d.ts +2 -3
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService, LayoutModes } from "@topconsultnpm/sdk-ts";
|
|
4
4
|
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals, searchResultToMetadataValues, getColumnFormatInfo, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat } from '../../../helper';
|
|
5
5
|
import ShowAlert from '../../base/TMAlert';
|
|
@@ -7,12 +7,13 @@ import TMToppyMessage from '../../../helper/TMToppyMessage';
|
|
|
7
7
|
import { TMColors } from '../../../utils/theme';
|
|
8
8
|
import { StyledDivHorizontal, StyledBadge } from '../../base/Styled';
|
|
9
9
|
import TMTreeView from '../../base/TMTreeView';
|
|
10
|
-
import
|
|
10
|
+
import TMWaitPanelManager from '../../base/waitPanel/TMWaitPanelManager';
|
|
11
11
|
import TMDataListItemViewer from '../../viewers/TMDataListItemViewer';
|
|
12
12
|
import TMDcmtIcon from './TMDcmtIcon';
|
|
13
13
|
import TMDataUserIdItemViewer from '../../viewers/TMDataUserIdItemViewer';
|
|
14
14
|
import TMTooltip from '../../base/TMTooltip';
|
|
15
15
|
import TMSpinner from '../../base/TMSpinner';
|
|
16
|
+
import { applyRelationTreeState, collectRelationTreeState, findRelationNodeByPath } from './relationTreeState';
|
|
16
17
|
/**
|
|
17
18
|
* Check if document type has detail relations
|
|
18
19
|
*/
|
|
@@ -65,12 +66,24 @@ export const getDisplayValueByColumn = (col, value) => {
|
|
|
65
66
|
return formatNumberByMetadataFormat(value, format, formatCulture);
|
|
66
67
|
return value;
|
|
67
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Attende la chiamata, ma smette di aspettarla (restituendo undefined) appena l'utente interrompe.
|
|
71
|
+
* Serve perché il SearchEngine dell'SDK non accetta un AbortSignal: senza, "Interrompi" aspetterebbe la fine della chiamata in corso.
|
|
72
|
+
*/
|
|
73
|
+
const untilAborted = (promise, signal) => {
|
|
74
|
+
if (!signal)
|
|
75
|
+
return promise;
|
|
76
|
+
if (signal.aborted)
|
|
77
|
+
return Promise.resolve(undefined);
|
|
78
|
+
const aborted = new Promise(resolve => signal.addEventListener('abort', () => resolve(undefined), { once: true }));
|
|
79
|
+
// Vince chi termina prima: la risposta del server oppure l'interruzione (la chiamata prosegue in background e viene ignorata)
|
|
80
|
+
return Promise.race([promise, aborted]);
|
|
81
|
+
};
|
|
68
82
|
/**
|
|
69
83
|
* Convert SearchResultDescriptor to structured data source with metadata
|
|
70
|
-
* I valori dei documenti sono
|
|
84
|
+
* I valori dei documenti sono già presenti nelle righe restituite dalla ricerca:
|
|
71
85
|
* qui vengono solo abbinati ai rispettivi MetadataDescriptor (perm,
|
|
72
|
-
* isSpecialSearchOutput, ...), risolti
|
|
73
|
-
* Nessuna chiamata al server per riga.
|
|
86
|
+
* isSpecialSearchOutput, ...), risolti una sola volta per tipo documento.
|
|
74
87
|
*/
|
|
75
88
|
export const searchResultToDataSource = async (searchResult, hideSysMetadata, signal) => {
|
|
76
89
|
const rows = searchResult?.dtdResult?.rows ?? [];
|
|
@@ -143,7 +156,7 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata, si
|
|
|
143
156
|
return output;
|
|
144
157
|
};
|
|
145
158
|
export const DEFAULT_RELATION_EXPAND_LEVEL = 4; // Default maximum depth level for expansion (can be adjusted)
|
|
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,
|
|
159
|
+
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, showExpandAllButton = false, defaultExpandAll = false, onLoadingStateChanged, onStopCalculationReady, onCalculationStopped, initialTreeState, onTreeStateChange }) => {
|
|
147
160
|
// State
|
|
148
161
|
const [dcmtTypes, setDcmtTypes] = useState([]);
|
|
149
162
|
const [treeData, setTreeData] = useState([]);
|
|
@@ -152,21 +165,21 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
152
165
|
const getInitialExpandLevel = () => SDKUI_Globals.userSettings?.searchSettings?.relationExpandLevel ?? DEFAULT_RELATION_EXPAND_LEVEL;
|
|
153
166
|
const [expandLevel, setExpandLevel] = useState(getInitialExpandLevel);
|
|
154
167
|
const [isAllCollapsed, setIsAllCollapsed] = useState(false);
|
|
155
|
-
const initialExpandAllAppliedRef =
|
|
156
|
-
|
|
157
|
-
const [
|
|
158
|
-
const
|
|
159
|
-
const [waitPanelMaxValuePrimary, setWaitPanelMaxValuePrimary] = useState(0);
|
|
168
|
+
const initialExpandAllAppliedRef = useRef(false);
|
|
169
|
+
// Calcolo iniziale: il pannello e' imperativo, qui resta solo il flag per il render.
|
|
170
|
+
const [isInitialLoading, setIsInitialLoading] = useState(false);
|
|
171
|
+
const loadPanelRef = useRef(undefined);
|
|
160
172
|
const [abortController] = useState(new AbortController());
|
|
161
173
|
// True quando l'utente ha interrotto il calcolo delle correlazioni (pulsante "Interrompi")
|
|
162
174
|
const [loadStoppedByUser, setLoadStoppedByUser] = useState(false);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const [
|
|
166
|
-
|
|
167
|
-
const
|
|
175
|
+
// Espansione di un nodo: il pannello e' imperativo, qui resta solo il flag per il render.
|
|
176
|
+
// qui resta solo il flag che serve al render e alla notifica al padre.
|
|
177
|
+
const [isExpansionLoading, setIsExpansionLoading] = useState(false);
|
|
178
|
+
// AbortController dell'espansione in corso, accessibile da callback stabili
|
|
179
|
+
const expansionAbortControllerRef = useRef(undefined);
|
|
180
|
+
const expansionPanelRef = useRef(undefined);
|
|
168
181
|
// Ref to track last loaded input to prevent unnecessary reloads
|
|
169
|
-
const lastLoadedInputRef =
|
|
182
|
+
const lastLoadedInputRef = useRef('');
|
|
170
183
|
// State to track loaded input key - triggers re-render for focus selection
|
|
171
184
|
const [loadedInputKey, setLoadedInputKey] = React.useState('');
|
|
172
185
|
// State to track how many GetMetadataAsync calls failed
|
|
@@ -174,9 +187,17 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
174
187
|
// State to track total master documents found (used when isForMaster is true)
|
|
175
188
|
const [totalMasterDocuments, setTotalMasterDocuments] = React.useState(0);
|
|
176
189
|
// Ref to track if user has manually expanded/collapsed static items
|
|
177
|
-
const userInteractedWithStaticItemsRef =
|
|
190
|
+
const userInteractedWithStaticItemsRef = useRef(false);
|
|
178
191
|
// Ref to track the last inputKey for which we set the focused item
|
|
179
|
-
const lastFocusedInputRef =
|
|
192
|
+
const lastFocusedInputRef = useRef('');
|
|
193
|
+
// Catturato al mount (il padre lo aggiorna di continuo) e azzerato dopo l'uso,
|
|
194
|
+
// così vale solo per il primo caricamento
|
|
195
|
+
const stateToRestoreRef = useRef(initialTreeState);
|
|
196
|
+
// Parte dallo stato ricevuto: il padre azzera il fuoco prima di rimontare, quindi
|
|
197
|
+
// la prima notifica dopo il rimontaggio lo perderebbe
|
|
198
|
+
const lastReportedStateRef = useRef(initialTreeState);
|
|
199
|
+
// Percorso su cui rimettere il fuoco dopo un ripristino
|
|
200
|
+
const pendingFocusPathRef = useRef(undefined);
|
|
180
201
|
// State for all users (used for checkout status display)
|
|
181
202
|
const [allUsers, setAllUsers] = useState([]);
|
|
182
203
|
// Load all users for checkout status resolution
|
|
@@ -189,25 +210,19 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
189
210
|
}, []);
|
|
190
211
|
// Notify parent when loading state changes
|
|
191
212
|
useEffect(() => {
|
|
192
|
-
const isLoading =
|
|
213
|
+
const isLoading = isInitialLoading || isExpansionLoading;
|
|
193
214
|
onLoadingStateChanged?.(isLoading);
|
|
194
|
-
}, [
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
useEffect(() => {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const expansionAbortControllerRef = React.useRef(undefined);
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
expansionAbortControllerRef.current = expansionAbortController;
|
|
204
|
-
}, [expansionAbortController]);
|
|
215
|
+
}, [isInitialLoading, isExpansionLoading, onLoadingStateChanged]);
|
|
216
|
+
// I pannelli vivono fuori dall'albero React: se il viewer viene smontato mentre un
|
|
217
|
+
// caricamento e' in corso vanno chiusi a mano, altrimenti resterebbero a schermo.
|
|
218
|
+
useEffect(() => () => {
|
|
219
|
+
loadPanelRef.current?.close();
|
|
220
|
+
expansionPanelRef.current?.close();
|
|
221
|
+
}, []);
|
|
205
222
|
/**
|
|
206
223
|
* Interrompe il calcolo delle correlazioni (iniziale e/o espansione in corso):
|
|
207
224
|
* non vengono eseguite ulteriori chiamate GetMetadata e vengono mantenute
|
|
208
225
|
* solo le correlazioni già calcolate.
|
|
209
|
-
* È sincrona: può essere invocata immediatamente prima di smontare il viewer
|
|
210
|
-
* (es. pulsante "Indietro"), quando un effect non farebbe in tempo.
|
|
211
226
|
*/
|
|
212
227
|
const stopCalculation = useCallback(() => {
|
|
213
228
|
if (!abortController.signal.aborted)
|
|
@@ -265,7 +280,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
265
280
|
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
266
281
|
if (!searchEngine)
|
|
267
282
|
return items;
|
|
268
|
-
const results = await searchEngine.GetAllDetailDcmtsAsync(mTID, mDID) ?? [];
|
|
283
|
+
const results = await untilAborted(searchEngine.GetAllDetailDcmtsAsync(mTID, mDID), signal) ?? [];
|
|
269
284
|
for (const searchResult of results) {
|
|
270
285
|
// Interruzione richiesta dall'utente: restituisce le correlazioni già calcolate
|
|
271
286
|
if (signal?.aborted)
|
|
@@ -355,7 +370,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
355
370
|
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
356
371
|
if (!searchEngine)
|
|
357
372
|
return items;
|
|
358
|
-
const results = await searchEngine.GetAllMasterDcmtsAsync(dTID, dDID) ?? [];
|
|
373
|
+
const results = await untilAborted(searchEngine.GetAllMasterDcmtsAsync(dTID, dDID), signal) ?? [];
|
|
359
374
|
for (const searchResult of results) {
|
|
360
375
|
// Interruzione richiesta dall'utente: restituisce le correlazioni già calcolate
|
|
361
376
|
if (signal?.aborted)
|
|
@@ -479,6 +494,26 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
479
494
|
return { ...node, hidden: shouldHide, items: updatedItems };
|
|
480
495
|
});
|
|
481
496
|
}, [showZeroDcmts]);
|
|
497
|
+
/** Messaggio informativo in testa se tutti i figli sono nascosti dal filtro; senza figli il nodo resta vuoto (nessuna freccina). */
|
|
498
|
+
const applyZeroFilterInfoMessage = useCallback((nodeKey, items) => {
|
|
499
|
+
const cleaned = items.filter(child => !(child.isInfoMessage && child.key?.startsWith('__info__')));
|
|
500
|
+
if (showZeroDcmts)
|
|
501
|
+
return cleaned;
|
|
502
|
+
const realChildren = cleaned.filter(child => !child.isInfoMessage);
|
|
503
|
+
if (realChildren.length === 0 || !realChildren.every(child => child.hidden))
|
|
504
|
+
return cleaned;
|
|
505
|
+
return [
|
|
506
|
+
{
|
|
507
|
+
key: `__info__${nodeKey}`,
|
|
508
|
+
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
509
|
+
isContainer: false,
|
|
510
|
+
isDcmt: false,
|
|
511
|
+
isInfoMessage: true,
|
|
512
|
+
isExpandible: false
|
|
513
|
+
},
|
|
514
|
+
...cleaned // Keep hidden containers so they can be shown when toggling
|
|
515
|
+
];
|
|
516
|
+
}, [showZeroDcmts]);
|
|
482
517
|
/**
|
|
483
518
|
* Helper function to set up initial tree expansion state.
|
|
484
519
|
* Called after all data is loaded but before setTreeData.
|
|
@@ -566,10 +601,22 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
566
601
|
});
|
|
567
602
|
return result;
|
|
568
603
|
};
|
|
604
|
+
/**
|
|
605
|
+
* Carica i figli di un documento durante il ripristino. Usa i loader e non
|
|
606
|
+
* calculateItemsForNode, che accenderebbe il wait panel di espansione mentre
|
|
607
|
+
* è già attivo quello del caricamento principale.
|
|
608
|
+
*/
|
|
609
|
+
const loadChildrenForRestore = async (node) => {
|
|
610
|
+
if (!node.tid || !node.did)
|
|
611
|
+
return [];
|
|
612
|
+
if (isForMaster && invertMasterNavigation)
|
|
613
|
+
return await getMasterDcmtsAsync(node.tid, node.did, 1, abortController.signal);
|
|
614
|
+
return await getDetailDcmtsAsync(node.tid, node.did, 1, abortController.signal);
|
|
615
|
+
};
|
|
569
616
|
/**
|
|
570
617
|
* Main data loading function
|
|
571
618
|
*/
|
|
572
|
-
const loadData = useCallback(async () => {
|
|
619
|
+
const loadData = useCallback(async (panel) => {
|
|
573
620
|
if (!inputDcmts || inputDcmts.length === 0 || dcmtTypes.length === 0) {
|
|
574
621
|
setTreeData([]);
|
|
575
622
|
return;
|
|
@@ -584,14 +631,14 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
584
631
|
break;
|
|
585
632
|
}
|
|
586
633
|
// Update wait panel progress
|
|
587
|
-
|
|
634
|
+
panel.setSubtitle(`Caricamento correlazione ${processedCount + 1} di ${inputDcmts.length}`);
|
|
588
635
|
const searchEngine = SDK_Globals.tmSession?.NewSearchEngine();
|
|
589
636
|
if (!searchEngine)
|
|
590
637
|
continue;
|
|
591
638
|
// Load document metadata
|
|
592
639
|
let result;
|
|
593
640
|
try {
|
|
594
|
-
result = await searchEngine.GetMetadataAsync(dcmt.TID, dcmt.DID, false);
|
|
641
|
+
result = await untilAborted(searchEngine.GetMetadataAsync(dcmt.TID, dcmt.DID, false), abortController.signal);
|
|
595
642
|
}
|
|
596
643
|
catch (metadataError) {
|
|
597
644
|
console.warn('[TMRelationViewer] GetMetadataAsync failed for TID:', dcmt.TID, 'DID:', dcmt.DID, metadataError);
|
|
@@ -604,9 +651,12 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
604
651
|
});
|
|
605
652
|
// Skip this document and continue with the next one
|
|
606
653
|
processedCount++;
|
|
607
|
-
|
|
654
|
+
await panel.step();
|
|
608
655
|
continue;
|
|
609
656
|
}
|
|
657
|
+
// Interrotto durante la chiamata: esce con le correlazioni gia' calcolate
|
|
658
|
+
if (abortController.signal.aborted)
|
|
659
|
+
break;
|
|
610
660
|
const dtd = await DcmtTypeListCacheService.GetAsync(dcmt.TID);
|
|
611
661
|
// Parse document values
|
|
612
662
|
const docValues = await searchResultToDataSource(result, undefined, abortController.signal);
|
|
@@ -782,7 +832,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
782
832
|
}
|
|
783
833
|
// Update progress counter
|
|
784
834
|
processedCount++;
|
|
785
|
-
|
|
835
|
+
// step() attende anche la conferma di interruzione: col dialogo aperto il ciclo resta fermo
|
|
836
|
+
await panel.step();
|
|
786
837
|
}
|
|
787
838
|
/**
|
|
788
839
|
* Helper function to check if a node has any actual correlated documents
|
|
@@ -852,12 +903,20 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
852
903
|
}
|
|
853
904
|
// FIRST setup initial expansion state (root container expanded, first document expanded with focus, first correlation folder expanded)
|
|
854
905
|
// This must run BEFORE updateHiddenProperty so that infoMessage logic sees expanded=true
|
|
855
|
-
|
|
906
|
+
let expandedTree = setupInitialTreeExpansion(tree);
|
|
907
|
+
// Stato precedente da ripristinare (rimontaggio dopo un'operazione): si riapplica
|
|
908
|
+
// sopra l'espansione iniziale, che resta necessaria perché marca isRoot.
|
|
909
|
+
const stateToRestore = stateToRestoreRef.current;
|
|
910
|
+
stateToRestoreRef.current = undefined;
|
|
911
|
+
if (stateToRestore && stateToRestore.inputKey === getInputKey()) {
|
|
912
|
+
expandedTree = await applyRelationTreeState(expandedTree, stateToRestore, loadChildrenForRestore, () => abortController.signal.aborted);
|
|
913
|
+
pendingFocusPathRef.current = stateToRestore.focusedPath;
|
|
914
|
+
}
|
|
856
915
|
// THEN apply hidden property transformations (creates new objects, adds infoMessage where needed)
|
|
857
916
|
// Now it will correctly detect expanded nodes and add infoMessage if all children are hidden
|
|
858
917
|
const processedTree = updateHiddenProperty(expandedTree);
|
|
859
918
|
setTreeData(processedTree);
|
|
860
|
-
}, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, abortController, updateHiddenProperty, showMainDocument, labelMainContainer, onNoRelationsFound, onCalculationStopped]);
|
|
919
|
+
}, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, abortController, updateHiddenProperty, showMainDocument, labelMainContainer, onNoRelationsFound, onCalculationStopped, getInputKey]);
|
|
861
920
|
/**
|
|
862
921
|
* Merge main tree data with additional static items
|
|
863
922
|
*/
|
|
@@ -872,6 +931,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
872
931
|
// and may contain custom properties that would be lost by the spread operator
|
|
873
932
|
return [...treeData, ...itemsToMerge];
|
|
874
933
|
}, [treeData, additionalStaticItems, staticItemsState]);
|
|
934
|
+
/** Notifica al padre lo stato dell'albero, così che possa restituirlo dopo un refresh. */
|
|
935
|
+
useEffect(() => {
|
|
936
|
+
if (!onTreeStateChange)
|
|
937
|
+
return;
|
|
938
|
+
// Ad albero vuoto (caricamento in corso) si sovrascriverebbe lo stato da ripristinare
|
|
939
|
+
if (treeData.length === 0)
|
|
940
|
+
return;
|
|
941
|
+
// Il padre azzera il fuoco all'avvio di un refresh: si conserva l'ultimo noto
|
|
942
|
+
const state = collectRelationTreeState(treeData, getInputKey(), focusedItem?.key, lastReportedStateRef.current?.focusedPath);
|
|
943
|
+
lastReportedStateRef.current = state;
|
|
944
|
+
onTreeStateChange(state);
|
|
945
|
+
}, [treeData, focusedItem, getInputKey, onTreeStateChange]);
|
|
875
946
|
/**
|
|
876
947
|
* Notify parent with a flattened list of all items whenever the merged tree data changes.
|
|
877
948
|
*/
|
|
@@ -912,20 +983,28 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
912
983
|
lastLoadedInputRef.current = currentKey;
|
|
913
984
|
// Reset interaction flag when loading new data
|
|
914
985
|
userInteractedWithStaticItemsRef.current = false;
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
986
|
+
setIsInitialLoading(true);
|
|
987
|
+
const panel = TMWaitPanelManager.show({
|
|
988
|
+
title: isForMaster ? SDKUI_Localizator.LoadingMasterDocuments : SDKUI_Localizator.LoadingDetailDocuments,
|
|
989
|
+
max: inputDcmts.length,
|
|
990
|
+
showCounters: false,
|
|
991
|
+
cancelable: true,
|
|
992
|
+
onAbort: () => abortController.abort(),
|
|
993
|
+
});
|
|
994
|
+
loadPanelRef.current = panel;
|
|
918
995
|
// Call loadData and use .then() instead of await to allow React to render
|
|
919
|
-
loadData().then(() => {
|
|
996
|
+
loadData(panel).then(() => {
|
|
920
997
|
// Mark as loaded AFTER data is ready - state update triggers re-render for focus selection
|
|
921
998
|
lastLoadedInputRef.current = currentKey;
|
|
922
999
|
setLoadedInputKey(currentKey);
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1000
|
+
}).finally(() => {
|
|
1001
|
+
// Il pannello resta aperto per tutto loadData, ripristini inclusi
|
|
1002
|
+
panel.close();
|
|
1003
|
+
if (loadPanelRef.current === panel)
|
|
1004
|
+
loadPanelRef.current = undefined;
|
|
1005
|
+
setIsInitialLoading(false);
|
|
927
1006
|
});
|
|
928
|
-
}, [inputDcmts, dcmtTypes, maxDepthLevel, getInputKey, loadData, treeData.length]);
|
|
1007
|
+
}, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, abortController, getInputKey, loadData, treeData.length]);
|
|
929
1008
|
/**
|
|
930
1009
|
* Update tree when showZeroDcmts changes
|
|
931
1010
|
* Updates the visualization without re-fetching data (isLoaded stays true)
|
|
@@ -951,6 +1030,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
951
1030
|
if (lastFocusedInputRef.current === currentInputKey) {
|
|
952
1031
|
return;
|
|
953
1032
|
}
|
|
1033
|
+
// Ripristino dopo un refresh. Se il nodo non esiste più (es. documento cancellato
|
|
1034
|
+
// fisicamente) si prosegue con il fuoco predefinito sul root.
|
|
1035
|
+
const focusPathToRestore = pendingFocusPathRef.current;
|
|
1036
|
+
pendingFocusPathRef.current = undefined;
|
|
1037
|
+
if (focusPathToRestore) {
|
|
1038
|
+
const nodeToFocus = findRelationNodeByPath(treeData, focusPathToRestore);
|
|
1039
|
+
if (nodeToFocus) {
|
|
1040
|
+
onFocusedItemChanged(nodeToFocus);
|
|
1041
|
+
lastFocusedInputRef.current = currentInputKey;
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
954
1045
|
// Helper function to recursively find the first document with isRoot=true
|
|
955
1046
|
const findFirstRootDocument = (items) => {
|
|
956
1047
|
for (const item of items) {
|
|
@@ -1028,29 +1119,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1028
1119
|
if (node.isLoaded && node.items) {
|
|
1029
1120
|
// Apply current show/hide logic based on showZeroDcmts
|
|
1030
1121
|
const updatedItems = updateHiddenProperty(node.items);
|
|
1031
|
-
|
|
1032
|
-
if (node.isContainer) {
|
|
1033
|
-
// Remove any existing info messages
|
|
1034
|
-
const filteredItems = updatedItems.filter(child => !(child.isInfoMessage && child.key?.startsWith('__info__')));
|
|
1035
|
-
// Check if all real children are hidden
|
|
1036
|
-
const realChildren = filteredItems.filter(child => !child.isInfoMessage);
|
|
1037
|
-
const allChildrenHidden = realChildren.length > 0 && realChildren.every(child => child.hidden);
|
|
1038
|
-
// If showZeroDcmts is false and all items are hidden, show info message + keep hidden containers
|
|
1039
|
-
if (!showZeroDcmts && allChildrenHidden) {
|
|
1040
|
-
return [
|
|
1041
|
-
{
|
|
1042
|
-
key: `__info__${node.key}`,
|
|
1043
|
-
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
1044
|
-
isContainer: false,
|
|
1045
|
-
isDcmt: false,
|
|
1046
|
-
isInfoMessage: true,
|
|
1047
|
-
isExpandible: false
|
|
1048
|
-
},
|
|
1049
|
-
...filteredItems // Keep hidden containers so they can be shown when toggling
|
|
1050
|
-
];
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
return updatedItems;
|
|
1122
|
+
return applyZeroFilterInfoMessage(node.key, updatedItems);
|
|
1054
1123
|
}
|
|
1055
1124
|
// ============================================
|
|
1056
1125
|
// CONTAINER: Show items immediately (no API calls)
|
|
@@ -1064,21 +1133,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1064
1133
|
if (!node.items)
|
|
1065
1134
|
return [];
|
|
1066
1135
|
const updatedItems = updateHiddenProperty(node.items);
|
|
1067
|
-
|
|
1068
|
-
if (!showZeroDcmts && updatedItems.length > 0 && updatedItems.every(item => item.hidden)) {
|
|
1069
|
-
return [
|
|
1070
|
-
{
|
|
1071
|
-
key: `__info__${node.key}`,
|
|
1072
|
-
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
1073
|
-
isContainer: false,
|
|
1074
|
-
isDcmt: false,
|
|
1075
|
-
isInfoMessage: true,
|
|
1076
|
-
isExpandible: false
|
|
1077
|
-
},
|
|
1078
|
-
...updatedItems // Keep hidden containers so they can be shown when toggling
|
|
1079
|
-
];
|
|
1080
|
-
}
|
|
1081
|
-
return updatedItems;
|
|
1136
|
+
return applyZeroFilterInfoMessage(node.key, updatedItems);
|
|
1082
1137
|
}
|
|
1083
1138
|
// ============================================
|
|
1084
1139
|
// DOCUMENT: Load its children (relation containers) lazily
|
|
@@ -1086,11 +1141,19 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1086
1141
|
// ============================================
|
|
1087
1142
|
if (node.isDcmt && node.tid && node.did) {
|
|
1088
1143
|
const newAbortController = new AbortController();
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1144
|
+
expansionAbortControllerRef.current = newAbortController;
|
|
1145
|
+
setIsExpansionLoading(true);
|
|
1146
|
+
// Un solo nodo: niente contatori ne' stima dei tempi, solo l'attesa annullabile.
|
|
1147
|
+
const panel = TMWaitPanelManager.show({
|
|
1148
|
+
title: isForMaster ? SDKUI_Localizator.LoadingMasterDocuments : SDKUI_Localizator.LoadingDetailDocuments,
|
|
1149
|
+
subtitle: 'Caricamento documenti correlati...',
|
|
1150
|
+
max: 1,
|
|
1151
|
+
showCounters: false,
|
|
1152
|
+
showEta: false,
|
|
1153
|
+
cancelable: true,
|
|
1154
|
+
onAbort: () => newAbortController.abort(),
|
|
1155
|
+
});
|
|
1156
|
+
expansionPanelRef.current = panel;
|
|
1094
1157
|
try {
|
|
1095
1158
|
// Check for abort
|
|
1096
1159
|
if (newAbortController.signal.aborted) {
|
|
@@ -1119,34 +1182,22 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1119
1182
|
// - Relation type containers are always visible (even if empty)
|
|
1120
1183
|
// - Other containers with zero items can be hidden based on showZeroDcmts
|
|
1121
1184
|
const updatedItems = updateHiddenProperty(loadedItems);
|
|
1122
|
-
|
|
1123
|
-
if (!showZeroDcmts && updatedItems.length > 0 && updatedItems.every(item => item.hidden)) {
|
|
1124
|
-
return [
|
|
1125
|
-
{
|
|
1126
|
-
key: `__info__${node.key}`,
|
|
1127
|
-
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
1128
|
-
isContainer: false,
|
|
1129
|
-
isDcmt: false,
|
|
1130
|
-
isInfoMessage: true,
|
|
1131
|
-
isExpandible: false
|
|
1132
|
-
},
|
|
1133
|
-
...updatedItems // Keep hidden containers so they can be shown when toggling
|
|
1134
|
-
];
|
|
1135
|
-
}
|
|
1136
|
-
return updatedItems;
|
|
1185
|
+
return applyZeroFilterInfoMessage(node.key, updatedItems);
|
|
1137
1186
|
}
|
|
1138
1187
|
catch (error) {
|
|
1139
1188
|
console.error('Error loading document relations:', error);
|
|
1140
1189
|
return [];
|
|
1141
1190
|
}
|
|
1142
1191
|
finally {
|
|
1143
|
-
|
|
1144
|
-
|
|
1192
|
+
panel.close();
|
|
1193
|
+
setIsExpansionLoading(false);
|
|
1194
|
+
expansionAbortControllerRef.current = undefined;
|
|
1195
|
+
expansionPanelRef.current = undefined;
|
|
1145
1196
|
}
|
|
1146
1197
|
}
|
|
1147
1198
|
// Default: return existing items
|
|
1148
1199
|
return node.items;
|
|
1149
|
-
}, [isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty, showZeroDcmts]);
|
|
1200
|
+
}, [isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty, applyZeroFilterInfoMessage, showZeroDcmts]);
|
|
1150
1201
|
/**
|
|
1151
1202
|
* Default item renderer with metadata display (adapted from TMMasterDetailDcmts.tsx)
|
|
1152
1203
|
*/
|
|
@@ -1179,8 +1230,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1179
1230
|
gap: '10px',
|
|
1180
1231
|
height: '32px',
|
|
1181
1232
|
padding: '6px 0',
|
|
1182
|
-
opacity: item.isZero ? 0.
|
|
1183
|
-
transition: 'opacity 0.2s ease-in-out'
|
|
1233
|
+
opacity: item.isZero ? 0.4 : 1,
|
|
1184
1234
|
};
|
|
1185
1235
|
// Se è il container principale (root) e showMainDocument è false,
|
|
1186
1236
|
// non mostrare il badge perché conterrebbe il numero di sotto-container, non di documenti
|
|
@@ -1210,8 +1260,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1210
1260
|
alignItems: 'center',
|
|
1211
1261
|
cursor: 'pointer',
|
|
1212
1262
|
userSelect: 'none',
|
|
1213
|
-
opacity: item.isZero ? 0.
|
|
1214
|
-
transition: 'opacity 0.2s ease-in-out',
|
|
1263
|
+
opacity: item.isZero ? 0.4 : 1,
|
|
1215
1264
|
textDecoration: isLogicallyDeleted ? 'line-through' : 'none'
|
|
1216
1265
|
};
|
|
1217
1266
|
const documentStyle = customDocumentStyle ? { ...defaultDocumentStyle, ...customDocumentStyle(item) } : defaultDocumentStyle;
|
|
@@ -1271,7 +1320,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1271
1320
|
checkoutStatusIcon = checkoutStatus.icon;
|
|
1272
1321
|
}
|
|
1273
1322
|
}
|
|
1274
|
-
return (_jsxs("div", { onDoubleClick: handleDoubleClick, style: documentStyle, children: [item.did && item.tid && showCurrentDcmtIndicator && inputDcmts?.some(d => d.DID === item.did && d.TID === item.tid) ? _jsx(IconBackhandIndexPointingRight, { fontSize: 22, overflow: 'visible' }) : _jsx(_Fragment, {}), item.values && (_jsx(TMDcmtIcon, { tid: item.values?.TID?.value, did: item.values?.DID?.value, fileExtension: item.values?.FILEEXT?.value, fileCount: item.values?.FILECOUNT?.value, isLexProt: item.values?.IsLexProt?.value, isMail: item.values?.ISMAIL?.value, isShared: item.values?.ISSHARED?.value, isSigned: item.values?.ISSIGNED?.value, downloadMode: 'openInNewWindow'
|
|
1323
|
+
return (_jsxs("div", { onDoubleClick: handleDoubleClick, style: documentStyle, children: [item.did && item.tid && showCurrentDcmtIndicator && inputDcmts?.some(d => d.DID === item.did && d.TID === item.tid) ? _jsx(IconBackhandIndexPointingRight, { fontSize: 22, overflow: 'visible' }) : _jsx(_Fragment, {}), item.values && (_jsx(TMDcmtIcon, { tid: item.values?.TID?.value, did: item.values?.DID?.value, fileExtension: item.values?.FILEEXT?.value, fileCount: item.values?.FILECOUNT?.value, isLexProt: item.values?.IsLexProt?.value, isMail: item.values?.ISMAIL?.value, isShared: item.values?.ISSHARED?.value, isSigned: item.values?.ISSIGNED?.value, downloadMode: 'openInNewWindow' })), checkoutStatusIcon, metadataContent] }));
|
|
1275
1324
|
}, [onDocumentDoubleClick, showCurrentDcmtIndicator, inputDcmts, customMainContainerContent, customDocumentStyle, customDocumentContent, showMetadataNames, showMainDocument, allUsers]);
|
|
1276
1325
|
/**
|
|
1277
1326
|
* Wrapper renderer that handles custom rendering if provided
|
|
@@ -1385,15 +1434,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1385
1434
|
}
|
|
1386
1435
|
const targetLevel = expandLevel;
|
|
1387
1436
|
const newAbortController = new AbortController();
|
|
1388
|
-
|
|
1437
|
+
expansionAbortControllerRef.current = newAbortController;
|
|
1438
|
+
// Aperto solo se servono chiamate API (vedi hasApiCalls): con i figli già in
|
|
1439
|
+
// memoria l'espansione è immediata e il pannello lampeggerebbe soltanto.
|
|
1440
|
+
let panel;
|
|
1389
1441
|
// CONTATORI DINAMICI:
|
|
1390
1442
|
// - totalNodes: cresce quando scopriamo nuovi nodi (evita che percentuale > 100%)
|
|
1391
1443
|
// - processedNodes: quanti nodi abbiamo già processato
|
|
1392
|
-
// -
|
|
1444
|
+
// - shownProgress: percentuale mostrata, che non torna mai indietro
|
|
1393
1445
|
let totalNodes = 0;
|
|
1394
1446
|
let processedNodes = 0;
|
|
1395
1447
|
let hasApiCalls = false;
|
|
1396
|
-
let
|
|
1448
|
+
let shownProgress = 0;
|
|
1397
1449
|
/**
|
|
1398
1450
|
* Conta i nodi espandibili in un array (solo primo livello, non ricorsivo).
|
|
1399
1451
|
* Usato per aggiornare totalNodes man mano che scopriamo nuovi figli.
|
|
@@ -1409,6 +1461,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1409
1461
|
};
|
|
1410
1462
|
// Conta iniziale: solo i nodi al livello root
|
|
1411
1463
|
totalNodes = countNodesAtLevel([...workingTreeData, ...workingStaticData]);
|
|
1464
|
+
const initialTotalNodes = totalNodes;
|
|
1412
1465
|
/**
|
|
1413
1466
|
* FUNZIONE RICORSIVA DI ESPANSIONE
|
|
1414
1467
|
*
|
|
@@ -1462,9 +1515,17 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1462
1515
|
if (!hasApiCalls) {
|
|
1463
1516
|
hasApiCalls = true;
|
|
1464
1517
|
TMSpinner.hide();
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1518
|
+
setIsExpansionLoading(true);
|
|
1519
|
+
// Avanzamento in centesimi: il totale cambia mentre si scoprono i figli, niente ETA.
|
|
1520
|
+
panel = TMWaitPanelManager.show({
|
|
1521
|
+
title: isForMaster ? SDKUI_Localizator.LoadingMasterDocuments : SDKUI_Localizator.LoadingDetailDocuments,
|
|
1522
|
+
max: 100,
|
|
1523
|
+
showCounters: false,
|
|
1524
|
+
showEta: false,
|
|
1525
|
+
cancelable: true,
|
|
1526
|
+
onAbort: () => newAbortController.abort(),
|
|
1527
|
+
});
|
|
1528
|
+
expansionPanelRef.current = panel;
|
|
1468
1529
|
}
|
|
1469
1530
|
try {
|
|
1470
1531
|
let loadedItems = [];
|
|
@@ -1479,7 +1540,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1479
1540
|
loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1, newAbortController.signal);
|
|
1480
1541
|
}
|
|
1481
1542
|
// Applica le regole di visibilità (showZeroDcmts)
|
|
1482
|
-
|
|
1543
|
+
// Stesse regole dell'espansione manuale (messaggio informativo se tutto nascosto)
|
|
1544
|
+
expandedNode.items = applyZeroFilterInfoMessage(node.key, updateHiddenProperty(loadedItems));
|
|
1483
1545
|
expandedNode.isLoaded = true;
|
|
1484
1546
|
expandedNode.itemsCount = loadedItems.length;
|
|
1485
1547
|
// IMPORTANTE: Aggiungi i nuovi nodi scoperti al contatore totale
|
|
@@ -1506,14 +1568,15 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1506
1568
|
}
|
|
1507
1569
|
// Aggiorna il progresso DOPO aver processato questo nodo
|
|
1508
1570
|
processedNodes++;
|
|
1509
|
-
//
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1571
|
+
// La barra non torna mai indietro: segue il valore reale quando sale, altrimenti avanza verso il 99%
|
|
1572
|
+
const realProgress = totalNodes > 0 ? (processedNodes / totalNodes) * 100 : 0;
|
|
1573
|
+
shownProgress = Math.min(99, realProgress > shownProgress
|
|
1574
|
+
? realProgress
|
|
1575
|
+
: shownProgress + (99 - shownProgress) * 0.01);
|
|
1576
|
+
panel?.setValue(shownProgress);
|
|
1577
|
+
// Seconda riga: spiega perché percentuale e conteggio non vanno di pari passo
|
|
1578
|
+
panel?.setSubtitle(SDKUI_Localizator.ExpansionProgress.replaceParams(processedNodes.toString(), totalNodes.toString())
|
|
1579
|
+
+ (totalNodes > initialTotalNodes ? `\n${SDKUI_Localizator.ExpansionProgressIsEstimated}` : ''));
|
|
1517
1580
|
// ═══════════════════════════════════════════════════════════════════
|
|
1518
1581
|
// PASSO 3: CHIAMATA RICORSIVA SUI FIGLI
|
|
1519
1582
|
// Questo è il punto chiave: i nuovi nodi appena caricati vengono
|
|
@@ -1541,10 +1604,12 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1541
1604
|
finally {
|
|
1542
1605
|
// Cleanup: nascondi spinner e pannello di attesa
|
|
1543
1606
|
TMSpinner.hide();
|
|
1544
|
-
|
|
1545
|
-
|
|
1607
|
+
panel?.close();
|
|
1608
|
+
setIsExpansionLoading(false);
|
|
1609
|
+
expansionAbortControllerRef.current = undefined;
|
|
1610
|
+
expansionPanelRef.current = undefined;
|
|
1546
1611
|
}
|
|
1547
|
-
}, [expandLevel, treeData, staticItemsState, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty]);
|
|
1612
|
+
}, [expandLevel, treeData, staticItemsState, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty, applyZeroFilterInfoMessage]);
|
|
1548
1613
|
/**
|
|
1549
1614
|
* Apply defaultExpandAll once on initial tree load.
|
|
1550
1615
|
*/
|
|
@@ -1573,8 +1638,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1573
1638
|
// Reset collapsed state when user manually expands a node
|
|
1574
1639
|
setIsAllCollapsed(false);
|
|
1575
1640
|
}, []);
|
|
1576
|
-
|
|
1577
|
-
|
|
1641
|
+
// Il pannello di attesa è montato dal manager fuori dall'albero React: qui resta
|
|
1642
|
+
// solo il posto dell'albero, che compare a calcolo finito.
|
|
1643
|
+
if (isInitialLoading) {
|
|
1644
|
+
return _jsx("div", { style: { width: '100%', height: '100%' } });
|
|
1578
1645
|
}
|
|
1579
1646
|
if (mergedTreeData.length === 0) {
|
|
1580
1647
|
// Calcolo interrotto dall'utente prima di aver calcolato qualsiasi correlazione
|
|
@@ -1631,15 +1698,11 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1631
1698
|
whiteSpace: 'nowrap',
|
|
1632
1699
|
outline: 'none',
|
|
1633
1700
|
transition: 'background 0.2s'
|
|
1634
|
-
}, children: [_jsx(IconChevronRight, { fontSize: 14 }), _jsx("span", { children: SDKUI_Localizator.CollapseAll })] }) })] })), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto' }, children: _jsx(TMTreeView, { dataSource: mergedTreeData, itemRender: finalItemRender, calculateItemsForNode: calculateItemsForNode, onDataChanged: handleDataChanged, focusedItem: focusedItem, onFocusedItemChanged: handleFocusedItemChanged, allowMultipleSelection: allowMultipleSelection, selectedItems: selectedItems, itemsPerPage: 100, onSelectionChanged: handleSelectedItemsChanged, onItemContextMenu:
|
|
1701
|
+
}, children: [_jsx(IconChevronRight, { fontSize: 14 }), _jsx("span", { children: SDKUI_Localizator.CollapseAll })] }) })] })), _jsx("div", { style: { flex: 1, minHeight: 0, overflow: 'auto' }, children: _jsx(TMTreeView, { dataSource: mergedTreeData, itemRender: finalItemRender, calculateItemsForNode: calculateItemsForNode, onDataChanged: handleDataChanged, focusedItem: focusedItem, onFocusedItemChanged: handleFocusedItemChanged, allowMultipleSelection: allowMultipleSelection, selectedItems: selectedItems, itemsPerPage: 100, onSelectionChanged: handleSelectedItemsChanged, onItemContextMenu: isExpansionLoading ? undefined : onItemContextMenu, enableVirtualization: true, shouldDelayFocusOnEvent: (node, e) => {
|
|
1635
1702
|
// Ritarda il focus quando si clicca sull'icona del documento
|
|
1636
1703
|
// per permettere al doppio click di funzionare
|
|
1637
1704
|
const target = e.target;
|
|
1638
1705
|
return !!target.closest('.tm-dcmt-icon');
|
|
1639
|
-
} }) })
|
|
1640
|
-
setTimeout(() => {
|
|
1641
|
-
expansionAbortController?.abort();
|
|
1642
|
-
}, 100);
|
|
1643
|
-
} }))] }));
|
|
1706
|
+
} }) })] }));
|
|
1644
1707
|
};
|
|
1645
1708
|
export default TMRelationViewer;
|