@topconsultnpm/sdkui-react 6.20.0-dev2.47 → 6.20.0-dev2.49
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 +3 -1
- package/lib/components/base/TMTreeView.js +63 -20
- package/lib/components/features/documents/TMMasterDetailDcmts.js +66 -5
- package/lib/components/features/documents/TMRelationViewer.d.ts +7 -1
- package/lib/components/features/documents/TMRelationViewer.js +389 -76
- package/lib/components/features/tasks/TMTaskFormUtils.js +5 -5
- package/lib/helper/SDKUI_Localizator.d.ts +3 -0
- package/lib/helper/SDKUI_Localizator.js +30 -0
- package/package.json +1 -1
|
@@ -6,8 +6,9 @@ export interface ITMTreeItem {
|
|
|
6
6
|
hidden?: boolean;
|
|
7
7
|
isLoaded?: boolean;
|
|
8
8
|
isContainer: boolean;
|
|
9
|
+
isExpandible?: boolean;
|
|
9
10
|
items?: ITMTreeItem[];
|
|
10
|
-
|
|
11
|
+
currentPage?: number;
|
|
11
12
|
totalItemsCount?: number;
|
|
12
13
|
}
|
|
13
14
|
interface ITMTreeViewProps<T extends ITMTreeItem> {
|
|
@@ -31,3 +32,4 @@ export default TMTreeView;
|
|
|
31
32
|
export declare const StyledTreeNode: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
|
|
32
33
|
$isSelected?: boolean;
|
|
33
34
|
}>> & string;
|
|
35
|
+
export declare const StyledStickyPaginator: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
|
|
@@ -85,7 +85,9 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
|
|
|
85
85
|
let newItems = node.items;
|
|
86
86
|
// Solo se calculateItemsForNode è definito E (ctrl è premuto O non è già caricato)
|
|
87
87
|
if (calculateItemsForNode && (ctrlKey || !node.isLoaded)) {
|
|
88
|
-
|
|
88
|
+
// Se ctrl è premuto, passa un nodo con isLoaded resettato per forzare il refresh
|
|
89
|
+
const nodeForCalculation = ctrlKey ? { ...node, isLoaded: false } : node;
|
|
90
|
+
newItems = await calculateItemsForNode(nodeForCalculation);
|
|
89
91
|
const updatedNode = { ...node, expanded: true, items: newItems, isLoaded: true };
|
|
90
92
|
onNodeUpdate?.(updatedNode);
|
|
91
93
|
return updatedNode;
|
|
@@ -274,53 +276,62 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
|
|
|
274
276
|
return childKeys.every(key => selectedChildKeys.includes(key));
|
|
275
277
|
};
|
|
276
278
|
const hasVisibleItems = (node) => {
|
|
279
|
+
// If node has explicit isExpandible value, use that
|
|
280
|
+
if (node.isExpandible !== undefined) {
|
|
281
|
+
return node.isExpandible;
|
|
282
|
+
}
|
|
283
|
+
// Fallback: check if node has visible items
|
|
277
284
|
if (!node.items)
|
|
278
285
|
return false;
|
|
279
286
|
if (node.items.length <= 0)
|
|
280
287
|
return false;
|
|
281
288
|
return node.items.filter(o => !o.hidden).length > 0;
|
|
282
289
|
};
|
|
283
|
-
// Gestisce il
|
|
284
|
-
const
|
|
285
|
-
const
|
|
290
|
+
// Gestisce il cambio di pagina per un nodo
|
|
291
|
+
const handlePageChange = useCallback((nodeKey, newPage) => {
|
|
292
|
+
const updateNodePage = (nodes) => {
|
|
286
293
|
return nodes.map(node => {
|
|
287
294
|
if (node.key === nodeKey) {
|
|
288
|
-
const
|
|
289
|
-
const newVisible = Math.min(currentVisible + itemsPerPage, node.totalItemsCount ?? node.items?.length ?? 0);
|
|
290
|
-
const updatedNode = { ...node, visibleItemsCount: newVisible };
|
|
295
|
+
const updatedNode = { ...node, currentPage: newPage };
|
|
291
296
|
onNodeUpdate?.(updatedNode);
|
|
292
297
|
return updatedNode;
|
|
293
298
|
}
|
|
294
299
|
if (node.items) {
|
|
295
|
-
return { ...node, items:
|
|
300
|
+
return { ...node, items: updateNodePage(node.items) };
|
|
296
301
|
}
|
|
297
302
|
return node;
|
|
298
303
|
});
|
|
299
304
|
};
|
|
300
|
-
const updatedData =
|
|
305
|
+
const updatedData = updateNodePage(dataSource);
|
|
301
306
|
onDataChanged?.(updatedData);
|
|
302
|
-
}, [dataSource,
|
|
307
|
+
}, [dataSource, onDataChanged, onNodeUpdate]);
|
|
303
308
|
// Filtra gli items da mostrare in base alla paginazione
|
|
304
309
|
const getVisibleItems = useCallback((node) => {
|
|
305
310
|
if (!node.items)
|
|
306
311
|
return [];
|
|
307
312
|
const totalItems = node.items.length;
|
|
308
|
-
const visibleCount = node.visibleItemsCount ?? itemsPerPage;
|
|
309
313
|
// Se non c'è paginazione attiva o gli items sono pochi, mostra tutti
|
|
310
314
|
if (totalItems <= itemsPerPage || !showLoadMoreButton) {
|
|
311
315
|
return node.items;
|
|
312
316
|
}
|
|
313
|
-
// Altrimenti mostra solo
|
|
314
|
-
|
|
317
|
+
// Altrimenti mostra solo gli items della pagina corrente
|
|
318
|
+
const currentPage = node.currentPage ?? 0;
|
|
319
|
+
const startIndex = currentPage * itemsPerPage;
|
|
320
|
+
const endIndex = startIndex + itemsPerPage;
|
|
321
|
+
return node.items.slice(startIndex, endIndex);
|
|
315
322
|
}, [itemsPerPage, showLoadMoreButton]);
|
|
316
|
-
// Verifica se c'è bisogno del
|
|
317
|
-
const
|
|
323
|
+
// Verifica se c'è bisogno del paginatore
|
|
324
|
+
const needsPagination = useCallback((node) => {
|
|
318
325
|
if (!showLoadMoreButton || !node.items)
|
|
319
326
|
return false;
|
|
320
|
-
|
|
321
|
-
const visibleCount = node.visibleItemsCount ?? itemsPerPage;
|
|
322
|
-
return totalItems > itemsPerPage && visibleCount < totalItems;
|
|
327
|
+
return node.items.length > itemsPerPage;
|
|
323
328
|
}, [itemsPerPage, showLoadMoreButton]);
|
|
329
|
+
// Calcola il numero totale di pagine per un nodo
|
|
330
|
+
const getTotalPages = useCallback((node) => {
|
|
331
|
+
if (!node.items)
|
|
332
|
+
return 0;
|
|
333
|
+
return Math.ceil(node.items.length / itemsPerPage);
|
|
334
|
+
}, [itemsPerPage]);
|
|
324
335
|
const renderTree = useCallback((nodes) => {
|
|
325
336
|
return nodes.map(node => !node.hidden && (_jsxs("div", { style: { width: '100%', margin: 0, padding: 0 }, children: [_jsxs(StyledTreeNode, { "$isSelected": node.key === focusedItem?.key, children: [_jsx("div", { style: {
|
|
326
337
|
display: 'flex',
|
|
@@ -339,8 +350,8 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
|
|
|
339
350
|
if (input) {
|
|
340
351
|
input.indeterminate = isIndeterminate(node);
|
|
341
352
|
}
|
|
342
|
-
} })), _jsx("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, onClick: (e) => { handleNodeClick(node, e); }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: '100%' }, children: [renderTree(getVisibleItems(node)),
|
|
343
|
-
}, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems,
|
|
353
|
+
} })), _jsx("div", { style: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0 }, onClick: (e) => { handleNodeClick(node, e); }, children: itemRender(node) })] }), node.expanded && node.items && (_jsxs("div", { style: { paddingLeft: 20, width: '100%' }, children: [renderTree(getVisibleItems(node)), needsPagination(node) && (_jsxs(StyledStickyPaginator, { children: [_jsx(TMButton, { onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) - 1), showTooltip: false, caption: "\u25C4", disabled: (node.currentPage ?? 0) <= 0 }), _jsxs("span", { style: { fontSize: '12px', whiteSpace: 'nowrap', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', minWidth: 0 }, children: ["Pagina ", (node.currentPage ?? 0) + 1, " di ", getTotalPages(node), " (", node.items?.length ?? 0, " elementi)"] }), _jsx(TMButton, { onClick: () => handlePageChange(node.key, (node.currentPage ?? 0) + 1), showTooltip: false, caption: "\u25BA", disabled: (node.currentPage ?? 0) >= getTotalPages(node) - 1 })] }))] }))] }, node.key)));
|
|
354
|
+
}, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsPagination, handlePageChange, getTotalPages]);
|
|
344
355
|
return (_jsx("div", { style: { height: '100%', width: '100%', overflowY: 'auto', overflowX: 'hidden', padding: '0px 5px 2px 2px' }, children: renderTree(dataSource) }));
|
|
345
356
|
};
|
|
346
357
|
export default TMTreeView;
|
|
@@ -361,3 +372,35 @@ export const StyledTreeNode = styled.div `
|
|
|
361
372
|
background: ${() => `oklch(from var(--dx-color-primary) l c h / .1)`};
|
|
362
373
|
}
|
|
363
374
|
`;
|
|
375
|
+
export const StyledStickyPaginator = styled.div `
|
|
376
|
+
position: sticky;
|
|
377
|
+
bottom: 0;
|
|
378
|
+
display: flex;
|
|
379
|
+
align-items: center;
|
|
380
|
+
justify-content: center;
|
|
381
|
+
gap: 8px;
|
|
382
|
+
margin: 8px 0;
|
|
383
|
+
padding: 8px 12px;
|
|
384
|
+
background: oklch(from var(--dx-color-primary) l c h / .85);
|
|
385
|
+
border: 1px solid oklch(from var(--dx-color-primary) l c h / .9);
|
|
386
|
+
border-radius: 6px;
|
|
387
|
+
box-shadow: 0 -2px 8px oklch(from var(--dx-color-primary) l c h / .15);
|
|
388
|
+
transition: all 0.2s ease;
|
|
389
|
+
min-width: 0;
|
|
390
|
+
z-index: 10;
|
|
391
|
+
|
|
392
|
+
& > button {
|
|
393
|
+
flex-shrink: 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
& > span {
|
|
397
|
+
flex: 1 1 auto;
|
|
398
|
+
min-width: 0;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
&:hover {
|
|
402
|
+
background: oklch(from var(--dx-color-primary) l c h / .95);
|
|
403
|
+
border-color: oklch(from var(--dx-color-primary) l c h / 1);
|
|
404
|
+
box-shadow: 0 -2px 12px oklch(from var(--dx-color-primary) l c h / .2);
|
|
405
|
+
}
|
|
406
|
+
`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { DcmtTypeListCacheService, SDK_Localizator } from '@topconsultnpm/sdk-ts';
|
|
4
|
+
import styled from 'styled-components';
|
|
4
5
|
import TMRelationViewer from './TMRelationViewer';
|
|
5
6
|
import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
|
|
6
7
|
import { genUniqueId, IconMultipleSelection, IconCheckFile, IconDetailDcmts, SDKUI_Localizator, IconMail, IconDcmtTypeOnlyMetadata, IconCopy, IconMenuVertical, IconDataList, IconPreview, IconSearchCheck, IconBoard, IconDcmtTypeSys, IconShow, getMoreInfoTasksForDocument } from '../../../helper';
|
|
@@ -14,6 +15,44 @@ import { TMPanelManagerProvider, useTMPanelManagerContext } from '../../layout/p
|
|
|
14
15
|
import TMSearchResult from '../search/TMSearchResult';
|
|
15
16
|
import TMDcmtForm from './TMDcmtForm';
|
|
16
17
|
import { TMNothingToShow } from './TMDcmtPreview';
|
|
18
|
+
import TMButton from '../../base/TMButton';
|
|
19
|
+
const StyledNoRelationsOverlay = styled.div `
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
position: fixed;
|
|
23
|
+
top: 0;
|
|
24
|
+
left: 0;
|
|
25
|
+
z-index: 1501;
|
|
26
|
+
overflow: visible;
|
|
27
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
28
|
+
backdrop-filter: blur(8px);
|
|
29
|
+
`;
|
|
30
|
+
const StyledNoRelationsPanel = styled.div `
|
|
31
|
+
position: absolute;
|
|
32
|
+
top: 50%;
|
|
33
|
+
left: 50%;
|
|
34
|
+
transform: translate(-50%, -50%);
|
|
35
|
+
width: 400px;
|
|
36
|
+
background: white;
|
|
37
|
+
border-radius: 8px;
|
|
38
|
+
padding: 20px;
|
|
39
|
+
text-align: center;
|
|
40
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
41
|
+
display: flex;
|
|
42
|
+
flex-direction: column;
|
|
43
|
+
align-items: center;
|
|
44
|
+
`;
|
|
45
|
+
const StyledNoRelationsTitle = styled.h2 `
|
|
46
|
+
margin: 0 0 20px 0;
|
|
47
|
+
font-size: 1.3em;
|
|
48
|
+
color: #333;
|
|
49
|
+
`;
|
|
50
|
+
const StyledNoRelationsMessage = styled.p `
|
|
51
|
+
color: #666;
|
|
52
|
+
font-size: 1em;
|
|
53
|
+
margin: 0 0 25px 0;
|
|
54
|
+
line-height: 1.4;
|
|
55
|
+
`;
|
|
17
56
|
const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, deviceType, inputDcmts, isForMaster, showCurrentDcmtIndicator = true, allowNavigation, canNext, canPrev, onNext, onPrev, onBack, appendMasterDcmts, onTaskCreateRequest }) => {
|
|
18
57
|
const [id, setID] = useState('');
|
|
19
58
|
const [focusedItem, setFocusedItem] = useState();
|
|
@@ -21,6 +60,10 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
|
|
|
21
60
|
const [showZeroDcmts, setShowZeroDcmts] = useState(false);
|
|
22
61
|
const [allowMultipleSelection, setAllowMultipleSelection] = useState(false);
|
|
23
62
|
const [dtdMaster, setDtdMaster] = useState();
|
|
63
|
+
const [showNoRelationsModal, setShowNoRelationsModal] = useState(false);
|
|
64
|
+
const [shouldGoBackOnClose, setShouldGoBackOnClose] = useState(false);
|
|
65
|
+
// Ref to track if this is the first load (vs navigation with onPrev/onNext)
|
|
66
|
+
const isFirstLoadRef = useRef(true);
|
|
24
67
|
useEffect(() => { setID(genUniqueId()); }, []);
|
|
25
68
|
// Load dtdMaster when inputDcmts changes
|
|
26
69
|
useEffect(() => {
|
|
@@ -40,10 +83,23 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
|
|
|
40
83
|
}, [inputDcmts?.length, inputDcmts?.[0]?.TID, isForMaster]);
|
|
41
84
|
const handleFocusedItemChanged = useCallback((item) => {
|
|
42
85
|
setFocusedItem(item);
|
|
86
|
+
// When data is loaded and an item is focused, mark as no longer first load
|
|
87
|
+
if (item) {
|
|
88
|
+
isFirstLoadRef.current = false;
|
|
89
|
+
}
|
|
43
90
|
}, []);
|
|
44
91
|
const handleSelectedItemsChanged = useCallback((items) => {
|
|
45
92
|
setSelectedItems(items);
|
|
46
93
|
}, []);
|
|
94
|
+
const handleNoRelationsFound = useCallback(() => {
|
|
95
|
+
// Show modal only on first load, not during navigation with onPrev/onNext
|
|
96
|
+
if (isFirstLoadRef.current) {
|
|
97
|
+
setShowNoRelationsModal(true);
|
|
98
|
+
setShouldGoBackOnClose(true);
|
|
99
|
+
}
|
|
100
|
+
// Mark as no longer first load
|
|
101
|
+
isFirstLoadRef.current = false;
|
|
102
|
+
}, []);
|
|
47
103
|
const commandsMenuItems = [
|
|
48
104
|
{
|
|
49
105
|
icon: _jsx(IconMultipleSelection, { color: allowMultipleSelection ? TMColors.tertiary : TMColors.text_normal }),
|
|
@@ -153,7 +209,7 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
|
|
|
153
209
|
:
|
|
154
210
|
_jsx(TMRelationViewerWrapper, { inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, showZeroDcmts: showZeroDcmts,
|
|
155
211
|
// customItemRender={customItemRender}
|
|
156
|
-
allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged }) }), [inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, allowMultipleSelection, focusedItem, selectedItems, handleFocusedItemChanged, handleSelectedItemsChanged]);
|
|
212
|
+
allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: handleSelectedItemsChanged, onNoRelationsFound: handleNoRelationsFound }) }), [inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, allowMultipleSelection, focusedItem, selectedItems, handleFocusedItemChanged, handleSelectedItemsChanged, handleNoRelationsFound]);
|
|
157
213
|
const tmFormOrResult = useMemo(() => _jsx(TMFormOrResultWrapper, { deviceType: deviceType, focusedItem: focusedItem, onTaskCreateRequest: onTaskCreateRequest, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), [focusedItem, deviceType, allTasks, handleNavigateToWGs, handleNavigateToDossiers]);
|
|
158
214
|
const initialPanelDimensions = {
|
|
159
215
|
'tmTreeView': { width: '50%', height: '100%' },
|
|
@@ -231,7 +287,12 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
|
|
|
231
287
|
toolbarOptions: { icon: _jsx(IconSearchCheck, { fontSize: 24 }), visible: false, orderNumber: 2, isActive: allInitialPanelVisibility['tmFormOrResult'] }
|
|
232
288
|
}
|
|
233
289
|
], [tmTreeView, tmFormOrResult, focusedItem?.isDcmt, dtdMaster]);
|
|
234
|
-
return (_jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }))
|
|
290
|
+
return (_jsxs(_Fragment, { children: [_jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }), showNoRelationsModal && (_jsx(StyledNoRelationsOverlay, { children: _jsxs(StyledNoRelationsPanel, { children: [_jsx(StyledNoRelationsTitle, { children: SDKUI_Localizator.RelationsNotFound }), _jsx(StyledNoRelationsMessage, { children: SDKUI_Localizator.RelatedDcmtsNotFound }), _jsx(TMButton, { caption: "OK", showTooltip: false, onClick: () => {
|
|
291
|
+
setShowNoRelationsModal(false);
|
|
292
|
+
if (shouldGoBackOnClose) {
|
|
293
|
+
onBack?.();
|
|
294
|
+
}
|
|
295
|
+
}, btnStyle: "normal" })] }) }))] }));
|
|
235
296
|
};
|
|
236
297
|
export default TMMasterDetailDcmts;
|
|
237
298
|
/**
|
|
@@ -240,7 +301,7 @@ export default TMMasterDetailDcmts;
|
|
|
240
301
|
* - Panel visibility toggling
|
|
241
302
|
* - Focus delay handling
|
|
242
303
|
*/
|
|
243
|
-
const TMRelationViewerWrapper = ({ inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, customItemRender, allowMultipleSelection, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged }) => {
|
|
304
|
+
const TMRelationViewerWrapper = ({ inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, customItemRender, allowMultipleSelection, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onNoRelationsFound }) => {
|
|
244
305
|
const { setPanelVisibilityById, setToolbarButtonVisibility } = useTMPanelManagerContext();
|
|
245
306
|
// Handle focused item changes with panel visibility management
|
|
246
307
|
const handleFocusedItemChanged = useCallback((item) => {
|
|
@@ -259,7 +320,7 @@ const TMRelationViewerWrapper = ({ inputDcmts, isForMaster, showCurrentDcmtIndic
|
|
|
259
320
|
setToolbarButtonVisibility('tmDcmtForm', false);
|
|
260
321
|
}
|
|
261
322
|
}, [onFocusedItemChanged, setPanelVisibilityById, setToolbarButtonVisibility]);
|
|
262
|
-
return (_jsx(TMRelationViewer, { inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, initialShowZeroDcmts: showZeroDcmts, customItemRender: customItemRender, allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: onSelectedItemsChanged, maxDepthLevel: 1, invertMasterNavigation: false }));
|
|
323
|
+
return (_jsx(TMRelationViewer, { inputDcmts: inputDcmts, isForMaster: isForMaster, showCurrentDcmtIndicator: showCurrentDcmtIndicator, initialShowZeroDcmts: showZeroDcmts, customItemRender: customItemRender, allowMultipleSelection: allowMultipleSelection, focusedItem: focusedItem, selectedItems: selectedItems, onFocusedItemChanged: handleFocusedItemChanged, onSelectedItemsChanged: onSelectedItemsChanged, maxDepthLevel: 1, invertMasterNavigation: false, onNoRelationsFound: onNoRelationsFound }));
|
|
263
324
|
};
|
|
264
325
|
const TMFormOrResultWrapper = ({ deviceType, focusedItem, onTaskCreateRequest, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers }) => {
|
|
265
326
|
const { setPanelVisibilityById } = useTMPanelManagerContext();
|
|
@@ -16,8 +16,9 @@ export interface RelationTreeItem extends ITMTreeItem {
|
|
|
16
16
|
isRoot?: boolean;
|
|
17
17
|
isMaster?: boolean;
|
|
18
18
|
isCorrelated?: boolean;
|
|
19
|
-
isLoaded?: boolean;
|
|
20
19
|
isSeparator?: boolean;
|
|
20
|
+
isInfoMessage?: boolean;
|
|
21
|
+
isLogDel?: number;
|
|
21
22
|
values?: any;
|
|
22
23
|
searchResult?: SearchResultDescriptor[];
|
|
23
24
|
itemsCount?: number;
|
|
@@ -92,6 +93,11 @@ export interface TMRelationViewerProps {
|
|
|
92
93
|
* If not provided, uses the document type name.
|
|
93
94
|
*/
|
|
94
95
|
labelMainContainer?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Callback invoked when no relations are found for any of the input documents.
|
|
98
|
+
* Useful to notify parent component that there are no correlated documents to display.
|
|
99
|
+
*/
|
|
100
|
+
onNoRelationsFound?: () => void;
|
|
95
101
|
}
|
|
96
102
|
/**
|
|
97
103
|
* Check if document type has detail relations
|
|
@@ -1,7 +1,7 @@
|
|
|
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, SystemMIDs, MetadataDataDomains, RelationCacheService, RelationTypes } from "@topconsultnpm/sdk-ts";
|
|
4
|
-
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight } from '../../../helper';
|
|
4
|
+
import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo } from '../../../helper';
|
|
5
5
|
import { TMColors } from '../../../utils/theme';
|
|
6
6
|
import { StyledDivHorizontal, StyledBadge } from '../../base/Styled';
|
|
7
7
|
import TMTreeView from '../../base/TMTreeView';
|
|
@@ -136,7 +136,7 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
|
|
|
136
136
|
}
|
|
137
137
|
return output;
|
|
138
138
|
};
|
|
139
|
-
const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, }) => {
|
|
139
|
+
const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndicator = true, allowShowZeroDcmts = true, initialShowZeroDcmts = false, allowedTIDs, allowMultipleSelection = false, focusedItem, selectedItems, onFocusedItemChanged, onSelectedItemsChanged, onDocumentDoubleClick, customItemRender, customDocumentStyle, customMainContainerContent, customDocumentContent, showMetadataNames = false, maxDepthLevel = 2, invertMasterNavigation = true, additionalStaticItems, showMainDocument = true, labelMainContainer, onNoRelationsFound, }) => {
|
|
140
140
|
// State
|
|
141
141
|
const [dcmtTypes, setDcmtTypes] = useState([]);
|
|
142
142
|
const [treeData, setTreeData] = useState([]);
|
|
@@ -156,6 +156,8 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
156
156
|
const lastLoadedInputRef = React.useRef('');
|
|
157
157
|
// Ref to track if user has manually expanded/collapsed static items
|
|
158
158
|
const userInteractedWithStaticItemsRef = React.useRef(false);
|
|
159
|
+
// Ref to track if we've already set the initial focused item
|
|
160
|
+
const initialFocusSetRef = React.useRef(false);
|
|
159
161
|
/**
|
|
160
162
|
* Generate a stable key from inputDcmts to detect real changes
|
|
161
163
|
*/
|
|
@@ -219,20 +221,27 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
219
221
|
const source = await searchResultToDataSource(searchResult);
|
|
220
222
|
if (source && source.length > 0) {
|
|
221
223
|
const dcmtDetails = [];
|
|
224
|
+
// Check once if this document type can have detail relations
|
|
225
|
+
// (optimization: avoid checking for each document)
|
|
226
|
+
const canHaveDetails = await hasDetailRelations(searchResult.fromTID);
|
|
222
227
|
for (const row of source) {
|
|
223
228
|
const rowGUID = genUniqueId();
|
|
224
229
|
const tid = row?.TID?.value;
|
|
225
230
|
const did = row?.DID?.value;
|
|
231
|
+
const isLogDel = row?.ISLOGDEL?.value;
|
|
226
232
|
dcmtDetails.push({
|
|
227
233
|
tid: tid,
|
|
228
234
|
did: did,
|
|
235
|
+
isLogDel: isLogDel,
|
|
229
236
|
key: `${tid}_${did}_${searchResult.relationID}_${mTID}_${mDID}_${rowGUID}`,
|
|
230
237
|
isDcmt: true,
|
|
231
238
|
isContainer: false,
|
|
232
239
|
isZero: false, // Documents are never zero (they exist)
|
|
240
|
+
isExpandible: canHaveDetails, // Can this doc be expanded?
|
|
233
241
|
values: row,
|
|
234
242
|
searchResult: [searchResult],
|
|
235
|
-
itemsCount
|
|
243
|
+
// Leave items and itemsCount undefined so TMTreeView shows expand arrow based on isExpandible
|
|
244
|
+
// Children will be loaded lazily by calculateItemsForNode when expanded
|
|
236
245
|
expanded: false,
|
|
237
246
|
hidden: false,
|
|
238
247
|
name: row?.SYS_Abstract?.value || row?.SYS_SUBJECT?.value || `Documento ${did}`
|
|
@@ -293,20 +302,30 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
293
302
|
const source = await searchResultToDataSource(searchResult);
|
|
294
303
|
if (source && source.length > 0) {
|
|
295
304
|
const dcmtMasters = [];
|
|
305
|
+
// Check once if this document type can have master relations (for inverted mode)
|
|
306
|
+
// or detail relations (for standard mode when expanding masters)
|
|
307
|
+
// (optimization: avoid checking for each document)
|
|
308
|
+
const canExpand = isForMaster && invertMasterNavigation
|
|
309
|
+
? await hasMasterRelations(searchResult.fromTID)
|
|
310
|
+
: await hasDetailRelations(searchResult.fromTID);
|
|
296
311
|
for (const row of source) {
|
|
297
312
|
const rowGUID = genUniqueId();
|
|
298
313
|
const tid = row?.TID?.value;
|
|
299
314
|
const did = row?.DID?.value;
|
|
315
|
+
const isLogDel = row?.ISLOGDEL?.value;
|
|
300
316
|
dcmtMasters.push({
|
|
301
317
|
tid: tid,
|
|
302
318
|
did: did,
|
|
319
|
+
isLogDel: isLogDel,
|
|
303
320
|
key: `${tid}_${did}_${searchResult.relationID}_${dTID}_${dDID}_${rowGUID}`,
|
|
304
321
|
isDcmt: true,
|
|
305
322
|
isContainer: false,
|
|
306
323
|
isZero: false, // Documents are never zero (they exist)
|
|
324
|
+
isExpandible: canExpand, // Can this doc be expanded?
|
|
307
325
|
values: row,
|
|
308
326
|
searchResult: [searchResult],
|
|
309
|
-
itemsCount
|
|
327
|
+
// Leave items and itemsCount undefined so TMTreeView shows expand arrow based on isExpandible
|
|
328
|
+
// Children will be loaded lazily by calculateItemsForNode when expanded
|
|
310
329
|
expanded: false,
|
|
311
330
|
hidden: false,
|
|
312
331
|
name: row?.SYS_Abstract?.value || row?.SYS_SUBJECT?.value || `Documento ${did}`
|
|
@@ -324,17 +343,128 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
324
343
|
return items;
|
|
325
344
|
}, [allowedTIDs]);
|
|
326
345
|
/**
|
|
327
|
-
* Update hidden property based on showZeroDcmts
|
|
346
|
+
* Update hidden property based on showZeroDcmts
|
|
347
|
+
* Updates items in-place without resetting isLoaded (no API calls needed)
|
|
328
348
|
*/
|
|
329
349
|
const updateHiddenProperty = useCallback((nodes) => {
|
|
350
|
+
// Safety check: if nodes is undefined or not an array, return empty array
|
|
351
|
+
if (!nodes || !Array.isArray(nodes)) {
|
|
352
|
+
return [];
|
|
353
|
+
}
|
|
330
354
|
return nodes.map(node => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
355
|
+
let shouldHide = false;
|
|
356
|
+
let updatedItems = undefined;
|
|
357
|
+
if (node.items && Array.isArray(node.items)) {
|
|
358
|
+
// Recursively update children first - this creates a new array
|
|
359
|
+
let updatedChildren = updateHiddenProperty(node.items);
|
|
360
|
+
// Remove any existing auto-generated info messages (with key starting with __info__)
|
|
361
|
+
const filteredChildren = updatedChildren.filter(child => !(child.isInfoMessage && child.key?.startsWith('__info__')));
|
|
362
|
+
// Check if all real children (excluding info messages) are hidden
|
|
363
|
+
const realChildren = filteredChildren.filter(child => !child.isInfoMessage);
|
|
364
|
+
const allChildrenHidden = realChildren.length > 0 && realChildren.every(child => child.hidden);
|
|
365
|
+
// If node is expanded AND showZeroDcmts is false AND all children are hidden, add info message
|
|
366
|
+
// This applies to both containers and document nodes with children
|
|
367
|
+
if (node.expanded && !showZeroDcmts && allChildrenHidden) {
|
|
368
|
+
// Add info message at the beginning, keep original children (hidden but preserved)
|
|
369
|
+
updatedItems = [
|
|
370
|
+
{
|
|
371
|
+
key: `__info__${node.key}`,
|
|
372
|
+
name: 'Nessun documento correlato da visualizzare',
|
|
373
|
+
isContainer: false,
|
|
374
|
+
isDcmt: false,
|
|
375
|
+
isInfoMessage: true,
|
|
376
|
+
isExpandible: false
|
|
377
|
+
},
|
|
378
|
+
...filteredChildren
|
|
379
|
+
];
|
|
380
|
+
// Don't hide the node itself if it's showing an info message
|
|
381
|
+
shouldHide = false;
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
updatedItems = filteredChildren;
|
|
385
|
+
// Hide zero-item containers when showZeroDcmts is false (only if not showing info message)
|
|
386
|
+
shouldHide = !showZeroDcmts && (node.isZero ?? false);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
// No items, apply normal hide logic
|
|
391
|
+
shouldHide = !showZeroDcmts && (node.isZero ?? false);
|
|
334
392
|
}
|
|
335
|
-
|
|
393
|
+
// IMPORTANT: Always create new object to trigger React re-render
|
|
394
|
+
return { ...node, hidden: shouldHide, items: updatedItems };
|
|
336
395
|
});
|
|
337
396
|
}, [showZeroDcmts]);
|
|
397
|
+
/**
|
|
398
|
+
* Helper function to set up initial tree expansion state.
|
|
399
|
+
* Called after all data is loaded but before setTreeData.
|
|
400
|
+
* Ensures: root container expanded, first document expanded with isRoot=true (for focus), first correlation folder expanded
|
|
401
|
+
* Returns a NEW tree with the modifications (immutable approach)
|
|
402
|
+
*/
|
|
403
|
+
const setupInitialTreeExpansion = (tree) => {
|
|
404
|
+
if (tree.length === 0)
|
|
405
|
+
return tree;
|
|
406
|
+
// ALWAYS expand the first container (even if empty, to show infoMessage)
|
|
407
|
+
const firstRootContainer = tree[0];
|
|
408
|
+
if (!firstRootContainer)
|
|
409
|
+
return tree;
|
|
410
|
+
// Create a deep copy of the first container with expanded=true, isRoot=true
|
|
411
|
+
let newFirstContainer = {
|
|
412
|
+
...firstRootContainer,
|
|
413
|
+
expanded: true,
|
|
414
|
+
isRoot: true
|
|
415
|
+
};
|
|
416
|
+
// 2. Find first document/container and expand it
|
|
417
|
+
const firstRootItems = newFirstContainer.items;
|
|
418
|
+
if (firstRootItems && firstRootItems.length > 0) {
|
|
419
|
+
const firstDocOrContainer = firstRootItems[0];
|
|
420
|
+
if (firstDocOrContainer.isDcmt) {
|
|
421
|
+
// First item is a document - expand it and mark as root for focus
|
|
422
|
+
let newFirstDoc = {
|
|
423
|
+
...firstDocOrContainer,
|
|
424
|
+
expanded: true,
|
|
425
|
+
isRoot: true
|
|
426
|
+
};
|
|
427
|
+
// 3. Expand first correlation folder (child of the document)
|
|
428
|
+
const docItems = newFirstDoc.items;
|
|
429
|
+
if (docItems && docItems.length > 0 && docItems[0].isContainer) {
|
|
430
|
+
const newFirstCorrelation = { ...docItems[0], expanded: true };
|
|
431
|
+
newFirstDoc = {
|
|
432
|
+
...newFirstDoc,
|
|
433
|
+
items: [newFirstCorrelation, ...docItems.slice(1)]
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
// Update the container's items
|
|
437
|
+
newFirstContainer = {
|
|
438
|
+
...newFirstContainer,
|
|
439
|
+
items: [newFirstDoc, ...firstRootItems.slice(1)]
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
else if (firstDocOrContainer.isContainer) {
|
|
443
|
+
// First item is a container (correlation folder) - expand it
|
|
444
|
+
let newFirstCorrelation = {
|
|
445
|
+
...firstDocOrContainer,
|
|
446
|
+
expanded: true
|
|
447
|
+
};
|
|
448
|
+
// Find first document inside this container and mark for focus
|
|
449
|
+
const containerItems = newFirstCorrelation.items;
|
|
450
|
+
if (containerItems && containerItems.length > 0 && containerItems[0].isDcmt) {
|
|
451
|
+
const newFirstDoc = { ...containerItems[0], isRoot: true };
|
|
452
|
+
newFirstCorrelation = {
|
|
453
|
+
...newFirstCorrelation,
|
|
454
|
+
items: [newFirstDoc, ...containerItems.slice(1)]
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
// Update the container's items
|
|
458
|
+
newFirstContainer = {
|
|
459
|
+
...newFirstContainer,
|
|
460
|
+
items: [newFirstCorrelation, ...firstRootItems.slice(1)]
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// If firstRootItems is empty/undefined, the container is still expanded (will show infoMessage)
|
|
465
|
+
// Return new tree with the modified first container
|
|
466
|
+
return [newFirstContainer, ...tree.slice(1)];
|
|
467
|
+
};
|
|
338
468
|
/**
|
|
339
469
|
* Main data loading function
|
|
340
470
|
*/
|
|
@@ -405,13 +535,12 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
405
535
|
tid: dcmt.TID,
|
|
406
536
|
dtd,
|
|
407
537
|
isContainer: true,
|
|
408
|
-
isRoot: true,
|
|
409
538
|
isLoaded: true,
|
|
410
539
|
isZero: false,
|
|
411
540
|
searchResult: result ? [result] : [],
|
|
412
541
|
items: relatedDocs, // Directly show detail containers
|
|
413
542
|
itemsCount: relatedDocs.length,
|
|
414
|
-
expanded:
|
|
543
|
+
expanded: false,
|
|
415
544
|
hidden: false
|
|
416
545
|
};
|
|
417
546
|
tree.push(typeContainer);
|
|
@@ -426,10 +555,9 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
426
555
|
did: dcmt.DID,
|
|
427
556
|
isDcmt: true,
|
|
428
557
|
isContainer: false,
|
|
429
|
-
expanded:
|
|
558
|
+
expanded: false,
|
|
430
559
|
isZero: dcmt.DID === 0,
|
|
431
560
|
isMaster: !isForMaster,
|
|
432
|
-
isRoot: true,
|
|
433
561
|
isLoaded: true,
|
|
434
562
|
hidden: false,
|
|
435
563
|
values: docRow,
|
|
@@ -444,13 +572,12 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
444
572
|
tid: dcmt.TID,
|
|
445
573
|
dtd,
|
|
446
574
|
isContainer: true,
|
|
447
|
-
isRoot: true,
|
|
448
575
|
isLoaded: true,
|
|
449
576
|
isZero: false, // Type container is never zero (contains documents)
|
|
450
577
|
searchResult: result ? [result] : [],
|
|
451
578
|
items: [docNode],
|
|
452
579
|
itemsCount: 1,
|
|
453
|
-
expanded:
|
|
580
|
+
expanded: false,
|
|
454
581
|
hidden: false
|
|
455
582
|
};
|
|
456
583
|
tree.push(typeContainer);
|
|
@@ -460,8 +587,55 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
460
587
|
processedCount++;
|
|
461
588
|
setWaitPanelValuePrimary(processedCount);
|
|
462
589
|
}
|
|
463
|
-
|
|
464
|
-
|
|
590
|
+
/**
|
|
591
|
+
* Helper function to check if a node has any actual correlated documents
|
|
592
|
+
* Returns true if there are NO documents (relations are empty)
|
|
593
|
+
*/
|
|
594
|
+
const hasNoActualDocuments = (items) => {
|
|
595
|
+
if (!items || items.length === 0)
|
|
596
|
+
return true;
|
|
597
|
+
// Check each item
|
|
598
|
+
return items.every(item => {
|
|
599
|
+
// If it's a container, check if it's zero or has no documents
|
|
600
|
+
if (item.isContainer) {
|
|
601
|
+
// Container with isZero=true has no documents
|
|
602
|
+
if (item.isZero)
|
|
603
|
+
return true;
|
|
604
|
+
// Container with no items has no documents
|
|
605
|
+
if (!item.items || item.items.length === 0)
|
|
606
|
+
return true;
|
|
607
|
+
// Otherwise, it has documents
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
// If it's a document node, check its children (relation containers)
|
|
611
|
+
if (item.isDcmt) {
|
|
612
|
+
// Check if all child containers are empty
|
|
613
|
+
return hasNoActualDocuments(item.items);
|
|
614
|
+
}
|
|
615
|
+
// For other types, assume no documents
|
|
616
|
+
return true;
|
|
617
|
+
});
|
|
618
|
+
};
|
|
619
|
+
// Check if there are no relations for any document
|
|
620
|
+
const hasNoRelations = tree.length === 0 || tree.every(container => {
|
|
621
|
+
// Check if container has no items
|
|
622
|
+
if (!container.items || container.items.length === 0)
|
|
623
|
+
return true;
|
|
624
|
+
// Check recursively if there are any actual documents
|
|
625
|
+
return hasNoActualDocuments(container.items);
|
|
626
|
+
});
|
|
627
|
+
// If no relations found, notify parent
|
|
628
|
+
if (hasNoRelations && onNoRelationsFound) {
|
|
629
|
+
onNoRelationsFound();
|
|
630
|
+
}
|
|
631
|
+
// FIRST setup initial expansion state (root container expanded, first document expanded with focus, first correlation folder expanded)
|
|
632
|
+
// This must run BEFORE updateHiddenProperty so that infoMessage logic sees expanded=true
|
|
633
|
+
const expandedTree = setupInitialTreeExpansion(tree);
|
|
634
|
+
// THEN apply hidden property transformations (creates new objects, adds infoMessage where needed)
|
|
635
|
+
// Now it will correctly detect expanded nodes and add infoMessage if all children are hidden
|
|
636
|
+
const processedTree = updateHiddenProperty(expandedTree);
|
|
637
|
+
setTreeData(processedTree);
|
|
638
|
+
}, [inputDcmts, dcmtTypes, maxDepthLevel, isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, abortController, updateHiddenProperty, showMainDocument, labelMainContainer, onNoRelationsFound]);
|
|
465
639
|
/**
|
|
466
640
|
* Merge main tree data with additional static items
|
|
467
641
|
*/
|
|
@@ -509,10 +683,56 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
509
683
|
}, [inputDcmts, dcmtTypes, maxDepthLevel, getInputKey, loadData, treeData.length]);
|
|
510
684
|
/**
|
|
511
685
|
* Update tree when showZeroDcmts changes
|
|
686
|
+
* Updates the visualization without re-fetching data (isLoaded stays true)
|
|
512
687
|
*/
|
|
513
688
|
useEffect(() => {
|
|
514
689
|
setTreeData(prevData => updateHiddenProperty(prevData));
|
|
515
690
|
}, [showZeroDcmts, updateHiddenProperty]);
|
|
691
|
+
/**
|
|
692
|
+
* Set initial focused item when showMainDocument = true
|
|
693
|
+
* Focuses on the main document (first inputDcmts) when data is loaded
|
|
694
|
+
* For master mode with invertMasterNavigation=false, focuses on the first master document
|
|
695
|
+
*/
|
|
696
|
+
useEffect(() => {
|
|
697
|
+
// Only execute if:
|
|
698
|
+
// 1. showMainDocument is true
|
|
699
|
+
// 2. onFocusedItemChanged callback exists
|
|
700
|
+
// 3. We have tree data
|
|
701
|
+
// 4. We have input documents
|
|
702
|
+
// 5. We haven't already set the initial focus
|
|
703
|
+
if (!showMainDocument || !onFocusedItemChanged || !treeData.length || !inputDcmts?.length || initialFocusSetRef.current) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
// Helper function to recursively find the first document with isRoot=true
|
|
707
|
+
const findFirstRootDocument = (items) => {
|
|
708
|
+
for (const item of items) {
|
|
709
|
+
// Check if this item is a document with isRoot=true
|
|
710
|
+
if (item.isDcmt && item.isRoot) {
|
|
711
|
+
return item;
|
|
712
|
+
}
|
|
713
|
+
// Recursively search in children
|
|
714
|
+
if (item.items && Array.isArray(item.items)) {
|
|
715
|
+
const found = findFirstRootDocument(item.items);
|
|
716
|
+
if (found)
|
|
717
|
+
return found;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return null;
|
|
721
|
+
};
|
|
722
|
+
// Find the first document marked as root (set by setupInitialTreeExpansion)
|
|
723
|
+
const docNode = findFirstRootDocument(treeData);
|
|
724
|
+
if (docNode) {
|
|
725
|
+
// Set the focused item
|
|
726
|
+
onFocusedItemChanged(docNode);
|
|
727
|
+
initialFocusSetRef.current = true;
|
|
728
|
+
}
|
|
729
|
+
}, [treeData, showMainDocument, onFocusedItemChanged, inputDcmts]);
|
|
730
|
+
/**
|
|
731
|
+
* Reset initial focus flag when input documents change
|
|
732
|
+
*/
|
|
733
|
+
useEffect(() => {
|
|
734
|
+
initialFocusSetRef.current = false;
|
|
735
|
+
}, [getInputKey()]);
|
|
516
736
|
/**
|
|
517
737
|
* Sync static items state when additionalStaticItems change
|
|
518
738
|
* IMPORTANT: Only update if user hasn't manually interacted with the tree,
|
|
@@ -548,6 +768,10 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
548
768
|
/**
|
|
549
769
|
* Calculate items for node when expanded (lazy loading)
|
|
550
770
|
* Note: additionalStaticItems are already fully loaded, so skip calculation for them
|
|
771
|
+
*
|
|
772
|
+
* PERFORMANCE OPTIMIZATION:
|
|
773
|
+
* - Containers: Return items immediately (no API calls) - items are already loaded
|
|
774
|
+
* - Documents: Load children lazily only when the specific document is expanded (1 API call)
|
|
551
775
|
*/
|
|
552
776
|
const calculateItemsForNode = useCallback(async (node) => {
|
|
553
777
|
// Skip calculation for separator (it has no children)
|
|
@@ -558,62 +782,129 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
558
782
|
if (node.isStaticItem || node.isAdditionalContainer || node.isAdditional) {
|
|
559
783
|
return node.items;
|
|
560
784
|
}
|
|
561
|
-
// If
|
|
562
|
-
if (node.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
processedCount++;
|
|
586
|
-
setExpansionWaitPanelValue(processedCount);
|
|
587
|
-
setExpansionWaitPanelText(`Caricamento ${processedCount} di ${itemsToLoad}...`);
|
|
588
|
-
// Nella modalità originale (invertMasterNavigation=false),
|
|
589
|
-
// i documenti detail non devono caricare i master come figli
|
|
590
|
-
if (isForMaster && !invertMasterNavigation) {
|
|
591
|
-
// Carica i detail dei detail (navigazione naturale detail→detail)
|
|
592
|
-
const loadedItems = await getDetailDcmtsAsync(item.tid, item.did, 1);
|
|
593
|
-
item.items = updateHiddenProperty(loadedItems);
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
596
|
-
// Modalità standard o invertita
|
|
597
|
-
const loadedItems = isForMaster
|
|
598
|
-
? await getMasterDcmtsAsync(item.tid, item.did, 1)
|
|
599
|
-
: await getDetailDcmtsAsync(item.tid, item.did, 1);
|
|
600
|
-
item.items = updateHiddenProperty(loadedItems);
|
|
601
|
-
}
|
|
602
|
-
item.isLoaded = true;
|
|
785
|
+
// If already loaded, apply current visualization logic without re-fetching
|
|
786
|
+
if (node.isLoaded && node.items) {
|
|
787
|
+
// Apply current show/hide logic based on showZeroDcmts
|
|
788
|
+
const updatedItems = updateHiddenProperty(node.items);
|
|
789
|
+
// If this is a container, check if we need to show info message
|
|
790
|
+
if (node.isContainer) {
|
|
791
|
+
// Remove any existing info messages
|
|
792
|
+
const filteredItems = updatedItems.filter(child => !(child.isInfoMessage && child.key?.startsWith('__info__')));
|
|
793
|
+
// Check if all real children are hidden
|
|
794
|
+
const realChildren = filteredItems.filter(child => !child.isInfoMessage);
|
|
795
|
+
const allChildrenHidden = realChildren.length > 0 && realChildren.every(child => child.hidden);
|
|
796
|
+
// If showZeroDcmts is false and all items are hidden, show info message + keep hidden containers
|
|
797
|
+
if (!showZeroDcmts && allChildrenHidden) {
|
|
798
|
+
return [
|
|
799
|
+
{
|
|
800
|
+
key: `__info__${node.key}`,
|
|
801
|
+
name: 'Nessun documento correlato da visualizzare',
|
|
802
|
+
isContainer: false,
|
|
803
|
+
isDcmt: false,
|
|
804
|
+
isInfoMessage: true,
|
|
805
|
+
isExpandible: false
|
|
806
|
+
},
|
|
807
|
+
...filteredItems // Keep hidden containers so they can be shown when toggling
|
|
808
|
+
];
|
|
603
809
|
}
|
|
604
|
-
newItems.push(item);
|
|
605
810
|
}
|
|
606
|
-
return
|
|
811
|
+
return updatedItems;
|
|
607
812
|
}
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
813
|
+
// ============================================
|
|
814
|
+
// CONTAINER: Show items immediately (no API calls)
|
|
815
|
+
// Items are already loaded from initial load or parent expansion
|
|
816
|
+
// ============================================
|
|
817
|
+
if (node.isContainer) {
|
|
818
|
+
// No API calls needed - just return existing items
|
|
819
|
+
// Children of these items will be loaded lazily when user expands each document
|
|
820
|
+
// Apply updateHiddenProperty to respect current showZeroDcmts setting
|
|
821
|
+
// If node has no items, return empty array
|
|
822
|
+
if (!node.items)
|
|
823
|
+
return [];
|
|
824
|
+
const updatedItems = updateHiddenProperty(node.items);
|
|
825
|
+
// If showZeroDcmts is false and all items are hidden, add info message + keep hidden containers
|
|
826
|
+
if (!showZeroDcmts && updatedItems.length > 0 && updatedItems.every(item => item.hidden)) {
|
|
827
|
+
return [
|
|
828
|
+
{
|
|
829
|
+
key: `__info__${node.key}`,
|
|
830
|
+
name: 'Nessun documento correlato da visualizzare',
|
|
831
|
+
isContainer: false,
|
|
832
|
+
isDcmt: false,
|
|
833
|
+
isInfoMessage: true,
|
|
834
|
+
isExpandible: false
|
|
835
|
+
},
|
|
836
|
+
...updatedItems // Keep hidden containers so they can be shown when toggling
|
|
837
|
+
];
|
|
838
|
+
}
|
|
839
|
+
return updatedItems;
|
|
611
840
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
841
|
+
// ============================================
|
|
842
|
+
// DOCUMENT: Load its children (relation containers) lazily
|
|
843
|
+
// Only makes ONE API call for this specific document
|
|
844
|
+
// ============================================
|
|
845
|
+
if (node.isDcmt && node.tid && node.did) {
|
|
846
|
+
const newAbortController = new AbortController();
|
|
847
|
+
setExpansionAbortController(newAbortController);
|
|
848
|
+
setShowExpansionWaitPanel(true);
|
|
849
|
+
setExpansionWaitPanelMaxValue(1);
|
|
850
|
+
setExpansionWaitPanelValue(0);
|
|
851
|
+
setExpansionWaitPanelText(`Caricamento documenti correlati...`);
|
|
852
|
+
try {
|
|
853
|
+
// Check for abort
|
|
854
|
+
if (newAbortController.signal.aborted) {
|
|
855
|
+
return [];
|
|
856
|
+
}
|
|
857
|
+
// Determine which load function to use based on mode
|
|
858
|
+
let loadedItems = [];
|
|
859
|
+
if (isForMaster && !invertMasterNavigation) {
|
|
860
|
+
// Original mode: detail documents load detail documents (natural detail→detail navigation)
|
|
861
|
+
loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
|
|
862
|
+
}
|
|
863
|
+
else if (isForMaster) {
|
|
864
|
+
// Inverted master mode: load master documents
|
|
865
|
+
loadedItems = await getMasterDcmtsAsync(node.tid, node.did, 1);
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
// Standard mode: load detail documents
|
|
869
|
+
loadedItems = await getDetailDcmtsAsync(node.tid, node.did, 1);
|
|
870
|
+
}
|
|
871
|
+
// Espandi automaticamente il primo container se ci sono documenti correlati
|
|
872
|
+
if (loadedItems.length > 0 && loadedItems[0].isContainer) {
|
|
873
|
+
loadedItems[0].expanded = true;
|
|
874
|
+
}
|
|
875
|
+
// Apply updateHiddenProperty to respect current showZeroDcmts setting
|
|
876
|
+
// This ensures that dynamically loaded nodes respect the visibility rules:
|
|
877
|
+
// - Relation type containers are always visible (even if empty)
|
|
878
|
+
// - Other containers with zero items can be hidden based on showZeroDcmts
|
|
879
|
+
const updatedItems = updateHiddenProperty(loadedItems);
|
|
880
|
+
// If showZeroDcmts is false and all items are hidden, add info message + keep hidden containers
|
|
881
|
+
if (!showZeroDcmts && updatedItems.length > 0 && updatedItems.every(item => item.hidden)) {
|
|
882
|
+
return [
|
|
883
|
+
{
|
|
884
|
+
key: `__info__${node.key}`,
|
|
885
|
+
name: 'Nessun documento correlato da visualizzare',
|
|
886
|
+
isContainer: false,
|
|
887
|
+
isDcmt: false,
|
|
888
|
+
isInfoMessage: true,
|
|
889
|
+
isExpandible: false
|
|
890
|
+
},
|
|
891
|
+
...updatedItems // Keep hidden containers so they can be shown when toggling
|
|
892
|
+
];
|
|
893
|
+
}
|
|
894
|
+
return updatedItems;
|
|
895
|
+
}
|
|
896
|
+
catch (error) {
|
|
897
|
+
console.error('Error loading document relations:', error);
|
|
898
|
+
return [];
|
|
899
|
+
}
|
|
900
|
+
finally {
|
|
901
|
+
setShowExpansionWaitPanel(false);
|
|
902
|
+
setExpansionAbortController(undefined);
|
|
903
|
+
}
|
|
615
904
|
}
|
|
616
|
-
|
|
905
|
+
// Default: return existing items
|
|
906
|
+
return node.items;
|
|
907
|
+
}, [isForMaster, invertMasterNavigation, getDetailDcmtsAsync, getMasterDcmtsAsync, updateHiddenProperty, showZeroDcmts]);
|
|
617
908
|
/**
|
|
618
909
|
* Default item renderer with metadata display (adapted from TMMasterDetailDcmts.tsx)
|
|
619
910
|
*/
|
|
@@ -626,6 +917,18 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
626
917
|
e.stopPropagation();
|
|
627
918
|
onDocumentDoubleClick?.(item.tid, item.did, item.name);
|
|
628
919
|
};
|
|
920
|
+
// Info message rendering
|
|
921
|
+
if (item.isInfoMessage) {
|
|
922
|
+
return (_jsxs("div", { style: {
|
|
923
|
+
display: 'flex',
|
|
924
|
+
alignItems: 'center',
|
|
925
|
+
gap: '10px',
|
|
926
|
+
height: '32px',
|
|
927
|
+
padding: '6px 0',
|
|
928
|
+
color: '#666',
|
|
929
|
+
fontStyle: 'italic'
|
|
930
|
+
}, children: [_jsx(IconCircleInfo, { fontSize: 20, color: TMColors.iconLight }), _jsx("span", { children: item.name })] }));
|
|
931
|
+
}
|
|
629
932
|
// Container rendering
|
|
630
933
|
if (item.isContainer || !item.isDcmt) {
|
|
631
934
|
const defaultContainerStyle = {
|
|
@@ -634,7 +937,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
634
937
|
gap: '10px',
|
|
635
938
|
height: '32px',
|
|
636
939
|
padding: '6px 0',
|
|
637
|
-
opacity: item.isZero ? 0.
|
|
940
|
+
opacity: item.isZero ? 0.99 : 1,
|
|
638
941
|
transition: 'opacity 0.2s ease-in-out'
|
|
639
942
|
};
|
|
640
943
|
// Se è il container principale (root) e showMainDocument è false,
|
|
@@ -653,6 +956,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
653
956
|
return (_jsx("div", { style: defaultContainerStyle, children: content }));
|
|
654
957
|
}
|
|
655
958
|
// Document rendering with full metadata display
|
|
959
|
+
const isLogicallyDeleted = Number(item.isLogDel) === 1;
|
|
656
960
|
const defaultDocumentStyle = {
|
|
657
961
|
minWidth: '90px',
|
|
658
962
|
width: '100%',
|
|
@@ -664,18 +968,23 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
664
968
|
alignItems: 'center',
|
|
665
969
|
cursor: 'pointer',
|
|
666
970
|
userSelect: 'none',
|
|
667
|
-
opacity: item.isZero ? 0.
|
|
668
|
-
transition: 'opacity 0.2s ease-in-out'
|
|
971
|
+
opacity: item.isZero ? 0.99 : 1,
|
|
972
|
+
transition: 'opacity 0.2s ease-in-out',
|
|
973
|
+
textDecoration: isLogicallyDeleted ? 'line-through' : 'none'
|
|
669
974
|
};
|
|
670
975
|
const documentStyle = customDocumentStyle
|
|
671
976
|
? { ...defaultDocumentStyle, ...customDocumentStyle(item) }
|
|
672
977
|
: defaultDocumentStyle;
|
|
978
|
+
const textDecoration = isLogicallyDeleted ? 'line-through' : 'none';
|
|
979
|
+
const textColor = isLogicallyDeleted ? 'gray' : undefined;
|
|
673
980
|
const defaultMetadataContent = item.values && (_jsx(StyledDivHorizontal, { style: {
|
|
674
981
|
fontSize: '1rem',
|
|
675
982
|
overflow: 'hidden',
|
|
676
983
|
flex: 1,
|
|
677
984
|
minWidth: 0,
|
|
678
|
-
whiteSpace: 'nowrap'
|
|
985
|
+
whiteSpace: 'nowrap',
|
|
986
|
+
textDecoration: textDecoration,
|
|
987
|
+
color: textColor
|
|
679
988
|
}, children: getDcmtDisplayValue(item.values).map((key, index) => {
|
|
680
989
|
const md = item.values?.[key]?.md;
|
|
681
990
|
const value = item.values?.[key]?.value;
|
|
@@ -684,12 +993,16 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
684
993
|
return (_jsxs(StyledDivHorizontal, { style: {
|
|
685
994
|
flexShrink: isLast ? 1 : 0,
|
|
686
995
|
minWidth: isLast ? 0 : 'auto',
|
|
687
|
-
overflow: isLast ? 'hidden' : 'visible'
|
|
688
|
-
|
|
996
|
+
overflow: isLast ? 'hidden' : 'visible',
|
|
997
|
+
textDecoration: textDecoration,
|
|
998
|
+
color: textColor
|
|
999
|
+
}, 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: {
|
|
689
1000
|
fontWeight: 500,
|
|
690
1001
|
overflow: isLast ? 'hidden' : 'visible',
|
|
691
1002
|
textOverflow: isLast ? 'ellipsis' : 'clip',
|
|
692
|
-
whiteSpace: 'nowrap'
|
|
1003
|
+
whiteSpace: 'nowrap',
|
|
1004
|
+
textDecoration: textDecoration,
|
|
1005
|
+
color: textColor
|
|
693
1006
|
}, children: value }))] }, `${key}_${index}`));
|
|
694
1007
|
}) }));
|
|
695
1008
|
const metadataContent = customDocumentContent
|
|
@@ -744,7 +1057,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
|
|
|
744
1057
|
if (mergedTreeData.length === 0) {
|
|
745
1058
|
return _jsx("div", { style: { padding: '20px', textAlign: 'center', color: '#666' }, children: "Nessuna relazione disponibile." });
|
|
746
1059
|
}
|
|
747
|
-
return (_jsxs(_Fragment, { children: [_jsx(TMTreeView, { dataSource: mergedTreeData, itemRender: finalItemRender, calculateItemsForNode: calculateItemsForNode, onDataChanged: handleDataChanged, focusedItem: focusedItem, onFocusedItemChanged: handleFocusedItemChanged, allowMultipleSelection: allowMultipleSelection, selectedItems: selectedItems, onSelectionChanged: handleSelectedItemsChanged }), showExpansionWaitPanel && (_jsx(TMWaitPanel, { title: isForMaster ? 'Caricamento documenti master' : 'Caricamento documenti dettaglio', showPrimary: true, textPrimary: expansionWaitPanelText, valuePrimary: expansionWaitPanelValue, maxValuePrimary: expansionWaitPanelMaxValue, isCancelable: true, abortController: expansionAbortController, onAbortClick: (abortController) => {
|
|
1060
|
+
return (_jsxs(_Fragment, { children: [_jsx(TMTreeView, { dataSource: mergedTreeData, itemRender: finalItemRender, calculateItemsForNode: calculateItemsForNode, onDataChanged: handleDataChanged, focusedItem: focusedItem, onFocusedItemChanged: handleFocusedItemChanged, allowMultipleSelection: allowMultipleSelection, selectedItems: selectedItems, itemsPerPage: 100, onSelectionChanged: handleSelectedItemsChanged }), showExpansionWaitPanel && (_jsx(TMWaitPanel, { title: isForMaster ? 'Caricamento documenti master' : 'Caricamento documenti dettaglio', showPrimary: true, textPrimary: expansionWaitPanelText, valuePrimary: expansionWaitPanelValue, maxValuePrimary: expansionWaitPanelMaxValue, isCancelable: true, abortController: expansionAbortController, onAbortClick: (abortController) => {
|
|
748
1061
|
setTimeout(() => {
|
|
749
1062
|
abortController?.abort();
|
|
750
1063
|
}, 100);
|
|
@@ -274,9 +274,9 @@ export const RenderTaskFormStateField = (props) => {
|
|
|
274
274
|
const closeTaskCallback = () => {
|
|
275
275
|
if (!formData || !formData.id)
|
|
276
276
|
return;
|
|
277
|
-
const msg =
|
|
277
|
+
const msg = _jsxs("span", { children: ["Sei sicuro voler chiudere l'attivit\u00E0 \"", _jsx("b", { children: formData.name ?? "N/A" }), "\"?"] });
|
|
278
278
|
TMMessageBoxManager.show({
|
|
279
|
-
title: SDKUI_Localizator.
|
|
279
|
+
title: SDKUI_Localizator.CloseTask, message: msg, buttons: [ButtonNames.YES, ButtonNames.NO],
|
|
280
280
|
onButtonClick: async (e) => {
|
|
281
281
|
if (e !== ButtonNames.YES)
|
|
282
282
|
return;
|
|
@@ -345,7 +345,7 @@ export const TMChangeStateForm = (props) => {
|
|
|
345
345
|
const [dropdownValues, setDropdownValues] = React.useState([]);
|
|
346
346
|
useEffect(() => {
|
|
347
347
|
const availableTransitions = getAvailableTaskTransitions(formData?.state ?? Task_States.None, taskRole);
|
|
348
|
-
const values = getDropdownValuesFromTaskStates(availableTransitions
|
|
348
|
+
const values = getDropdownValuesFromTaskStates(availableTransitions);
|
|
349
349
|
setDropdownValues(values);
|
|
350
350
|
if (values.length > 0) {
|
|
351
351
|
const currentState = formData?.state ?? Task_States.None;
|
|
@@ -416,7 +416,7 @@ const getAvailableTaskTransitions = (currentStatus, role) => {
|
|
|
416
416
|
const transitions = STATUS_TRANSITIONS[role];
|
|
417
417
|
return transitions?.[currentStatus] ?? [];
|
|
418
418
|
};
|
|
419
|
-
const getDropdownValuesFromTaskStates = (states
|
|
419
|
+
const getDropdownValuesFromTaskStates = (states) => {
|
|
420
420
|
const map = {
|
|
421
421
|
[Task_States.Completed]: SDKUI_Localizator.Completed,
|
|
422
422
|
[Task_States.Closed]: SDKUI_Localizator.Closed,
|
|
@@ -427,6 +427,6 @@ const getDropdownValuesFromTaskStates = (states, currentState) => {
|
|
|
427
427
|
[Task_States.None]: "",
|
|
428
428
|
};
|
|
429
429
|
return states
|
|
430
|
-
.filter(state => state !== Task_States.None
|
|
430
|
+
.filter(state => state !== Task_States.None)
|
|
431
431
|
.map(state => ({ value: state, display: map[state] }));
|
|
432
432
|
};
|
|
@@ -100,6 +100,7 @@ export declare class SDKUI_Localizator {
|
|
|
100
100
|
static get ClearOTP(): "OTP löschen" | "Clear OTP" | "Borrar OTP" | "Effacer l'OTP" | "Limpar OTP" | "Cancella OTP";
|
|
101
101
|
static get Close(): "Ausgang" | "Close" | "Salida" | "Sortie" | "Saída" | "Chiudi";
|
|
102
102
|
static get Closed(): "Geschlossen" | "Closed" | "Cerrada" | "Fermée" | "Fechada" | "Chiusa";
|
|
103
|
+
static get CloseTask(): string;
|
|
103
104
|
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";
|
|
104
105
|
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";
|
|
105
106
|
static get Comment(): string;
|
|
@@ -517,6 +518,8 @@ export declare class SDKUI_Localizator {
|
|
|
517
518
|
static get Redo(): "Wiederherstellen" | "Redo" | "Rehacer" | "Rétablir" | "Refazer" | "Rifai";
|
|
518
519
|
static get Reject(): "Ablehnen" | "Reject" | "Rechazar" | "Rejeter" | "Rejeitar" | "Rifiuta";
|
|
519
520
|
static get Relations(): "Korrelationen" | "Correlations" | "Correlaciones" | "Relations" | "Correlacionados" | "Correlazioni";
|
|
521
|
+
static get RelationsNotFound(): "Keine Korrelationen gefunden" | "No correlations found" | "No se encontraron correlaciones" | "Aucune corrélation trouvée" | "Nenhuma correlação encontrada" | "Nessuna correlazione trovata";
|
|
522
|
+
static get RelatedDcmtsNotFound(): "Für das ausgewählte Dokument wurden keine zugehörigen Dokumente gefunden." | "No related documents were found for the selected document." | "No se encontraron documentos relacionados para el documento seleccionado." | "Aucun document associé n'a été trouvé pour le document sélectionné." | "Nenhum documento relacionado foi encontrado para o documento selecionado." | "Non sono stati trovati documenti correlati per il documento selezionato.";
|
|
520
523
|
static get RelationManyToMany(): "Folge viele mit vielen" | "Relation many to many" | "Correlación muchos a muchos" | "Corrélation plusieurs à plusieurs" | "Muitos para muitos relação" | "Correlazione molti a molti";
|
|
521
524
|
static get RelationType(): "Art der Beziehung" | "Relation type" | "Tipo de relación" | "Type de relation" | "Tipo de relacionamento" | "Tipo di relazione";
|
|
522
525
|
static get RemoveContextualFilter(): "Kontextbezogenen Filter entfernen" | "Remove contextual filter" | "Eliminar filtro contextual" | "Supprimer le filtre contextuel" | "Remover filtro contextual" | "Rimuovi filtro contestuale";
|
|
@@ -980,6 +980,16 @@ export class SDKUI_Localizator {
|
|
|
980
980
|
default: return "Chiusa";
|
|
981
981
|
}
|
|
982
982
|
}
|
|
983
|
+
static get CloseTask() {
|
|
984
|
+
switch (this._cultureID) {
|
|
985
|
+
case CultureIDs.De_DE: return "Aufgabe schließen";
|
|
986
|
+
case CultureIDs.En_US: return "Close task";
|
|
987
|
+
case CultureIDs.Es_ES: return "Cerrar tarea";
|
|
988
|
+
case CultureIDs.Fr_FR: return "Fermer la tâche";
|
|
989
|
+
case CultureIDs.Pt_PT: return "Fechar tarefa";
|
|
990
|
+
default: return "Chiudi attività";
|
|
991
|
+
}
|
|
992
|
+
}
|
|
983
993
|
static get Columns_All_Hide() {
|
|
984
994
|
switch (this._cultureID) {
|
|
985
995
|
case CultureIDs.De_DE: return "Alle Spalten ausblenden";
|
|
@@ -5135,6 +5145,26 @@ export class SDKUI_Localizator {
|
|
|
5135
5145
|
}
|
|
5136
5146
|
;
|
|
5137
5147
|
}
|
|
5148
|
+
static get RelationsNotFound() {
|
|
5149
|
+
switch (this._cultureID) {
|
|
5150
|
+
case CultureIDs.De_DE: return "Keine Korrelationen gefunden";
|
|
5151
|
+
case CultureIDs.En_US: return "No correlations found";
|
|
5152
|
+
case CultureIDs.Es_ES: return "No se encontraron correlaciones";
|
|
5153
|
+
case CultureIDs.Fr_FR: return "Aucune corrélation trouvée";
|
|
5154
|
+
case CultureIDs.Pt_PT: return "Nenhuma correlação encontrada";
|
|
5155
|
+
default: return "Nessuna correlazione trovata";
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
static get RelatedDcmtsNotFound() {
|
|
5159
|
+
switch (this._cultureID) {
|
|
5160
|
+
case CultureIDs.De_DE: return "Für das ausgewählte Dokument wurden keine zugehörigen Dokumente gefunden.";
|
|
5161
|
+
case CultureIDs.En_US: return "No related documents were found for the selected document.";
|
|
5162
|
+
case CultureIDs.Es_ES: return "No se encontraron documentos relacionados para el documento seleccionado.";
|
|
5163
|
+
case CultureIDs.Fr_FR: return "Aucun document associé n'a été trouvé pour le document sélectionné.";
|
|
5164
|
+
case CultureIDs.Pt_PT: return "Nenhum documento relacionado foi encontrado para o documento selecionado.";
|
|
5165
|
+
default: return "Non sono stati trovati documenti correlati per il documento selezionato.";
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5138
5168
|
static get RelationManyToMany() {
|
|
5139
5169
|
switch (this._cultureID) {
|
|
5140
5170
|
case CultureIDs.De_DE: return "Folge viele mit vielen";
|