@topconsultnpm/sdkui-react 6.21.0-t1 → 6.21.0-t3

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 (197) hide show
  1. package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +22 -1
  2. package/lib/components/NewComponents/ContextMenu/styles.d.ts +4 -4
  3. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +10 -10
  4. package/lib/components/base/Styled.d.ts +1 -1
  5. package/lib/components/base/TMAccordionNew.d.ts +1 -0
  6. package/lib/components/base/TMAccordionNew.js +6 -5
  7. package/lib/components/base/TMAreaManager.js +30 -3
  8. package/lib/components/base/TMCounterBar.d.ts +2 -2
  9. package/lib/components/base/TMCounterContainer.d.ts +2 -1
  10. package/lib/components/base/TMCustomButton.d.ts +1 -1
  11. package/lib/components/base/TMDataGrid.js +14 -4
  12. package/lib/components/base/TMDataGridExportForm.d.ts +2 -1
  13. package/lib/components/base/TMDataGridExportForm.js +19 -8
  14. package/lib/components/base/TMFileManager.d.ts +2 -1
  15. package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -1
  16. package/lib/components/base/TMFileManagerDataGridView.js +4 -4
  17. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  18. package/lib/components/base/TMFileManagerThumbnailItems.js +3 -3
  19. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  20. package/lib/components/base/TMFileManagerUtils.d.ts +7 -0
  21. package/lib/components/base/TMFileManagerUtils.js +14 -1
  22. package/lib/components/base/TMLayout.d.ts +4 -4
  23. package/lib/components/base/TMList.d.ts +2 -1
  24. package/lib/components/base/TMListView.d.ts +1 -1
  25. package/lib/components/base/TMModal.d.ts +1 -0
  26. package/lib/components/base/TMModal.js +4 -4
  27. package/lib/components/base/TMPanel.d.ts +7 -4
  28. package/lib/components/base/TMPanel.js +58 -26
  29. package/lib/components/base/TMPopUp.d.ts +1 -0
  30. package/lib/components/base/TMPopUp.js +59 -2
  31. package/lib/components/base/TMSpinner.d.ts +5 -2
  32. package/lib/components/base/TMSpinner.js +33 -6
  33. package/lib/components/base/TMTab.d.ts +4 -3
  34. package/lib/components/base/TMTooltip.d.ts +1 -1
  35. package/lib/components/base/TMTreeView.d.ts +1 -1
  36. package/lib/components/base/TMTreeView.js +24 -17
  37. package/lib/components/base/TMUserAvatar.d.ts +2 -1
  38. package/lib/components/base/TMVilViewer.d.ts +2 -1
  39. package/lib/components/base/TMWaitPanel.d.ts +5 -2
  40. package/lib/components/base/TMWaitPanel.js +14 -9
  41. package/lib/components/choosers/TMDistinctValues.js +35 -21
  42. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  43. package/lib/components/choosers/TMDynDataListItemChooser.js +6 -1
  44. package/lib/components/choosers/TMGroupChooser.js +1 -1
  45. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +2 -1
  46. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +2 -1
  47. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  48. package/lib/components/choosers/TMUserChooser.d.ts +6 -2
  49. package/lib/components/choosers/TMUserChooser.js +7 -5
  50. package/lib/components/editors/TMDateBox.js +4 -2
  51. package/lib/components/editors/TMEditorStyled.d.ts +6 -6
  52. package/lib/components/editors/TMFormulaEditor.d.ts +4 -1
  53. package/lib/components/editors/TMFormulaEditor.js +125 -22
  54. package/lib/components/editors/TMHtmlContentDisplay.d.ts +2 -1
  55. package/lib/components/editors/TMHtmlEditor.d.ts +2 -1
  56. package/lib/components/editors/TMMetadataEditor.js +6 -2
  57. package/lib/components/editors/TMMetadataValues.js +25 -7
  58. package/lib/components/editors/TMRadioButton.js +7 -5
  59. package/lib/components/editors/TMTextArea.d.ts +2 -0
  60. package/lib/components/editors/TMTextArea.js +6 -3
  61. package/lib/components/editors/TMTextBox.d.ts +2 -0
  62. package/lib/components/editors/TMTextBox.js +3 -3
  63. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  64. package/lib/components/features/archive/TMArchive.js +1 -1
  65. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  66. package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -1
  67. package/lib/components/features/blog/TMBlogCommentForm.js +5 -2
  68. package/lib/components/features/documents/TMCopyToFolderForm.d.ts +24 -0
  69. package/lib/components/features/documents/TMCopyToFolderForm.js +401 -0
  70. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  71. package/lib/components/features/documents/TMDcmtForm.js +166 -54
  72. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
  73. package/lib/components/features/documents/TMDcmtFormActionButtons.js +259 -60
  74. package/lib/components/features/documents/TMDcmtIcon.d.ts +2 -1
  75. package/lib/components/features/documents/TMDcmtIcon.js +1 -1
  76. package/lib/components/features/documents/TMDcmtPreview.d.ts +2 -1
  77. package/lib/components/features/documents/TMDcmtPreview.js +2 -2
  78. package/lib/components/features/documents/TMDcmtTasks.d.ts +3 -1
  79. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  80. package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +23 -0
  81. package/lib/components/features/documents/TMDownloadRelationViewerSection.js +173 -0
  82. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  83. package/lib/components/features/documents/TMFileUploader.js +1 -1
  84. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +2 -0
  85. package/lib/components/features/documents/TMMasterDetailDcmts.js +28 -9
  86. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +24 -0
  87. package/lib/components/features/documents/TMMergeToPdfForm.js +309 -0
  88. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
  89. package/lib/components/features/documents/TMRelationViewer.js +80 -6
  90. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +58 -0
  91. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +266 -0
  92. package/lib/components/features/search/SignatureParamsManager.d.ts +70 -0
  93. package/lib/components/features/search/SignatureParamsManager.js +145 -0
  94. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +2 -1
  95. package/lib/components/features/search/TMMetadataOutputForm.d.ts +18 -0
  96. package/lib/components/features/search/TMMetadataOutputForm.js +225 -0
  97. package/lib/components/features/search/TMMetadataSorterForm.d.ts +18 -0
  98. package/lib/components/features/search/TMMetadataSorterForm.js +243 -0
  99. package/lib/components/features/search/TMSavedQuerySelector.d.ts +3 -3
  100. package/lib/components/features/search/TMSavedQuerySelector.js +3 -2
  101. package/lib/components/features/search/TMSearch.d.ts +4 -1
  102. package/lib/components/features/search/TMSearch.js +16 -10
  103. package/lib/components/features/search/TMSearchQueryEditor.js +14 -8
  104. package/lib/components/features/search/TMSearchQueryPanel.js +250 -59
  105. package/lib/components/features/search/TMSearchResult.d.ts +3 -0
  106. package/lib/components/features/search/TMSearchResult.js +154 -38
  107. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  108. package/lib/components/features/search/TMSignatureInfoContent.d.ts +2 -1
  109. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +2 -1
  110. package/lib/components/features/search/TMViewHistoryDcmt.js +2 -3
  111. package/lib/components/features/search/metadataFormHelper.d.ts +16 -0
  112. package/lib/components/features/search/metadataFormHelper.js +77 -0
  113. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  114. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  115. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  116. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  117. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  118. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  119. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  120. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  121. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +3 -2
  122. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +8 -7
  123. package/lib/components/features/workflow/TMWorkflowPopup.js +3 -0
  124. package/lib/components/features/workflow/diagram/queryDescriptorParser.js +3 -6
  125. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  126. package/lib/components/forms/Login/TMLoginForm.d.ts +9 -0
  127. package/lib/components/forms/Login/TMLoginForm.js +76 -3
  128. package/lib/components/forms/TMChooserForm.d.ts +2 -1
  129. package/lib/components/forms/TMResultDialog.d.ts +1 -1
  130. package/lib/components/forms/TMResultDialog.js +4 -2
  131. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  132. package/lib/components/grids/TMBlogAttachments.d.ts +3 -1
  133. package/lib/components/grids/TMBlogAttachments.js +39 -13
  134. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  135. package/lib/components/grids/TMBlogsPost.d.ts +1 -1
  136. package/lib/components/grids/TMBlogsPost.js +12 -4
  137. package/lib/components/grids/TMBlogsPostUtils.d.ts +10 -9
  138. package/lib/components/grids/TMBlogsPostUtils.js +14 -18
  139. package/lib/components/grids/TMValidationItemsList.d.ts +2 -1
  140. package/lib/components/index.d.ts +1 -0
  141. package/lib/components/index.js +1 -0
  142. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +2 -1
  143. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
  144. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +1 -1
  145. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  146. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  147. package/lib/components/pages/TMPage.d.ts +1 -1
  148. package/lib/components/pages/TMPage.js +3 -1
  149. package/lib/components/query/TMQueryEditor.js +2 -2
  150. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  151. package/lib/components/sidebar/TMAboutApp.d.ts +2 -1
  152. package/lib/components/sidebar/TMHeader.d.ts +3 -3
  153. package/lib/components/viewers/TMDataListItemViewer.d.ts +3 -2
  154. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +3 -2
  155. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  156. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  157. package/lib/components/viewers/TMTidViewer.js +1 -1
  158. package/lib/components/wizard/TMWizard.d.ts +1 -0
  159. package/lib/components/wizard/TMWizard.js +5 -3
  160. package/lib/helper/Enum_Localizator.js +1 -0
  161. package/lib/helper/GlobalStyles.js +6 -0
  162. package/lib/helper/MergePdfManager.d.ts +45 -0
  163. package/lib/helper/MergePdfManager.js +148 -0
  164. package/lib/helper/SDKUI_Globals.d.ts +15 -0
  165. package/lib/helper/SDKUI_Globals.js +16 -1
  166. package/lib/helper/SDKUI_Localizator.d.ts +112 -2
  167. package/lib/helper/SDKUI_Localizator.js +1120 -12
  168. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  169. package/lib/helper/TMIcons.d.ts +278 -278
  170. package/lib/helper/TMPdfViewer.d.ts +2 -1
  171. package/lib/helper/TMPdfViewer.js +25 -24
  172. package/lib/helper/TMToppyMessage.d.ts +2 -2
  173. package/lib/helper/TMUtils.d.ts +25 -1
  174. package/lib/helper/TMUtils.js +72 -0
  175. package/lib/helper/ZipManager.d.ts +56 -0
  176. package/lib/helper/ZipManager.js +127 -0
  177. package/lib/helper/checkinCheckoutManager.d.ts +4 -3
  178. package/lib/helper/checkinCheckoutManager.js +29 -11
  179. package/lib/helper/helpers.d.ts +3 -2
  180. package/lib/helper/helpers.js +1 -0
  181. package/lib/helper/index.d.ts +1 -0
  182. package/lib/helper/index.js +1 -0
  183. package/lib/hooks/useCheckInOutOperations.d.ts +4 -3
  184. package/lib/hooks/useDataUserIdItem.js +6 -4
  185. package/lib/hooks/useDcmtOperations.d.ts +26 -2
  186. package/lib/hooks/useDcmtOperations.js +292 -38
  187. package/lib/hooks/useDocumentOperations.d.ts +3 -0
  188. package/lib/hooks/useDocumentOperations.js +254 -26
  189. package/lib/hooks/useForm.js +5 -2
  190. package/lib/hooks/useInputDialog.d.ts +2 -1
  191. package/lib/hooks/useRelatedDocuments.js +4 -4
  192. package/lib/hooks/useResizeObserver.d.ts +1 -1
  193. package/lib/hooks/useResizeObserver.js +16 -15
  194. package/lib/services/platform_services.d.ts +7 -6
  195. package/lib/ts/types.d.ts +3 -1
  196. package/lib/ts/types.js +1 -0
  197. package/package.json +15 -7
@@ -15,7 +15,7 @@ export const useDataUserIdItem = () => {
15
15
  if (userIDs.size === 0)
16
16
  return;
17
17
  try {
18
- const results = await Promise.all(Array.from(userIDs).map(id => UserListCacheService.GetAsync(id).then(user => ({ id, user }))
18
+ const results = await Promise.all(Array.from(userIDs).filter(id => id > 0).map(id => UserListCacheService.GetAsync(id).then(user => ({ id, user }))
19
19
  .catch(() => ({ id, user: undefined }))));
20
20
  const newCache = new Map();
21
21
  results.forEach(({ id, user }) => {
@@ -70,17 +70,19 @@ export const useDataUserIdItem = () => {
70
70
  * @returns Elemento React per visualizzare l'utente
71
71
  */
72
72
  const renderUserIdViewer = useCallback((userId, showIcon = false, showTitile = true) => {
73
- const ud = userId && userId > 0 ? getUserItem(userId) : undefined;
73
+ const ud = userId !== undefined && userId > 0 ? getUserItem(userId) : undefined;
74
74
  const getIcon = () => {
75
75
  if (!showIcon)
76
76
  return null;
77
- if (!userId)
77
+ if (userId === undefined || userId === null)
78
78
  return null;
79
79
  return ud ? _jsx(TMUserIcon, { ud: ud }) : _jsx("span", { title: showTitile ? SDKUI_Localizator.ValueNotPresent : undefined, style: { display: 'inline-flex', alignItems: 'center' }, children: _jsx(IconWarning, { color: TMColors.warning }) });
80
80
  };
81
81
  const getDescription = () => {
82
- if (!userId)
82
+ if (userId == null)
83
83
  return undefined;
84
+ if (userId === 0)
85
+ return SDKUI_Localizator.SystemUser;
84
86
  return ud ? getCompleteUserName(ud.domain, ud.name) : userId.toString() ?? SDKUI_Localizator.NoneSelection;
85
87
  };
86
88
  return (_jsxs("span", { style: { display: 'inline-flex', alignItems: 'center', gap: '4px', lineHeight: 1 }, children: [getIcon(), _jsx("span", { style: { lineHeight: 'normal' }, children: getDescription() })] }));
@@ -1,5 +1,29 @@
1
- import { RetrieveFileOptions, FileDescriptor } from '@topconsultnpm/sdk-ts';
1
+ import { RetrieveFileOptions, DcmtOpers, FileDescriptor, GeneralRetrieveFormats, InvoiceRetrieveFormats, OrderRetrieveFormats, FileFormats } from '@topconsultnpm/sdk-ts';
2
2
  import { DcmtInfo, DcmtOperationTypes, DownloadModes, DownloadTypes } from '../ts';
3
+ export interface RetrieveFormatOptions {
4
+ retrieveReason?: DcmtOpers;
5
+ cvtFormat?: FileFormats;
6
+ generalRetrieveFormat?: GeneralRetrieveFormats;
7
+ invoiceRetrieveFormat?: InvoiceRetrieveFormats;
8
+ orderRetrieveFormat?: OrderRetrieveFormats;
9
+ }
10
+ export interface DownloadDcmtsAsyncParams {
11
+ inputDcmts: DcmtInfo[] | undefined;
12
+ downloadType?: DownloadTypes;
13
+ downloadMode?: DownloadModes;
14
+ onFileDownloaded?: (dcmtFile: File, dcmtInfo: DcmtInfo) => void | Promise<void>;
15
+ confirmAttachments?: (list: FileDescriptor[]) => Promise<string[] | undefined>;
16
+ skipConfirmation?: boolean;
17
+ retrieveOptions?: RetrieveFormatOptions;
18
+ useCache?: boolean;
19
+ showSuccessAlert?: boolean;
20
+ /**
21
+ * Controlla la priorità del nome file per il download:
22
+ * - true: usa il fileName da inputDcmts (dcmtInfo.fileName) come priorità
23
+ * - false (default): usa il nome file recuperato dal backend (file.name) come priorità
24
+ */
25
+ useInputFileName?: boolean;
26
+ }
3
27
  export interface UseDcmtOperationsReturn {
4
28
  abortController: AbortController;
5
29
  showWaitPanel: boolean;
@@ -12,7 +36,7 @@ export interface UseDcmtOperationsReturn {
12
36
  waitPanelTextSecondary: string;
13
37
  waitPanelValueSecondary: number;
14
38
  waitPanelMaxValueSecondary: number;
15
- downloadDcmtsAsync: (inputDcmts: DcmtInfo[] | undefined, downloadType?: DownloadTypes, downloadMode?: DownloadModes, onFileDownloaded?: (dcmtFile: File) => void, confirmAttachments?: (list: FileDescriptor[]) => Promise<string[] | undefined>, skipConfirmation?: boolean) => Promise<void>;
39
+ downloadDcmtsAsync: (params: DownloadDcmtsAsyncParams) => Promise<void>;
16
40
  getDcmtFileAsync: (inputDcmt: DcmtInfo | undefined, rfo: RetrieveFileOptions, operationTitle: string, keepWaitPanelPrimary: boolean, bypassCache?: boolean) => Promise<{
17
41
  file: File | undefined;
18
42
  isFromCache: boolean;
@@ -1,12 +1,13 @@
1
1
  import { useState } from 'react';
2
2
  import { LocalizeDcmtOperationTypes } from '../helper/Enum_Localizator';
3
- import { SDK_Globals, RetrieveFileOptions, DcmtOpers, ResultTypes, RecentCategories, MetadataDataTypes, MetadataDataDomains, DataListCacheService } from '@topconsultnpm/sdk-ts';
3
+ import { SDK_Globals, RetrieveFileOptions, DcmtOpers, ResultTypes, RecentCategories, MetadataDataTypes, MetadataDataDomains, DataListCacheService, DcmtTypeListCacheService, TemplateTIDs } from '@topconsultnpm/sdk-ts';
4
4
  import { ShowAlert, TMResultManager, FormulaHelper, TMExceptionBoxManager, TMSpinner } from '../components';
5
- import { Globalization, getExceptionMessage, dialogConfirmOperation, extensionHandler, downloadBase64File, SDKUI_Globals, dcmtsFileCacheDownload, CACHE_SIZE_LIMIT, clearDcmtsFileCache, dcmtsFileCachePreview, isDcmtFileInCache, removeDcmtsFileCache, SDKUI_Localizator } from '../helper';
5
+ import { Globalization, getExceptionMessage, dialogConfirmOperation, extensionHandler, downloadBase64File, SDKUI_Globals, dcmtsFileCacheDownload, CACHE_SIZE_LIMIT, clearDcmtsFileCache, dcmtsFileCachePreview, isDcmtFileInCache, removeDcmtsFileCache, SDKUI_Localizator, ZipManager } from '../helper';
6
6
  import { DcmtOperationTypes, DownloadTypes, FileExtensionHandler } from '../ts';
7
7
  import { useFileDialog, useFileSourceDialog } from './useInputDialog';
8
8
  import { isXMLFileExt } from '../helper/dcmtsHelper';
9
9
  import { ShowConfirm } from '../components/base/TMConfirm';
10
+ import { generateTargetFileName } from '../components/features/documents/copyAndMergeDcmtsShared';
10
11
  const isScannerLicenseConfigured = () => {
11
12
  try {
12
13
  const scannerLicense = SDKUI_Globals.userSettings.advancedSettings.scannerLicense;
@@ -18,16 +19,91 @@ const isScannerLicenseConfigured = () => {
18
19
  };
19
20
  let abortController = new AbortController();
20
21
  const downloadCountMap = new Map();
21
- const getDownloadFileName = (fileName) => {
22
- const firstDot = fileName.indexOf('.');
23
- const lastDot = fileName.lastIndexOf('.');
24
- if (firstDot === -1 || firstDot === lastDot)
25
- return fileName;
26
- const count = downloadCountMap.get(fileName) ?? 0;
27
- downloadCountMap.set(fileName, count + 1);
28
- if (count === 0)
29
- return fileName;
30
- return `${fileName.slice(0, firstDot)}(${count})${fileName.slice(firstDot)}`;
22
+ /**
23
+ * Genera il nome file per il download con logica di priorità configurabile.
24
+ *
25
+ * @param file - File recuperato dal backend (può contenere il nome originale)
26
+ * @param dcmtInfo - Informazioni del documento (fileName, DID, FILEEXT)
27
+ * @param useInputFileName - Controlla la priorità del nome:
28
+ * - true: priorità a dcmtInfo.fileName file.name → DID
29
+ * - false (default): priorità a file.name → dcmtInfo.fileName → DID
30
+ *
31
+ * Gestisce anche:
32
+ * - Aggiunta automatica dell'estensione se mancante
33
+ * - Duplicati per file con estensioni multiple (es: file.pdf.p7m)
34
+ */
35
+ const getDownloadFileName = (file, dcmtInfo, useInputFileName = false) => {
36
+ // === FASE 1: Costruzione nome base con fallback ===
37
+ // Determina l'estensione con fallback: prima dal backend, poi dal documento
38
+ const fileExtFromBackend = file?.name?.split('.').pop()?.toLowerCase();
39
+ const fileExtFromDcmt = dcmtInfo.FILEEXT?.toLowerCase();
40
+ const fileExtension = fileExtFromBackend ?? fileExtFromDcmt ?? '';
41
+ let baseFileName;
42
+ /**
43
+ * Logica di priorità per il nome file:
44
+ *
45
+ * Se useInputFileName = true:
46
+ * 1. Usa dcmtInfo.fileName (nome passato nell'input)
47
+ * 2. Fallback a file.name (nome dal backend)
48
+ * 3. Fallback finale a DID
49
+ *
50
+ * Se useInputFileName = false (default):
51
+ * 1. Usa file.name (nome recuperato dal backend)
52
+ * 2. Fallback a dcmtInfo.fileName (nome salvato nel documento)
53
+ * 3. Fallback finale a DID
54
+ */
55
+ if (useInputFileName) {
56
+ // Priorità al nome da inputDcmts (dcmtInfo.fileName)
57
+ if (dcmtInfo.fileName) {
58
+ const hasExtension = dcmtInfo.fileName.includes('.');
59
+ baseFileName = hasExtension
60
+ ? dcmtInfo.fileName
61
+ : (fileExtension ? `${dcmtInfo.fileName}.${fileExtension}` : dcmtInfo.fileName);
62
+ }
63
+ // Seconda priorità: nome dal backend
64
+ else if (file?.name) {
65
+ baseFileName = file.name;
66
+ }
67
+ // Fallback finale: ID documento con estensione
68
+ else {
69
+ baseFileName = fileExtension ? `${dcmtInfo.DID}.${fileExtension}` : `${dcmtInfo.DID}`;
70
+ }
71
+ }
72
+ else {
73
+ // Comportamento default: priorità al nome dal backend
74
+ // 1. Priorità massima: nome dal backend
75
+ if (file?.name) {
76
+ baseFileName = file.name;
77
+ }
78
+ // 2. Seconda priorità: nome salvato nel documento
79
+ else if (dcmtInfo.fileName) {
80
+ const hasExtension = dcmtInfo.fileName.includes('.');
81
+ baseFileName = hasExtension
82
+ ? dcmtInfo.fileName
83
+ : (fileExtension ? `${dcmtInfo.fileName}.${fileExtension}` : dcmtInfo.fileName);
84
+ }
85
+ // 3. Fallback finale: ID documento con estensione
86
+ else {
87
+ baseFileName = fileExtension ? `${dcmtInfo.DID}.${fileExtension}` : `${dcmtInfo.DID}`;
88
+ }
89
+ }
90
+ // === FASE 2: Gestione duplicati per file con estensioni multiple ===
91
+ const firstDot = baseFileName.indexOf('.');
92
+ const lastDot = baseFileName.lastIndexOf('.');
93
+ // Se non ci sono punti o c'è una sola estensione, ritorna il nome così com'è
94
+ if (firstDot === -1 || firstDot === lastDot) {
95
+ return baseFileName;
96
+ }
97
+ // Gestisce il contatore per evitare sovrascritture
98
+ const count = downloadCountMap.get(baseFileName) ?? 0;
99
+ downloadCountMap.set(baseFileName, count + 1);
100
+ // Prima occorrenza: nome originale
101
+ if (count === 0) {
102
+ return baseFileName;
103
+ }
104
+ // Download successivi: inserisce contatore dopo il nome base
105
+ // Es: "file.pdf.p7m" -> "file(1).pdf.p7m"
106
+ return `${baseFileName.slice(0, firstDot)}(${count})${baseFileName.slice(firstDot)}`;
31
107
  };
32
108
  export const useDcmtOperations = () => {
33
109
  const [showWaitPanel, setShowWaitPanel] = useState(false);
@@ -42,7 +118,145 @@ export const useDcmtOperations = () => {
42
118
  const [waitPanelMaxValueSecondary, setWaitPanelMaxValueSecondary] = useState(0);
43
119
  const { OpenFileDialog } = useFileDialog();
44
120
  const [selectFileSource, FileSourceDialog] = useFileSourceDialog();
45
- const _downloadDcmtsAsync = async (inputDcmts, downloadMode = "download", onFileDownloaded, skipConfirmation = false) => {
121
+ const copyCompliantDcmtsAsync = async (inputDcmt, onFileDownloaded) => {
122
+ return await _copyCompliantDcmtsAsync(inputDcmt, onFileDownloaded);
123
+ };
124
+ const _copyCompliantDcmtsAsync = async (inputDcmt, onFileDownloaded) => {
125
+ if (inputDcmt === undefined)
126
+ return;
127
+ let returnDcmtFiles = [];
128
+ let returnDcmtInfos = [];
129
+ const rfo = new RetrieveFileOptions();
130
+ rfo.retrieveReason = DcmtOpers.ShowFile;
131
+ let firstBlock = true;
132
+ let maxFileSize = 0;
133
+ let signerInfoDescriptor = undefined;
134
+ if (inputDcmt?.FILEEXT == undefined || inputDcmt.FILEEXT == '') {
135
+ throw new Error('WARNING#Documento di soli metadati');
136
+ }
137
+ let ue = SDK_Globals.tmSession?.NewUpdateEngineByID();
138
+ if (ue) {
139
+ ue.TID = inputDcmt?.TID;
140
+ ue.DID = inputDcmt?.DID;
141
+ //Verifichiamo la nostra firma che nel Lex è sempre CadES
142
+ if (inputDcmt?.FILEEXT && inputDcmt.FILEEXT?.toLowerCase().includes('p7m')) {
143
+ //Verifica firma e recupero informazioni firmatari
144
+ await ue.VerifySignAsync();
145
+ //Recuperiamo le impronte
146
+ signerInfoDescriptor = await ue.GetSignersAsync();
147
+ }
148
+ }
149
+ //Documenti master
150
+ let dsRes = await SDK_Globals.tmSession?.NewSearchEngine().GetAllMasterDcmtsAsync(inputDcmt?.TID, inputDcmt?.DID);
151
+ if (dsRes == undefined || dsRes.length === 0) {
152
+ throw new Error('Nessun documento master trovato');
153
+ }
154
+ //Cerchiamo quello con modello IdC
155
+ let serachResultIdC = null;
156
+ for (const dtRes of dsRes) {
157
+ let dtdCur = await DcmtTypeListCacheService.GetAsync(dtRes.fromTID);
158
+ if (dtdCur?.templateTID === TemplateTIDs.IDC_DcmtType && dtRes.dcmtsFound && dtRes.dcmtsFound > 0) {
159
+ serachResultIdC = { ...dtRes };
160
+ }
161
+ }
162
+ if (serachResultIdC == null || serachResultIdC.dcmtsFound !== 1) {
163
+ throw new Error('Nessun IdC correlato al documento');
164
+ }
165
+ if (ue) {
166
+ ue.Metadata_ClearAll();
167
+ ue.TID = serachResultIdC.dtdResult.rows[0][0];
168
+ ue.DID = serachResultIdC.dtdResult.rows[0][1];
169
+ //Verifica dell'IdC
170
+ await ue.VerifySignAsync();
171
+ const signerInfoDescriptorIdC = await ue.GetSignersAsync();
172
+ //Controllo se marcato temporalmente
173
+ if (signerInfoDescriptorIdC) {
174
+ if (signerInfoDescriptorIdC.signers?.filter(s => s.isTimeStamp === true).length === 0) {
175
+ throw new Error('IdC non marcato temporalmente!');
176
+ }
177
+ }
178
+ else
179
+ throw new Error('IdC non firmato e non marcato temporalmente!');
180
+ //Ricerca dell'impronta SHA256 nel contenuto dell'IdC
181
+ let fileIdC = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(serachResultIdC.dtdResult.rows[0][0], serachResultIdC.dtdResult.rows[0][1], rfo, abortController.signal, (pd) => {
182
+ if (firstBlock) {
183
+ maxFileSize = pd.ProgressBarMaximum ?? 0;
184
+ setWaitPanelMaxValueSecondary(maxFileSize);
185
+ firstBlock = false;
186
+ }
187
+ setWaitPanelValueSecondary(pd.ProgressBarValue);
188
+ setWaitPanelTextSecondary(`Downloading IdC... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`);
189
+ if (pd.ProgressBarValue === pd.ProgressBarMaximum) {
190
+ setWaitPanelMaxValueSecondary(0);
191
+ setWaitPanelValueSecondary(0);
192
+ setWaitPanelTextSecondary('');
193
+ firstBlock = true;
194
+ }
195
+ });
196
+ let hashOk = false;
197
+ if (fileIdC) {
198
+ try {
199
+ const contenuto = await fileIdC.text();
200
+ if (contenuto && signerInfoDescriptor?.shA256) {
201
+ hashOk = contenuto.toLocaleUpperCase().includes(signerInfoDescriptor.shA256.toLocaleUpperCase());
202
+ }
203
+ }
204
+ catch (errDebug) {
205
+ throw new Error(`Errore nella lettura del file IdC: ${errDebug}`);
206
+ }
207
+ }
208
+ if (!hashOk) {
209
+ throw new Error('Impronta non trovata nel file IdC o non corrispondente a quella del documento');
210
+ }
211
+ let file;
212
+ file = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(inputDcmt.TID, inputDcmt.DID, rfo, abortController.signal, (pd) => {
213
+ if (firstBlock) {
214
+ maxFileSize = pd.ProgressBarMaximum ?? 0;
215
+ setWaitPanelMaxValueSecondary(maxFileSize);
216
+ firstBlock = false;
217
+ }
218
+ setWaitPanelValueSecondary(pd.ProgressBarValue);
219
+ setWaitPanelTextSecondary(`Downloading... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`);
220
+ if (pd.ProgressBarValue === pd.ProgressBarMaximum) {
221
+ setWaitPanelMaxValueSecondary(0);
222
+ setWaitPanelValueSecondary(0);
223
+ setWaitPanelTextSecondary('');
224
+ firstBlock = true;
225
+ }
226
+ });
227
+ if (file && fileIdC) {
228
+ returnDcmtFiles.push(file);
229
+ returnDcmtInfos.push(inputDcmt);
230
+ returnDcmtFiles.push(fileIdC);
231
+ returnDcmtInfos.push({ ...inputDcmt, fileName: inputDcmt.fileName + "_IdC", FILEEXT: 'TXT.P7M.TSD' });
232
+ }
233
+ onFileDownloaded && await onFileDownloaded(returnDcmtFiles, returnDcmtInfos);
234
+ }
235
+ };
236
+ const zipGetName = async (operation, tid) => {
237
+ let nameZip = tid ? tid.toString() + ".zip" : operation.toString() + ".zip";
238
+ switch (operation) {
239
+ case DcmtOperationTypes.CopyCompliant:
240
+ nameZip = `Duplicato_Informatico_${tid ?? '1'}`;
241
+ break;
242
+ }
243
+ return nameZip.trim().toLowerCase().endsWith('.zip')
244
+ ? nameZip.trim() : nameZip.trim() + '.zip';
245
+ };
246
+ const zipDocuments = async (zipEntries, typeOperation, tid, passwordZip) => {
247
+ if (zipEntries.length > 0) {
248
+ const zipFileName = await zipGetName(typeOperation, tid);
249
+ // Crea il blob ZIP
250
+ const zipBlob = await ZipManager.createZip(zipEntries, {
251
+ compressionLevel: 6,
252
+ password: passwordZip || undefined,
253
+ });
254
+ // Download zip nella cartella Downloads del browser
255
+ ZipManager.downloadBlob(zipBlob, zipFileName);
256
+ ShowAlert({ message: SDKUI_Localizator.ZipCreatedSavedInFolder.replaceParams(zipFileName, "Zip creato con successo"), mode: 'success', duration: 5000, title: SDKUI_Localizator.CompressToZipFile });
257
+ }
258
+ };
259
+ const _downloadDcmtsAsync = async (inputDcmts, downloadMode = "download", onFileDownloaded, skipConfirmation = false, retrieveOptions, useCache = true, showSuccessAlert = true, useInputFileName = false) => {
46
260
  if (inputDcmts === undefined)
47
261
  return;
48
262
  if (inputDcmts.length <= 0)
@@ -72,9 +286,13 @@ export const useDcmtOperations = () => {
72
286
  setWaitPanelTitle(operationTitle);
73
287
  abortController = new AbortController();
74
288
  const rfo = new RetrieveFileOptions();
75
- rfo.retrieveReason = DcmtOpers.ShowFile;
76
- rfo.invoiceRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
77
- rfo.orderRetrieveFormat = SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
289
+ rfo.retrieveReason = retrieveOptions?.retrieveReason ?? DcmtOpers.ShowFile;
290
+ if (retrieveOptions?.cvtFormat !== undefined)
291
+ rfo.cvtFormat = retrieveOptions.cvtFormat;
292
+ if (retrieveOptions?.generalRetrieveFormat !== undefined)
293
+ rfo.generalRetrieveFormat = retrieveOptions.generalRetrieveFormat;
294
+ rfo.invoiceRetrieveFormat = retrieveOptions?.invoiceRetrieveFormat ?? SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
295
+ rfo.orderRetrieveFormat = retrieveOptions?.orderRetrieveFormat ?? SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
78
296
  let result = [];
79
297
  setWaitPanelMaxValuePrimary(inputDcmts.length);
80
298
  let firstBlock = true;
@@ -88,7 +306,7 @@ export const useDcmtOperations = () => {
88
306
  setWaitPanelTextPrimary(`Download file ${i + 1} di ${inputDcmts.length}`);
89
307
  let file;
90
308
  const cacheKey = `${inputDcmts[i].TID}-${inputDcmts[i].DID}`;
91
- if (dcmtsFileCacheDownload.has(cacheKey)) {
309
+ if (useCache && dcmtsFileCacheDownload.has(cacheKey)) {
92
310
  file = dcmtsFileCacheDownload.get(cacheKey);
93
311
  }
94
312
  else {
@@ -111,24 +329,31 @@ export const useDcmtOperations = () => {
111
329
  setWaitPanelValuePrimary(i + 1);
112
330
  const fileURL = window.URL.createObjectURL(file);
113
331
  if (downloadMode === "openInNewWindow") {
114
- onFileDownloaded
115
- ? onFileDownloaded(file)
332
+ (onFileDownloaded && file)
333
+ ? onFileDownloaded(file, inputDcmts[i])
116
334
  : window.open(fileURL, '_blank', 'noopener');
117
335
  }
118
336
  else {
119
- const alink2 = document.createElement('a');
120
- alink2.href = fileURL;
121
- const baseFileName = inputDcmts[i].fileName ?? (inputDcmts[i].FILEEXT ? `${inputDcmts[i].DID}.${inputDcmts[i].FILEEXT}` : file?.name);
122
- alink2.download = getDownloadFileName(baseFileName);
123
- alink2.target = "_blank";
124
- alink2.rel = "noreferrer";
125
- alink2.click();
337
+ if (onFileDownloaded && file) {
338
+ await onFileDownloaded(file, inputDcmts[i]);
339
+ }
340
+ else {
341
+ const alink2 = document.createElement('a');
342
+ alink2.href = fileURL;
343
+ // Usa useInputFileName per determinare la priorità del nome file
344
+ alink2.download = getDownloadFileName(file, inputDcmts[i], useInputFileName);
345
+ alink2.target = "_blank";
346
+ alink2.rel = "noreferrer";
347
+ alink2.click();
348
+ }
126
349
  }
127
- if (dcmtsFileCacheDownload.size >= CACHE_SIZE_LIMIT) {
128
- const oldestKey = dcmtsFileCacheDownload.keys().next().value;
129
- dcmtsFileCacheDownload.delete(oldestKey);
350
+ if (useCache) {
351
+ if (dcmtsFileCacheDownload.size >= CACHE_SIZE_LIMIT) {
352
+ const oldestKey = dcmtsFileCacheDownload.keys().next().value;
353
+ dcmtsFileCacheDownload.delete(oldestKey);
354
+ }
355
+ dcmtsFileCacheDownload.set(cacheKey, file);
130
356
  }
131
- dcmtsFileCacheDownload.set(cacheKey, file);
132
357
  result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.SUCCESS });
133
358
  }
134
359
  catch (ex) {
@@ -146,9 +371,9 @@ export const useDcmtOperations = () => {
146
371
  setWaitPanelMaxValueSecondary(0);
147
372
  setWaitPanelValueSecondary(0);
148
373
  setShowWaitPanel(false);
149
- TMResultManager.show(result, operationTitle, "TID", "DID");
374
+ TMResultManager.show(result, operationTitle, "TID", "DID", undefined, undefined, showSuccessAlert);
150
375
  };
151
- const _downloadAttachmentsAsync = async (inputDcmts, confirmAttachments) => {
376
+ const _downloadAttachmentsAsync = async (inputDcmts, confirmAttachments, showSuccessAlert = true) => {
152
377
  if (inputDcmts === undefined)
153
378
  return;
154
379
  if (inputDcmts.length !== 1)
@@ -196,7 +421,7 @@ export const useDcmtOperations = () => {
196
421
  }
197
422
  }
198
423
  }
199
- TMResultManager.show(result, operationTitle, "TID", "DID");
424
+ TMResultManager.show(result, operationTitle, "TID", "DID", undefined, undefined, showSuccessAlert);
200
425
  }
201
426
  catch (ex) {
202
427
  TMSpinner.hide();
@@ -208,11 +433,14 @@ export const useDcmtOperations = () => {
208
433
  TMExceptionBoxManager.show({ exception: err });
209
434
  }
210
435
  };
211
- const downloadDcmtsAsync = async (inputDcmts, downloadType = DownloadTypes.Attachment, downloadMode = "download", onFileDownloaded, confirmAttachments, skipConfirmation = false) => {
436
+ const downloadDcmtsAsync = async (params) => {
437
+ const { inputDcmts, downloadType = DownloadTypes.Attachment, downloadMode = "download", onFileDownloaded, confirmAttachments, skipConfirmation = false, retrieveOptions, useCache = true, showSuccessAlert = true, useInputFileName = false, // Default: usa il nome dal backend
438
+ } = params;
212
439
  switch (downloadType) {
213
- case DownloadTypes.Dcmt: return await _downloadDcmtsAsync(inputDcmts, downloadMode, onFileDownloaded, skipConfirmation);
214
- case DownloadTypes.Attachment: return await _downloadAttachmentsAsync(inputDcmts, confirmAttachments);
215
- default: return await _downloadDcmtsAsync(inputDcmts, undefined, undefined, skipConfirmation);
440
+ // Per il download di documenti, passa useInputFileName per controllare la priorità del nome
441
+ case DownloadTypes.Dcmt: return await _downloadDcmtsAsync(inputDcmts, downloadMode, onFileDownloaded, skipConfirmation, retrieveOptions, useCache, showSuccessAlert, useInputFileName);
442
+ case DownloadTypes.Attachment: return await _downloadAttachmentsAsync(inputDcmts, confirmAttachments, showSuccessAlert);
443
+ default: return await _downloadDcmtsAsync(inputDcmts, undefined, undefined, skipConfirmation, retrieveOptions, useCache, showSuccessAlert, useInputFileName);
216
444
  }
217
445
  };
218
446
  const uploadDcmtsAsync = async (inputDcmts, operationTitle, operType, actionAfterOperationAsync) => {
@@ -438,6 +666,7 @@ export const useDcmtOperations = () => {
438
666
  await uploadDcmtsAsync(inputDcmts, operationTitle, undefined, actionAfterOperationAsync);
439
667
  return;
440
668
  }
669
+ let zipEntries = [];
441
670
  setShowWaitPanel(true);
442
671
  setShowPrimary(true);
443
672
  setShowSecondary(false);
@@ -486,6 +715,23 @@ export const useDcmtOperations = () => {
486
715
  }
487
716
  break;
488
717
  }
718
+ case DcmtOperationTypes.CopyCompliant:
719
+ const collectFileForZip = async (file, dcmtInfo) => {
720
+ if (file.length !== dcmtInfo.length) {
721
+ console.warn(`Numero di file (${file.length}) e documenti (${dcmtInfo.length}) non corrispondono. Impossibile associare correttamente i file ai documenti per la creazione dello zip.`);
722
+ return;
723
+ }
724
+ for (let j = 0; j < file.length; j++) {
725
+ let targetFileName = await generateTargetFileName(file[j], dcmtInfo[j], {
726
+ fileNamingMode: 'documentTypeAndDid',
727
+ separatorChar: '_',
728
+ });
729
+ targetFileName = targetFileName.replace(/\.xml\.p7m\.tsd$/i, '_IdC.XML.P7M.TSD');
730
+ zipEntries.push({ filename: targetFileName, data: file[j] });
731
+ }
732
+ };
733
+ await copyCompliantDcmtsAsync(inputDcmts[i], collectFileForZip);
734
+ break;
489
735
  case DcmtOperationTypes.CheckFile:
490
736
  await SDK_Globals.tmSession?.NewSearchEngine().CheckFileAsync(inputDcmts[i].TID, inputDcmts[i].DID);
491
737
  break;
@@ -538,7 +784,12 @@ export const useDcmtOperations = () => {
538
784
  result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.SUCCESS });
539
785
  }
540
786
  catch (ex) {
541
- result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(ex) });
787
+ let msg = getExceptionMessage(ex);
788
+ if (msg.startsWith('WARNING#')) {
789
+ result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.WARNING, description: msg.replace('WARNING#', '') });
790
+ }
791
+ else
792
+ result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.ERROR, description: msg });
542
793
  const err = ex;
543
794
  if (err.name === 'CanceledError') {
544
795
  ShowAlert({ message: err.message, mode: 'warning', duration: 3000, title: 'Abort' });
@@ -546,6 +797,9 @@ export const useDcmtOperations = () => {
546
797
  }
547
798
  setWaitPanelValuePrimary(i + 1);
548
799
  }
800
+ if (zipEntries.length > 0) {
801
+ await zipDocuments(zipEntries, dcmtOperationType, inputDcmts[0].TID);
802
+ }
549
803
  setWaitPanelMaxValuePrimary(0);
550
804
  setWaitPanelValuePrimary(0);
551
805
  setWaitPanelTextPrimary('');
@@ -38,6 +38,8 @@ export interface DocumentDataProps {
38
38
  s4TViewerDialogComponent?: React.ReactNode;
39
39
  };
40
40
  }
41
+ export type TMCopyToFolderMode = 'onlySelected' | 'customized';
42
+ export type TMCopyToFolderOperationType = 'copyToFolder' | 'mergeToPdf';
41
43
  export interface ExportDataProps {
42
44
  dataColumns?: Array<IColumnProps>;
43
45
  dataSource?: Array<any>;
@@ -110,6 +112,7 @@ export interface UseDocumentOperationsResult {
110
112
  isOpenBatchUpdate: boolean;
111
113
  isModifiedBatchUpdate: boolean;
112
114
  updateBatchUpdateForm: (value: boolean) => void;
115
+ closeDcmtFormHandler: () => void;
113
116
  handleSignApprove: () => void;
114
117
  showSearchTMDatagrid: boolean;
115
118
  showExportForm: boolean;