@topconsultnpm/sdkui-react 6.21.0-dev4.15 → 6.21.0-dev4.17
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/TMFileUploader.js +1 -1
- package/lib/components/features/documents/TMMasterDetailDcmts.js +47 -10
- package/lib/components/features/documents/TMRelationViewer.d.ts +10 -1
- package/lib/components/features/documents/TMRelationViewer.js +296 -30
- package/lib/helper/SDKUI_Globals.d.ts +1 -0
- package/lib/helper/SDKUI_Globals.js +1 -0
- package/lib/helper/SDKUI_Localizator.d.ts +16 -0
- package/lib/helper/SDKUI_Localizator.js +160 -0
- package/lib/helper/helpers.js +9 -0
- package/package.json +2 -1
|
@@ -1,16 +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
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 } from '../../../helper';
|
|
4
|
+
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals } from '../../../helper';
|
|
5
5
|
import ShowAlert from '../../base/TMAlert';
|
|
6
6
|
import TMToppyMessage from '../../../helper/TMToppyMessage';
|
|
7
7
|
import { TMColors } from '../../../utils/theme';
|
|
8
|
-
import { StyledDivHorizontal, StyledBadge
|
|
8
|
+
import { StyledDivHorizontal, StyledBadge } from '../../base/Styled';
|
|
9
9
|
import TMTreeView from '../../base/TMTreeView';
|
|
10
10
|
import { TMWaitPanel } from '../../base/TMWaitPanel';
|
|
11
11
|
import TMDataListItemViewer from '../../viewers/TMDataListItemViewer';
|
|
12
12
|
import TMDcmtIcon from './TMDcmtIcon';
|
|
13
13
|
import TMDataUserIdItemViewer from '../../viewers/TMDataUserIdItemViewer';
|
|
14
|
+
import TMTooltip from '../../base/TMTooltip';
|
|
15
|
+
import TMSpinner from '../../base/TMSpinner';
|
|
14
16
|
/**
|
|
15
17
|
* Check if document type has detail relations
|
|
16
18
|
*/
|
|
@@ -124,13 +126,16 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
|
|
|
124
126
|
}
|
|
125
127
|
return output;
|
|
126
128
|
};
|
|
127
|
-
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 }) => {
|
|
128
131
|
// State
|
|
129
132
|
const [dcmtTypes, setDcmtTypes] = useState([]);
|
|
130
133
|
const [treeData, setTreeData] = useState([]);
|
|
131
134
|
const [showZeroDcmts, setShowZeroDcmts] = useState(initialShowZeroDcmts);
|
|
132
135
|
const [staticItemsState, setStaticItemsState] = useState([]);
|
|
133
|
-
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);
|
|
134
139
|
const initialExpandAllAppliedRef = React.useRef(false);
|
|
135
140
|
const [showWaitPanel, setShowWaitPanel] = useState(false);
|
|
136
141
|
const [waitPanelTextPrimary, setWaitPanelTextPrimary] = useState('');
|
|
@@ -164,6 +169,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
164
169
|
};
|
|
165
170
|
fetchAllUsers();
|
|
166
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]);
|
|
167
184
|
/**
|
|
168
185
|
* Generate a stable key from inputDcmts to detect real changes
|
|
169
186
|
*/
|
|
@@ -192,7 +209,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
192
209
|
return [];
|
|
193
210
|
if (!mDID)
|
|
194
211
|
return [];
|
|
195
|
-
|
|
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)
|
|
196
216
|
return [];
|
|
197
217
|
const dcmtTypeHasRel = await hasDetailRelations(mTID);
|
|
198
218
|
if (!dcmtTypeHasRel)
|
|
@@ -275,7 +295,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
275
295
|
return [];
|
|
276
296
|
if (!dDID)
|
|
277
297
|
return [];
|
|
278
|
-
|
|
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)
|
|
279
302
|
return [];
|
|
280
303
|
const dcmtTypeHasRel = await hasMasterRelations(dTID);
|
|
281
304
|
if (!dcmtTypeHasRel)
|
|
@@ -1214,13 +1237,231 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1214
1237
|
return { ...node, expanded: canExpand ? expanded : node.expanded, items: newItems };
|
|
1215
1238
|
});
|
|
1216
1239
|
}, []);
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
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]);
|
|
1224
1465
|
/**
|
|
1225
1466
|
* Apply defaultExpandAll once on initial tree load.
|
|
1226
1467
|
*/
|
|
@@ -1246,9 +1487,11 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1246
1487
|
setStaticItemsState(staticItems); // Preserve static items state (expanded/collapsed)
|
|
1247
1488
|
// Mark that user has interacted with the tree (expanded/collapsed nodes)
|
|
1248
1489
|
userInteractedWithStaticItemsRef.current = true;
|
|
1490
|
+
// Reset collapsed state when user manually expands a node
|
|
1491
|
+
setIsAllCollapsed(false);
|
|
1249
1492
|
}, []);
|
|
1250
1493
|
if (showWaitPanel) {
|
|
1251
|
-
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); } }) });
|
|
1252
1495
|
}
|
|
1253
1496
|
if (mergedTreeData.length === 0) {
|
|
1254
1497
|
// Se NON isForMaster e tutti i GetMetadataAsync sono falliti
|
|
@@ -1264,27 +1507,50 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
1264
1507
|
if (isForMaster && totalMasterDocuments === 0) {
|
|
1265
1508
|
return _jsx(TMToppyMessage, { message: SDKUI_Localizator.NoMasterDocumentsAvailable });
|
|
1266
1509
|
}
|
|
1267
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0, width: '100%' }, children: [showExpandAllButton && (
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
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) => {
|
|
1281
1547
|
// Ritarda il focus quando si clicca sull'icona del documento
|
|
1282
1548
|
// per permettere al doppio click di funzionare
|
|
1283
1549
|
const target = e.target;
|
|
1284
1550
|
return !!target.closest('.tm-dcmt-icon');
|
|
1285
|
-
} }) }), 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: () => {
|
|
1286
1552
|
setTimeout(() => {
|
|
1287
|
-
|
|
1553
|
+
expansionAbortController?.abort();
|
|
1288
1554
|
}, 100);
|
|
1289
1555
|
} }))] }));
|
|
1290
1556
|
};
|
|
@@ -122,6 +122,7 @@ export class SearchSettings {
|
|
|
122
122
|
this.maxDcmtsToBeReturned = DEFAULT_MAX_DCMTS_TO_BE_RETURNED;
|
|
123
123
|
this.floatingMenuBar = new FloatingMenuBarSettings();
|
|
124
124
|
this.panelLayout = {};
|
|
125
|
+
this.relationExpandLevel = 4; // Livello di espansione predefinito per le correlazioni
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
export class FloatingMenuBarSettings {
|
|
@@ -110,7 +110,9 @@ export declare class SDKUI_Localizator {
|
|
|
110
110
|
static get Close(): "Ausgang" | "Close" | "Salida" | "Sortie" | "Saída" | "Chiudi";
|
|
111
111
|
static get Closed(): "Geschlossen" | "Closed" | "Cerrada" | "Fermée" | "Fechada" | "Chiusa";
|
|
112
112
|
static get CloseTask(): string;
|
|
113
|
+
static get Collapse(): "Reduzieren" | "Collapse" | "Contraer" | "Réduire" | "Recolher" | "Comprimi";
|
|
113
114
|
static get CollapseAll(): "Alle reduzieren" | "Collapse all" | "Contraer todo" | "Tout réduire" | "Recolher tudo" | "Comprimi tutto";
|
|
115
|
+
static get CollapseTree(): "Gesamten Baum reduzieren" | "Collapse entire tree" | "Contraer todo el árbol" | "Réduire tout l'arbre" | "Recolher toda a árvore" | "Comprimi tutto l'albero";
|
|
114
116
|
static get Columns_All_Hide(): "Alle Spalten ausblenden" | "Hide all columns" | "Ocultar todas las columnas" | "Masquer toutes les colonnes" | "Ocultar todas as colunas" | "Nascondi tutte le colonne";
|
|
115
117
|
static get Columns_All_Show(): "Alle Spalten anzeigen" | "Show all columns" | "Mostrar todas las columnas" | "Afficher toutes les colonnes" | "Mostrar todas as colunas" | "Visualizza tutte le colonne";
|
|
116
118
|
static get Comment(): string;
|
|
@@ -273,6 +275,17 @@ export declare class SDKUI_Localizator {
|
|
|
273
275
|
static get ExtractedOn(): "Ausgezogen am" | "Extracted on" | "Extraído el" | "Extrait le" | "Extraído em" | "Estratto il";
|
|
274
276
|
static get EvaluateResult(): "Bewerten Sie das Ergebnis" | "Evaluate result" | "Valorar el resultado" | "Évalue les résultats" | "Avalia os resultados" | "Valuta il risultato";
|
|
275
277
|
static get ExpandAll(): "Alle erweitern" | "Expand all" | "Expandir todo" | "Tout développer" | "Expandir tudo" | "Espandi tutto";
|
|
278
|
+
static get ExpandLevels(): "Erweitern ({{0}} Ebenen)" | "Expand ({{0}} levels)" | "Expandir ({{0}} niveles)" | "Développer ({{0}} niveaux)" | "Expandir ({{0}} níveis)" | "Espandi ({{0}} livelli)";
|
|
279
|
+
static get ExpandAllLevels(): "Erweitern (alle Ebenen)" | "Expand (all levels)" | "Expandir (todos los niveles)" | "Développer (tous les niveaux)" | "Expandir (todos os níveis)" | "Espandi (tutti i livelli)";
|
|
280
|
+
static get CtrlClickToReloadAll(): "Strg+Klick = alles neu laden" | "Ctrl+click = reload all" | "Ctrl+clic = recargar todo" | "Ctrl+clic = tout recharger" | "Ctrl+clique = recarregar tudo" | "Ctrl+click = ricarica tutto";
|
|
281
|
+
static get ExpandComplete(): "Erweiterung abgeschlossen" | "Expand complete" | "Expansión completada" | "Expansion terminée" | "Expansão concluída" | "Espansione completata";
|
|
282
|
+
static get ExpandToLevel(): "Erweitern bis Ebene {{0}}" | "Expand to level {{0}}" | "Expandir hasta el nivel {{0}}" | "Développer jusqu'au niveau {{0}}" | "Expandir até o nível {{0}}" | "Espandi fino al livello {{0}}";
|
|
283
|
+
static get ExpansionLevel(): "Erweiterungsebene" | "Expansion level" | "Nivel de expansión" | "Niveau d'expansion" | "Nível de expansão" | "Livello di espansione";
|
|
284
|
+
static get ExpansionLevelSettings(): "Erweiterungsebene Einstellungen" | "Expansion level settings" | "Configuración del nivel de expansión" | "Paramètres du niveau d'expansion" | "Configurações do nível de expansão" | "Impostazioni livello espansione";
|
|
285
|
+
static get ExpansionSettings(): "Erweiterungseinstellungen" | "Expansion settings" | "Configuración de expansión" | "Paramètres d'expansion" | "Configurações de expansão" | "Impostazioni espansione";
|
|
286
|
+
static get ExpansionInProgress(): "Erweiterung läuft..." | "Expansion in progress..." | "Expansión en curso..." | "Expansion en cours..." | "Expansão em andamento..." | "Espansione in corso...";
|
|
287
|
+
static get FullReloadInProgress(): "Vollständiges Neuladen läuft..." | "Full reload in progress..." | "Recarga completa en curso..." | "Rechargement complet en cours..." | "Recarregamento completo em andamento..." | "Ricaricamento completo in corso...";
|
|
288
|
+
static get ExpansionProgress(): "Erweiterung {{0}} von {{1}}..." | "Expansion {{0}} of {{1}}..." | "Expansión {{0}} de {{1}}..." | "Expansion {{0}} sur {{1}}..." | "Expansão {{0}} de {{1}}..." | "Espansione {{0}} di {{1}}...";
|
|
276
289
|
static get Expected(): "Erwartet" | "Expected" | "Esperado" | "Attendu" | "Atteso";
|
|
277
290
|
static get Expiration(): "Ablaufdatum" | "Expiration" | "Fecha de expiración" | "Date d'expiration" | "Data de expiração" | "Scadenza";
|
|
278
291
|
static get ExpirationDate(): "Ablaufdatum" | "Expiration date" | "Fecha de vencimiento" | "Date d'échéance" | "Data de validade" | "Data di scadenza";
|
|
@@ -422,7 +435,10 @@ export declare class SDKUI_Localizator {
|
|
|
422
435
|
static get List(): "Liste" | "List" | "Lista";
|
|
423
436
|
static get List_Hide(): "Liste ausblenden" | "Hide list" | "Ocultar lista" | "Masquer la liste" | "Nascondi la lista";
|
|
424
437
|
static get List_Show(): "liste anzeigen" | "Show list" | "Ver lista" | "Afficher la liste" | "Visualizza la lista";
|
|
438
|
+
static get Levels(): "Ebenen" | "Levels" | "Niveles" | "Niveaux" | "Níveis" | "Livelli";
|
|
425
439
|
static get Loading(): "Laden" | "Loading" | "Carga" | "Chargement" | "Caricamento";
|
|
440
|
+
static get LoadingDetailDocuments(): "Laden der Detaildokumente" | "Loading detail documents" | "Cargando documentos de detalle" | "Chargement des documents de détail" | "Carregando documentos de detalhe" | "Caricamento documenti dettaglio";
|
|
441
|
+
static get LoadingMasterDocuments(): "Laden der Masterdokumente" | "Loading master documents" | "Cargando documentos maestros" | "Chargement des documents maîtres" | "Carregando documentos mestres" | "Caricamento documenti master";
|
|
426
442
|
static get Localization(): "Lokalisierung" | "Localization" | "Localización" | "Localisation" | "Localização" | "Localizzazione";
|
|
427
443
|
static get LoadingWorkGroups(): string;
|
|
428
444
|
static get LoadingParticipants(): string;
|