@topconsultnpm/sdkui-react 6.22.0-dev3.9 → 6.22.0-dev4.11

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.
Files changed (97) hide show
  1. package/lib/components/base/TMAlert.js +6 -8
  2. package/lib/components/base/TMAreaManager.js +53 -55
  3. package/lib/components/base/TMButton.js +4 -2
  4. package/lib/components/base/TMCounterContainer.d.ts +3 -1
  5. package/lib/components/base/TMCounterContainer.js +16 -1
  6. package/lib/components/base/TMCustomButton.js +40 -48
  7. package/lib/components/base/TMDataGrid.js +24 -4
  8. package/lib/components/base/TMPanel.js +173 -170
  9. package/lib/components/base/TMSpinner.d.ts +2 -1
  10. package/lib/components/base/TMSpinner.js +9 -7
  11. package/lib/components/base/TMTabControl.d.ts +5 -0
  12. package/lib/components/base/TMTabControl.js +18 -7
  13. package/lib/components/base/TMTreeView.js +20 -0
  14. package/lib/components/base/TMWaitPanel.js +1 -1
  15. package/lib/components/base/waitPanel/TMWaitPanelConfirm.d.ts +12 -0
  16. package/lib/components/base/waitPanel/TMWaitPanelConfirm.js +185 -0
  17. package/lib/components/base/waitPanel/TMWaitPanelManager.d.ts +179 -0
  18. package/lib/components/base/waitPanel/TMWaitPanelManager.js +373 -0
  19. package/lib/components/base/waitPanel/TMWaitPanelView.d.ts +58 -0
  20. package/lib/components/base/waitPanel/TMWaitPanelView.js +346 -0
  21. package/lib/components/base/waitPanel/index.d.ts +1 -0
  22. package/lib/components/base/waitPanel/index.js +1 -0
  23. package/lib/components/choosers/TMDistinctValues.js +3 -3
  24. package/lib/components/choosers/TMPathChooser.js +17 -34
  25. package/lib/components/editors/TMTextBox.d.ts +4 -0
  26. package/lib/components/editors/TMTextBox.js +99 -11
  27. package/lib/components/features/archive/TMArchive.js +7 -2
  28. package/lib/components/features/assistant/TMHelpOnLineChat.d.ts +28 -0
  29. package/lib/components/features/assistant/TMHelpOnLineChat.js +1231 -0
  30. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.js +2 -2
  31. package/lib/components/features/documents/TMBatchUpdateForm.js +3 -4
  32. package/lib/components/features/documents/TMCopyToFolderForm.js +53 -84
  33. package/lib/components/features/documents/TMDcmtForm.js +50 -61
  34. package/lib/components/features/documents/TMDcmtIcon.d.ts +1 -3
  35. package/lib/components/features/documents/TMDcmtIcon.js +3 -5
  36. package/lib/components/features/documents/TMDcmtPreview.js +5 -3
  37. package/lib/components/features/documents/TMDcmtTasks.js +2 -9
  38. package/lib/components/features/documents/TMFileUploader.js +26 -26
  39. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  40. package/lib/components/features/documents/TMMasterDetailDcmts.js +53 -148
  41. package/lib/components/features/documents/TMMasterInfoFields.js +3 -2
  42. package/lib/components/features/documents/TMMergeToPdfForm.js +52 -56
  43. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +14 -15
  44. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +1 -1
  45. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.js +3 -3
  46. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -14
  47. package/lib/components/features/documents/TMRelationViewer.js +206 -143
  48. package/lib/components/features/documents/relationTreeState.d.ts +32 -0
  49. package/lib/components/features/documents/relationTreeState.js +89 -0
  50. package/lib/components/features/search/TMSearch.js +3 -4
  51. package/lib/components/features/search/TMSearchQueryPanel.js +0 -4
  52. package/lib/components/features/search/TMSearchResult.d.ts +5 -0
  53. package/lib/components/features/search/TMSearchResult.js +51 -24
  54. package/lib/components/features/search/TMTreeSelector.js +23 -27
  55. package/lib/components/features/search/TMViewHistoryDcmt.js +15 -26
  56. package/lib/components/features/tasks/TMTasksView.js +97 -90
  57. package/lib/components/features/wg/TMWGsCopyMoveForm.js +104 -100
  58. package/lib/components/forms/TMResultDialog.js +1 -1
  59. package/lib/components/grids/TMBlogsPost.js +93 -97
  60. package/lib/components/index.d.ts +5 -1
  61. package/lib/components/index.js +4 -1
  62. package/lib/components/layout/panelManager/TMPanelManagerContainer.js +16 -15
  63. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +1 -0
  64. package/lib/components/layout/panelManager/TMPanelManagerContext.js +5 -1
  65. package/lib/components/layout/panelManager/TMPanelManagerLoader.d.ts +6 -0
  66. package/lib/components/layout/panelManager/TMPanelManagerLoader.js +18 -0
  67. package/lib/components/layout/panelManager/TMPanelManagerToolbar.js +4 -8
  68. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +1 -1
  69. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.js +2 -1
  70. package/lib/components/pages/TMPage.js +32 -31
  71. package/lib/components/query/TMQueryEditor.d.ts +3 -0
  72. package/lib/components/query/TMQueryEditor.js +2 -1
  73. package/lib/components/sidebar/TMHeader.d.ts +1 -0
  74. package/lib/components/sidebar/TMHeader.js +2 -2
  75. package/lib/helper/Enum_Localizator.js +1 -0
  76. package/lib/helper/SDKUI_Globals.d.ts +7 -2
  77. package/lib/helper/SDKUI_Globals.js +7 -2
  78. package/lib/helper/SDKUI_Localizator.d.ts +31 -6
  79. package/lib/helper/SDKUI_Localizator.js +301 -51
  80. package/lib/helper/ZipManager.d.ts +1 -1
  81. package/lib/helper/ZipManager.js +2 -1
  82. package/lib/helper/checkinCheckoutManager.js +2 -3
  83. package/lib/helper/dcmtsHelper.d.ts +2 -0
  84. package/lib/helper/dcmtsHelper.js +3 -1
  85. package/lib/hooks/useCheckInOutOperations.d.ts +0 -6
  86. package/lib/hooks/useCheckInOutOperations.js +16 -37
  87. package/lib/hooks/useDcmtOperations.d.ts +3 -19
  88. package/lib/hooks/useDcmtOperations.js +175 -229
  89. package/lib/hooks/useDocumentOperations.d.ts +1 -0
  90. package/lib/hooks/useDocumentOperations.js +16 -29
  91. package/lib/hooks/useMultiMasterDetailDcmts.d.ts +0 -15
  92. package/lib/hooks/useMultiMasterDetailDcmts.js +70 -68
  93. package/lib/hooks/usePreventFileDrop.js +9 -0
  94. package/lib/hooks/useWorkflowApprove.js +33 -17
  95. package/lib/services/caseflow/CaseFlowService.d.ts +69 -9
  96. package/lib/services/caseflow/CaseFlowService.js +126 -58
  97. package/package.json +2 -2
@@ -21,7 +21,7 @@ import { useDcmtOperations } from "./useDcmtOperations";
21
21
  import useFloatingBarPinnedItems from "./useFloatingBarPinnedItems";
22
22
  import { useInputAttachmentsDialog, useInputCvtFormatDialog } from "./useInputDialog";
23
23
  import { useRelatedDocuments } from "./useRelatedDocuments";
24
- import { convertSearchResultDescriptorToFileItems, dcmtsFileCachePreview, getDcmtCicoStatus, getMoreInfoTasksForDocument, IconActivity, IconArchiveDetail, IconArchiveDoc, IconArchiveMaster, IconBatchUpdate, IconCheck, IconCheckFile, IconCheckIn, IconCircleInfo, IconCloseCircle, IconConvertFilePdf, IconCopy, IconCustom, IconDelete, IconDetailDcmts, IconDotsVerticalCircleOutline, IconDownload, IconEdit, IconExportTo, IconFileDots, IconHide, IconInfo, IconMenuCAArchive, IconMoveToFolder, IconPair, IconPin, IconPlatform, IconPreview, IconRelation, IconSearch, IconShare, IconSharedDcmt, IconShow, IconSignaturePencil, IconStar, IconSubstFile, IconUndo, IconUnpair, IconUserGroupOutline, isConvertibleToPdfExt, isPdfEditorAvailable, S4T_USER_REGISTRY_MASTER, SDKUI_Globals, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary, IconCertificateBadge, IconArchiveMultipleDetailDocuments, isDraftsDTD } from '../helper';
24
+ import { convertSearchResultDescriptorToFileItems, getDcmtCicoStatus, getMoreInfoTasksForDocument, IconActivity, IconArchiveDetail, IconArchiveDoc, IconArchiveMaster, IconBatchUpdate, IconCheck, IconCheckFile, IconCheckIn, IconCircleInfo, IconCloseCircle, IconConvertFilePdf, IconCopy, IconCustom, IconDelete, IconDetailDcmts, IconDotsVerticalCircleOutline, IconDownload, IconEdit, IconExportTo, IconFileDots, IconHide, IconInfo, IconMenuCAArchive, IconMoveToFolder, IconPair, IconPin, IconPlatform, IconPreview, IconRelation, IconSearch, IconShare, IconSharedDcmt, IconShow, IconSignaturePencil, IconStar, IconSubstFile, IconUndo, IconUnpair, IconUserGroupOutline, isConvertibleToPdfExt, isPdfEditorAvailable, S4T_USER_REGISTRY_MASTER, SDKUI_Globals, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary, IconCertificateBadge, IconArchiveMultipleDetailDocuments, isDraftsDTD } from '../helper';
25
25
  import { isXMLFileExt } from "../helper/dcmtsHelper";
26
26
  import TMCopyToFolderForm from "../components/features/documents/TMCopyToFolderForm";
27
27
  import TMMergeToPdfForm from "../components/features/documents/TMMergeToPdfForm";
@@ -86,7 +86,7 @@ export const useDocumentOperations = (props) => {
86
86
  const { dataColumns, dataSource, selectedRowKeys, } = exportData ?? {};
87
87
  const { visibleItems = [], onRefreshSearchAsyncDatagrid, onRefreshDataRowsAsync, refreshFocusedDataRowAsync, onRefreshBlogDatagrid, onRefreshPreviewDatagrid, refreshOperationsTrigger = 0, onRefreshOperationsDatagrid, } = datagridUtility ?? {};
88
88
  const { approvalVID, dcmtDataRowForCicoStatus, selectedDcmtSearchResultRelations, dcmtTIDHasDetailRelations = false, dcmtTIDHasMasterRelations = false, updateCurrentDcmt, onCloseDcmtForm, onRefreshBlogForm, onRefreshPreviewForm, taskFormDialogComponent, s4TViewerDialogComponent } = dcmtUtility ?? {};
89
- const { floatingBarContainerRef, customButtonsLayout, workingGroupContext, openS4TViewer = false, openDcmtFormAsModal = false, showDcmtFormSidebar = true, allowFloatingBar = true, enablePinIcons = true, allowRelations = true, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, editPdfForm = false, inputDcmtFormLayoutMode = LayoutModes.Update, graphometricManager, } = uiConfig;
89
+ const { floatingBarContainerRef, customButtonsLayout, workingGroupContext, openS4TViewer = false, openDcmtFormAsModal = false, showDcmtFormSidebar = true, allowFloatingBar = true, enablePinIcons = true, allowRelations = true, showTodoDcmtForm = false, showToppyDraggableHelpCenter = true, toppyHelpCenterUsePortal = false, editPdfForm = false, inputDcmtFormLayoutMode = LayoutModes.Update, graphometricManager, showSelector = false, } = uiConfig;
90
90
  const { allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback } = tasks;
91
91
  const {
92
92
  // Refresh operations (data consistency)
@@ -109,10 +109,10 @@ export const useDocumentOperations = (props) => {
109
109
  // Context helpers
110
110
  const isDcmtFormContext = context === SearchResultContext.DCMT_FORM;
111
111
  const isMasterDetailContext = context === SearchResultContext.MASTER_DETAIL;
112
- const { showHistory, showHistoryCallback, hideHistoryCallback, showCheckoutInformationForm, commentFormState, hideCommentFormCallback, showCheckoutInformationFormCallback, hideCheckoutInformationFormCallback, copyCheckoutPathToClipboardCallback, handleCheckOutCallback, handleCheckInCallback, showCicoWaitPanel, cicoWaitPanelTitle, showCicoPrimaryProgress, cicoPrimaryProgressText, cicoPrimaryProgressValue, cicoPrimaryProgressMax, } = useCheckInOutOperations({
112
+ const { showHistory, showHistoryCallback, hideHistoryCallback, showCheckoutInformationForm, commentFormState, hideCommentFormCallback, showCheckoutInformationFormCallback, hideCheckoutInformationFormCallback, copyCheckoutPathToClipboardCallback, handleCheckOutCallback, handleCheckInCallback, } = useCheckInOutOperations({
113
113
  onRefreshPreview: onRefreshPreviewCallback
114
114
  });
115
- const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, FileSourceDialog } = useDcmtOperations();
115
+ const { downloadDcmtsAsync, runOperationAsync, getDcmtFileAsync, clearDcmtsFileCache, removeDcmtsFileCache, isDcmtFileInCache, FileSourceDialog } = useDcmtOperations();
116
116
  const {
117
117
  // Data
118
118
  relatedDcmts, pairedSearchResults, manyToManyRelations, selectedManyToManyRelation, manyToManyChooserDataSource, relatedDcmtsChooserDataSource,
@@ -178,8 +178,14 @@ export const useDocumentOperations = (props) => {
178
178
  const [isOpenDetailsModal, setIsOpenDetailsModal] = useState(false);
179
179
  const [isOpenMasterModal, setIsOpenMasterModal] = useState(false);
180
180
  const [isOpenMultiDetailModal, setIsOpenMultiDetailModal] = useState(false);
181
- const openDetailDcmtsFormHandler = (value) => { setIsOpenDetails(value); };
182
- const openMasterDcmtsFormHandler = (value) => { setIsOpenMaster(value); };
181
+ // La maschera delle correlazioni viene montata subito (parte il calcolo, con il wait panel)
182
+ // ma resa visibile (isOpen...) solo a calcolo finito: intanto sotto restano i risultati.
183
+ const [isMountedDetails, setIsMountedDetails] = useState(false);
184
+ const [isMountedMaster, setIsMountedMaster] = useState(false);
185
+ const openDetailDcmtsFormHandler = (value) => { setIsMountedDetails(value); if (!value)
186
+ setIsOpenDetails(false); };
187
+ const openMasterDcmtsFormHandler = (value) => { setIsMountedMaster(value); if (!value)
188
+ setIsOpenMaster(false); };
183
189
  const openDetailDcmtsModalHandler = (value) => { setIsOpenDetailsModal(value); };
184
190
  const openMasterDcmtsModalHandler = (value) => { setIsOpenMasterModal(value); };
185
191
  // State to control whether the export form (for exporting to Excel/CSV/txt and others) should be shown
@@ -458,9 +464,7 @@ export const useDocumentOperations = (props) => {
458
464
  return;
459
465
  const dcmts = selectedDcmtInfos.map(dcmt => {
460
466
  const cacheKey = `${dcmt.TID}-${dcmt.DID}`;
461
- if (dcmtsFileCachePreview.has(cacheKey)) {
462
- removeDcmtsFileCache(cacheKey);
463
- }
467
+ removeDcmtsFileCache(cacheKey);
464
468
  return { ...dcmt, fileFormat: format };
465
469
  });
466
470
  const refreshFn = async () => {
@@ -1073,7 +1077,7 @@ export const useDocumentOperations = (props) => {
1073
1077
  ]
1074
1078
  };
1075
1079
  };
1076
- const canToggleDcmtTypesSelection = !isMobile && context === SearchResultContext.WORKFLOW_APPROVE;
1080
+ const canToggleDcmtTypesSelection = !isMobile && showSelector && currentSearchResults?.length === 1;
1077
1081
  const otherOperationsMenuItem = () => {
1078
1082
  return {
1079
1083
  id: 'oth',
@@ -1413,8 +1417,8 @@ export const useDocumentOperations = (props) => {
1413
1417
  onRefreshBlogDatagrid,
1414
1418
  onRefreshPreviewDatagrid
1415
1419
  }, fetchRemoteCertificates: fetchRemoteCertificates, graphometricManager: graphometricManager })) }), (showHistory && dtd && selectedDcmtInfos.length > 0) && _jsx(TMViewHistoryDcmt, { fromDTD: dtd, deviceType: deviceType, inputDcmt: selectedDcmtInfos[0], onClose: hideHistoryCallback, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers }), (commentFormState.show && selectedDcmtInfos.length > 0) && _jsx(TMBlogCommentForm, { context: { engine: 'SearchEngine', object: { tid: selectedDcmtInfos[0].TID, did: selectedDcmtInfos[0].DID } }, onClose: hideCommentFormCallback, refreshCallback: onRefreshBlog, participants: [], showAttachmentsSection: true, allArchivedDocumentsFileItems: convertSearchResultDescriptorToFileItems(currentSearchResults ?? []), isCommentRequired: commentFormState.isRequired, removeAndEditAttachment: commentFormState.removeAndEditAttachment, selectedAttachmentDid: [Number(selectedDcmtInfos[0].DID)] }), (showCheckoutInformationForm && dtd && selectedDcmtInfos.length > 0) &&
1416
- _jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), isOpenDetailsModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenDetailsModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetailsModal(false) }) }), _jsx(StyledMultiViewPanel, { $isVisible: isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetails(false) }) }), (isOpenMultiDetailModal && dtd) &&
1417
- _jsx(TMMultiMasterDetailDcmtsForm, { dtd: dtd, masterDcmt: selectedDcmtInfos[0], onClose: () => setIsOpenMultiDetailModal(false), canNavigateMaster: canNavigateMultiDetailMaster ? canNavigateHandler : undefined, onNavigateMaster: canNavigateMultiDetailMaster ? onNavigateHandler : undefined, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, fetchRemoteCertificates: fetchRemoteCertificates, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick, onTaskCreateRequest: onTaskCreateRequest, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onFileOpened: onFileOpened, passToArchiveCallback: passToArchiveCallback, openWGsCopyMoveForm: openWGsCopyMoveForm }), isOpenMasterModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenMasterModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onBack: () => setIsOpenMasterModal(false) }) }), _jsxs(StyledMultiViewPanel, { $isVisible: isOpenMaster, children: [isOpenMaster && _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onBack: () => setIsOpenMaster(false) }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
1420
+ _jsx(TMDcmtCheckoutInfoForm, { dtdName: dtd.name ?? SDKUI_Localizator.SearchResult, selectedDcmtOrFocused: selectedDcmtInfos[0], onClose: hideCheckoutInformationFormCallback }), isOpenDetailsModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenDetailsModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onBack: () => setIsOpenDetailsModal(false) }) }), _jsx(StyledMultiViewPanel, { $isVisible: isOpenDetails, children: isMountedDetails && _jsx(TMMasterDetailDcmts, { ...masterDetailDetailsCommonProps, onFirstLoadCompleted: () => setIsOpenDetails(true), onBack: () => openDetailDcmtsFormHandler(false) }) }), (isOpenMultiDetailModal && dtd) &&
1421
+ _jsx(TMMultiMasterDetailDcmtsForm, { dtd: dtd, masterDcmt: selectedDcmtInfos[0], onClose: () => setIsOpenMultiDetailModal(false), canNavigateMaster: canNavigateMultiDetailMaster ? canNavigateHandler : undefined, onNavigateMaster: canNavigateMultiDetailMaster ? onNavigateHandler : undefined, allTasks: allTasks, getAllTasks: getAllTasks, deleteTaskByIdsCallback: deleteTaskByIdsCallback, addTaskCallback: addTaskCallback, editTaskCallback: editTaskCallback, handleNavigateToWGs: handleNavigateToWGs, handleNavigateToDossiers: handleNavigateToDossiers, showDcmtFormSidebar: showDcmtFormSidebar, showTodoDcmtForm: showTodoDcmtForm, openFileUploaderPdfEditor: openFileUploaderPdfEditor, graphometricManager: graphometricManager, editPdfForm: editPdfForm, openS4TViewer: openS4TViewer, showToppyDraggableHelpCenter: showToppyDraggableHelpCenter, toppyHelpCenterUsePortal: toppyHelpCenterUsePortal, fetchRemoteCertificates: fetchRemoteCertificates, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onOpenPdfEditorRequest: onOpenPdfEditorRequest, onReferenceClick: onReferenceClick, onTaskCreateRequest: onTaskCreateRequest, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onFileOpened: onFileOpened, passToArchiveCallback: passToArchiveCallback, openWGsCopyMoveForm: openWGsCopyMoveForm }), isOpenMasterModal && _jsx(TMModal, { width: "95%", height: "95%", onClose: () => setIsOpenMasterModal(false), title: SDKUI_Localizator.Relations, children: _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onBack: () => setIsOpenMasterModal(false) }) }), _jsxs(StyledMultiViewPanel, { $isVisible: isOpenMaster, children: [isMountedMaster && _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, onFirstLoadCompleted: () => setIsOpenMaster(true), onBack: () => openMasterDcmtsFormHandler(false) }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
1418
1422
  return (_jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { ...masterDetailMasterCommonProps, inputDcmts: [dcmt], allowNavigation: false, onBack: () => handleRemoveItem(dcmt.TID, dcmt.DID) }) }, `${index}-${dcmt.DID}`));
1419
1423
  })] }), isOpenArchiveRelationForm && _jsx(TMDcmtForm, { isModal: true, titleModal: SDKUI_Localizator.Archive + ' - ' + (archiveType === 'detail' ? SDKUI_Localizator.DcmtsDetail : SDKUI_Localizator.DcmtsMaster), TID: archiveRelatedDcmtFormTID, layoutMode: LayoutModes.Ark, inputMids: archiveRelatedDcmtFormMids, showBackButton: false, allowButtonsRefs: false, onClose: () => {
1420
1424
  setIsOpenArchiveRelationForm(false);
@@ -1513,25 +1517,8 @@ export const useDocumentOperations = (props) => {
1513
1517
  copyCheckoutPathToClipboardCallback,
1514
1518
  handleCheckOutCallback,
1515
1519
  handleCheckInCallback,
1516
- showCicoWaitPanel,
1517
- cicoWaitPanelTitle,
1518
- showCicoPrimaryProgress,
1519
- cicoPrimaryProgressText,
1520
- cicoPrimaryProgressValue,
1521
- cicoPrimaryProgressMax,
1522
1520
  },
1523
1521
  dcmtOperations: {
1524
- abortController,
1525
- showWaitPanel,
1526
- showPrimary,
1527
- waitPanelTitle,
1528
- waitPanelTextPrimary,
1529
- waitPanelValuePrimary,
1530
- waitPanelMaxValuePrimary,
1531
- showSecondary,
1532
- waitPanelTextSecondary,
1533
- waitPanelValueSecondary,
1534
- waitPanelMaxValueSecondary,
1535
1522
  downloadDcmtsAsync,
1536
1523
  getDcmtFileAsync,
1537
1524
  clearDcmtsFileCache,
@@ -16,19 +16,6 @@ export type MidValue = {
16
16
  mid: number;
17
17
  value: string;
18
18
  };
19
- /** Stato del wait panel: le chiavi sono quelle dei props di TMLayoutWaitingContainer */
20
- export type WaitPanelState = {
21
- showWaitPanel: boolean;
22
- waitPanelTitle: string;
23
- showWaitPanelPrimary: boolean;
24
- waitPanelTextPrimary: string;
25
- waitPanelValuePrimary: number;
26
- waitPanelMaxValuePrimary: number;
27
- showWaitPanelSecondary: boolean;
28
- waitPanelTextSecondary: string;
29
- waitPanelValueSecondary: number;
30
- waitPanelMaxValueSecondary: number;
31
- };
32
19
  interface UseMultiMasterDetailDcmtsParams {
33
20
  /** Tipo documento del master */
34
21
  dtd: DcmtTypeDescriptor;
@@ -108,6 +95,4 @@ export declare const useMultiMasterDetailDcmts: ({ dtd, masterDcmt, onClose, can
108
95
  setStopOnFirstError: import("react").Dispatch<import("react").SetStateAction<boolean>>;
109
96
  isArchiving: boolean;
110
97
  archiveAllAsync: () => Promise<void>;
111
- waitPanel: WaitPanelState;
112
- abortController: AbortController | undefined;
113
98
  };
@@ -2,9 +2,10 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { AccessLevels, ArchiveConstraints, ArchiveEngineByID, DcmtOpers, GeneralRetrieveFormats, MetadataDataDomains, MetadataDataTypes, RelationCacheService, RelationTypes, ResultTypes, RetrieveFileOptions, SDK_Globals, SystemMIDsAsNumber } from '@topconsultnpm/sdk-ts';
3
3
  import { MetadataValueDescriptorEx } from '../ts';
4
4
  import { clearMultiDetailLayout, Globalization, getExceptionMessage, getMultiDetailSectionsOpen, handleArchiveVisibility, hasMultiDetailLayout, saveMultiDetailSectionsOpen, SDKUI_Localizator } from '../helper';
5
- import { getDcmtMetadataByMid, getUserMetadataSorted, mapAssociationsFromMetadata } from '../helper/dcmtsHelper';
5
+ import { canViewMetadata, getDcmtMetadataByMid, getUserMetadataSorted, mapAssociationsFromMetadata } from '../helper/dcmtsHelper';
6
6
  import { ButtonNames, TMExceptionBoxManager, TMMessageBoxManager } from '../components/base/TMPopUp';
7
7
  import TMSpinner from '../components/base/TMSpinner';
8
+ import { TMWaitPanelManager } from '../components/base/waitPanel';
8
9
  import ShowAlert from '../components/base/TMAlert';
9
10
  import { TMResultManager } from '../components/forms/TMResultDialog';
10
11
  import { useDataListItem } from './useDataListItem';
@@ -17,18 +18,6 @@ export var MultiDetailArchivePhase;
17
18
  /** Riepilogo delle archiviazioni */
18
19
  MultiDetailArchivePhase[MultiDetailArchivePhase["ArchiveSummary"] = 1] = "ArchiveSummary";
19
20
  })(MultiDetailArchivePhase || (MultiDetailArchivePhase = {}));
20
- const CLOSED_WAIT_PANEL = {
21
- showWaitPanel: false,
22
- waitPanelTitle: '',
23
- showWaitPanelPrimary: false,
24
- waitPanelTextPrimary: '',
25
- waitPanelValuePrimary: 0,
26
- waitPanelMaxValuePrimary: 0,
27
- showWaitPanelSecondary: false,
28
- waitPanelTextSecondary: '',
29
- waitPanelValueSecondary: 0,
30
- waitPanelMaxValueSecondary: 0,
31
- };
32
21
  /**
33
22
  * Logica dell'archiviazione multipla dei dettagli: relazioni, sezioni, righe del riepilogo e
34
23
  * archiviazione. Il rendering sta in TMMultiMasterDetailDcmtsForm
@@ -76,12 +65,11 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose, canNavigat
76
65
  // Archiviazione finale
77
66
  const [stopOnFirstError, setStopOnFirstError] = useState(true);
78
67
  const [isArchiving, setIsArchiving] = useState(false);
79
- const [waitPanel, setWaitPanel] = useState(CLOSED_WAIT_PANEL);
80
- const abortControllerRef = useRef(undefined);
81
68
  const selectedItem = detailRelationItems.find(item => item.relation === selectedRelation);
82
69
  const hasMultipleTypes = detailRelationItems.length > 1;
83
70
  const canUpdateMaster = canUpdateMasterCallback(dtd, masterDcmt);
84
- const masterFieldsCount = useMemo(() => getUserMetadataSorted(dtd).length, [dtd]);
71
+ // Stessi metadati delle card del master (vedi TMMasterInfoFields): quelli non visibili non contano
72
+ const masterFieldsCount = useMemo(() => getUserMetadataSorted(dtd).filter(canViewMetadata).length, [dtd]);
85
73
  // Nel riepilogo si mostrano solo le righe del tipo selezionato
86
74
  const currentRows = useMemo(() => archiveRows.filter(r => r.__tid === selectedRelation?.detailTID), [archiveRows, selectedRelation?.detailTID]);
87
75
  const archivedDetailsCount = archivedDetailResults.reduce((total, r) => total + (r.dcmtsFound ?? r.jsonResult?.length ?? 0), 0);
@@ -619,44 +607,72 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose, canNavigat
619
607
  dataTypeByMid.set(md.id, md.dataType); });
620
608
  // Collegamenti della relazione valorizzati dal master (prevalgono sui valori del form)
621
609
  const associationMids = await getMasterAssociationsForDetailAsync(selectedRelation);
622
- // Barra primaria: avanzamento documenti. Barra secondaria: upload del file corrente
623
- const abortController = new AbortController();
624
- abortControllerRef.current = abortController;
625
- setWaitPanel({
626
- ...CLOSED_WAIT_PANEL,
627
- showWaitPanel: true,
628
- waitPanelTitle: SDKUI_Localizator.Archiving,
629
- showWaitPanelPrimary: rowsToArchive.length > 1,
630
- waitPanelMaxValuePrimary: rowsToArchive.length,
631
- showWaitPanelSecondary: true,
610
+ // Con piu' righe: primaria sui documenti, secondaria sui byte. Con una riga sola solo i byte.
611
+ const isBatch = rowsToArchive.length > 1;
612
+ const waitPanel = TMWaitPanelManager.show({
613
+ title: SDKUI_Localizator.Archiving,
614
+ max: isBatch ? rowsToArchive.length : 0,
615
+ cancelable: true,
616
+ showSecondary: isBatch,
617
+ showCounters: isBatch,
618
+ primaryLabel: isBatch ? SDKUI_Localizator.Documents : undefined,
619
+ secondaryLabel: isBatch ? 'File corrente' : undefined,
632
620
  });
621
+ const publishBytes = (loaded, total) => {
622
+ const text = total > 0
623
+ ? `Uploading... ${Globalization.getNumberDisplayValue(loaded, true)} / ${Globalization.getNumberDisplayValue(total, true)}`
624
+ : '';
625
+ if (isBatch)
626
+ waitPanel.setSecondary({ value: loaded, max: total, text });
627
+ else
628
+ waitPanel.update({ value: loaded, max: total, subtitle: text });
629
+ };
633
630
  const result = [];
634
631
  const archivedRowIds = new Set();
635
- for (let i = 0; i < rowsToArchive.length; i++) {
636
- if (abortController.signal.aborted) {
637
- result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.WARNING, description: `Operazione interrotta. Elaborati ${i} documenti` });
638
- break;
639
- }
640
- const rowData = rowsToArchive[i];
641
- try {
642
- setWaitPanel(prev => ({ ...prev, waitPanelTextPrimary: `${SDKUI_Localizator.Archiving} ${i + 1} / ${rowsToArchive.length}` }));
643
- const newDID = await archiveRowAsync(rowData, detailTID, dataTypeByMid, associationMids, abortController.signal);
644
- setWaitPanel(prev => ({ ...prev, waitPanelValuePrimary: i + 1 }));
645
- archivedRowIds.add(rowData.id);
646
- result.push({ rowIndex: i, id1: detailTID, id2: newDID, resultType: ResultTypes.SUCCESS });
647
- }
648
- catch (error) {
649
- const err = error;
650
- // Annullamento richiesto dall'utente: interrompe senza mostrare l'errore
651
- if (err?.name === 'CanceledError' || abortController.signal.aborted) {
652
- result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.WARNING, description: `Operazione interrotta. Elaborati ${i} documenti` });
632
+ try {
633
+ for (let i = 0; i < rowsToArchive.length; i++) {
634
+ // Con la conferma di interruzione aperta il loop resta in pausa qui
635
+ await waitPanel.waitWhilePaused();
636
+ if (waitPanel.aborted) {
637
+ const description = SDKUI_Localizator.OperationDcmtsInterrupted.replaceParams(i);
638
+ result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.WARNING, description });
639
+ waitPanel.warning(1, description);
653
640
  break;
654
641
  }
655
- result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.ERROR, description: getExceptionMessage(error) });
656
- if (stopOnFirstError)
657
- break;
642
+ if (isBatch)
643
+ waitPanel.setSubtitle(`${SDKUI_Localizator.Archiving} ${i + 1} / ${rowsToArchive.length}`);
644
+ const rowData = rowsToArchive[i];
645
+ try {
646
+ const newDID = await archiveRowAsync(rowData, detailTID, dataTypeByMid, associationMids, waitPanel.signal, publishBytes);
647
+ archivedRowIds.add(rowData.id);
648
+ result.push({ rowIndex: i, id1: detailTID, id2: newDID, resultType: ResultTypes.SUCCESS });
649
+ waitPanel.ok();
650
+ }
651
+ catch (error) {
652
+ const err = error;
653
+ // Annullamento richiesto dall'utente: interrompe senza mostrare l'errore
654
+ if (err?.name === 'CanceledError' || waitPanel.aborted) {
655
+ const description = SDKUI_Localizator.OperationDcmtsInterrupted.replaceParams(i);
656
+ result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.WARNING, description });
657
+ waitPanel.warning(1, description);
658
+ break;
659
+ }
660
+ const description = getExceptionMessage(error);
661
+ result.push({ rowIndex: i, id1: detailTID, id2: undefined, resultType: ResultTypes.ERROR, description });
662
+ // La riga non ha ancora un DID: la si indica con la sua posizione.
663
+ waitPanel.error(1, `${SDKUI_Localizator.RowNumber.replaceParams(i + 1)}: ${description}`);
664
+ if (stopOnFirstError)
665
+ break;
666
+ }
667
+ // Avanza a elaborazione conclusa: la barra non arriva al 100% prima dell'ultimo documento
668
+ if (isBatch)
669
+ await waitPanel.step();
658
670
  }
659
671
  }
672
+ finally {
673
+ // Chiuso prima del riepilogo dei risultati
674
+ waitPanel.close();
675
+ }
660
676
  // Le righe archiviate escono dal riepilogo
661
677
  if (archivedRowIds.size > 0) {
662
678
  setArchiveRows(prev => prev.filter(r => !archivedRowIds.has(r.id)));
@@ -676,13 +692,11 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose, canNavigat
676
692
  TMExceptionBoxManager.show({ exception: error });
677
693
  }
678
694
  finally {
679
- abortControllerRef.current = undefined;
680
- setWaitPanel(CLOSED_WAIT_PANEL);
681
695
  setIsArchiving(false);
682
696
  }
683
697
  };
684
- // Archiviazione di una singola riga, con avanzamento dell'upload sulla barra secondaria
685
- const archiveRowAsync = async (row, detailTID, dataTypeByMid, associationMids, signal) => {
698
+ // Archiviazione di una singola riga, con avanzamento dell'upload notificato a onBytes
699
+ const archiveRowAsync = async (row, detailTID, dataTypeByMid, associationMids, signal, onBytes) => {
686
700
  const ae = new ArchiveEngineByID(SDK_Globals.tmSession);
687
701
  ae.TID = detailTID;
688
702
  ae.Metadata_ClearAll();
@@ -714,23 +728,12 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose, canNavigat
714
728
  });
715
729
  if (row.__file)
716
730
  ae.ArchivingFile = row.__file;
717
- let firstBlock = true;
718
- let maxFileSize = 0;
719
731
  return ae.ArchiveAsync(signal, (pd) => {
720
- if (firstBlock) {
721
- maxFileSize = pd.ProgressBarMaximum ?? 0;
722
- setWaitPanel(prev => ({ ...prev, waitPanelMaxValueSecondary: maxFileSize }));
723
- firstBlock = false;
724
- }
725
- setWaitPanel(prev => ({
726
- ...prev,
727
- waitPanelValueSecondary: pd.ProgressBarValue,
728
- waitPanelTextSecondary: `Uploading... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`,
729
- }));
730
- if (pd.ProgressBarValue === pd.ProgressBarMaximum) {
731
- setWaitPanel(prev => ({ ...prev, waitPanelValueSecondary: 0, waitPanelMaxValueSecondary: 0, waitPanelTextSecondary: '' }));
732
- firstBlock = true;
733
- }
732
+ // Upload completato: la barra si azzera per il file successivo
733
+ if (pd.ProgressBarValue === pd.ProgressBarMaximum)
734
+ onBytes(0, 0);
735
+ else
736
+ onBytes(pd.ProgressBarValue ?? 0, pd.ProgressBarMaximum ?? 0);
734
737
  });
735
738
  };
736
739
  return {
@@ -755,6 +758,5 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose, canNavigat
755
758
  openAddForm, openEditForm, closeAddForm, deleteRow, duplicateRow, upsertRow, updateRowValues, copyArchivedDetailToRows,
756
759
  // Archiviazione
757
760
  stopOnFirstError, setStopOnFirstError, isArchiving, archiveAllAsync,
758
- waitPanel, abortController: abortControllerRef.current,
759
761
  };
760
762
  };
@@ -2,7 +2,12 @@ import { useEffect } from "react";
2
2
  const usePreventFileDrop = (allowedDropZones) => {
3
3
  useEffect(() => {
4
4
  const isOverAllowedZone = (event) => allowedDropZones.some((ref) => ref.current?.contains(event.target));
5
+ // Il blocco vale solo per i file trascinati da fuori: i drag interni all'applicazione
6
+ // (riordino di metadati, colonne, tab, ...) devono restare liberi di completarsi
7
+ const isFileDrag = (event) => event.dataTransfer?.types?.includes("Files") === true;
5
8
  const handleDragOver = (event) => {
9
+ if (!isFileDrag(event))
10
+ return;
6
11
  if (isOverAllowedZone(event)) {
7
12
  // Riafferma "copy" ad ogni dragover: altrimenti un "none"
8
13
  // impostato mentre si era fuori zona resta e mostra "not-allowed"
@@ -17,6 +22,8 @@ const usePreventFileDrop = (allowedDropZones) => {
17
22
  }
18
23
  };
19
24
  const handleDragEnter = (event) => {
25
+ if (!isFileDrag(event))
26
+ return;
20
27
  if (isOverAllowedZone(event)) {
21
28
  document.body.style.cursor = "default";
22
29
  }
@@ -28,6 +35,8 @@ const usePreventFileDrop = (allowedDropZones) => {
28
35
  document.body.style.cursor = "default";
29
36
  };
30
37
  const handleDrop = (event) => {
38
+ if (!isFileDrag(event))
39
+ return;
31
40
  if (!isOverAllowedZone(event)) {
32
41
  event.preventDefault();
33
42
  document.body.style.cursor = "default";
@@ -1,5 +1,25 @@
1
1
  import { useState, useEffect, useCallback } from 'react';
2
2
  import { SDK_Globals } from '@topconsultnpm/sdk-ts';
3
+ const WORKFLOW_APPROVE_CHANGED_EVENT = 'onWorkflowApproveChange';
4
+ /** Totale dei documenti da approvare: somma dei dcmtsFound delle singole categorie. */
5
+ const calcTotalDcmtsFound = (data) => {
6
+ return data.reduce((sum, item) => sum + (item.dcmtsFound || 0), 0);
7
+ };
8
+ /**
9
+ * Fetch in corso.
10
+ *
11
+ * La WFAppr non porta un contatore ma l'intera lista di approvazione con le righe
12
+ * dei documenti, ed è chiesta da più istanze del hook a ridosso l'una dell'altra
13
+ * (coda del login, pagina di approvazione, widget della home). Chi arriva mentre
14
+ * è già in volo aspetta la stessa risposta invece di aprire una seconda richiesta.
15
+ */
16
+ let inFlight;
17
+ /** Ricarica i dati e notifica tutte le istanze del hook. */
18
+ const load = async () => {
19
+ const result = await SDK_Globals.tmSession?.NewWorkflowEngine().WFApprAsync(1);
20
+ SDK_Globals.currentWorkflowApproveData = result ?? [];
21
+ window.dispatchEvent(new CustomEvent(WORKFLOW_APPROVE_CHANGED_EVENT));
22
+ };
3
23
  /**
4
24
  * Hook per gestire i dati di approvazione del workflow.
5
25
  * Fornisce il dataSource, lo stato di caricamento e una funzione per aggiornare i dati.
@@ -7,13 +27,10 @@ import { SDK_Globals } from '@topconsultnpm/sdk-ts';
7
27
  export const useWorkflowApprove = () => {
8
28
  const [workflowApproveData, setWorkflowApproveData] = useState(SDK_Globals.currentWorkflowApproveData);
9
29
  const [isLoading, setIsLoading] = useState(false);
10
- const [totalDcmtsFound, setTotalDcmtsFound] = useState(0);
11
- /**
12
- * Calcola il numero totale di dcmtsFound dai dati del workflow.
13
- */
14
- const calculateTotalDcmtsFound = useCallback((data) => {
15
- return data.reduce((sum, item) => sum + (item.dcmtsFound || 0), 0);
16
- }, []);
30
+ // Seminato dai dati già in cache: un'istanza montata a login concluso parte dal
31
+ // totale reale e non da zero, altrimenti chi confronta questo valore con il
32
+ // contatore della home vede una differenza inesistente e ricarica a vuoto.
33
+ const [totalDcmtsFound, setTotalDcmtsFound] = useState(() => calcTotalDcmtsFound(SDK_Globals.currentWorkflowApproveData));
17
34
  /**
18
35
  * Ottiene tutti i work items che corrispondono a un determinato DID.
19
36
  * Restituisce un array di oggetti { tid, did }.
@@ -40,12 +57,10 @@ export const useWorkflowApprove = () => {
40
57
  }
41
58
  setIsLoading(true);
42
59
  try {
43
- const result = await SDK_Globals.tmSession.NewWorkflowEngine().WFApprAsync(1);
44
- SDK_Globals.currentWorkflowApproveData = result ?? [];
45
- // Aggiorna anche il totale dei dcmtsFound
46
- setTotalDcmtsFound(calculateTotalDcmtsFound(SDK_Globals.currentWorkflowApproveData));
47
- // Notifica tutte le istanze del hook che i dati sono cambiati.
48
- window.dispatchEvent(new CustomEvent('onWorkflowApproveChange'));
60
+ if (!inFlight) {
61
+ inFlight = load().finally(() => { inFlight = undefined; });
62
+ }
63
+ await inFlight;
49
64
  }
50
65
  catch (error) {
51
66
  console.error("Errore durante il fetch dei dati di approvazione workflow:", error);
@@ -53,18 +68,19 @@ export const useWorkflowApprove = () => {
53
68
  finally {
54
69
  setIsLoading(false);
55
70
  }
56
- }, [calculateTotalDcmtsFound]); // useCallback con array vuoto perché non ha dipendenze esterne a React
71
+ }, []);
57
72
  // Questo useEffect serve a sincronizzare lo stato tra diverse istanze del hook.
58
73
  // Se il componente A chiama refreshWorkflowApprove, il componente B (che usa lo stesso hook)
59
74
  // riceverà l'evento e aggiornerà il suo stato locale.
60
75
  useEffect(() => {
61
76
  const handleUpdate = () => {
62
77
  setWorkflowApproveData(SDK_Globals.currentWorkflowApproveData);
78
+ setTotalDcmtsFound(calcTotalDcmtsFound(SDK_Globals.currentWorkflowApproveData));
63
79
  };
64
- window.addEventListener('onWorkflowApproveChange', handleUpdate);
80
+ window.addEventListener(WORKFLOW_APPROVE_CHANGED_EVENT, handleUpdate);
65
81
  return () => {
66
- window.removeEventListener('onWorkflowApproveChange', handleUpdate);
82
+ window.removeEventListener(WORKFLOW_APPROVE_CHANGED_EVENT, handleUpdate);
67
83
  };
68
- }, [calculateTotalDcmtsFound]);
84
+ }, []);
69
85
  return { workflowApproveData, isLoading, refreshWorkflowApprove, totalDcmtsFound, getWorkItemsByDID };
70
86
  };
@@ -3,20 +3,42 @@ type PendingGroup = Array<{
3
3
  caseflow: CaseFlowInstanceDescriptor;
4
4
  workItems: CaseFlowWorkItem[];
5
5
  }>;
6
+ /** Numero massimo di pratiche restituite da una ricerca, se non indicato. */
7
+ export declare const CASEFLOW_SEARCH_DEFAULT_MAX_RESULTS = 500;
8
+ /**
9
+ * Tetto di `maxResults`. Il server non restituisce mai più di 5000 pratiche e
10
+ * se ne chiede una in più per sapere se il risultato è troncato: oltre 4999
11
+ * il troncamento non sarebbe più riconoscibile.
12
+ */
13
+ export declare const CASEFLOW_SEARCH_MAX_RESULTS = 4999;
6
14
  /** Criteri di ricerca delle istanze (pannello Ricerca e Process Mining). */
7
15
  export interface CaseFlowSearchCriteria {
8
16
  templateId?: number;
17
+ /** Contenuto nel nome, senza distinzione fra maiuscole e minuscole. */
9
18
  name?: string;
19
+ /** Contenuto nella descrizione, senza distinzione fra maiuscole e minuscole. */
10
20
  description?: string;
11
21
  state?: CF_States;
22
+ /** Creata dal giorno indicato, compreso (formato `YYYY-MM-DD`, come un `<input type="date">`). */
12
23
  dateFrom?: string;
24
+ /** Creata fino al giorno indicato, compreso (formato `YYYY-MM-DD`). */
13
25
  dateTo?: string;
26
+ /** Filtri per metadato di copertina ("contiene"), tutti da soddisfare. */
14
27
  metadataFilters?: Array<{
15
28
  mid: number;
16
29
  value: string;
17
30
  }>;
18
- /** Ricerca libera: cerca il valore in tutti i metadati di qualsiasi template */
31
+ /** Ricerca libera: nome, descrizione o un qualunque valore di copertina della pratica. */
19
32
  freeTextMetadata?: string;
33
+ /** Massimo numero di pratiche (default {@link CASEFLOW_SEARCH_DEFAULT_MAX_RESULTS}, tetto {@link CASEFLOW_SEARCH_MAX_RESULTS}). */
34
+ maxResults?: number;
35
+ }
36
+ /** Esito di una ricerca di istanze. */
37
+ export interface CaseFlowSearchResult {
38
+ /** Pratiche trovate, dalla più recente; con `truncated` sono le prime `maxResults`. */
39
+ items: CaseFlowInstanceDescriptor[];
40
+ /** true se le pratiche che soddisfano i criteri sono più di `maxResults`. */
41
+ truncated: boolean;
20
42
  }
21
43
  /** Documento non cancellato durante l'eliminazione di un'istanza (orfano). */
22
44
  export interface CaseFlowDeleteOrphan {
@@ -74,8 +96,16 @@ export declare class CaseFlowService {
74
96
  static retrieveCaseflow(id: number, cftid?: number): Promise<CaseFlowInstanceDescriptor | undefined>;
75
97
  /** Istanze di cui l'utente indicato è proprietario. */
76
98
  static getMyCaseflows(userId: number): Promise<CaseFlowInstanceDescriptor[]>;
77
- /** Ricerca avanzata sulle istanze applicando i filtri indicati. */
78
- static searchCaseflows(criteria: CaseFlowSearchCriteria): Promise<CaseFlowInstanceDescriptor[]>;
99
+ /**
100
+ * Ricerca avanzata sulle istanze, eseguita dal server (`usp_Cfi_Search`):
101
+ * restituisce solo le pratiche visibili all'utente che soddisfano i
102
+ * criteri, già con la copertina. Tutti i confronti di testo sono
103
+ * "contiene", senza distinzione fra maiuscole e minuscole.
104
+ *
105
+ * Per riconoscere un risultato troncato si chiede al server una pratica
106
+ * in più di `maxResults`: se arriva, la si scarta e `truncated` vale true.
107
+ */
108
+ static searchCaseflows(criteria: CaseFlowSearchCriteria): Promise<CaseFlowSearchResult>;
79
109
  /** WorkItem pendenti assegnati all'utente, raggruppati per istanza. */
80
110
  static getMyPendingWorkItems(userId: number): Promise<PendingGroup>;
81
111
  /**
@@ -103,6 +133,17 @@ export declare class CaseFlowService {
103
133
  * @returns id della nuova istanza.
104
134
  */
105
135
  static CreateCaseFlowInstance(template: CaseFlowTemplateDescriptor, instanceName: string, instanceDescription: string | undefined, metadataValues: Record<number, string>): Promise<number>;
136
+ /**
137
+ * Avvia un'istanza tramite StartAsync(cftid, id): il backend porta la pratica
138
+ * da `New` a `InProgress` e materializza i workitem della prima azione.
139
+ *
140
+ * NON va chiamata dopo `CreateCaseFlowInstance`: la Create dell'API REST
141
+ * esegue già lo start internamente, quindi un'istanza appena creata è
142
+ * ancora `New` solo nel descrittore inviato, non lato server. Questa resta
143
+ * per le istanze che si trovano davvero in `New` (avvio differito); sulle
144
+ * altre il backend rifiuta.
145
+ */
146
+ static startCaseflow(caseFlowId: number, cftid?: number): Promise<void>;
106
147
  /**
107
148
  * Elimina un'istanza tramite DeleteAsync(cftid, id). Il cftid è preso dal
108
149
  * template fornito (se disponibile) oppure risolto dall'istanza.
@@ -190,11 +231,10 @@ export declare class CaseFlowService {
190
231
  /**
191
232
  * Stato "l'utente corrente segue questa pratica" letto dal descrittore.
192
233
  *
193
- * Restituisce `undefined` quando il descrittore non porta l'informazione —
194
- * cioè SEMPRE, finché il backend non aggiunge `IsFollow` in output a
195
- * `usp_Cfi_RetrieveAll`/`usp_Cfi_Retrieve` e la relativa proprietà al
196
- * contratto. Il tipo è tollerante perché la colonna è un BIT/NUMBER e può
197
- * arrivare come booleano, come 0/1 o come stringa.
234
+ * `isFollow` fa ormai parte del contratto (`CaseFlowInstanceDescriptor`):
235
+ * arriva valorizzato da `usp_Cfi_RetrieveAll`/`usp_Cfi_Retrieve`. Resta
236
+ * `undefined` solo quando il descrittore proviene da una sorgente che non
237
+ * popola il campo.
198
238
  *
199
239
  * Da NON dedurre dalla bacheca Home come fanno pratiche-dossier e gruppi di
200
240
  * lavoro (filtro su `HomeBlogPost.classID`): quella query prende `TOP 30`
@@ -213,7 +253,27 @@ export declare class CaseFlowService {
213
253
  static completeDataCompletionWorkItem(caseFlowId: number, workItemId: number, metadataValues: Record<number, string>, response?: string, cftid?: number): Promise<void>;
214
254
  /** Rifiuta un workitem. Il motivo viene pubblicato in bacheca dal backend. */
215
255
  static rejectWorkItem(caseFlowId: number, workItemId: number, response?: string, cftid?: number): Promise<void>;
216
- /** Assegna un'azione a un utente creando il relativo workitem (operazione Assign). */
256
+ /**
257
+ * Prende in carico un'azione per se stessi (operazione Claim): il backend
258
+ * crea il workitem intestato al chiamante e porta l'azione in lavorazione.
259
+ *
260
+ * Non e' un caso particolare di `createWorkItemForAction`: assegnare e'
261
+ * riservato a Owner e Supervisore, prendere in carico e' di chiunque lavori
262
+ * alla pratica. Passando dall'operazione Assign, un Partecipante si vedeva
263
+ * rifiutare la presa in carico (TMC-2789).
264
+ */
265
+ static claimAction(caseFlowId: number, actionID: number, cftid?: number): Promise<void>;
266
+ /**
267
+ * Rilascia un workitem preso in carico (operazione ReleaseClaim): il backend
268
+ * lo cancella e, se per quell'azione non restano altri destinatari, la riporta
269
+ * disponibile per la presa in carico.
270
+ *
271
+ * Stessa chiamata per due gesti diversi, e' la guardia della SP a distinguerli:
272
+ * il detentore rilascia il proprio workitem, un Owner/Supervisore annulla
273
+ * l'assegnazione di un altro. Chi chiama non deve dire quale dei due sta facendo.
274
+ */
275
+ static releaseClaim(caseFlowId: number, workItemId: number, cftid?: number): Promise<void>;
276
+ /** Assegna un'azione a un ALTRO utente creando il relativo workitem (operazione Assign). */
217
277
  static createWorkItemForAction(caseFlowId: number, actionID: number, toUserID: number, description?: string, cftid?: number): Promise<void>;
218
278
  /** Forza il completamento di un'azione (supervisor). */
219
279
  static forceCompleteAction(caseFlowId: number, actionID: number, reason?: string, cftid?: number): Promise<void>;