@topconsultnpm/sdkui-react 6.21.0-dev4.9 → 6.21.0-dev5.2
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/base/TMTreeView.d.ts +16 -13
- package/lib/components/base/TMTreeView.js +230 -64
- package/lib/components/features/documents/TMDcmtIcon.d.ts +3 -1
- package/lib/components/features/documents/TMDcmtIcon.js +5 -32
- package/lib/components/features/documents/TMFileUploader.js +1 -1
- package/lib/components/features/documents/TMMasterDetailDcmts.js +50 -11
- package/lib/components/features/documents/TMRelationViewer.d.ts +12 -10
- package/lib/components/features/documents/TMRelationViewer.js +400 -96
- package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +4 -3
- package/lib/components/features/documents/copyAndMergeDcmtsShared.js +47 -23
- package/lib/components/features/search/TMSearchResult.js +20 -5
- package/lib/components/viewers/TMTidViewer.js +14 -2
- package/lib/helper/SDKUI_Globals.d.ts +1 -0
- package/lib/helper/SDKUI_Globals.js +1 -0
- package/lib/helper/SDKUI_Localizator.d.ts +28 -0
- package/lib/helper/SDKUI_Localizator.js +280 -0
- package/lib/helper/TMUtils.d.ts +33 -1
- package/lib/helper/TMUtils.js +104 -1
- package/lib/helper/helpers.js +9 -0
- package/package.json +3 -4
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataFormats,
|
|
4
|
-
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator } from '../../../helper';
|
|
3
|
+
import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataFormats, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService } from "@topconsultnpm/sdk-ts";
|
|
4
|
+
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals } from '../../../helper';
|
|
5
|
+
import ShowAlert from '../../base/TMAlert';
|
|
6
|
+
import TMToppyMessage from '../../../helper/TMToppyMessage';
|
|
5
7
|
import { TMColors } from '../../../utils/theme';
|
|
6
|
-
import { StyledDivHorizontal, StyledBadge
|
|
8
|
+
import { StyledDivHorizontal, StyledBadge } from '../../base/Styled';
|
|
7
9
|
import TMTreeView from '../../base/TMTreeView';
|
|
8
10
|
import { TMWaitPanel } from '../../base/TMWaitPanel';
|
|
9
11
|
import TMDataListItemViewer from '../../viewers/TMDataListItemViewer';
|
|
10
12
|
import TMDcmtIcon from './TMDcmtIcon';
|
|
11
13
|
import TMDataUserIdItemViewer from '../../viewers/TMDataUserIdItemViewer';
|
|
14
|
+
import TMTooltip from '../../base/TMTooltip';
|
|
15
|
+
import TMSpinner from '../../base/TMSpinner';
|
|
12
16
|
/**
|
|
13
17
|
* Check if document type has detail relations
|
|
14
18
|
*/
|
|
@@ -41,31 +45,6 @@ const isManyToManyRelation = async (relationID) => {
|
|
|
41
45
|
const rdlManyToMany = allRelations.filter(o => o.relationType == RelationTypes.ManyToMany && o.id === relationID) ?? [];
|
|
42
46
|
return rdlManyToMany.length > 0;
|
|
43
47
|
};
|
|
44
|
-
/**
|
|
45
|
-
* Get metadata keys excluding system metadata
|
|
46
|
-
*/
|
|
47
|
-
export const getMetadataKeys = (obj) => {
|
|
48
|
-
if (!obj)
|
|
49
|
-
return [];
|
|
50
|
-
const keys = Object.keys(obj);
|
|
51
|
-
// Escludi metadati di sistema (MID < 100 che sono uppercase) e altri campi tecnici
|
|
52
|
-
const sysMIDs = Object.values(SystemMIDs).map(o => o.toUpperCase());
|
|
53
|
-
return keys.filter(k => obj?.[k].value && !sysMIDs.includes(k)).filter(o => o !== "rowIndex" && o !== "ISLEXPROT");
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Get display value keys for a document (max 5, prioritize SYS_Abstract)
|
|
57
|
-
*/
|
|
58
|
-
export const getDcmtDisplayValue = (obj) => {
|
|
59
|
-
if (!obj)
|
|
60
|
-
return [];
|
|
61
|
-
// Prima cerca SYS_Abstract
|
|
62
|
-
if (obj['SYS_Abstract']?.value) {
|
|
63
|
-
return ['SYS_Abstract'];
|
|
64
|
-
}
|
|
65
|
-
// Altrimenti prendi i primi 5 metadati non di sistema
|
|
66
|
-
const mdKeys = getMetadataKeys(obj);
|
|
67
|
-
return mdKeys.slice(0, 5);
|
|
68
|
-
};
|
|
69
48
|
/**
|
|
70
49
|
* Get display value formatted by column type
|
|
71
50
|
*/
|
|
@@ -113,36 +92,50 @@ export const getDisplayValueByColumn = (col, value) => {
|
|
|
113
92
|
export const searchResultToDataSource = async (searchResult, hideSysMetadata) => {
|
|
114
93
|
const rows = searchResult?.dtdResult?.rows ?? [];
|
|
115
94
|
const tid = searchResult?.fromTID;
|
|
116
|
-
|
|
95
|
+
// IMPORTANT: Pass true to get full metadata with all properties (isSpecialSearchOutput, etc.)
|
|
96
|
+
const dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
|
|
117
97
|
const output = [];
|
|
118
98
|
for (let index = 0; index < rows.length; index++) {
|
|
119
99
|
const item = { rowIndex: index };
|
|
120
100
|
const row = rows[index];
|
|
121
101
|
for (let i = 0; i < row.length; i++) {
|
|
122
|
-
const
|
|
102
|
+
const column = searchResult?.dtdResult?.columns?.[i];
|
|
103
|
+
const mid = Number(column?.extendedProperties?.["MID"] ?? "0");
|
|
123
104
|
if (hideSysMetadata && mid < 100)
|
|
124
105
|
continue;
|
|
125
|
-
|
|
126
|
-
|
|
106
|
+
// For system metadata (MID <= 100), use UPPERCASE caption as key
|
|
107
|
+
// For custom metadata (MID > 100), use caption as key but handle duplicates
|
|
108
|
+
let key = column?.caption ?? '';
|
|
109
|
+
if (mid <= 100) {
|
|
127
110
|
key = key.toUpperCase();
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
// If key already exists with a different MID, append MID to make it unique
|
|
114
|
+
if (item[key] !== undefined && item[key]?.md?.id !== mid) {
|
|
115
|
+
key = `${key}_${mid}`;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
128
118
|
const value = row[i];
|
|
129
119
|
const md = dtd?.metadata?.find(o => o.id == mid);
|
|
130
120
|
item[key] = {
|
|
131
121
|
md: md,
|
|
132
|
-
value: getDisplayValueByColumn(
|
|
122
|
+
value: getDisplayValueByColumn(column, value)
|
|
133
123
|
};
|
|
134
124
|
}
|
|
135
125
|
output.push(item);
|
|
136
126
|
}
|
|
137
127
|
return output;
|
|
138
128
|
};
|
|
139
|
-
const
|
|
129
|
+
export const DEFAULT_RELATION_EXPAND_LEVEL = 4; // Default maximum depth level for expansion (can be adjusted)
|
|
130
|
+
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 }) => {
|
|
140
131
|
// State
|
|
141
132
|
const [dcmtTypes, setDcmtTypes] = useState([]);
|
|
142
133
|
const [treeData, setTreeData] = useState([]);
|
|
143
134
|
const [showZeroDcmts, setShowZeroDcmts] = useState(initialShowZeroDcmts);
|
|
144
135
|
const [staticItemsState, setStaticItemsState] = useState([]);
|
|
145
|
-
const
|
|
136
|
+
const getInitialExpandLevel = () => SDKUI_Globals.userSettings?.searchSettings?.relationExpandLevel ?? DEFAULT_RELATION_EXPAND_LEVEL;
|
|
137
|
+
const [expandLevel, setExpandLevel] = useState(getInitialExpandLevel);
|
|
138
|
+
const [isAllCollapsed, setIsAllCollapsed] = useState(false);
|
|
146
139
|
const initialExpandAllAppliedRef = React.useRef(false);
|
|
147
140
|
const [showWaitPanel, setShowWaitPanel] = useState(false);
|
|
148
141
|
const [waitPanelTextPrimary, setWaitPanelTextPrimary] = useState('');
|
|
@@ -158,6 +151,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
158
151
|
const lastLoadedInputRef = React.useRef('');
|
|
159
152
|
// State to track loaded input key - triggers re-render for focus selection
|
|
160
153
|
const [loadedInputKey, setLoadedInputKey] = React.useState('');
|
|
154
|
+
// State to track how many GetMetadataAsync calls failed
|
|
155
|
+
const [metadataErrorCount, setMetadataErrorCount] = React.useState(0);
|
|
156
|
+
// State to track total master documents found (used when isForMaster is true)
|
|
157
|
+
const [totalMasterDocuments, setTotalMasterDocuments] = React.useState(0);
|
|
161
158
|
// Ref to track if user has manually expanded/collapsed static items
|
|
162
159
|
const userInteractedWithStaticItemsRef = React.useRef(false);
|
|
163
160
|
// Ref to track the last inputKey for which we set the focused item
|
|
@@ -172,6 +169,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
172
169
|
};
|
|
173
170
|
fetchAllUsers();
|
|
174
171
|
}, []);
|
|
172
|
+
// Notify parent when loading state changes
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
const isLoading = showWaitPanel || showExpansionWaitPanel;
|
|
175
|
+
onLoadingStateChanged?.(isLoading);
|
|
176
|
+
}, [showWaitPanel, showExpansionWaitPanel, onLoadingStateChanged]);
|
|
177
|
+
// Sincronizza expandLevel quando userSettings.searchSettings.relationExpandLevel cambia
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
const globalExpandLevel = SDKUI_Globals.userSettings?.searchSettings?.relationExpandLevel;
|
|
180
|
+
if (globalExpandLevel !== undefined && globalExpandLevel !== expandLevel) {
|
|
181
|
+
setExpandLevel(globalExpandLevel);
|
|
182
|
+
}
|
|
183
|
+
}, [SDKUI_Globals.userSettings?.searchSettings?.relationExpandLevel]);
|
|
175
184
|
/**
|
|
176
185
|
* Generate a stable key from inputDcmts to detect real changes
|
|
177
186
|
*/
|
|
@@ -200,7 +209,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
200
209
|
return [];
|
|
201
210
|
if (!mDID)
|
|
202
211
|
return [];
|
|
203
|
-
|
|
212
|
+
// maxLevel = 0 means unlimited depth (expand as much as possible)
|
|
213
|
+
// maxLevel > 0 means specific depth limit
|
|
214
|
+
// maxLevel < 0 means stop recursion
|
|
215
|
+
if (maxLevel < 0)
|
|
204
216
|
return [];
|
|
205
217
|
const dcmtTypeHasRel = await hasDetailRelations(mTID);
|
|
206
218
|
if (!dcmtTypeHasRel)
|
|
@@ -283,7 +295,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
283
295
|
return [];
|
|
284
296
|
if (!dDID)
|
|
285
297
|
return [];
|
|
286
|
-
|
|
298
|
+
// maxLevel = 0 means unlimited depth (expand as much as possible)
|
|
299
|
+
// maxLevel > 0 means specific depth limit
|
|
300
|
+
// maxLevel < 0 means stop recursion
|
|
301
|
+
if (maxLevel < 0)
|
|
287
302
|
return [];
|
|
288
303
|
const dcmtTypeHasRel = await hasMasterRelations(dTID);
|
|
289
304
|
if (!dcmtTypeHasRel)
|
|
@@ -387,7 +402,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
387
402
|
updatedItems = [
|
|
388
403
|
{
|
|
389
404
|
key: `__info__${node.key}`,
|
|
390
|
-
name:
|
|
405
|
+
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
391
406
|
isContainer: false,
|
|
392
407
|
isDcmt: false,
|
|
393
408
|
isInfoMessage: true,
|
|
@@ -498,6 +513,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
498
513
|
}
|
|
499
514
|
const tree = [];
|
|
500
515
|
let processedCount = 0;
|
|
516
|
+
let errorCount = 0;
|
|
501
517
|
for (const dcmt of inputDcmts) {
|
|
502
518
|
// Check for abort
|
|
503
519
|
if (abortController.signal.aborted) {
|
|
@@ -510,7 +526,24 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
510
526
|
if (!searchEngine)
|
|
511
527
|
continue;
|
|
512
528
|
// Load document metadata
|
|
513
|
-
|
|
529
|
+
let result;
|
|
530
|
+
try {
|
|
531
|
+
result = await searchEngine.GetMetadataAsync(dcmt.TID, dcmt.DID, false);
|
|
532
|
+
}
|
|
533
|
+
catch (metadataError) {
|
|
534
|
+
console.warn('[TMRelationViewer] GetMetadataAsync failed for TID:', dcmt.TID, 'DID:', dcmt.DID, metadataError);
|
|
535
|
+
errorCount++;
|
|
536
|
+
ShowAlert({
|
|
537
|
+
title: SDKUI_Localizator.Warning,
|
|
538
|
+
message: `Il documento (TID: ${dcmt.TID}, DID: ${dcmt.DID}) non esiste più o non è accessibile.`,
|
|
539
|
+
mode: 'warning',
|
|
540
|
+
duration: 5000
|
|
541
|
+
});
|
|
542
|
+
// Skip this document and continue with the next one
|
|
543
|
+
processedCount++;
|
|
544
|
+
setWaitPanelValuePrimary(processedCount);
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
514
547
|
const dtd = await DcmtTypeListCacheService.GetAsync(dcmt.TID);
|
|
515
548
|
// Parse document values
|
|
516
549
|
const docValues = await searchResultToDataSource(result);
|
|
@@ -715,6 +748,24 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
715
748
|
if (hasNoRelations && onNoRelationsFound) {
|
|
716
749
|
onNoRelationsFound();
|
|
717
750
|
}
|
|
751
|
+
// Update metadata error count state
|
|
752
|
+
setMetadataErrorCount(errorCount);
|
|
753
|
+
// Count total master documents (only relevant when isForMaster is true)
|
|
754
|
+
if (isForMaster) {
|
|
755
|
+
const countMasterDocuments = (items) => {
|
|
756
|
+
let count = 0;
|
|
757
|
+
for (const item of items) {
|
|
758
|
+
if (item.isDcmt && !item.isZero) {
|
|
759
|
+
count++;
|
|
760
|
+
}
|
|
761
|
+
if (item.items && Array.isArray(item.items)) {
|
|
762
|
+
count += countMasterDocuments(item.items);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return count;
|
|
766
|
+
};
|
|
767
|
+
setTotalMasterDocuments(countMasterDocuments(tree));
|
|
768
|
+
}
|
|
718
769
|
// FIRST setup initial expansion state (root container expanded, first document expanded with focus, first correlation folder expanded)
|
|
719
770
|
// This must run BEFORE updateHiddenProperty so that infoMessage logic sees expanded=true
|
|
720
771
|
const expandedTree = setupInitialTreeExpansion(tree);
|
|
@@ -905,7 +956,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
905
956
|
return [
|
|
906
957
|
{
|
|
907
958
|
key: `__info__${node.key}`,
|
|
908
|
-
name:
|
|
959
|
+
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
909
960
|
isContainer: false,
|
|
910
961
|
isDcmt: false,
|
|
911
962
|
isInfoMessage: true,
|
|
@@ -934,7 +985,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
934
985
|
return [
|
|
935
986
|
{
|
|
936
987
|
key: `__info__${node.key}`,
|
|
937
|
-
name:
|
|
988
|
+
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
938
989
|
isContainer: false,
|
|
939
990
|
isDcmt: false,
|
|
940
991
|
isInfoMessage: true,
|
|
@@ -989,7 +1040,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
989
1040
|
return [
|
|
990
1041
|
{
|
|
991
1042
|
key: `__info__${node.key}`,
|
|
992
|
-
name:
|
|
1043
|
+
name: SDKUI_Localizator.NoRelatedDocumentsToDisplay,
|
|
993
1044
|
isContainer: false,
|
|
994
1045
|
isDcmt: false,
|
|
995
1046
|
isInfoMessage: true,
|
|
@@ -1084,34 +1135,36 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1084
1135
|
: defaultDocumentStyle;
|
|
1085
1136
|
const textDecoration = isLogicallyDeleted ? 'line-through' : 'none';
|
|
1086
1137
|
const textColor = isLogicallyDeleted ? 'gray' : undefined;
|
|
1087
|
-
const defaultMetadataContent = item.values && (
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1138
|
+
const defaultMetadataContent = item.values && (() => {
|
|
1139
|
+
const displayKeys = buildDcmtDisplayName(item.values);
|
|
1140
|
+
return (_jsx(StyledDivHorizontal, { style: {
|
|
1141
|
+
fontSize: '1rem',
|
|
1142
|
+
overflow: 'hidden',
|
|
1143
|
+
flex: 1,
|
|
1144
|
+
minWidth: 0,
|
|
1145
|
+
whiteSpace: 'nowrap',
|
|
1146
|
+
textDecoration: textDecoration,
|
|
1147
|
+
color: textColor
|
|
1148
|
+
}, children: displayKeys.map((key, index) => {
|
|
1149
|
+
const md = item.values?.[key]?.md;
|
|
1150
|
+
const value = item.values?.[key]?.value;
|
|
1151
|
+
const isLast = index === displayKeys.length - 1;
|
|
1152
|
+
return (_jsxs(StyledDivHorizontal, { style: {
|
|
1153
|
+
flexShrink: isLast ? 1 : 0,
|
|
1154
|
+
minWidth: isLast ? 0 : 'auto',
|
|
1155
|
+
overflow: isLast ? 'hidden' : 'visible',
|
|
1156
|
+
textDecoration: textDecoration,
|
|
1157
|
+
color: textColor
|
|
1158
|
+
}, children: [index > 0 && _jsx("span", { style: { margin: '0 5px', color: textColor || '#999', textDecoration: textDecoration }, children: "\u2022" }), showMetadataNames && (_jsxs("span", { style: { color: textColor || '#666', marginRight: '5px', textDecoration: textDecoration }, children: [md?.name || key, ":"] })), md?.dataDomain === MetadataDataDomains.DataList ? (_jsx("span", { style: { textDecoration: textDecoration, color: textColor }, children: _jsx(TMDataListItemViewer, { dataListId: md.dataListID, viewMode: md.dataListViewMode, value: value }) })) : md?.dataDomain === MetadataDataDomains.UserID ? (_jsx("span", { style: { textDecoration: textDecoration, color: textColor }, children: _jsx(TMDataUserIdItemViewer, { userId: value, showIcon: true }) })) : (_jsx("span", { style: {
|
|
1159
|
+
fontWeight: 500,
|
|
1160
|
+
overflow: isLast ? 'hidden' : 'visible',
|
|
1161
|
+
textOverflow: isLast ? 'ellipsis' : 'clip',
|
|
1162
|
+
whiteSpace: 'nowrap',
|
|
1163
|
+
textDecoration: textDecoration,
|
|
1164
|
+
color: textColor
|
|
1165
|
+
}, children: value }))] }, `${key}_${index}`));
|
|
1166
|
+
}) }));
|
|
1167
|
+
})();
|
|
1115
1168
|
const metadataContent = customDocumentContent
|
|
1116
1169
|
? customDocumentContent(item, defaultMetadataContent || _jsx(_Fragment, {}))
|
|
1117
1170
|
: defaultMetadataContent;
|
|
@@ -1138,7 +1191,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1138
1191
|
checkoutStatusIcon = checkoutStatus.icon;
|
|
1139
1192
|
}
|
|
1140
1193
|
}
|
|
1141
|
-
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] }));
|
|
1194
|
+
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', usePortal: true })), checkoutStatusIcon, metadataContent] }));
|
|
1142
1195
|
}, [onDocumentDoubleClick, showCurrentDcmtIndicator, inputDcmts, customMainContainerContent, customDocumentStyle, customDocumentContent, showMetadataNames, showMainDocument, allUsers]);
|
|
1143
1196
|
/**
|
|
1144
1197
|
* Wrapper renderer that handles custom rendering if provided
|
|
@@ -1184,13 +1237,231 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1184
1237
|
return { ...node, expanded: canExpand ? expanded : node.expanded, items: newItems };
|
|
1185
1238
|
});
|
|
1186
1239
|
}, []);
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1240
|
+
// Collassa l'albero impostando tutti i nodi come non espansi
|
|
1241
|
+
const handleCollapseTree = useCallback(() => {
|
|
1242
|
+
// Funzione helper per collassare ricorsivamente tutti i nodi
|
|
1243
|
+
const collapseAllNodes = (nodes) => {
|
|
1244
|
+
return nodes.map(node => ({
|
|
1245
|
+
...node,
|
|
1246
|
+
expanded: false,
|
|
1247
|
+
items: node.items ? collapseAllNodes(node.items) : node.items
|
|
1248
|
+
}));
|
|
1249
|
+
};
|
|
1250
|
+
// Collassa tutti i nodi dell'albero
|
|
1251
|
+
setTreeData(prevData => collapseAllNodes(prevData));
|
|
1252
|
+
setStaticItemsState(prevData => collapseAllNodes(prevData));
|
|
1253
|
+
setIsAllCollapsed(true);
|
|
1254
|
+
}, []);
|
|
1255
|
+
/**
|
|
1256
|
+
* Espande ricorsivamente l'albero fino a `expandLevel`.
|
|
1257
|
+
* Carica i figli lazy (API) solo se non già in memoria (isLoaded).
|
|
1258
|
+
* Il contatore totalNodes cresce dinamicamente per una % progresso accurata.
|
|
1259
|
+
*
|
|
1260
|
+
* @param forceReload - Se true (Ctrl+click), ricarica tutto ignorando la cache
|
|
1261
|
+
*/
|
|
1262
|
+
const handleExpandToLevel = useCallback(async (forceReload = false) => {
|
|
1263
|
+
// Mostra spinner per feedback immediato all'utente
|
|
1264
|
+
TMSpinner.show({ description: forceReload ? SDKUI_Localizator.FullReloadInProgress : SDKUI_Localizator.ExpansionInProgress });
|
|
1265
|
+
// Piccolo delay per permettere allo spinner di renderizzarsi prima del processing pesante
|
|
1266
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
1267
|
+
/**
|
|
1268
|
+
* Se forceReload è true, prima resettiamo tutti i nodi come se non fossero mai stati caricati.
|
|
1269
|
+
* Questo significa rimuovere isLoaded e items da tutti i nodi documento,
|
|
1270
|
+
* così l'espansione successiva li ricaricherà tutti da API.
|
|
1271
|
+
*/
|
|
1272
|
+
const resetLoadedState = (nodes) => {
|
|
1273
|
+
return nodes.map(node => {
|
|
1274
|
+
const resetNode = { ...node };
|
|
1275
|
+
// Reset isLoaded per forzare il ricaricamento
|
|
1276
|
+
if (resetNode.isDcmt || resetNode.isExpandible) {
|
|
1277
|
+
resetNode.isLoaded = false;
|
|
1278
|
+
// Manteniamo items solo per i container (cartelle),
|
|
1279
|
+
// perché i container non vengono ricaricati via API
|
|
1280
|
+
// I documenti invece devono ricaricare i loro figli (correlazioni)
|
|
1281
|
+
if (resetNode.isDcmt) {
|
|
1282
|
+
resetNode.items = undefined;
|
|
1283
|
+
resetNode.itemsCount = undefined;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
// Reset ricorsivo sui figli
|
|
1287
|
+
if (resetNode.items && Array.isArray(resetNode.items)) {
|
|
1288
|
+
resetNode.items = resetLoadedState(resetNode.items);
|
|
1289
|
+
}
|
|
1290
|
+
return resetNode;
|
|
1291
|
+
});
|
|
1292
|
+
};
|
|
1293
|
+
// Se forceReload, reset dello stato prima di iniziare
|
|
1294
|
+
let workingTreeData = treeData;
|
|
1295
|
+
let workingStaticData = staticItemsState;
|
|
1296
|
+
if (forceReload) {
|
|
1297
|
+
workingTreeData = resetLoadedState(treeData);
|
|
1298
|
+
workingStaticData = resetLoadedState(staticItemsState);
|
|
1299
|
+
// Aggiorna subito lo stato per riflettere il reset
|
|
1300
|
+
setTreeData(workingTreeData);
|
|
1301
|
+
setStaticItemsState(workingStaticData);
|
|
1302
|
+
}
|
|
1303
|
+
const targetLevel = expandLevel;
|
|
1304
|
+
const newAbortController = new AbortController();
|
|
1305
|
+
setExpansionAbortController(newAbortController);
|
|
1306
|
+
// CONTATORI DINAMICI:
|
|
1307
|
+
// - totalNodes: cresce quando scopriamo nuovi nodi (evita che percentuale > 100%)
|
|
1308
|
+
// - processedNodes: quanti nodi abbiamo già processato
|
|
1309
|
+
// - maxReachedProgress: percentuale massima raggiunta (evita che la barra torni indietro)
|
|
1310
|
+
let totalNodes = 0;
|
|
1311
|
+
let processedNodes = 0;
|
|
1312
|
+
let hasApiCalls = false;
|
|
1313
|
+
let maxReachedProgress = 0;
|
|
1314
|
+
/**
|
|
1315
|
+
* Conta i nodi espandibili in un array (solo primo livello, non ricorsivo).
|
|
1316
|
+
* Usato per aggiornare totalNodes man mano che scopriamo nuovi figli.
|
|
1317
|
+
*/
|
|
1318
|
+
const countNodesAtLevel = (nodes) => {
|
|
1319
|
+
let count = 0;
|
|
1320
|
+
for (const node of nodes) {
|
|
1321
|
+
if (node.isContainer || node.isExpandible || node.isDcmt) {
|
|
1322
|
+
count++;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
return count;
|
|
1326
|
+
};
|
|
1327
|
+
// Conta iniziale: solo i nodi al livello root
|
|
1328
|
+
totalNodes = countNodesAtLevel([...workingTreeData, ...workingStaticData]);
|
|
1329
|
+
/**
|
|
1330
|
+
* FUNZIONE RICORSIVA DI ESPANSIONE
|
|
1331
|
+
*
|
|
1332
|
+
* @param nodes - Array di nodi da processare
|
|
1333
|
+
* @param currentLevel - Livello corrente (0 = root)
|
|
1334
|
+
* @returns Array di nodi con expanded=true e figli caricati
|
|
1335
|
+
*
|
|
1336
|
+
* FLUSSO:
|
|
1337
|
+
* 1. Se targetLevel > 0 e currentLevel >= targetLevel → STOP, ritorna i nodi così come sono
|
|
1338
|
+
* (Se targetLevel = 0 → espandi senza limiti, non applicare mai il limite)
|
|
1339
|
+
* 2. Per ogni nodo espandibile:
|
|
1340
|
+
* a) Imposta expanded = true
|
|
1341
|
+
* b) Se i figli non sono caricati → chiama API per caricarli
|
|
1342
|
+
* c) Aggiorna totalNodes con i nuovi figli scoperti
|
|
1343
|
+
* d) CHIAMATA RICORSIVA su expandedNode.items con currentLevel + 1
|
|
1344
|
+
* → QUESTO È IL PUNTO CHIAVE: i nuovi nodi vengono espansi!
|
|
1345
|
+
*/
|
|
1346
|
+
const expandToLevel = async (nodes, currentLevel) => {
|
|
1347
|
+
// CONDIZIONE DI USCITA: abbiamo raggiunto il livello target
|
|
1348
|
+
// targetLevel = 0 significa espandi senza limiti (non applicare mai il limite)
|
|
1349
|
+
// targetLevel > 0 significa applica il limite normalmente
|
|
1350
|
+
if (targetLevel > 0 && currentLevel >= targetLevel)
|
|
1351
|
+
return nodes;
|
|
1352
|
+
// Controlla se l'utente ha annullato l'operazione
|
|
1353
|
+
if (newAbortController.signal.aborted)
|
|
1354
|
+
return nodes;
|
|
1355
|
+
const result = [];
|
|
1356
|
+
for (const node of nodes) {
|
|
1357
|
+
// Controlla abort per ogni nodo (permette cancellazione veloce)
|
|
1358
|
+
if (newAbortController.signal.aborted) {
|
|
1359
|
+
result.push(node);
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
// Crea copia del nodo (immutabilità React)
|
|
1363
|
+
let expandedNode = { ...node };
|
|
1364
|
+
// Verifica se questo nodo può essere espanso
|
|
1365
|
+
const canExpand = node.isContainer || node.isExpandible || node.isDcmt;
|
|
1366
|
+
if (canExpand) {
|
|
1367
|
+
// PASSO 1: Imposta il nodo come espanso
|
|
1368
|
+
expandedNode.expanded = true;
|
|
1369
|
+
// PASSO 2: Verifica se i figli sono già caricati o vanno caricati via API
|
|
1370
|
+
// Se forceReload è true, ricarica sempre (ignora isLoaded e items esistenti)
|
|
1371
|
+
const hasLoadedItems = !forceReload && node.items && Array.isArray(node.items) && node.items.length > 0;
|
|
1372
|
+
const actualHasItems = node.items && Array.isArray(node.items) && node.items.length > 0;
|
|
1373
|
+
const needsLoading = (forceReload || (!hasLoadedItems && !node.isLoaded)) && (node.isExpandible || node.isDcmt);
|
|
1374
|
+
if (needsLoading && node.tid && node.did) {
|
|
1375
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1376
|
+
// CASO A: I figli NON sono in memoria → CHIAMATA API
|
|
1377
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1378
|
+
// Mostra pannello di attesa solo quando ci sono chiamate API
|
|
1379
|
+
if (!hasApiCalls) {
|
|
1380
|
+
hasApiCalls = true;
|
|
1381
|
+
TMSpinner.hide();
|
|
1382
|
+
setShowExpansionWaitPanel(true);
|
|
1383
|
+
setExpansionWaitPanelMaxValue(100);
|
|
1384
|
+
setExpansionWaitPanelValue(0);
|
|
1385
|
+
}
|
|
1386
|
+
try {
|
|
1387
|
+
let loadedItems = [];
|
|
1388
|
+
// Carica i documenti correlati (detail o master in base alla modalità)
|
|
1389
|
+
if (isForMaster && !invertMasterNavigation) {
|
|
1390
|
+
loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
|
|
1391
|
+
}
|
|
1392
|
+
else if (isForMaster) {
|
|
1393
|
+
loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1);
|
|
1394
|
+
}
|
|
1395
|
+
else {
|
|
1396
|
+
loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
|
|
1397
|
+
}
|
|
1398
|
+
// Applica le regole di visibilità (showZeroDcmts)
|
|
1399
|
+
expandedNode.items = updateHiddenProperty(loadedItems);
|
|
1400
|
+
expandedNode.isLoaded = true;
|
|
1401
|
+
expandedNode.itemsCount = loadedItems.length;
|
|
1402
|
+
// IMPORTANTE: Aggiungi i nuovi nodi scoperti al contatore totale
|
|
1403
|
+
// Questo viene fatto SOLO se non siamo all'ultimo livello
|
|
1404
|
+
// (perché i nodi dell'ultimo livello non verranno espansi)
|
|
1405
|
+
// targetLevel = 0 significa illimitato, quindi aggiungi sempre
|
|
1406
|
+
if (targetLevel === 0 || currentLevel + 1 < targetLevel) {
|
|
1407
|
+
const newExpandableCount = countNodesAtLevel(loadedItems);
|
|
1408
|
+
totalNodes += newExpandableCount;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
catch (error) {
|
|
1412
|
+
console.error('Errore nel caricamento dei figli del nodo:', error);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
else if (actualHasItems && (targetLevel === 0 || currentLevel + 1 < targetLevel)) {
|
|
1416
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1417
|
+
// CASO B: I figli esistono già in memoria (non ricaricati via API)
|
|
1418
|
+
// Aggiungiamo comunque il loro conteggio a totalNodes
|
|
1419
|
+
// Usiamo actualHasItems invece di hasLoadedItems per gestire anche forceReload
|
|
1420
|
+
// ═══════════════════════════════════════════════════════════════
|
|
1421
|
+
const childCount = countNodesAtLevel(node.items);
|
|
1422
|
+
totalNodes += childCount;
|
|
1423
|
+
}
|
|
1424
|
+
// Aggiorna il progresso DOPO aver processato questo nodo
|
|
1425
|
+
processedNodes++;
|
|
1426
|
+
// Calcola percentuale e aggiorna solo se è più alta di prima
|
|
1427
|
+
// (evita che la barra di progresso torni indietro)
|
|
1428
|
+
const currentProgress = totalNodes > 0 ? Math.floor((processedNodes / totalNodes) * 100) : 0;
|
|
1429
|
+
if (currentProgress > maxReachedProgress) {
|
|
1430
|
+
maxReachedProgress = currentProgress;
|
|
1431
|
+
setExpansionWaitPanelValue(maxReachedProgress);
|
|
1432
|
+
}
|
|
1433
|
+
setExpansionWaitPanelText(SDKUI_Localizator.ExpansionProgress.replaceParams(processedNodes.toString(), totalNodes.toString()));
|
|
1434
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1435
|
+
// PASSO 3: CHIAMATA RICORSIVA SUI FIGLI
|
|
1436
|
+
// Questo è il punto chiave: i nuovi nodi appena caricati vengono
|
|
1437
|
+
// passati a expandToLevel con currentLevel + 1, quindi anche loro
|
|
1438
|
+
// verranno espansi (se non abbiamo raggiunto il livello target)
|
|
1439
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
1440
|
+
if (expandedNode.items && Array.isArray(expandedNode.items) && expandedNode.items.length > 0) {
|
|
1441
|
+
expandedNode.items = await expandToLevel(expandedNode.items, currentLevel + 1);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
result.push(expandedNode);
|
|
1445
|
+
}
|
|
1446
|
+
return result;
|
|
1447
|
+
};
|
|
1448
|
+
try {
|
|
1449
|
+
// Avvia l'espansione dal livello 0 (root)
|
|
1450
|
+
const expandedTree = await expandToLevel(workingTreeData, 0);
|
|
1451
|
+
setTreeData(expandedTree);
|
|
1452
|
+
// Espandi anche gli item statici (se presenti)
|
|
1453
|
+
const expandedStatic = await expandToLevel(workingStaticData, 0);
|
|
1454
|
+
setStaticItemsState(expandedStatic);
|
|
1455
|
+
setIsAllCollapsed(false);
|
|
1456
|
+
userInteractedWithStaticItemsRef.current = true;
|
|
1457
|
+
}
|
|
1458
|
+
finally {
|
|
1459
|
+
// Cleanup: nascondi spinner e pannello di attesa
|
|
1460
|
+
TMSpinner.hide();
|
|
1461
|
+
setShowExpansionWaitPanel(false);
|
|
1462
|
+
setExpansionAbortController(undefined);
|
|
1463
|
+
}
|
|
1464
|
+
}, [expandLevel, treeData, staticItemsState, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty]);
|
|
1194
1465
|
/**
|
|
1195
1466
|
* Apply defaultExpandAll once on initial tree load.
|
|
1196
1467
|
*/
|
|
@@ -1216,37 +1487,70 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1216
1487
|
setStaticItemsState(staticItems); // Preserve static items state (expanded/collapsed)
|
|
1217
1488
|
// Mark that user has interacted with the tree (expanded/collapsed nodes)
|
|
1218
1489
|
userInteractedWithStaticItemsRef.current = true;
|
|
1490
|
+
// Reset collapsed state when user manually expands a node
|
|
1491
|
+
setIsAllCollapsed(false);
|
|
1219
1492
|
}, []);
|
|
1220
1493
|
if (showWaitPanel) {
|
|
1221
|
-
return _jsx("div", { style: { padding: '20px', textAlign: 'center' }, children: _jsx(TMWaitPanel, { title:
|
|
1494
|
+
return _jsx("div", { style: { padding: '20px', textAlign: 'center' }, children: _jsx(TMWaitPanel, { title: SDKUI_Localizator.LoadingDetailDocuments, showPrimary: true, textPrimary: waitPanelTextPrimary, valuePrimary: waitPanelValuePrimary, maxValuePrimary: waitPanelMaxValuePrimary, isCancelable: true, abortController: abortController, onAbortClick: () => { setTimeout(() => { abortController.abort(); }, 1000); } }) });
|
|
1222
1495
|
}
|
|
1223
1496
|
if (mergedTreeData.length === 0) {
|
|
1497
|
+
// Se NON isForMaster e tutti i GetMetadataAsync sono falliti
|
|
1498
|
+
if (!isForMaster && metadataErrorCount === inputDcmts.length) {
|
|
1499
|
+
return _jsx(TMToppyMessage, { message: SDKUI_Localizator.DocumentsNotAvailableOrNoCorrelations });
|
|
1500
|
+
}
|
|
1224
1501
|
// If parent handles no-relations via callback, render nothing to avoid UI flash
|
|
1225
1502
|
if (onNoRelationsFound)
|
|
1226
1503
|
return null;
|
|
1227
|
-
return _jsx("div", { style: { padding: '20px', textAlign: 'center', color: '#666' }, children:
|
|
1504
|
+
return _jsx("div", { style: { padding: '20px', textAlign: 'center', color: '#666' }, children: SDKUI_Localizator.NoRelationsAvailable });
|
|
1505
|
+
}
|
|
1506
|
+
// Se isForMaster e non ci sono master documents disponibili
|
|
1507
|
+
if (isForMaster && totalMasterDocuments === 0) {
|
|
1508
|
+
return _jsx(TMToppyMessage, { message: SDKUI_Localizator.NoMasterDocumentsAvailable });
|
|
1228
1509
|
}
|
|
1229
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0, width: '100%' }, children: [showExpandAllButton && (
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1510
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0, width: '100%' }, children: [showExpandAllButton && (_jsxs("div", { style: { flexShrink: 0, display: 'flex', alignItems: 'center', gap: '6px', height: '40px', paddingLeft: '10px', backgroundColor: TMColors.toolbar_background }, children: [_jsx(TMTooltip, { content: expandLevel === 0
|
|
1511
|
+
? `${SDKUI_Localizator.ExpandAllLevels} (${SDKUI_Localizator.CtrlClickToReloadAll})`
|
|
1512
|
+
: `${SDKUI_Localizator.ExpandToLevel.replaceParams(expandLevel.toString())} (${SDKUI_Localizator.CtrlClickToReloadAll})`, children: _jsxs("button", { type: "button", onClick: (e) => handleExpandToLevel(e.ctrlKey), style: {
|
|
1513
|
+
display: 'inline-flex',
|
|
1514
|
+
alignItems: 'center',
|
|
1515
|
+
justifyContent: 'center',
|
|
1516
|
+
gap: '5px',
|
|
1517
|
+
height: '28px',
|
|
1518
|
+
padding: '0 10px',
|
|
1519
|
+
fontSize: '0.8rem',
|
|
1520
|
+
fontWeight: 500,
|
|
1521
|
+
color: 'white',
|
|
1522
|
+
background: TMColors.primary,
|
|
1523
|
+
border: 'none',
|
|
1524
|
+
borderRadius: '4px',
|
|
1525
|
+
cursor: 'pointer',
|
|
1526
|
+
whiteSpace: 'nowrap',
|
|
1527
|
+
outline: 'none',
|
|
1528
|
+
transition: 'background 0.2s'
|
|
1529
|
+
}, children: [_jsx(IconChevronDown, { fontSize: 14 }), _jsx("span", { children: expandLevel === 0 ? SDKUI_Localizator.ExpandAllLevels : SDKUI_Localizator.ExpandLevels.replaceParams(expandLevel.toString()) })] }) }), _jsx(TMTooltip, { content: SDKUI_Localizator.CollapseTree, children: _jsxs("button", { type: "button", onClick: handleCollapseTree, disabled: isAllCollapsed, style: {
|
|
1530
|
+
display: 'inline-flex',
|
|
1531
|
+
alignItems: 'center',
|
|
1532
|
+
justifyContent: 'center',
|
|
1533
|
+
gap: '5px',
|
|
1534
|
+
height: '28px',
|
|
1535
|
+
padding: '0 10px',
|
|
1536
|
+
fontSize: '0.8rem',
|
|
1537
|
+
fontWeight: 500,
|
|
1538
|
+
color: isAllCollapsed ? '#999' : 'white',
|
|
1539
|
+
background: isAllCollapsed ? '#e0e0e0' : TMColors.secondary || '#6c757d',
|
|
1540
|
+
border: 'none',
|
|
1541
|
+
borderRadius: '4px',
|
|
1542
|
+
cursor: isAllCollapsed ? 'not-allowed' : 'pointer',
|
|
1543
|
+
whiteSpace: 'nowrap',
|
|
1544
|
+
outline: 'none',
|
|
1545
|
+
transition: 'background 0.2s'
|
|
1546
|
+
}, 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: showExpansionWaitPanel ? undefined : onItemContextMenu, enableVirtualization: true, shouldDelayFocusOnEvent: (node, e) => {
|
|
1243
1547
|
// Ritarda il focus quando si clicca sull'icona del documento
|
|
1244
1548
|
// per permettere al doppio click di funzionare
|
|
1245
1549
|
const target = e.target;
|
|
1246
1550
|
return !!target.closest('.tm-dcmt-icon');
|
|
1247
|
-
} }) }), showExpansionWaitPanel && (_jsx(TMWaitPanel, { title: isForMaster ?
|
|
1551
|
+
} }) }), showExpansionWaitPanel && (_jsx(TMWaitPanel, { title: isForMaster ? SDKUI_Localizator.LoadingMasterDocuments : SDKUI_Localizator.LoadingDetailDocuments, showPrimary: true, textPrimary: expansionWaitPanelText, valuePrimary: expansionWaitPanelValue, maxValuePrimary: expansionWaitPanelMaxValue, isCancelable: true, abortController: expansionAbortController, onAbortClick: () => {
|
|
1248
1552
|
setTimeout(() => {
|
|
1249
|
-
|
|
1553
|
+
expansionAbortController?.abort();
|
|
1250
1554
|
}, 100);
|
|
1251
1555
|
} }))] }));
|
|
1252
1556
|
};
|