@topconsultnpm/sdkui-react 6.21.0-dev1.12 → 6.21.0-dev1.14

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.
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { DcmtTypeListCacheService, LayoutModes, SDK_Globals, SDK_Localizator } from '@topconsultnpm/sdk-ts';
4
4
  import TMRelationViewer from './TMRelationViewer';
5
5
  import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
6
- import { IconMultipleSelection, IconCheckFile, IconDetailDcmts, SDKUI_Localizator, IconMenuVertical, IconDataList, IconPreview, IconSearchCheck, IconBoard, IconDcmtTypeSys, IconShow, getMoreInfoTasksForDocument, isApprovalWorkflowView, searchResultToMetadataValues } from '../../../helper';
6
+ import { IconMultipleSelection, IconCheckFile, IconDetailDcmts, SDKUI_Localizator, IconMenuVertical, IconDataList, IconPreview, IconSearchCheck, IconBoard, IconDcmtTypeSys, IconShow, getMoreInfoTasksForDocument, isApprovalWorkflowView, searchResultToMetadataValues, IconRefresh } from '../../../helper';
7
7
  import { FormModes, SearchResultContext } from '../../../ts';
8
8
  import { TMColors } from '../../../utils/theme';
9
9
  import ShowAlert from '../../base/TMAlert';
@@ -14,7 +14,7 @@ import { TMPanelManagerProvider, useTMPanelManagerContext } from '../../layout/p
14
14
  import TMSearchResult from '../search/TMSearchResult';
15
15
  import TMDcmtForm from './TMDcmtForm';
16
16
  import { TMNothingToShow } from './TMDcmtPreview';
17
- import { Spinner } from '../..';
17
+ import { Spinner, TMButton } from '../..';
18
18
  import { useDocumentOperations } from '../../../hooks/useDocumentOperations';
19
19
  const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, deviceType, inputDcmts, isForMaster, showCurrentDcmtIndicator = true, allowNavigation, canNext, canPrev, onNext, onPrev, onBack, appendMasterDcmts, onTaskCreateRequest, onRefreshAfterAddDcmtToFavs, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, datagridUtility, dcmtUtility }) => {
20
20
  const floatingBarContainerRef = useRef(null);
@@ -29,8 +29,8 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
29
29
  const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
30
30
  const [dtdFocused, setDtdFocused] = useState();
31
31
  const [refreshKey, setRefreshKey] = useState(0);
32
- // Stato per gestire la transizione fluida durante il refresh
33
- const [isRefreshing, setIsRefreshing] = useState(false);
32
+ // Separate refresh key for TMFormOrResultWrapper only (doesn't affect tmTreeView)
33
+ const [refreshKeyFormOrResult, setRefreshKeyFormOrResult] = useState(0);
34
34
  /** State for transformed focusedItem metadata values (similar to formData in TMDcmtForm) */
35
35
  const [focusedItemFormData, setFocusedItemFormData] = useState([]);
36
36
  // Trigger operationItems refresh (after file substitution, etc.)
@@ -39,20 +39,15 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
39
39
  const onRefreshOperationsDatagrid = useCallback(async () => {
40
40
  setRefreshOperationsTrigger(prev => prev + 1);
41
41
  }, []);
42
- // Refresh con transizione fluida: fade-out -> update -> fade-in
43
- const onRefreshSearch = async () => {
44
- await dcmtUtility?.onRefreshPreviewForm?.();
45
- // Avvia fade-out
46
- setIsRefreshing(true);
47
- // Attendi che il fade-out sia completato, poi aggiorna
48
- setTimeout(() => {
49
- setRefreshKey(prev => prev + 1);
50
- onRefreshOperationsDatagrid();
51
- // Attendi un po' per dare tempo al re-render, poi fade-in
52
- setTimeout(() => {
53
- setIsRefreshing(false);
54
- }, 300); // Durata extra dell'overlay dopo l'update
55
- }, 200); // Durata del fade-out
42
+ // Refresh ALL panels (tree view + search results) with fade-out -> update -> fade-in transition
43
+ const onRefreshAllPanels = async () => {
44
+ await dcmtUtility?.onRefreshPreviewForm?.(); // Refresh preview form data
45
+ setFocusedItem(undefined); // Clear focused item to avoid stale references
46
+ setTimeout(async () => {
47
+ setRefreshKey(prev => prev + 1); // Force re-render of tmTreeView
48
+ setRefreshKeyFormOrResult(prev => prev + 1); // Force re-render of TMFormOrResultWrapper
49
+ await onRefreshOperationsDatagrid(); // Refresh operation items
50
+ }, 200); // Wait for fade-out animation
56
51
  };
57
52
  useEffect(() => {
58
53
  const fetchFocusedItemMetadata = async () => {
@@ -134,11 +129,11 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
134
129
  // searchResult: selectedSearchResult,
135
130
  datagridUtility: {
136
131
  visibleItems: [],
137
- onRefreshSearchAsyncDatagrid: onRefreshSearch,
138
- onRefreshDataRowsAsync: onRefreshSearch,
139
- refreshFocusedDataRowAsync: datagridUtility?.refreshFocusedDataRowAsync,
140
- onRefreshBlogDatagrid: datagridUtility?.onRefreshBlogDatagrid,
141
- onRefreshPreviewDatagrid: datagridUtility?.onRefreshPreviewDatagrid,
132
+ onRefreshSearchAsyncDatagrid: onRefreshAllPanels,
133
+ onRefreshDataRowsAsync: onRefreshAllPanels,
134
+ refreshFocusedDataRowAsync: onRefreshAllPanels,
135
+ onRefreshBlogDatagrid: onRefreshAllPanels,
136
+ onRefreshPreviewDatagrid: onRefreshAllPanels,
142
137
  refreshOperationsTrigger,
143
138
  onRefreshOperationsDatagrid,
144
139
  },
@@ -148,10 +143,10 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
148
143
  selectedDcmtSearchResultRelations: dcmtUtility?.selectedDcmtSearchResultRelations,
149
144
  dcmtTIDHasDetailRelations: dcmtUtility?.dcmtTIDHasDetailRelations,
150
145
  dcmtTIDHasMasterRelations: dcmtUtility?.dcmtTIDHasMasterRelations,
151
- updateCurrentDcmt: onRefreshSearch,
146
+ updateCurrentDcmt: onRefreshAllPanels,
152
147
  onCloseDcmtForm: dcmtUtility?.onCloseDcmtForm,
153
148
  onRefreshBlogForm: dcmtUtility?.onRefreshBlogForm,
154
- onRefreshPreviewForm: onRefreshSearch,
149
+ onRefreshPreviewForm: onRefreshAllPanels,
155
150
  taskFormDialogComponent: dcmtUtility?.taskFormDialogComponent,
156
151
  s4TViewerDialogComponent: dcmtUtility?.s4TViewerDialogComponent
157
152
  },
@@ -271,7 +266,7 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
271
266
  }
272
267
  }
273
268
  ];
274
- const toolbar = _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [allowMultipleSelection && _jsx("p", { style: { color: TMColors.colorHeader, textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${selectedItems.filter(item => item.isDcmt).length} selezionati` }), allowNavigation && canPrev != undefined && _jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', iconColor: 'white', isModified: false, formMode: FormModes.ReadOnly, canPrev: canPrev, onPrev: onPrev }), allowNavigation && canNext != undefined && _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', iconColor: 'white', isModified: false, formMode: FormModes.ReadOnly, canNext: canNext, onNext: onNext }), _jsx(TMContextMenu, { items: commandsMenuItems, trigger: 'left', children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) })] });
269
+ const toolbar = _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [allowMultipleSelection && _jsx("p", { style: { color: TMColors.colorHeader, textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${selectedItems.filter(item => item.isDcmt).length} selezionati` }), allowNavigation && canPrev != undefined && _jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', iconColor: 'white', isModified: false, formMode: FormModes.ReadOnly, canPrev: canPrev, onPrev: onPrev }), allowNavigation && canNext != undefined && _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', iconColor: 'white', isModified: false, formMode: FormModes.ReadOnly, canNext: canNext, onNext: onNext }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: onRefreshAllPanels }), _jsx(TMContextMenu, { items: commandsMenuItems, trigger: 'left', children: _jsx(IconMenuVertical, { color: 'white', cursor: 'pointer' }) })] });
275
270
  const getTitle = () => isForMaster ? `${SDKUI_Localizator.DcmtsMaster} - ${dtdMaster?.nameLoc}` : SDKUI_Localizator.DcmtsDetail;
276
271
  const isMobile = deviceType === DeviceType.MOBILE;
277
272
  const tmTreeView = useMemo(() => _jsx(_Fragment, { children: !inputDcmts || inputDcmts.length === 0
@@ -290,7 +285,7 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
290
285
  position: contextMenuPosition,
291
286
  onClose: () => setContextMenuVisible(false)
292
287
  } })] }) }), [inputDcmts, isForMaster, showCurrentDcmtIndicator, showZeroDcmts, allowMultipleSelection, focusedItem, selectedItems, handleFocusedItemChanged, handleSelectedItemsChanged, handleNoRelationsFound, onItemContextMenu, contextMenuVisible, contextMenuPosition, refreshKey, focusedItemFormData]);
293
- const tmFormOrResult = useMemo(() => _jsx(TMFormOrResultWrapper, { refreshKey: refreshKey, deviceType: deviceType, focusedItem: focusedItem, onTaskCreateRequest: onTaskCreateRequest, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest }), [focusedItem, deviceType, allTasks, handleNavigateToWGs, handleNavigateToDossiers, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onRefreshAfterAddDcmtToFavs, refreshKey]);
288
+ const tmFormOrResult = useMemo(() => _jsx(TMFormOrResultWrapper, { refreshKey: refreshKeyFormOrResult, deviceType: deviceType, focusedItem: focusedItem, onTaskCreateRequest: onTaskCreateRequest, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onRefreshSearchResults: onRefreshAllPanels }), [focusedItem, deviceType, allTasks, handleNavigateToWGs, handleNavigateToDossiers, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onRefreshAfterAddDcmtToFavs, refreshKeyFormOrResult]);
294
289
  const initialPanelDimensions = {
295
290
  'tmTreeView': { width: '50%', height: '100%' },
296
291
  'tmFormOrResult': { width: '50%', height: '100%' },
@@ -367,28 +362,7 @@ const TMMasterDetailDcmts = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallba
367
362
  toolbarOptions: { icon: _jsx(IconSearchCheck, { fontSize: 24 }), visible: false, orderNumber: 2, isActive: allInitialPanelVisibility['tmFormOrResult'] }
368
363
  }
369
364
  ], [tmTreeView, tmFormOrResult, focusedItem?.isDcmt, dtdMaster]);
370
- return (_jsxs("div", { style: { width: '100%', height: '100%', position: 'relative' }, children: [isCheckingFirstLoad && (_jsx(Spinner, { description: SDKUI_Localizator.Loading, flat: true })), _jsxs("div", { style: isCheckingFirstLoad ? { position: 'absolute', width: 0, height: 0, overflow: 'hidden', opacity: 0, pointerEvents: 'none' } : { width: '100%', height: '100%' }, children: [_jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }), _jsxs("div", { style: {
371
- position: 'absolute',
372
- top: 0,
373
- left: 0,
374
- right: 0,
375
- bottom: 0,
376
- backgroundColor: 'rgba(255, 255, 255, 0.7)',
377
- display: 'flex',
378
- alignItems: 'center',
379
- justifyContent: 'center',
380
- opacity: isRefreshing ? 1 : 0,
381
- pointerEvents: isRefreshing ? 'auto' : 'none',
382
- transition: 'opacity 200ms ease-in-out',
383
- zIndex: 10,
384
- }, children: [_jsx("div", { style: {
385
- width: 40,
386
- height: 40,
387
- border: '3px solid #e0e0e0',
388
- borderTopColor: TMColors.primaryColor,
389
- borderRadius: '50%',
390
- animation: 'spin 0.8s linear infinite',
391
- } }), _jsx("style", { children: `@keyframes spin { to { transform: rotate(360deg); } }` })] }), renderDcmtOperations, renderFloatingBar] })] }));
365
+ return (_jsxs("div", { style: { width: '100%', height: '100%', position: 'relative' }, children: [isCheckingFirstLoad && (_jsx(Spinner, { description: SDKUI_Localizator.Loading, flat: true })), _jsxs("div", { style: isCheckingFirstLoad ? { position: 'absolute', width: 0, height: 0, overflow: 'hidden', opacity: 0, pointerEvents: 'none' } : { width: '100%', height: '100%' }, children: [_jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmTreeView', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }), renderDcmtOperations, renderFloatingBar] })] }));
392
366
  };
393
367
  export default TMMasterDetailDcmts;
394
368
  /**
@@ -430,11 +404,11 @@ const TMRelationViewerWrapper = ({ refreshKey, inputDcmts, isForMaster, showCurr
430
404
  }, [onItemContextMenu, handleFocusedItemChanged]);
431
405
  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, onItemContextMenu: onContextMenu, focusedItemFormData: focusedItemFormData }, refreshKey));
432
406
  };
433
- const TMFormOrResultWrapper = ({ refreshKey, deviceType, focusedItem, onTaskCreateRequest, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, onRefreshAfterAddDcmtToFavs, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onRefreshSearchAsyncDatagrid }) => {
407
+ const TMFormOrResultWrapper = ({ refreshKey, deviceType, focusedItem, onTaskCreateRequest, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, handleNavigateToWGs, handleNavigateToDossiers, onRefreshAfterAddDcmtToFavs, editPdfForm, openS4TViewer, onOpenS4TViewerRequest, onOpenPdfEditorRequest, onRefreshSearchAsyncDatagrid, onRefreshSearchResults }) => {
434
408
  const { setPanelVisibilityById } = useTMPanelManagerContext();
435
409
  return (_jsx(_Fragment, { children: focusedItem?.isDcmt ?
436
410
  _jsx(TMDcmtForm, { groupId: 'tmFormOrResult', TID: focusedItem?.tid, DID: focusedItem.did, allowButtonsRefs: true, isClosable: deviceType !== DeviceType.MOBILE, allowNavigation: false, allowRelations: deviceType !== DeviceType.MOBILE, showDcmtFormSidebar: false, onClose: () => { setPanelVisibilityById('tmTreeView', true); }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, moreInfoTasks: getMoreInfoTasksForDocument(allTasks, focusedItem?.tid, focusedItem?.did), openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, datagridUtility: {
437
411
  onRefreshSearchAsyncDatagrid,
438
412
  } }, refreshKey) :
439
- _jsx(TMSearchResult, { groupId: 'tmFormOrResult', isClosable: deviceType !== DeviceType.MOBILE, context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, allowRelations: false, openDcmtFormAsModal: true, searchResults: focusedItem?.searchResult ?? [], showSearchResultSidebar: false, showDcmtFormSidebar: false, onTaskCreateRequest: onTaskCreateRequest, onClose: () => { setPanelVisibilityById('tmTreeView', true); }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, enablePinIcons: false, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, showBackButton: false }, refreshKey) }));
413
+ _jsx(TMSearchResult, { groupId: 'tmFormOrResult', isClosable: deviceType !== DeviceType.MOBILE, context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, allowRelations: false, openDcmtFormAsModal: true, searchResults: focusedItem?.searchResult ?? [], showSearchResultSidebar: false, showDcmtFormSidebar: false, onTaskCreateRequest: onTaskCreateRequest, onClose: () => { setPanelVisibilityById('tmTreeView', true); }, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, editPdfForm: editPdfForm, onOpenPdfEditorRequest: onOpenPdfEditorRequest, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, enablePinIcons: false, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, showBackButton: false, onRefreshSearchAsyncDatagrid: onRefreshSearchResults }, refreshKey) }));
440
414
  };
@@ -628,6 +628,7 @@ const TMRelationViewer = ({ inputDcmts, isForMaster = false, showCurrentDcmtIndi
628
628
  isZero: dcmt.DID === 0,
629
629
  isMaster: !isForMaster,
630
630
  isLoaded: true,
631
+ isLogDel: docRow?.ISLOGDEL?.value,
631
632
  hidden: false,
632
633
  values: docRow,
633
634
  searchResult: result ? [result] : [],
@@ -352,7 +352,7 @@ handleNavigateToWGs, handleNavigateToDossiers, }) => {
352
352
  openTaskFormHandler,
353
353
  },
354
354
  });
355
- const { isOpenDcmtForm, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showExportForm, isOpenBatchUpdate, isModifiedBatchUpdate, updateBatchUpdateForm, handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
355
+ const { isOpenDcmtForm, openFormHandler, dcmtFormLayoutMode, onDcmtFormOpenChange, showSearchTMDatagrid, showExportForm, isOpenBatchUpdate, isModifiedBatchUpdate, updateBatchUpdateForm, handleSignApprove, checkoutInfo: { showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, }, dcmtOperations: { abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, FileSourceDialog, }, relatedDocumentsInfo: { isOpenDetails, isOpenMaster, checkRelatedDcmtsArchiveCapability, checkManyToManyCapability, }, toppyOperations: { showApprovePopup, showRejectPopup, showReAssignPopup, showMoreInfoPopup, updateShowApprovePopup, updateShowRejectPopup, updateShowReAssignPopup, updateShowMoreInfoPopup } } = features;
356
356
  const deviceType = useDeviceType();
357
357
  const isMobile = deviceType === DeviceType.MOBILE;
358
358
  const selectedDocs = getSelectedDcmtsOrFocused(selectedItems, focusedItem);
@@ -703,26 +703,7 @@ const TMQueryEditor = ({ formMode, inputData, onQDChanged, isExpertMode, showDis
703
703
  }
704
704
  };
705
705
  // #endregion
706
- const getQueryCountLocalAsync = async (qd, showSpinner) => {
707
- if (IsParametricQuery(qd)) {
708
- const qdParams = await confirmQueryParams(qd, lastQdParams);
709
- setLastQdParams(qdParams);
710
- if (!qdParams || qdParams.length <= 0)
711
- return;
712
- for (const qpd of qdParams) {
713
- let wi = qd.where?.find(o => o.value1 == qpd.name);
714
- if (wi)
715
- wi.value1 = wi.value1?.replace(wi.value1, !qpd.value ? '' : qpd.value.toString());
716
- else {
717
- wi = qd.where?.find(o => o.value2 == qpd.name);
718
- if (wi)
719
- wi.value2 = wi.value2?.replace(wi.value2, !qpd.value ? '' : qpd.value.toString());
720
- }
721
- }
722
- }
723
- await getQueryCountAsync(qd, showSpinner);
724
- };
725
- return (_jsxs(_Fragment, { children: [_jsxs(TMApplyForm, { isModal: false, formMode: formMode, isModified: calcIsModified(formData, formDataOrig), exception: exception, validationItems: validationItems, hasNavigation: false, customToolbarElements: _jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Search, color: 'tertiary', icon: _jsx(IconSearch, {}), disabled: errorsCount > 0, onClick: async () => await onSearchAsync(formData) }), _jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Count, icon: _jsx(IconCount, {}), disabled: errorsCount > 0, onClick: () => getQueryCountLocalAsync(formData, true) }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Passa ad archiviazione", icon: _jsx(IconArchiveDoc, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Passa ad archiviazione", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Vai a risultato", icon: _jsx(IconArrowRight, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Vai a risultato", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } })] }), showToolbar: showToolbar, showApply: showApply, showUndo: showUndo, showBack: showBack, onApply: () => applyData(), onClose: () => onClose?.(), onUndo: () => setFormData(formDataOrig), children: [_jsxs(Accordion, { elementAttr: { class: 'tm-query-dx-accordion' }, height: height, multiple: true, collapsible: true, repaintChangesOnly: true, deferRendering: false, animationDuration: 0, onContentReady: (e) => {
706
+ return (_jsxs(_Fragment, { children: [_jsxs(TMApplyForm, { isModal: false, formMode: formMode, isModified: calcIsModified(formData, formDataOrig), exception: exception, validationItems: validationItems, hasNavigation: false, customToolbarElements: _jsxs(_Fragment, { children: [_jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Search, color: 'tertiary', icon: _jsx(IconSearch, {}), disabled: errorsCount > 0, onClick: async () => await onSearchAsync(formData) }), _jsx(TMButton, { btnStyle: 'toolbar', caption: SDKUI_Localizator.Count, icon: _jsx(IconCount, {}), disabled: errorsCount > 0, onClick: () => getQueryCountAsync(formData, true) }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Passa ad archiviazione", icon: _jsx(IconArchiveDoc, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Passa ad archiviazione", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID == AppModules.SURFER && _jsx(TMButton, { caption: "Vai a risultato", icon: _jsx(IconArrowRight, {}), btnStyle: 'toolbar', fontSize: '1.3rem', onClick: () => { ShowAlert({ message: "TODO Vai a risultato", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } })] }), showToolbar: showToolbar, showApply: showApply, showUndo: showUndo, showBack: showBack, onApply: () => applyData(), onClose: () => onClose?.(), onUndo: () => setFormData(formDataOrig), children: [_jsxs(Accordion, { elementAttr: { class: 'tm-query-dx-accordion' }, height: height, multiple: true, collapsible: true, repaintChangesOnly: true, deferRendering: false, animationDuration: 0, onContentReady: (e) => {
726
707
  let items = e.component.option("items");
727
708
  if (items && items.length > 0) {
728
709
  for (let i = 0; i < items.length; i++) {
@@ -123,4 +123,6 @@ export declare class DcmtFormSettings {
123
123
  }
124
124
  export declare class SDKUI_Globals {
125
125
  static userSettings: UserSettings;
126
+ /** Global handler for scanner requests. Set by the host app (e.g. surfer) to open the scanner UI. */
127
+ static scanRequestHandler?: (mode: 'new' | 'edit', onFileScanned: (file: File) => void, onCancel: () => void, existingFile?: File) => void;
126
128
  }
@@ -21,5 +21,6 @@ export interface UseDcmtOperationsReturn {
21
21
  removeDcmtsFileCache: (key: string) => void;
22
22
  isDcmtFileInCache: (key: string) => boolean;
23
23
  runOperationAsync: (inputDcmts: DcmtInfo[] | undefined, dcmtOperationType: DcmtOperationTypes, actionAfterOperationAsync?: () => Promise<void>) => Promise<void>;
24
+ FileSourceDialog: () => JSX.Element;
24
25
  }
25
26
  export declare const useDcmtOperations: () => UseDcmtOperationsReturn;
@@ -4,9 +4,19 @@ import { SDK_Globals, RetrieveFileOptions, DcmtOpers, ResultTypes, RecentCategor
4
4
  import { ShowAlert, TMResultManager, FormulaHelper, TMExceptionBoxManager, TMSpinner } from '../components';
5
5
  import { Globalization, getExceptionMessage, dialogConfirmOperation, extensionHandler, downloadBase64File, SDKUI_Globals, dcmtsFileCacheDownload, CACHE_SIZE_LIMIT, clearDcmtsFileCache, dcmtsFileCachePreview, isDcmtFileInCache, removeDcmtsFileCache, SDKUI_Localizator } from '../helper';
6
6
  import { DcmtOperationTypes, DownloadTypes, FileExtensionHandler } from '../ts';
7
- import { useFileDialog } from './useInputDialog';
7
+ import { useFileDialog, useFileSourceDialog } from './useInputDialog';
8
8
  import { isXMLFileExt } from '../helper/dcmtsHelper';
9
9
  import { ShowConfirm } from '../components/base/TMConfirm';
10
+ import { useBetaFeatures } from './useBetaFeatures';
11
+ const isScannerLicenseConfigured = () => {
12
+ try {
13
+ const scannerLicense = SDKUI_Globals.userSettings.advancedSettings.scannerLicense;
14
+ return scannerLicense && scannerLicense.trim() !== '';
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ };
10
20
  let abortController = new AbortController();
11
21
  const downloadCountMap = new Map();
12
22
  const getDownloadFileName = (fileName) => {
@@ -32,6 +42,8 @@ export const useDcmtOperations = () => {
32
42
  const [waitPanelValueSecondary, setWaitPanelValueSecondary] = useState(0);
33
43
  const [waitPanelMaxValueSecondary, setWaitPanelMaxValueSecondary] = useState(0);
34
44
  const { OpenFileDialog } = useFileDialog();
45
+ const isBetaFeaturesEnabled = useBetaFeatures();
46
+ const [selectFileSource, FileSourceDialog] = useFileSourceDialog();
35
47
  const _downloadDcmtsAsync = async (inputDcmts, downloadMode = "download", onFileDownloaded, skipConfirmation = false) => {
36
48
  if (inputDcmts === undefined)
37
49
  return;
@@ -210,7 +222,60 @@ export const useDcmtOperations = () => {
210
222
  return;
211
223
  if (inputDcmts.length <= 0)
212
224
  return;
213
- let file = inputDcmts[0].FILE ?? await OpenFileDialog();
225
+ let file = inputDcmts[0].FILE;
226
+ if (!file) {
227
+ if (isBetaFeaturesEnabled && isScannerLicenseConfigured()) {
228
+ const source = await selectFileSource();
229
+ if (!source)
230
+ return;
231
+ switch (source) {
232
+ case 'filesystem':
233
+ file = await OpenFileDialog();
234
+ break;
235
+ case 'scanner-new':
236
+ if (SDKUI_Globals.scanRequestHandler) {
237
+ file = await new Promise((resolve) => {
238
+ SDKUI_Globals.scanRequestHandler('new', (scannedFile) => resolve(scannedFile), () => resolve(undefined));
239
+ });
240
+ }
241
+ else {
242
+ ShowAlert({ message: 'Funzionalità scanner non disponibile in questo contesto.', mode: 'info', duration: 3000, title: 'Scanner' });
243
+ return;
244
+ }
245
+ break;
246
+ case 'scanner-edit':
247
+ if (SDKUI_Globals.scanRequestHandler) {
248
+ // Download the existing file from the document
249
+ let existingFile;
250
+ try {
251
+ const rfo = new RetrieveFileOptions();
252
+ rfo.retrieveReason = DcmtOpers.None;
253
+ const retrievedFile = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(inputDcmts[0].TID, inputDcmts[0].DID, rfo);
254
+ existingFile = retrievedFile;
255
+ }
256
+ catch (ex) {
257
+ TMExceptionBoxManager.show({ exception: getExceptionMessage(ex) });
258
+ return;
259
+ }
260
+ if (!existingFile) {
261
+ ShowAlert({ message: 'Impossibile recuperare il file del documento.', mode: 'warning', duration: 3000, title: 'Scanner' });
262
+ return;
263
+ }
264
+ file = await new Promise((resolve) => {
265
+ SDKUI_Globals.scanRequestHandler('edit', (scannedFile) => resolve(scannedFile), () => resolve(undefined), existingFile);
266
+ });
267
+ }
268
+ else {
269
+ ShowAlert({ message: 'Funzionalità scanner non disponibile in questo contesto.', mode: 'info', duration: 3000, title: 'Scanner' });
270
+ return;
271
+ }
272
+ break;
273
+ }
274
+ }
275
+ else {
276
+ file = await OpenFileDialog();
277
+ }
278
+ }
214
279
  if (!file)
215
280
  return;
216
281
  setShowWaitPanel(true);
@@ -489,10 +554,16 @@ export const useDcmtOperations = () => {
489
554
  actionAfterOperationAsync?.();
490
555
  TMResultManager.show(result, operationTitle, "TID", "DID");
491
556
  };
492
- dialogConfirmOperation(operationTitle, msg, doOperationAsync);
557
+ // Per SubstituteFile con beta features e scanner, non mostrare conferma
558
+ if (dcmtOperationType === DcmtOperationTypes.SubstituteFile && isBetaFeaturesEnabled && isScannerLicenseConfigured()) {
559
+ await doOperationAsync();
560
+ }
561
+ else {
562
+ dialogConfirmOperation(operationTitle, msg, doOperationAsync);
563
+ }
493
564
  };
494
565
  return {
495
566
  abortController, showWaitPanel, showPrimary, waitPanelTitle, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary,
496
- downloadDcmtsAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, runOperationAsync
567
+ downloadDcmtsAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, runOperationAsync, FileSourceDialog
497
568
  };
498
569
  };
@@ -109,7 +109,7 @@ export const useDocumentOperations = (props) => {
109
109
  const { showHistory, showHistoryCallback, hideHistoryCallback, showCheckoutInformationForm, commentFormState, hideCommentFormCallback, showCheckoutInformationFormCallback, hideCheckoutInformationFormCallback, copyCheckoutPathToClipboardCallback, handleCheckOutCallback, handleCheckInCallback, showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, } = useCheckInOutOperations({
110
110
  onRefreshPreview: onRefreshPreviewCallback
111
111
  });
112
- const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache } = useDcmtOperations();
112
+ const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, FileSourceDialog } = useDcmtOperations();
113
113
  const {
114
114
  // Data
115
115
  relatedDcmts, pairedSearchResults, manyToManyRelations, selectedManyToManyRelation, manyToManyChooserDataSource, relatedDcmtsChooserDataSource,
@@ -1081,6 +1081,7 @@ export const useDocumentOperations = (props) => {
1081
1081
  ...(inputDcmtFormLayoutMode === LayoutModes.Update ? [addToFavoriteOperation()] : []),
1082
1082
  addReplaceFileOperation(),
1083
1083
  openFormOperation(),
1084
+ deletetionMenuItem(),
1084
1085
  fileCheckMenuItem(),
1085
1086
  fileConversionsMenuItem(),
1086
1087
  ...(SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ? [createContextualTaskMenuItem()] : []),
@@ -1182,7 +1183,7 @@ export const useDocumentOperations = (props) => {
1182
1183
  updateBatchUpdateForm(false);
1183
1184
  setIsModifiedBatchUpdate(false);
1184
1185
  await onRefreshDataRowsAsync?.();
1185
- }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, onClose: () => updateShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { fromDTD: dtd, TID: contextConfig.approvalTID, DID: focusedItem?.DID, deviceType: deviceType, onCompleted: handleWFOperationCompleted, onClose: () => updateShowMoreInfoPopup(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, triggerBlogRefresh: onRefreshBlogDatagrid }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1186
+ }, onStatusChanged: (isModified) => { setIsModifiedBatchUpdate(isModified); } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 0, onClose: () => updateShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, isReject: 1, onClose: () => updateShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, selectedItems: selectedDcmtInfos, onClose: () => updateShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { fromDTD: dtd, TID: contextConfig.approvalTID, DID: focusedItem?.DID, deviceType: deviceType, onCompleted: handleWFOperationCompleted, onClose: () => updateShowMoreInfoPopup(false), allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, triggerBlogRefresh: onRefreshBlogDatagrid }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {}), _jsx(FileSourceDialog, {}), taskFormDialogComponent, s4TViewerDialogComponent, currentCustomButton && _jsx(TMCustomButton, { button: currentCustomButton, formData: currentMetadataValues, selectedItems: selectedItemsFull, onClose: () => setCurrentCustomButton(undefined) })] }));
1186
1187
  return {
1187
1188
  operationItems: operationItems(),
1188
1189
  renderFloatingBar,
@@ -1235,6 +1236,7 @@ export const useDocumentOperations = (props) => {
1235
1236
  removeDcmtsFileCache,
1236
1237
  isDcmtFileInCache,
1237
1238
  runOperationAsync,
1239
+ FileSourceDialog,
1238
1240
  },
1239
1241
  relatedDocumentsInfo: {
1240
1242
  // Data
@@ -7,3 +7,5 @@ export declare const useInputAttachmentsDialog: () => {
7
7
  openConfirmAttachmentsDialog: (list: FileDescriptor[]) => Promise<string[] | undefined>;
8
8
  ConfirmAttachmentsDialog: () => import("react/jsx-runtime").JSX.Element | null;
9
9
  };
10
+ export type FileSourceType = 'filesystem' | 'scanner-new' | 'scanner-edit' | undefined;
11
+ export declare const useFileSourceDialog: () => [() => Promise<FileSourceType>, () => JSX.Element];
@@ -103,3 +103,37 @@ export const useInputAttachmentsDialog = () => {
103
103
  };
104
104
  return { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog };
105
105
  };
106
+ const fileSourceOptions = [
107
+ { value: 'filesystem', display: 'Da file system' },
108
+ { value: 'scanner-new', display: 'Da scanner (nuova scansione)' },
109
+ { value: 'scanner-edit', display: 'Da scanner (modifica scansione)' },
110
+ ];
111
+ export const useFileSourceDialog = () => {
112
+ const [promise, setPromise] = useState(null);
113
+ const [open, setOpen] = useState(false);
114
+ const handleClose = () => {
115
+ setOpen(false);
116
+ setPromise(null);
117
+ };
118
+ const handleConfirm = (source) => {
119
+ promise?.resolve(source);
120
+ handleClose();
121
+ };
122
+ const handleCancel = () => {
123
+ promise?.resolve(undefined);
124
+ handleClose();
125
+ };
126
+ const FileSourceDialog = () => {
127
+ const [source, setSource] = useState('filesystem');
128
+ return (open ?
129
+ _jsx(TMModal, { title: SDKUI_Localizator.AddOrSubstFile, height: "max-content", width: "320px", onClose: handleCancel, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '5px', padding: '10px', height: '100%' }, children: [_jsx(TMRadioButton, { dataSource: fileSourceOptions, direction: 'column', value: source, onValueChanged: (newValue) => { setSource(newValue); } }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', gap: '5px', paddingTop: '10px', justifyContent: 'center', alignItems: 'center', height: '50px' }, children: [_jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconApply, {}), caption: "OK", advancedColor: TMColors.tertiary, onClick: () => handleConfirm(source) }), _jsx(TMButton, { btnStyle: "advanced", showTooltip: false, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Cancel, onClick: handleCancel })] })] }) })
130
+ : _jsx(_Fragment, {}));
131
+ };
132
+ const selectFileSource = () => {
133
+ return new Promise((resolve) => {
134
+ setOpen(true);
135
+ setPromise({ resolve });
136
+ });
137
+ };
138
+ return [selectFileSource, FileSourceDialog];
139
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.21.0-dev1.12",
3
+ "version": "6.21.0-dev1.14",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",