@topconsultnpm/sdkui-react 6.21.0-dev2.57 → 6.21.0-dev2.59

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.
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useRef, useState } from 'react';
3
3
  import { DownloadTypes } from '../../../ts';
4
- import { calcResponsiveSizes, IconFolderOpen, IconPlay, IconUndo, SDKUI_Globals, SDKUI_Localizator, } from '../../../helper';
4
+ import { calcResponsiveSizes, IconFolderOpen, IconPlay, IconUndo, isConvertibleToPdfExt, SDKUI_Globals, SDKUI_Localizator, } from '../../../helper';
5
5
  import { DcmtOpers, FileFormats, GeneralRetrieveFormats, ResultTypes, RetrieveFileOptions, ValidationItem, } from '@topconsultnpm/sdk-ts';
6
6
  import TMModal from '../../base/TMModal';
7
7
  import { useDeviceType } from '../../base/TMDeviceProvider';
@@ -72,20 +72,6 @@ const TMMergeToPdfForm = ({ mode, selectedDcmtInfos, onClose, showTMRelationView
72
72
  if (!pdfFileName.trim()) {
73
73
  pdfValidationItems.push(new ValidationItem(ResultTypes.ERROR, SDKUI_Localizator.PdfFileName, SDKUI_Localizator.RequiredField));
74
74
  }
75
- // ---- Helper per file convertibili in PDF ----
76
- const isConvertibleToPdfExt = (ext) => {
77
- if (!ext)
78
- return false;
79
- const normalized = ext.toString().trim().toLowerCase().replace(/^\./, '');
80
- return [
81
- 'doc', 'docx', 'dot', 'dotx', 'docm', 'dotm', 'odt', 'rtf', 'txt',
82
- 'csv', 'xls', 'xlsx',
83
- 'ppt', 'pptx', 'ppsx',
84
- 'htm', 'html', 'xml',
85
- 'bmp', 'jpg', 'jpeg', 'tif', 'tiff',
86
- 'eml', 'msg'
87
- ].includes(normalized);
88
- };
89
75
  // ---- Statistiche selezione PDF / convertibili / non-PDF ----
90
76
  const convertibleSelectedItems = (() => {
91
77
  if (showTMRelationViewer) {
@@ -13,7 +13,10 @@ export declare const dedupeByTidDid: (items: ReadonlyArray<IRelatedDcmt>) => Arr
13
13
  /** Verifica se showDirectoryPicker è supportato (Chrome, Edge) */
14
14
  export declare const isDirectoryPickerSupported: () => boolean;
15
15
  /**
16
- * Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf".
16
+ * Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf"
17
+ * o un PDF firmato (pdf.p7m, pdf.tsd, pdf.m7m).
18
+ * Questi formati firmati vengono trattati come PDF nativi perché con OriginalUnsigned
19
+ * il file viene restituito senza firma.
17
20
  */
18
21
  export declare const isPdfExt: (ext: string | null | undefined) => boolean;
19
22
  /**
@@ -50,13 +50,16 @@ export const isDirectoryPickerSupported = () => {
50
50
  return 'showDirectoryPicker' in window;
51
51
  };
52
52
  /**
53
- * Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf".
53
+ * Verifica se un'estensione (con o senza punto iniziale, case-insensitive) è "pdf"
54
+ * o un PDF firmato (pdf.p7m, pdf.tsd, pdf.m7m).
55
+ * Questi formati firmati vengono trattati come PDF nativi perché con OriginalUnsigned
56
+ * il file viene restituito senza firma.
54
57
  */
55
58
  export const isPdfExt = (ext) => {
56
59
  if (!ext)
57
60
  return false;
58
61
  const normalized = ext.trim().toLowerCase().replace(/^\./, '');
59
- return normalized === 'pdf';
62
+ return normalized === 'pdf' || normalized === 'pdf.p7m' || normalized === 'pdf.tsd' || normalized === 'pdf.m7m';
60
63
  };
61
64
  /**
62
65
  * Estensioni di firma/marca temporale note che possono avvolgere altre estensioni.
@@ -598,6 +598,8 @@ export declare class SDKUI_Localizator {
598
598
  static get Priority(): string;
599
599
  static get PriorityLegend(): "Legende der Prioritäten" | "Priority Legend" | "Leyenda de prioridades" | "Légende des priorités" | "Lenda das prioridades" | "Legenda delle priorità";
600
600
  static get Print(): "Drucken" | "Print" | "Imprimir" | "Imprimer" | "Stampa";
601
+ static get PrintConfirmConversion(): "Die Originaldatei kann nicht direkt gedruckt werden und wird in PDF konvertiert." | "The original file cannot be printed directly and will be converted to PDF." | "El archivo original no se puede imprimir directamente y se convertirá a PDF." | "Le fichier original ne peut pas être imprimé directement et sera converti en PDF." | "O arquivo original não pode ser impresso diretamente e será convertido para PDF." | "Il file originale non è stampabile direttamente e verrà convertito in PDF.";
602
+ static get PrintConfirmQuestion(): "Möchten Sie mit dem Drucken fortfahren?" | "Do you want to proceed with printing?" | "¿Desea continuar con la impresión?" | "Voulez-vous continuer l'impression ?" | "Deseja continuar com a impressão?" | "Vuoi procedere con la stampa?";
601
603
  static get ProceedAnyway(): "Dennoch fortfahren?" | "Proceed anyway?" | "¿Proceder de todos modos?" | "Procéder quand même ?" | "Prosseguir mesmo assim?" | "Procedere comunque?";
602
604
  static get ProcessedItems(): "Durchdachte Elemente" | "Processed items" | "Elementos elaborados" | "Items traités" | "Itens processados" | "Elementi elaborati";
603
605
  static get Properties(): "Eigenschaften" | "Properties" | "Propiedades" | "Propriétés" | "Propriedades" | "Proprietà";
@@ -5952,6 +5952,26 @@ export class SDKUI_Localizator {
5952
5952
  default: return "Stampa";
5953
5953
  }
5954
5954
  }
5955
+ static get PrintConfirmConversion() {
5956
+ switch (this._cultureID) {
5957
+ case CultureIDs.De_DE: return "Die Originaldatei kann nicht direkt gedruckt werden und wird in PDF konvertiert.";
5958
+ case CultureIDs.En_US: return "The original file cannot be printed directly and will be converted to PDF.";
5959
+ case CultureIDs.Es_ES: return "El archivo original no se puede imprimir directamente y se convertirá a PDF.";
5960
+ case CultureIDs.Fr_FR: return "Le fichier original ne peut pas être imprimé directement et sera converti en PDF.";
5961
+ case CultureIDs.Pt_PT: return "O arquivo original não pode ser impresso diretamente e será convertido para PDF.";
5962
+ default: return "Il file originale non è stampabile direttamente e verrà convertito in PDF.";
5963
+ }
5964
+ }
5965
+ static get PrintConfirmQuestion() {
5966
+ switch (this._cultureID) {
5967
+ case CultureIDs.De_DE: return "Möchten Sie mit dem Drucken fortfahren?";
5968
+ case CultureIDs.En_US: return "Do you want to proceed with printing?";
5969
+ case CultureIDs.Es_ES: return "¿Desea continuar con la impresión?";
5970
+ case CultureIDs.Fr_FR: return "Voulez-vous continuer l'impression ?";
5971
+ case CultureIDs.Pt_PT: return "Deseja continuar com a impressão?";
5972
+ default: return "Vuoi procedere con la stampa?";
5973
+ }
5974
+ }
5955
5975
  static get ProceedAnyway() {
5956
5976
  switch (this._cultureID) {
5957
5977
  case CultureIDs.De_DE: return "Dennoch fortfahren?";
@@ -72,4 +72,5 @@ export type MergePdfManagerType = {
72
72
  pageCount: number;
73
73
  }>;
74
74
  };
75
+ export declare const isConvertibleToPdfExt: (ext: string | undefined | null) => boolean;
75
76
  export {};
@@ -358,3 +358,20 @@ export const getDcmtFormToolbarVisibility = (appModuleID) => {
358
358
  };
359
359
  }
360
360
  };
361
+ // ---- Helper per file convertibili in PDF ----
362
+ export const isConvertibleToPdfExt = (ext) => {
363
+ if (!ext)
364
+ return false;
365
+ // Rimuove le estensioni di firma digitale (P7M, M7M, TSR, TSD, TS) prima di normalizzare
366
+ const normalized = ext.toString().trim().toUpperCase()
367
+ .replace(/\.P7M/g, '').replace(/\.M7M/g, '').replace(/\.TSR/g, '').replace(/\.TSD/g, '').replace(/\.TS/g, '')
368
+ .toLowerCase().replace(/^\./, '').split('.').pop() ?? '';
369
+ return [
370
+ 'doc', 'docx', 'dot', 'dotx', 'docm', 'dotm', 'odt', 'rtf', 'txt',
371
+ 'csv', 'xls', 'xlsx',
372
+ 'ppt', 'pptx', 'ppsx',
373
+ 'htm', 'html', 'xml',
374
+ 'bmp', 'jpg', 'jpeg', 'tif', 'tiff',
375
+ 'eml', 'msg'
376
+ ].includes(normalized);
377
+ };
@@ -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, isPdfEditorAvailable, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary } from '../helper';
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, SDKUI_Globals, SDKUI_Localizator, searchResultToMetadataValues, TMImageLibrary } 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";
@@ -646,6 +646,80 @@ export const useDocumentOperations = (props) => {
646
646
  return;
647
647
  copyCheckoutPathToClipboardCallback(firstDoc, dtd?.name ?? SDKUI_Localizator.SearchResult);
648
648
  };
649
+ const printMenuItem = () => {
650
+ // Take the first document (used for validation checks)
651
+ const firstDoc = selectedDcmtInfos?.[0];
652
+ // Check if the selected document is a PDF or can be converted to PDF by the backend
653
+ // Include signed PDFs (p7m, tsd, m7m) since generalRetrieveFormat is OriginalUnsigned
654
+ const fileExtLower = firstDoc?.FILEEXT?.toLowerCase();
655
+ const isPdf = fileExtLower === "pdf" || fileExtLower === "pdf.p7m" || fileExtLower === "pdf.tsd" || fileExtLower === "pdf.m7m";
656
+ const isConvertible = isConvertibleToPdfExt(firstDoc?.FILEEXT);
657
+ const canPrint = isPdf || isConvertible;
658
+ const executePrint = async () => {
659
+ const handlePrint = async (file, _dcmtInfo) => {
660
+ const fileURL = window.URL.createObjectURL(file);
661
+ // Usa un iframe nascosto con sandbox per:
662
+ // 1. Bloccare l'esecuzione di JavaScript nel PDF
663
+ // 2. Non aprire un nuovo tab
664
+ const printFrame = document.createElement('iframe');
665
+ printFrame.style.position = 'fixed';
666
+ printFrame.style.right = '0';
667
+ printFrame.style.bottom = '0';
668
+ printFrame.style.width = '0';
669
+ printFrame.style.height = '0';
670
+ printFrame.style.border = 'none';
671
+ printFrame.src = fileURL;
672
+ document.body.appendChild(printFrame);
673
+ printFrame.onload = () => {
674
+ try {
675
+ printFrame.contentWindow?.focus();
676
+ printFrame.contentWindow?.print();
677
+ }
678
+ catch (e) {
679
+ console.error('Errore durante la stampa:', e);
680
+ }
681
+ // Cleanup dopo un delay per permettere la stampa
682
+ setTimeout(() => {
683
+ document.body.removeChild(printFrame);
684
+ window.URL.revokeObjectURL(fileURL);
685
+ }, 60000);
686
+ };
687
+ };
688
+ const rfo = new RetrieveFileOptions();
689
+ rfo.retrieveReason = DcmtOpers.Print;
690
+ rfo.generalRetrieveFormat = GeneralRetrieveFormats.OriginalUnsigned;
691
+ rfo.cvtFormat = FileFormats.PDF;
692
+ rfo.invoiceRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.invoiceRetrieveFormat;
693
+ rfo.orderRetrieveFormat = SDKUI_Globals.userSettings?.searchSettings.orderRetrieveFormat;
694
+ await downloadDcmtsAsync(selectedDcmtInfos, DownloadTypes.Dcmt, "download", handlePrint, undefined, true, rfo, true, false);
695
+ };
696
+ return {
697
+ id: 'print',
698
+ icon: _jsx("i", { className: "dx-icon-print", style: { fontSize: '20px' } }),
699
+ name: SDKUI_Localizator.Print,
700
+ operationType: 'singleRow',
701
+ disabled: !canPrint || isDisabledForSingleRow(),
702
+ onClick: canPrint ? async () => {
703
+ // Se non è un PDF nativo ma è convertibile, chiedi conferma
704
+ if (!isPdf && isConvertible) {
705
+ TMMessageBoxManager.show({
706
+ title: SDKUI_Localizator.Print,
707
+ message: (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px' }, children: [_jsx("p", { style: { margin: 0, color: '#333' }, children: SDKUI_Localizator.PrintConfirmConversion.split('PDF').map((part, i, arr) => (_jsxs("span", { children: [part, i < arr.length - 1 && _jsx("strong", { children: "PDF" })] }, i))) }), _jsx("p", { style: { margin: 0, fontWeight: 500, color: '#333' }, children: SDKUI_Localizator.PrintConfirmQuestion })] })),
708
+ buttons: [ButtonNames.YES, ButtonNames.NO],
709
+ showToppy: false,
710
+ onButtonClick: async (e) => {
711
+ if (e === ButtonNames.YES) {
712
+ await executePrint();
713
+ }
714
+ }
715
+ });
716
+ }
717
+ else {
718
+ await executePrint();
719
+ }
720
+ } : undefined,
721
+ };
722
+ };
649
723
  const checkinMenuItem = () => {
650
724
  // Take the first document (used for validation checks)
651
725
  let dcmt = focusedItem;
@@ -1082,6 +1156,7 @@ export const useDocumentOperations = (props) => {
1082
1156
  batchUpdateMenuItem(),
1083
1157
  passToArchive(),
1084
1158
  ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : []),
1159
+ ...(!isMobile ? [printMenuItem()] : [])
1085
1160
  ]
1086
1161
  },
1087
1162
  signatureMenuItem(),
@@ -1125,6 +1200,7 @@ export const useDocumentOperations = (props) => {
1125
1200
  commentFromWgMenuItem(false),
1126
1201
  relationsMenuItem(true),
1127
1202
  removeFromWgMenuItem(SDKUI_Localizator.RemoveFromWorkgroup),
1203
+ ...(!isMobile ? [printMenuItem()] : [])
1128
1204
  ].sort((a, b) => a.name.localeCompare(b.name));
1129
1205
  return [
1130
1206
  ...sortedItems,
@@ -1148,6 +1224,7 @@ export const useDocumentOperations = (props) => {
1148
1224
  downloadFileMenuItem(),
1149
1225
  downloadXMLAttachmentsMenuItem(),
1150
1226
  ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : []),
1227
+ ...(!isMobile ? [printMenuItem()] : [])
1151
1228
  ]
1152
1229
  },
1153
1230
  signatureMenuItem(),
@@ -1173,7 +1250,8 @@ export const useDocumentOperations = (props) => {
1173
1250
  ...(SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ? [createContextualTaskMenuItem()] : []),
1174
1251
  downloadFileMenuItem(),
1175
1252
  downloadXMLAttachmentsMenuItem(),
1176
- ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : [])
1253
+ ...(selectedDcmtInfos.length > 0 && isPdfEditorAvailable(dtd, selectedDcmtInfos[0]?.FILEEXT) && onOpenPdfEditorRequest ? [pdfEditorMenuItem(onOpenPdfEditorRequest)] : []),
1254
+ ...(!isMobile ? [printMenuItem()] : [])
1177
1255
  ]
1178
1256
  },
1179
1257
  signatureMenuItem(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.21.0-dev2.57",
3
+ "version": "6.21.0-dev2.59",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",