@topconsultnpm/sdkui-react 6.20.0-dev2.46 → 6.20.0-dev2.48

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.
@@ -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
- visibleItemsCount?: number;
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
- newItems = await calculateItemsForNode(node);
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 caricamento di più items per un nodo
284
- const handleLoadMoreItems = useCallback((nodeKey) => {
285
- const updateNodeVisibleCount = (nodes) => {
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 currentVisible = node.visibleItemsCount ?? itemsPerPage;
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: updateNodeVisibleCount(node.items) };
300
+ return { ...node, items: updateNodePage(node.items) };
296
301
  }
297
302
  return node;
298
303
  });
299
304
  };
300
- const updatedData = updateNodeVisibleCount(dataSource);
305
+ const updatedData = updateNodePage(dataSource);
301
306
  onDataChanged?.(updatedData);
302
- }, [dataSource, itemsPerPage, onDataChanged, onNodeUpdate]);
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 i primi N items
314
- return node.items.slice(0, visibleCount);
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 bottone "Load More"
317
- const needsLoadMoreButton = useCallback((node) => {
323
+ // Verifica se c'è bisogno del paginatore
324
+ const needsPagination = useCallback((node) => {
318
325
  if (!showLoadMoreButton || !node.items)
319
326
  return false;
320
- const totalItems = node.items.length;
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)), needsLoadMoreButton(node) && (_jsx("div", { style: { display: 'flex', justifyContent: 'center', margin: '5px 0' }, children: _jsx(TMButton, { onClick: () => handleLoadMoreItems(node.key), showTooltip: false, caption: `Carica altri ${itemsPerPage}... (${node.visibleItemsCount ?? itemsPerPage} / ${node.items?.length ?? 0})` }) }))] }))] }, node.key)));
343
- }, [handleNodeClick, handleNodeToggle, handleCheckboxChange, focusedItem, selectedItems, allowMultipleSelection, getVisibleItems, needsLoadMoreButton, handleLoadMoreItems, itemsPerPage]);
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
+ `;
@@ -81,15 +81,14 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
81
81
  }, [maxValue, minValue, currentValue, currentType]);
82
82
  // Handle autofocus behavior on mount
83
83
  useEffect(() => {
84
- if (autoFocus && inputRef.current) {
85
- if (fromModal) // utilizzato per i textBox derivanti da una Modal che non riescono a utilizzare l'autofocus
86
- setTimeout(() => {
87
- inputRef.current && inputRef.current.focus(); // Focus the input field
88
- }, 100);
89
- else
90
- inputRef.current.focus(); // Focus the input field
91
- }
92
- }, [autoFocus]); // This effect runs when the autoFocus prop changes
84
+ if (!autoFocus || !inputRef.current)
85
+ return;
86
+ const delay = fromModal ? 100 : 50;
87
+ const timeoutId = setTimeout(() => {
88
+ inputRef.current?.focus();
89
+ }, delay);
90
+ return () => clearTimeout(timeoutId);
91
+ }, [autoFocus, fromModal]); // This effect runs when the autoFocus or fromModal prop changes
93
92
  useEffect(() => {
94
93
  if (formulaItems && formulaItems.length > 0) {
95
94
  let menuItems = [];
@@ -8,7 +8,7 @@ import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
8
8
  import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
9
9
  import { useRelatedDocuments } from '../../../hooks/useRelatedDocuments';
10
10
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
11
- import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, IconFileDots, IconCustom, buildWorkItemsFromWFCtrl, IconLock, getDcmtFormToolbarVisibility, TASK_MORE_INFO_PREFIX_NAME, calcResponsiveSizes } from '../../../helper';
11
+ import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, IconFileDots, IconCustom, buildWorkItemsFromWFCtrl, IconLock, getDcmtFormToolbarVisibility, TASK_MORE_INFO_PREFIX_NAME, taskModalSizes } from '../../../helper';
12
12
  import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
13
13
  import { Gutters, TMColors } from '../../../utils/theme';
14
14
  import { ReferencesContainer, StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledReferenceButton, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
@@ -1683,7 +1683,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
1683
1683
  setArchiveRelatedDcmtFormTID(undefined);
1684
1684
  setArchiveRelatedDcmtFormMids([]);
1685
1685
  await fetchData();
1686
- }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onReferenceClick: handleNavigateToReference })), showPairDcmtsModal && (_jsx(TMModal, { title: (isPairingManyToMany ? "Abbina" : "Disabbina") + " documenti", onClose: () => setShowPairDcmtsModal(false), width: isMobile ? '90%' : '50%', height: isMobile ? '90%' : '70%', children: _jsx(TMSearchResult, { searchResults: pairedSearchResults, onRefreshSearchAsync: async () => await fetchData(), onTaskCreateRequest: onTaskCreateRequest, allowFloatingBar: false, floatingActionConfig: pairFloatingActionConfig, showBackButton: false, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, toppyHelpCenterUsePortal: true }) })), (showMoreInfoTaskPopup && showMoreInfoTaskTask && showMoreInfoTaskTask.id && handleNavigateToWGs && handleNavigateToDossiers && getAllTasks && deleteTaskByIdsCallback && addTaskCallback && editTaskCallback) && _jsx(TMTaskForm, { id: Number(showMoreInfoTaskTask.id), title: showMoreInfoTaskTask.name ?? 'N/A', formMode: FormModes.Update, onSaved: onSavedTaskFormCallback, editTaskCallback: editTaskCallback, onClose: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, onCancel: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, isModal: true, showBackButton: false, hasNavigation: false, width: calcResponsiveSizes(deviceType, '670px', '670px', '95%'), height: calcResponsiveSizes(deviceType, '670px', '670px', '95%'), handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, visualizedTasks: [], currentTask: null, setCurrentTask: () => { }, selectedRowKeys: [], handleFocusedRowKeyChange: () => { }, onStatusChanged: () => { }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback })] }));
1686
+ }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onReferenceClick: handleNavigateToReference })), showPairDcmtsModal && (_jsx(TMModal, { title: (isPairingManyToMany ? "Abbina" : "Disabbina") + " documenti", onClose: () => setShowPairDcmtsModal(false), width: isMobile ? '90%' : '50%', height: isMobile ? '90%' : '70%', children: _jsx(TMSearchResult, { searchResults: pairedSearchResults, onRefreshSearchAsync: async () => await fetchData(), onTaskCreateRequest: onTaskCreateRequest, allowFloatingBar: false, floatingActionConfig: pairFloatingActionConfig, showBackButton: false, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, toppyHelpCenterUsePortal: true }) })), (showMoreInfoTaskPopup && showMoreInfoTaskTask && showMoreInfoTaskTask.id && handleNavigateToWGs && handleNavigateToDossiers && getAllTasks && deleteTaskByIdsCallback && addTaskCallback && editTaskCallback) && _jsx(TMTaskForm, { id: Number(showMoreInfoTaskTask.id), title: showMoreInfoTaskTask.name ?? 'N/A', formMode: FormModes.Update, onSaved: onSavedTaskFormCallback, editTaskCallback: editTaskCallback, onClose: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, onCancel: () => { setShowMoreInfoTaskPopup(false); setShowMoreInfoTaskTask(undefined); }, isModal: true, showBackButton: false, hasNavigation: false, width: taskModalSizes(deviceType, FormModes.Update).width, height: taskModalSizes(deviceType, FormModes.Update).height, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, visualizedTasks: [], currentTask: null, setCurrentTask: () => { }, selectedRowKeys: [], handleFocusedRowKeyChange: () => { }, onStatusChanged: () => { }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback })] }));
1687
1687
  };
1688
1688
  export default TMDcmtForm;
1689
1689
  /**
@@ -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