@topconsultnpm/sdkui-react 6.22.0-dev3.2 → 6.22.0-dev3.20

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 (137) hide show
  1. package/lib/components/NewComponents/ContextMenu/styles.d.ts +43 -17
  2. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +78 -19
  3. package/lib/components/base/Styled.d.ts +79 -27
  4. package/lib/components/base/Styled.js +7 -5
  5. package/lib/components/base/TMCounterBar.d.ts +2 -2
  6. package/lib/components/base/TMCounterContainer.d.ts +2 -1
  7. package/lib/components/base/TMCustomButton.d.ts +1 -1
  8. package/lib/components/base/TMDataGrid.d.ts +2 -0
  9. package/lib/components/base/TMDataGrid.js +34 -6
  10. package/lib/components/base/TMDataGridExportForm.d.ts +2 -1
  11. package/lib/components/base/TMFileManager.d.ts +2 -1
  12. package/lib/components/base/TMFileManagerDataGridView.d.ts +2 -1
  13. package/lib/components/base/TMFileManagerThumbnailItems.d.ts +1 -1
  14. package/lib/components/base/TMFileManagerThumbnailsView.d.ts +1 -1
  15. package/lib/components/base/TMFileManagerUtils.d.ts +3 -1
  16. package/lib/components/base/TMLayout.d.ts +4 -4
  17. package/lib/components/base/TMList.d.ts +2 -1
  18. package/lib/components/base/TMListView.d.ts +1 -1
  19. package/lib/components/base/TMPanel.js +167 -167
  20. package/lib/components/base/TMSpinner.d.ts +2 -1
  21. package/lib/components/base/TMTab.d.ts +4 -3
  22. package/lib/components/base/TMTabControl.d.ts +106 -0
  23. package/lib/components/base/TMTabControl.js +664 -0
  24. package/lib/components/base/TMTooltip.d.ts +1 -1
  25. package/lib/components/base/TMTreeView.d.ts +13 -5
  26. package/lib/components/base/TMTreeView.js +19 -1
  27. package/lib/components/base/TMUserAvatar.d.ts +2 -1
  28. package/lib/components/base/TMVilViewer.d.ts +2 -1
  29. package/lib/components/base/TMWaitPanel.d.ts +3 -2
  30. package/lib/components/base/TMWaitPanel.js +1 -1
  31. package/lib/components/choosers/TMDistinctValues.js +27 -18
  32. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +1 -1
  33. package/lib/components/choosers/TMInvoiceRetrieveFormats.d.ts +2 -1
  34. package/lib/components/choosers/TMOrderRetrieveFormats.d.ts +2 -1
  35. package/lib/components/choosers/TMQuickSearchInfo.d.ts +2 -1
  36. package/lib/components/choosers/TMRelationChooser.d.ts +3 -3
  37. package/lib/components/choosers/TMUserChooser.d.ts +2 -2
  38. package/lib/components/editors/TMEditorStyled.d.ts +15 -5
  39. package/lib/components/editors/TMFormulaEditor.d.ts +1 -1
  40. package/lib/components/editors/TMHtmlContentDisplay.d.ts +2 -1
  41. package/lib/components/editors/TMHtmlEditor.d.ts +2 -1
  42. package/lib/components/editors/TMMetadataValues.js +5 -5
  43. package/lib/components/editors/TMTreeDropDown.d.ts +1 -1
  44. package/lib/components/features/archive/TMArchive.js +7 -2
  45. package/lib/components/features/assistant/TMToppyDraggableHelpCenter.d.ts +1 -1
  46. package/lib/components/features/blog/TMBlogCommentForm.d.ts +2 -1
  47. package/lib/components/features/documents/TMCopyToFolderForm.js +18 -7
  48. package/lib/components/features/documents/TMDcmtForm.js +3 -2
  49. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +1 -1
  50. package/lib/components/features/documents/TMDcmtIcon.d.ts +2 -1
  51. package/lib/components/features/documents/TMDcmtPreview.d.ts +7 -3
  52. package/lib/components/features/documents/TMDcmtTasks.d.ts +2 -1
  53. package/lib/components/features/documents/TMDragDropOverlay.d.ts +1 -1
  54. package/lib/components/features/documents/TMFileUploader.js +26 -26
  55. package/lib/components/features/documents/TMMasterDetailDcmts.js +40 -13
  56. package/lib/components/features/documents/TMMasterInfoFields.d.ts +2 -1
  57. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +2 -1
  58. package/lib/components/features/documents/TMMergeToPdfForm.js +8 -7
  59. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.d.ts +2 -1
  60. package/lib/components/features/documents/TMMultiMasterDetailDcmtsForm.js +13 -15
  61. package/lib/components/features/documents/TMMultiMasterDetailDcmtsUtils.d.ts +4 -4
  62. package/lib/components/features/documents/TMRelationViewer.d.ts +21 -3
  63. package/lib/components/features/documents/TMRelationViewer.js +140 -104
  64. package/lib/components/features/documents/relationTreeState.d.ts +32 -0
  65. package/lib/components/features/documents/relationTreeState.js +89 -0
  66. package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +2 -1
  67. package/lib/components/features/search/TMMetadataOutputForm.d.ts +2 -1
  68. package/lib/components/features/search/TMMetadataSorterForm.d.ts +2 -1
  69. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  70. package/lib/components/features/search/TMSearch.d.ts +1 -1
  71. package/lib/components/features/search/TMSearch.js +68 -9
  72. package/lib/components/features/search/TMSearchQueryPanel.d.ts +9 -3
  73. package/lib/components/features/search/TMSearchResult.d.ts +5 -0
  74. package/lib/components/features/search/TMSearchResult.js +13 -4
  75. package/lib/components/features/search/TMSearchResultFloatingActionButton.d.ts +1 -1
  76. package/lib/components/features/search/TMSignatureInfoContent.d.ts +2 -1
  77. package/lib/components/features/search/TMTreeSelector.js +37 -35
  78. package/lib/components/features/search/TMViewHistoryDcmt.d.ts +2 -1
  79. package/lib/components/features/tasks/TMTaskForm.d.ts +1 -1
  80. package/lib/components/features/tasks/TMTaskFormUtils.d.ts +10 -10
  81. package/lib/components/features/tasks/TMTasksAgenda.d.ts +1 -1
  82. package/lib/components/features/tasks/TMTasksCalendar.d.ts +1 -1
  83. package/lib/components/features/tasks/TMTasksHeader.d.ts +1 -1
  84. package/lib/components/features/tasks/TMTasksPanelContent.d.ts +1 -1
  85. package/lib/components/features/tasks/TMTasksUtilsView.d.ts +5 -5
  86. package/lib/components/features/tasks/TMTasksView.d.ts +1 -1
  87. package/lib/components/features/tasks/TMTasksView.js +6 -12
  88. package/lib/components/features/wg/TMWGsCopyMoveForm.d.ts +3 -2
  89. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +8 -7
  90. package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +3 -1
  91. package/lib/components/forms/Login/ChangePasswordInputs.d.ts +3 -1
  92. package/lib/components/forms/Login/Chooser.d.ts +2 -2
  93. package/lib/components/forms/TMChooserForm.d.ts +2 -1
  94. package/lib/components/forms/TMResultDialog.js +1 -1
  95. package/lib/components/forms/TMSaveForm.d.ts +4 -4
  96. package/lib/components/grids/TMBlogAttachments.d.ts +2 -1
  97. package/lib/components/grids/TMBlogHeader.d.ts +1 -1
  98. package/lib/components/grids/TMBlogsPost.d.ts +1 -1
  99. package/lib/components/grids/TMBlogsPostUtils.d.ts +9 -9
  100. package/lib/components/grids/TMValidationItemsList.d.ts +2 -1
  101. package/lib/components/index.d.ts +2 -0
  102. package/lib/components/index.js +2 -0
  103. package/lib/components/layout/panelManager/TMPanelManagerContainer.d.ts +2 -1
  104. package/lib/components/layout/panelManager/TMPanelManagerContext.d.ts +2 -2
  105. package/lib/components/layout/panelManager/TMPanelManagerToolbar.d.ts +4 -2
  106. package/lib/components/layout/panelManager/TMPanelManagerWithPersistenceProvider.d.ts +2 -2
  107. package/lib/components/layout/panelManager/TMPanelWrapper.d.ts +2 -2
  108. package/lib/components/pages/TMPage.d.ts +1 -1
  109. package/lib/components/query/TMQueryEditor.d.ts +12 -4
  110. package/lib/components/settings/SettingsAppearance.d.ts +2 -1
  111. package/lib/components/sidebar/TMAboutApp.d.ts +2 -1
  112. package/lib/components/sidebar/TMCommandsPanel.d.ts +3 -1
  113. package/lib/components/sidebar/TMHeader.d.ts +3 -3
  114. package/lib/components/viewers/TMDataListItemViewer.d.ts +3 -2
  115. package/lib/components/viewers/TMDataUserIdItemViewer.d.ts +3 -2
  116. package/lib/components/viewers/TMMidViewer.d.ts +2 -2
  117. package/lib/components/viewers/TMTidViewer.d.ts +2 -2
  118. package/lib/helper/Enum_Localizator.js +1 -0
  119. package/lib/helper/SDKUI_Localizator.d.ts +6 -0
  120. package/lib/helper/SDKUI_Localizator.js +60 -0
  121. package/lib/helper/TMAppUpdatedModal.d.ts +2 -1
  122. package/lib/helper/TMAppUpdatedModal.js +93 -93
  123. package/lib/helper/TMCommandsContextMenu.d.ts +1 -1
  124. package/lib/helper/TMIcons.d.ts +280 -280
  125. package/lib/helper/TMPdfViewer.d.ts +2 -1
  126. package/lib/helper/TMToppyMessage.d.ts +2 -2
  127. package/lib/helper/TMUtils.d.ts +10 -4
  128. package/lib/helper/helpers.d.ts +1 -1
  129. package/lib/hooks/useDcmtOperations.js +94 -56
  130. package/lib/hooks/useDocumentOperations.d.ts +1 -0
  131. package/lib/hooks/useDocumentOperations.js +2 -2
  132. package/lib/hooks/useInputDialog.d.ts +2 -1
  133. package/lib/hooks/usePreventFileDrop.js +9 -0
  134. package/lib/services/caseflow/CaseFlowService.d.ts +32 -1
  135. package/lib/services/caseflow/CaseFlowService.js +58 -1
  136. package/lib/services/platform_services.d.ts +3 -2
  137. package/package.json +22 -22
@@ -1,8 +1,9 @@
1
+ import React from "react";
1
2
  interface TMPdfViewerProps {
2
3
  pdfBlob: Blob;
3
4
  title?: string;
4
5
  isResizingActive?: boolean;
5
6
  enableFitToWidth?: boolean;
6
7
  }
7
- declare const TMPdfViewer: (props: TMPdfViewerProps) => import("react/jsx-runtime").JSX.Element;
8
+ declare const TMPdfViewer: (props: TMPdfViewerProps) => React.JSX.Element;
8
9
  export default TMPdfViewer;
@@ -1,8 +1,8 @@
1
- import { ReactNode } from 'react';
1
+ import React, { ReactNode } from 'react';
2
2
  interface TMToppyMessageProps {
3
3
  message: ReactNode;
4
4
  titleTooltip?: string;
5
5
  maxWidth?: string;
6
6
  }
7
- declare const TMToppyMessage: (props: TMToppyMessageProps) => import("react/jsx-runtime").JSX.Element;
7
+ declare const TMToppyMessage: (props: TMToppyMessageProps) => React.JSX.Element;
8
8
  export default TMToppyMessage;
@@ -24,7 +24,7 @@ export declare const getFullFileExtension: (fileName: string, depth?: number) =>
24
24
  * Es: pdf.p7m.tsd → pdf, pdf.p7m → pdf, pdf → pdf
25
25
  */
26
26
  export declare const getBaseExtension: (ext: string) => string;
27
- export declare const getFileIcon: (fileExtension: string | undefined, fileCount: number | undefined, tooltipContent?: JSX.Element | string) => import("react/jsx-runtime").JSX.Element;
27
+ export declare const getFileIcon: (fileExtension: string | undefined, fileCount: number | undefined, tooltipContent?: JSX.Element | string) => React.JSX.Element;
28
28
  export declare function formatBytes(bytes: number | undefined, decimalPlaces?: number): string;
29
29
  export interface RowData {
30
30
  [key: string]: string | number | null;
@@ -52,9 +52,15 @@ interface TabItemProps {
52
52
  $isSelected: boolean;
53
53
  $activeGradient?: string;
54
54
  }
55
- export declare const StyledTabItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, TabItemProps>> & string;
56
- export declare const StyledTabIcon: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, TabItemProps>> & string;
57
- export declare const TMCountBadge: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
55
+ export declare const StyledTabItem: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
56
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
57
+ }, TabItemProps>> & string;
58
+ export declare const StyledTabIcon: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "style"> & {
59
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
60
+ }, TabItemProps>> & string;
61
+ export declare const TMCountBadge: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
62
+ style?: React.CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
63
+ }> & string;
58
64
  export declare const PDGS_COLORS: {
59
65
  DOSSIER: string;
60
66
  DOCUMENT: string;
@@ -77,7 +77,7 @@ export { openApps, calcResponsiveDirection, calcResponsiveSizes, taskModalSizes,
77
77
  export declare function moduleVersion(module: moduleTypes): string;
78
78
  export declare function buildtype(module: moduleTypes): string;
79
79
  export declare const highlightText: (text: string, searchValue: string) => JSX.Element;
80
- export declare const renderHighlightedText: (text: string, searchText: string, isSelected: boolean) => string | (string | import("react/jsx-runtime").JSX.Element)[];
80
+ export declare const renderHighlightedText: (text: string, searchText: string, isSelected: boolean) => string | (string | React.JSX.Element)[];
81
81
  export declare function versionAndBuildtypeInfo(module: moduleTypes): string;
82
82
  export declare const getListMaxItems: (deviceType: DeviceType | undefined) => number;
83
83
  export declare const svgToString: (icon: React.ReactElement) => string;
@@ -9,6 +9,8 @@ import { importCertificatesAsync } from '../helper/certificateImportHelper';
9
9
  import { isXMLFileExt } from '../helper/dcmtsHelper';
10
10
  import { ShowConfirm } from '../components/base/TMConfirm';
11
11
  import { generateTargetFileName } from '../components/features/documents/copyAndMergeDcmtsShared';
12
+ /** Intervallo minimo (ms) fra due aggiornamenti della progress bar di download. */
13
+ const DOWNLOAD_PROGRESS_THROTTLE_MS = 100;
12
14
  const isScannerLicenseConfigured = () => {
13
15
  try {
14
16
  const scannerLicense = SDKUI_Globals.userSettings.advancedSettings.scannerLicense;
@@ -286,6 +288,8 @@ export const useDcmtOperations = () => {
286
288
  setShowSecondary(true);
287
289
  setWaitPanelTitle(operationTitle);
288
290
  abortController = new AbortController();
291
+ // Riferimento const: il narrowing su inputDcmts non sopravvive dentro le closure.
292
+ const dcmts = inputDcmts;
289
293
  const rfo = new RetrieveFileOptions();
290
294
  rfo.retrieveReason = retrieveOptions?.retrieveReason ?? DcmtOpers.ShowFile;
291
295
  if (retrieveOptions?.cvtFormat !== undefined)
@@ -294,77 +298,111 @@ export const useDcmtOperations = () => {
294
298
  rfo.generalRetrieveFormat = retrieveOptions.generalRetrieveFormat;
295
299
  rfo.invoiceRetrieveFormat = retrieveOptions?.invoiceRetrieveFormat ?? SDKUI_Globals.userSettings.searchSettings.invoiceRetrieveFormat;
296
300
  rfo.orderRetrieveFormat = retrieveOptions?.orderRetrieveFormat ?? SDKUI_Globals.userSettings.searchSettings.orderRetrieveFormat;
297
- let result = [];
298
- setWaitPanelMaxValuePrimary(inputDcmts.length);
299
- let firstBlock = true;
300
- let maxFileSize = 0;
301
- for (let i = 0; i < inputDcmts.length; i++) {
302
- if (abortController.signal.aborted) {
303
- result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.WARNING, description: `Operazione interrotta. Elaborati ${i + 1} documenti` });
304
- break;
301
+ const results = [];
302
+ setWaitPanelMaxValuePrimary(dcmts.length);
303
+ // ---- Progress secondaria: throttlata ----
304
+ // Gli eventi di avanzamento di axios arrivano a ogni chunk: senza throttle ognuno
305
+ // provoca un re-render dell'intera form (relation viewer compreso).
306
+ let currentBytes;
307
+ let pendingSecondary;
308
+ let secondaryTimer;
309
+ const flushSecondaryProgress = () => {
310
+ secondaryTimer = undefined;
311
+ if (!pendingSecondary)
312
+ return;
313
+ setWaitPanelMaxValueSecondary(pendingSecondary.max);
314
+ setWaitPanelValueSecondary(pendingSecondary.value);
315
+ setWaitPanelTextSecondary(pendingSecondary.text);
316
+ pendingSecondary = undefined;
317
+ };
318
+ const publishSecondaryProgress = () => {
319
+ const loaded = currentBytes?.loaded ?? 0;
320
+ const total = currentBytes?.total ?? 0;
321
+ pendingSecondary = total > 0
322
+ ? { value: loaded, max: total, text: `Downloading... ${Globalization.getNumberDisplayValue(loaded, true)} / ${Globalization.getNumberDisplayValue(total, true)}` }
323
+ : { value: 0, max: 0, text: '' };
324
+ if (secondaryTimer === undefined)
325
+ secondaryTimer = setTimeout(flushSecondaryProgress, DOWNLOAD_PROGRESS_THROTTLE_MS);
326
+ };
327
+ // ---- Download sequenziale: un documento per volta ----
328
+ let completed = 0;
329
+ const downloadOne = async (i) => {
330
+ setWaitPanelTextPrimary(`Download file ${i + 1} di ${dcmts.length}`);
331
+ let file;
332
+ const cacheKey = `${dcmts[i].TID}-${dcmts[i].DID}`;
333
+ if (useCache && dcmtsFileCacheDownload.has(cacheKey)) {
334
+ file = dcmtsFileCacheDownload.get(cacheKey);
305
335
  }
306
- try {
307
- setWaitPanelTextPrimary(`Download file ${i + 1} di ${inputDcmts.length}`);
308
- let file;
309
- const cacheKey = `${inputDcmts[i].TID}-${inputDcmts[i].DID}`;
310
- if (useCache && dcmtsFileCacheDownload.has(cacheKey)) {
311
- file = dcmtsFileCacheDownload.get(cacheKey);
336
+ else {
337
+ currentBytes = { loaded: 0, total: 0 };
338
+ try {
339
+ file = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(dcmts[i].TID, dcmts[i].DID, rfo, abortController.signal, (pd) => {
340
+ currentBytes = { loaded: pd.ProgressBarValue, total: pd.ProgressBarMaximum ?? 0 };
341
+ publishSecondaryProgress();
342
+ });
343
+ }
344
+ finally {
345
+ currentBytes = undefined;
346
+ publishSecondaryProgress();
347
+ }
348
+ }
349
+ completed++;
350
+ setWaitPanelValuePrimary(completed);
351
+ if (downloadMode === "openInNewWindow") {
352
+ if (onFileDownloaded && file) {
353
+ onFileDownloaded(file, dcmts[i]);
312
354
  }
313
355
  else {
314
- file = await SDK_Globals.tmSession?.NewSearchEngine().RetrieveFileAsync(inputDcmts[i].TID, inputDcmts[i].DID, rfo, abortController.signal, (pd) => {
315
- if (firstBlock) {
316
- maxFileSize = pd.ProgressBarMaximum ?? 0;
317
- setWaitPanelMaxValueSecondary(maxFileSize);
318
- firstBlock = false;
319
- }
320
- setWaitPanelValueSecondary(pd.ProgressBarValue);
321
- setWaitPanelTextSecondary(`Downloading... ${Globalization.getNumberDisplayValue(pd.ProgressBarValue, true)} / ${Globalization.getNumberDisplayValue(maxFileSize, true)}`);
322
- if (pd.ProgressBarValue === pd.ProgressBarMaximum) {
323
- setWaitPanelMaxValueSecondary(0);
324
- setWaitPanelValueSecondary(0);
325
- setWaitPanelTextSecondary('');
326
- firstBlock = true;
327
- }
328
- });
356
+ window.open(window.URL.createObjectURL(file), '_blank', 'noopener');
329
357
  }
330
- setWaitPanelValuePrimary(i + 1);
331
- const fileURL = window.URL.createObjectURL(file);
332
- if (downloadMode === "openInNewWindow") {
333
- (onFileDownloaded && file)
334
- ? onFileDownloaded(file, inputDcmts[i])
335
- : window.open(fileURL, '_blank', 'noopener');
358
+ }
359
+ else {
360
+ if (onFileDownloaded && file) {
361
+ await onFileDownloaded(file, dcmts[i]);
336
362
  }
337
363
  else {
338
- if (onFileDownloaded && file) {
339
- await onFileDownloaded(file, inputDcmts[i]);
340
- }
341
- else {
342
- const alink2 = document.createElement('a');
343
- alink2.href = fileURL;
344
- // Usa useInputFileName per determinare la priorità del nome file
345
- alink2.download = getDownloadFileName(file, inputDcmts[i], useInputFileName);
346
- alink2.target = "_blank";
347
- alink2.rel = "noreferrer";
348
- alink2.click();
349
- }
364
+ // L'object URL serve solo in questo ramo: creato qui e revocato dopo il
365
+ // click, così i blob non restano agganciati al documento per sempre.
366
+ const fileURL = window.URL.createObjectURL(file);
367
+ const alink2 = document.createElement('a');
368
+ alink2.href = fileURL;
369
+ // Usa useInputFileName per determinare la priorità del nome file
370
+ alink2.download = getDownloadFileName(file, dcmts[i], useInputFileName);
371
+ alink2.target = "_blank";
372
+ alink2.rel = "noreferrer";
373
+ alink2.click();
374
+ // 60s come per l'iframe di stampa: revocare troppo presto può far fallire
375
+ // il download se il browser non ha ancora risolto il blob URL.
376
+ setTimeout(() => window.URL.revokeObjectURL(fileURL), 60000);
350
377
  }
351
- if (useCache) {
352
- if (dcmtsFileCacheDownload.size >= CACHE_SIZE_LIMIT) {
353
- const oldestKey = dcmtsFileCacheDownload.keys().next().value;
354
- dcmtsFileCacheDownload.delete(oldestKey);
355
- }
356
- dcmtsFileCacheDownload.set(cacheKey, file);
378
+ }
379
+ if (useCache) {
380
+ if (dcmtsFileCacheDownload.size >= CACHE_SIZE_LIMIT) {
381
+ const oldestKey = dcmtsFileCacheDownload.keys().next().value;
382
+ dcmtsFileCacheDownload.delete(oldestKey);
357
383
  }
358
- result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.SUCCESS });
384
+ dcmtsFileCacheDownload.set(cacheKey, file);
385
+ }
386
+ results.push({ rowIndex: i, id1: dcmts[i].TID, id2: dcmts[i].DID, resultType: ResultTypes.SUCCESS });
387
+ };
388
+ for (let i = 0; i < dcmts.length; i++) {
389
+ if (abortController.signal.aborted) {
390
+ results.push({ rowIndex: i, id1: dcmts[i].TID, id2: dcmts[i].DID, resultType: ResultTypes.WARNING, description: `Operazione interrotta. Elaborati ${completed} documenti` });
391
+ break;
392
+ }
393
+ try {
394
+ await downloadOne(i);
359
395
  }
360
396
  catch (ex) {
361
- result.push({ rowIndex: i, id1: inputDcmts[i].TID, id2: inputDcmts[i].DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(ex) });
397
+ results.push({ rowIndex: i, id1: dcmts[i].TID, id2: dcmts[i].DID, resultType: ResultTypes.ERROR, description: getExceptionMessage(ex) });
362
398
  const err = ex;
363
399
  if (err.name === 'CanceledError') {
364
400
  ShowAlert({ message: err.message, mode: 'warning', duration: 3000, title: 'Abort' });
365
401
  }
366
402
  }
367
403
  }
404
+ if (secondaryTimer !== undefined)
405
+ clearTimeout(secondaryTimer);
368
406
  setWaitPanelTextPrimary('');
369
407
  setWaitPanelMaxValuePrimary(0);
370
408
  setWaitPanelValuePrimary(0);
@@ -372,7 +410,7 @@ export const useDcmtOperations = () => {
372
410
  setWaitPanelMaxValueSecondary(0);
373
411
  setWaitPanelValueSecondary(0);
374
412
  setShowWaitPanel(false);
375
- TMResultManager.show(result, operationTitle, "TID", "DID", undefined, undefined, showSuccessAlert);
413
+ TMResultManager.show(results, operationTitle, "TID", "DID", undefined, undefined, showSuccessAlert);
376
414
  };
377
415
  const _downloadAttachmentsAsync = async (inputDcmts, confirmAttachments, showSuccessAlert = true) => {
378
416
  if (inputDcmts === undefined)
@@ -63,6 +63,7 @@ export interface UIConfigProps {
63
63
  toppyHelpCenterUsePortal?: boolean;
64
64
  inputDcmtFormLayoutMode?: LayoutModes;
65
65
  graphometricManager?: IGraphometricManagerProp;
66
+ showSelector?: boolean;
66
67
  }
67
68
  export interface TasksProps {
68
69
  allTasks?: Array<TaskDescriptor>;
@@ -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)
@@ -1073,7 +1073,7 @@ export const useDocumentOperations = (props) => {
1073
1073
  ]
1074
1074
  };
1075
1075
  };
1076
- const canToggleDcmtTypesSelection = !isMobile && context === SearchResultContext.WORKFLOW_APPROVE;
1076
+ const canToggleDcmtTypesSelection = !isMobile && showSelector && currentSearchResults?.length === 1;
1077
1077
  const otherOperationsMenuItem = () => {
1078
1078
  return {
1079
1079
  id: 'oth',
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import { FileDescriptor, FileFormats } from '@topconsultnpm/sdk-ts';
2
3
  export declare const useInputCvtFormatDialog: () => [() => Promise<FileFormats>, () => JSX.Element];
3
4
  export declare const useFileDialog: () => {
@@ -5,7 +6,7 @@ export declare const useFileDialog: () => {
5
6
  };
6
7
  export declare const useInputAttachmentsDialog: () => {
7
8
  openConfirmAttachmentsDialog: (list: FileDescriptor[]) => Promise<string[] | undefined>;
8
- ConfirmAttachmentsDialog: () => import("react/jsx-runtime").JSX.Element | null;
9
+ ConfirmAttachmentsDialog: () => React.JSX.Element | null;
9
10
  };
10
11
  export type FileSourceType = 'filesystem' | 'scanner-new' | 'scanner-edit' | undefined;
11
12
  export declare const useFileSourceDialog: () => [(hasExistingFile?: boolean) => Promise<FileSourceType>, () => JSX.Element];
@@ -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";
@@ -144,6 +144,17 @@ export declare class CaseFlowService {
144
144
  * cftid quando non passato (come per bacheca e partecipanti).
145
145
  */
146
146
  private static dcmtAddOrRemove;
147
+ /**
148
+ * Allega un file alla pratica tramite AttachAddAsync(cftid, id, ...).
149
+ * @returns il DID dell'allegato appena archiviato.
150
+ */
151
+ static addAttachment(caseFlowId: number, file: File, name?: string, description?: string, cftid?: number): Promise<number | undefined>;
152
+ /**
153
+ * Toglie l'allegato dalla pratica tramite AttachRemoveAsync(cftid, id, attachDID).
154
+ * A differenza dello sgancio di un documento d'archivio, qui il file viene
155
+ * anche cancellato: un allegato fuori dalla sua pratica non ha più senso.
156
+ */
157
+ static removeAttachment(caseFlowId: number, attachDID: number, cftid?: number): Promise<void>;
147
158
  /**
148
159
  * Aggiunge un partecipante all'istanza (o ne aggiorna ruolo/permessi se già
149
160
  * presente) tramite ParticipantsAddOrRemoveAsync(remove=false).
@@ -202,7 +213,27 @@ export declare class CaseFlowService {
202
213
  static completeDataCompletionWorkItem(caseFlowId: number, workItemId: number, metadataValues: Record<number, string>, response?: string, cftid?: number): Promise<void>;
203
214
  /** Rifiuta un workitem. Il motivo viene pubblicato in bacheca dal backend. */
204
215
  static rejectWorkItem(caseFlowId: number, workItemId: number, response?: string, cftid?: number): Promise<void>;
205
- /** Assegna un'azione a un utente creando il relativo workitem (operazione Assign). */
216
+ /**
217
+ * Prende in carico un'azione per se stessi (operazione Claim): il backend
218
+ * crea il workitem intestato al chiamante e porta l'azione in lavorazione.
219
+ *
220
+ * Non e' un caso particolare di `createWorkItemForAction`: assegnare e'
221
+ * riservato a Owner e Supervisore, prendere in carico e' di chiunque lavori
222
+ * alla pratica. Passando dall'operazione Assign, un Partecipante si vedeva
223
+ * rifiutare la presa in carico (TMC-2789).
224
+ */
225
+ static claimAction(caseFlowId: number, actionID: number, cftid?: number): Promise<void>;
226
+ /**
227
+ * Rilascia un workitem preso in carico (operazione ReleaseClaim): il backend
228
+ * lo cancella e, se per quell'azione non restano altri destinatari, la riporta
229
+ * disponibile per la presa in carico.
230
+ *
231
+ * Stessa chiamata per due gesti diversi, e' la guardia della SP a distinguerli:
232
+ * il detentore rilascia il proprio workitem, un Owner/Supervisore annulla
233
+ * l'assegnazione di un altro. Chi chiama non deve dire quale dei due sta facendo.
234
+ */
235
+ static releaseClaim(caseFlowId: number, workItemId: number, cftid?: number): Promise<void>;
236
+ /** Assegna un'azione a un ALTRO utente creando il relativo workitem (operazione Assign). */
206
237
  static createWorkItemForAction(caseFlowId: number, actionID: number, toUserID: number, description?: string, cftid?: number): Promise<void>;
207
238
  /** Forza il completamento di un'azione (supervisor). */
208
239
  static forceCompleteAction(caseFlowId: number, actionID: number, reason?: string, cftid?: number): Promise<void>;
@@ -353,6 +353,33 @@ export class CaseFlowService {
353
353
  throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
354
354
  await engine.DcmtAddOrRemoveAsync(resolvedCftid, caseFlowId, tid, did, remove);
355
355
  }
356
+ /**
357
+ * Allega un file alla pratica tramite AttachAddAsync(cftid, id, ...).
358
+ * @returns il DID dell'allegato appena archiviato.
359
+ */
360
+ static async addAttachment(caseFlowId, file, name, description, cftid) {
361
+ const engine = SDK_Globals.tmSession?.NewCaseFlowInstanceEngine();
362
+ if (!engine)
363
+ throw new Error('Motore delle istanze CaseFlow non disponibile.');
364
+ const resolvedCftid = cftid ?? (await this.getCaseflow(caseFlowId))?.cftid;
365
+ if (resolvedCftid == null)
366
+ throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
367
+ return await engine.AttachAddAsync(resolvedCftid, caseFlowId, name, description, file);
368
+ }
369
+ /**
370
+ * Toglie l'allegato dalla pratica tramite AttachRemoveAsync(cftid, id, attachDID).
371
+ * A differenza dello sgancio di un documento d'archivio, qui il file viene
372
+ * anche cancellato: un allegato fuori dalla sua pratica non ha più senso.
373
+ */
374
+ static async removeAttachment(caseFlowId, attachDID, cftid) {
375
+ const engine = SDK_Globals.tmSession?.NewCaseFlowInstanceEngine();
376
+ if (!engine)
377
+ throw new Error('Motore delle istanze CaseFlow non disponibile.');
378
+ const resolvedCftid = cftid ?? (await this.getCaseflow(caseFlowId))?.cftid;
379
+ if (resolvedCftid == null)
380
+ throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
381
+ await engine.AttachRemoveAsync(resolvedCftid, caseFlowId, attachDID);
382
+ }
356
383
  // ----- Partecipanti ------------------------------------------------------
357
384
  //
358
385
  // Per scelta del backend l'engine espone UNA sola API,
@@ -524,7 +551,37 @@ export class CaseFlowService {
524
551
  comment: response,
525
552
  }), cftid);
526
553
  }
527
- /** Assegna un'azione a un utente creando il relativo workitem (operazione Assign). */
554
+ /**
555
+ * Prende in carico un'azione per se stessi (operazione Claim): il backend
556
+ * crea il workitem intestato al chiamante e porta l'azione in lavorazione.
557
+ *
558
+ * Non e' un caso particolare di `createWorkItemForAction`: assegnare e'
559
+ * riservato a Owner e Supervisore, prendere in carico e' di chiunque lavori
560
+ * alla pratica. Passando dall'operazione Assign, un Partecipante si vedeva
561
+ * rifiutare la presa in carico (TMC-2789).
562
+ */
563
+ static async claimAction(caseFlowId, actionID, cftid) {
564
+ await this.executeWorkItemOperation(caseFlowId, CaseFlowWIOperationDescriptor.fromJS({
565
+ operation: CF_WIOperations.Claim,
566
+ actionID,
567
+ }), cftid);
568
+ }
569
+ /**
570
+ * Rilascia un workitem preso in carico (operazione ReleaseClaim): il backend
571
+ * lo cancella e, se per quell'azione non restano altri destinatari, la riporta
572
+ * disponibile per la presa in carico.
573
+ *
574
+ * Stessa chiamata per due gesti diversi, e' la guardia della SP a distinguerli:
575
+ * il detentore rilascia il proprio workitem, un Owner/Supervisore annulla
576
+ * l'assegnazione di un altro. Chi chiama non deve dire quale dei due sta facendo.
577
+ */
578
+ static async releaseClaim(caseFlowId, workItemId, cftid) {
579
+ await this.executeWorkItemOperation(caseFlowId, CaseFlowWIOperationDescriptor.fromJS({
580
+ operation: CF_WIOperations.ReleaseClaim,
581
+ wiid: workItemId,
582
+ }), cftid);
583
+ }
584
+ /** Assegna un'azione a un ALTRO utente creando il relativo workitem (operazione Assign). */
528
585
  static async createWorkItemForAction(caseFlowId, actionID, toUserID, description, cftid) {
529
586
  await this.executeWorkItemOperation(caseFlowId, CaseFlowWIOperationDescriptor.fromJS({
530
587
  operation: CF_WIOperations.Assign,
@@ -1,3 +1,4 @@
1
+ import React from "react";
1
2
  import { JobTypes, ObjectClasses, ProcessDescriptor, DcmtTypeDescriptor } from "@topconsultnpm/sdk-ts";
2
3
  export declare class PlatformObjectService {
3
4
  static readonly retrieveAllAsync: (objClass: ObjectClasses, refreshCache?: boolean) => Promise<import("@topconsultnpm/sdk-ts").AreaDescriptor[] | import("@topconsultnpm/sdk-ts").NotificationDescriptor[] | import("@topconsultnpm/sdk-ts").RelationDescriptor[] | import("@topconsultnpm/sdk-ts").TaskDescriptor[] | import("@topconsultnpm/sdk-ts").WorkingGroupDescriptor[] | undefined>;
@@ -13,6 +14,6 @@ export declare class PlatformObjectService {
13
14
  static readonly createAsync: (objClass: ObjectClasses, jobType: JobTypes, d: any) => Promise<number | undefined>;
14
15
  static readonly deleteAsync: (objClass: ObjectClasses, id: number) => Promise<number | undefined>;
15
16
  static readonly getName: (objClass: ObjectClasses, jobType?: JobTypes, isPlural?: boolean) => string;
16
- static readonly getIcon: (objClass: ObjectClasses, d: any) => import("react/jsx-runtime").JSX.Element;
17
- static readonly getTooltip: (objClass: ObjectClasses, d: any) => import("react/jsx-runtime").JSX.Element | null;
17
+ static readonly getIcon: (objClass: ObjectClasses, d: any) => React.JSX.Element;
18
+ static readonly getTooltip: (objClass: ObjectClasses, d: any) => React.JSX.Element | null;
18
19
  }
package/package.json CHANGED
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.22.0-dev3.2",
3
+ "version": "6.22.0-dev3.20",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
7
7
  "clean": "node -e \"const fs=require('fs');fs.rmSync('lib',{recursive:true,force:true});fs.mkdirSync('lib')\"",
8
8
  "copy-files": "cpx \"src/{assets/*.*,assets/ImageLibrary/*.*,assets/thumbnails/*.*,assets/IconsS4t/*.*,assets/Metadata/*.*,css/tm-sdkui.css}\" lib",
9
- "tm-license": "devextreme-license --out src/devextreme-license.ts --force && node scripts/check-license.js",
10
- "pretm-build": "npm run tm-license",
11
- "tm-build": "npm run clean && tsc && npm run copy-files",
12
- "tm-watch": "tsc -w",
13
- "tm-publish": "npm publish --tag latest",
14
- "tm-publish_wl": "npm publish",
15
- "prestorybook": "npm run tm-license",
16
- "storybook": "storybook dev -p 6006",
17
- "prebuild-storybook": "npm run tm-license",
18
- "build-storybook": "storybook build"
9
+ "tm-license": "devextreme-license --out src/devextreme-license.ts --force && node scripts/check-license.js",
10
+ "pretm-build": "npm run tm-license",
11
+ "tm-build": "npm run clean && tsc && npm run copy-files",
12
+ "tm-watch": "tsc -w",
13
+ "tm-publish": "npm publish --tag latest",
14
+ "tm-publish_wl": "npm publish",
15
+ "prestorybook": "npm run tm-license",
16
+ "storybook": "storybook dev -p 6006",
17
+ "prebuild-storybook": "npm run tm-license",
18
+ "build-storybook": "storybook build"
19
19
  },
20
20
  "author": "TopConsult",
21
21
  "license": "ISC",
@@ -42,17 +42,17 @@
42
42
  "lib"
43
43
  ],
44
44
  "dependencies": {
45
- "react-pdf": "^10.4.1",
46
- "@zip.js/zip.js": "2.8.26",
47
- "pdf-lib": "^1.17.1",
48
- "devextreme-exceljs-fork": "^4.4.13",
49
- "buffer": "^6.0.3",
50
- "@topconsultnpm/sdk-ts": "6.22.0-t2",
51
- "react-window": "^2.2.7",
52
- "devextreme": "^26.1.4",
53
- "htmlparser2": "^10.0.0",
54
- "styled-components": "^6.1.1",
55
- "devextreme-react": "^26.1.4"
45
+ "@topconsultnpm/sdk-ts": "6.22.0-dev3.4",
46
+ "@zip.js/zip.js": "2.8.26",
47
+ "buffer": "^6.0.3",
48
+ "devextreme": "^26.1.4",
49
+ "devextreme-exceljs-fork": "^4.4.13",
50
+ "devextreme-react": "^26.1.4",
51
+ "htmlparser2": "^10.0.0",
52
+ "pdf-lib": "^1.17.1",
53
+ "react-pdf": "^10.4.1",
54
+ "react-window": "^2.2.7",
55
+ "styled-components": "^6.1.1"
56
56
  },
57
57
  "overrides": {
58
58
  "esbuild": "^0.25.0",